1 /* -*- linux-c -*-
2 Copyright (C) 2004 Tom Szilagyi
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 of the License, or
7 (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
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., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 $Id: gui_main.c 1310 2015-07-26 19:11:40Z tszilagyi $
19 */
20
21 #include <config.h>
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <sys/stat.h>
28 #include <errno.h>
29 #include <time.h>
30 #include <glib.h>
31 #include <glib-object.h>
32 #include <gdk/gdk.h>
33 #include <gdk/gdkkeysyms.h>
34 #include <gdk-pixbuf/gdk-pixbuf.h>
35 #include <gtk/gtk.h>
36
37 #ifdef HAVE_JACK
38 #include <jack/jack.h>
39 #endif /* HAVE_JACK */
40
41 #ifdef HAVE_SRC
42 #include <samplerate.h>
43 #endif /* HAVE_SRC */
44
45 #ifdef HAVE_LADSPA
46 #include <lrdf.h>
47 #include "plugin.h"
48 #endif /* HAVE_LADSPA */
49
50 #ifdef HAVE_CDDA
51 #include "cdda.h"
52 #include "store_cdda.h"
53 #endif /* HAVE_CDDA */
54
55 #ifdef HAVE_JACK_MGMT
56 #include "ports.h"
57 #endif /* HAVE_JACK_MGMT */
58
59 #ifdef HAVE_LOOP
60 #include "loop_bar.h"
61 #endif /* HAVE_LOOP */
62
63 #ifdef HAVE_PODCAST
64 #include "store_podcast.h"
65 #endif /* HAVE_PODCAST */
66
67 #include "athread.h"
68 #include "ext_lua.h"
69 #include "common.h"
70 #include "utils.h"
71 #include "utils_gui.h"
72 #include "core.h"
73 #include "rb.h"
74 #include "cover.h"
75 #include "transceiver.h"
76 #include "decoder/file_decoder.h"
77 #include "about.h"
78 #include "options.h"
79 #include "skin.h"
80 #include "playlist.h"
81 #include "file_info.h"
82 #include "i18n.h"
83 #include "httpc.h"
84 #include "metadata.h"
85 #include "metadata_api.h"
86 #include "music_browser.h"
87 #include "version.h"
88 #include "gui_main.h"
89
90
91 /* receive at most this much remote messages in one run of timeout_callback() */
92 #define MAX_RCV_COUNT 32
93
94 /* period of main timeout callback [ms] */
95 #define TIMEOUT_PERIOD 100
96
97 extern options_t options;
98
99 char pl_color_active[14];
100 char pl_color_inactive[14];
101
102 PangoFontDescription *fd_playlist;
103 PangoFontDescription *fd_browser;
104 PangoFontDescription *fd_bigtimer;
105 PangoFontDescription *fd_smalltimer;
106 PangoFontDescription *fd_songtitle;
107 PangoFontDescription *fd_songinfo;
108 PangoFontDescription *fd_statusbar;
109
110 /* Communication between gui thread and disk thread */
111 extern AQUALUNG_MUTEX_DECLARE(disk_thread_lock)
112 extern AQUALUNG_COND_DECLARE(disk_thread_wake)
113 extern rb_t * rb_gui2disk;
114 extern rb_t * rb_disk2gui;
115
116 #ifdef HAVE_JACK
117 extern jack_client_t * jack_client;
118 extern char * client_name;
119 extern int jack_is_shutdown;
120 extern char * jack_shutdown_reason;
121 #endif /* HAVE_JACK */
122
123 extern int aqualung_socket_fd;
124 extern int aqualung_session_id;
125
126 extern GtkListStore * running_store;
127
128 extern GtkWidget * plist_menu;
129 extern GtkWidget * playlist_notebook;
130
131 void init_plist_menu(GtkWidget *append_menu);
132
133 /* file decoder instance used by the disk thread - use with caution! */
134 extern file_decoder_t * fdec;
135
136 /* the physical name of the file that is playing, or a '\0'. */
137 char current_file[MAXLEN];
138
139 /* embedded picture in the file that is playing */
140 void * embedded_picture = NULL;
141 int embedded_picture_size = 0;
142
143 /* default window title */
144 char win_title[MAXLEN];
145
146 /* current application title when a file is playing */
147 char playing_app_title[MAXLEN];
148
149 char send_cmd, recv_cmd;
150 fileinfo_t fileinfo;
151 status_t status;
152 unsigned long out_SR;
153 extern int output;
154 unsigned long rb_size;
155 unsigned long long total_samples;
156 unsigned long long sample_pos;
157
158 /* this flag set to 1 in core.c if --play
159 for current instance is specified. */
160 int immediate_start = 0;
161
162 /* Whether to stop playing after currently played song ends. */
163 int stop_after_current_song = 0;
164
165 /* Whether the systray is used in this instance */
166 int systray_used = 0;
167
168 /* the tab to load remote files */
169 char * tab_name;
170
171 /* volume & balance sliders */
172 double vol_prev = 0.0f;
173 double vol_lin = 1.0f;
174 double bal_prev = 0.0f;
175 extern double left_gain;
176 extern double right_gain;
177
178 /* label/display data */
179 fileinfo_t disp_info;
180 unsigned long disp_samples;
181 unsigned long disp_pos;
182
183 GtkWidget * main_window;
184
185 extern GtkWidget * browser_window;
186 extern GtkWidget * playlist_window;
187 extern GtkWidget * vol_window;
188 extern GtkWidget * browser_paned;
189
190 extern int music_store_changed;
191
192 #ifdef HAVE_LADSPA
193 extern int fxbuilder_on;
194 extern GtkWidget * fxbuilder_window;
195 GtkWidget * plugin_toggle;
196 #endif /* HAVE_LADSPA */
197
198 GtkObject * adj_pos;
199 GtkObject * adj_vol;
200 GtkObject * adj_bal;
201 GtkWidget * scale_pos;
202 GtkWidget * scale_vol;
203 GtkWidget * scale_bal;
204
205 GtkWidget * vbox_sep;
206
207 #ifdef HAVE_LOOP
208 GtkWidget * loop_bar;
209 #endif /* HAVE_LOOP */
210
211 GtkWidget * time_labels[3];
212 int refresh_time_label = 1;
213
214
215 gulong play_id;
216 gulong pause_id;
217
218 GtkWidget * play_button;
219 GtkWidget * pause_button;
220 GtkWidget * prev_button;
221 GtkWidget * stop_button;
222 GtkWidget * next_button;
223 GtkWidget * repeat_button;
224 GtkWidget * repeat_all_button;
225 GtkWidget * shuffle_button;
226
227 GtkWidget * label_title;
228 GtkWidget * label_format;
229 GtkWidget * label_samplerate;
230 GtkWidget * label_bps;
231 GtkWidget * label_mono;
232 GtkWidget * label_output;
233 GtkWidget * label_src_type;
234
235 int x_scroll_start;
236 int x_scroll_pos;
237 int scroll_btn;
238
239 GtkWidget * musicstore_toggle;
240 GtkWidget * playlist_toggle;
241
242 guint timeout_tag;
243 guint vol_bal_timeout_tag = 0;
244
245 gint timeout_callback(gpointer data);
246
247 /* whether we are refreshing the scale on STATUS commands recv'd from disk thread */
248 int refresh_scale = 1;
249 /* suppress scale refreshing after seeking (discard this much STATUS packets).
250 Prevents position slider to momentarily jump back to original position. */
251 int refresh_scale_suppress = 0;
252
253 /* whether we allow seeks (depending on if we are at the end of the track) */
254 int allow_seeks = 1;
255
256 /* controls when to load the new file's data on display */
257 int fresh_new_file = 1;
258 int fresh_new_file_prev = 1;
259
260 /* whether we have a file loaded, that is currently playing (or paused) */
261 int is_file_loaded = 0;
262
263 /* whether playback is paused */
264 int is_paused = 0;
265
266 /* Whether the next key binding should be for a custom key binding */
267 int custom_main_keybinding_expected = 0;
268
269 /* popup menu for configuration */
270 GtkWidget * conf_menu;
271 GtkWidget * conf__options;
272 GtkWidget * conf__skin;
273 GtkWidget * conf__fileinfo;
274 GtkWidget * conf__about;
275 GtkWidget * conf__quit;
276 #ifdef HAVE_JACK_MGMT
277 extern GtkWidget * ports_window;
278 GtkWidget * conf__jack;
279 #endif /* HAVE_JACK_MGMT */
280
281 GtkWidget * bigtimer_label;
282 GtkWidget * smalltimer_label_1;
283 GtkWidget * smalltimer_label_2;
284
285 /* systray stuff */
286 #ifdef HAVE_SYSTRAY
287
288 GtkStatusIcon * systray_icon;
289
290 GtkWidget * systray_menu;
291 GtkWidget * systray__show;
292 GtkWidget * systray__hide;
293 GtkWidget * systray__play;
294 GtkWidget * systray__pause;
295 GtkWidget * systray__stop;
296 GtkWidget * systray__prev;
297 GtkWidget * systray__next;
298 GtkWidget * systray__quit;
299
300 int wm_not_systray_capable = 0;
301
302 void hide_all_windows(gpointer data);
303
304 /* Used for not reacting too quickly to consecutive mouse wheel events */
305 guint32 last_systray_scroll_event_time = 0;
306
307 #endif /* HAVE_SYSTRAY */
308
309 int systray_main_window_on = 1;
310
311 void create_main_window(char * skin_path);
312
313 void toggle_noeffect(int id, int state);
314
315 gint prev_event(GtkWidget * widget, GdkEvent * event, gpointer data);
316 gint play_event(GtkWidget * widget, GdkEvent * event, gpointer data);
317 gint pause_event(GtkWidget * widget, GdkEvent * event, gpointer data);
318 gint stop_event(GtkWidget * widget, GdkEvent * event, gpointer data);
319 gint next_event(GtkWidget * widget, GdkEvent * event, gpointer data);
320
321 void load_config(void);
322
323 void playlist_toggled(GtkWidget * widget, gpointer data);
324
325 GtkWidget * cover_align;
326 GtkWidget * c_event_box;
327 GtkWidget * cover_image_area;
328 gint cover_show_flag;
329
330 extern char fileinfo_name[MAXLEN];
331 extern char fileinfo_file[MAXLEN];
332
333 extern GtkWidget * plist__fileinfo;
334
335 extern gint playlist_state;
336 extern gint browser_state;
337
338
339 void
try_waking_disk_thread(void)340 try_waking_disk_thread(void) {
341
342 if (AQUALUNG_MUTEX_TRYLOCK(disk_thread_lock)) {
343 AQUALUNG_COND_SIGNAL(disk_thread_wake)
344 AQUALUNG_MUTEX_UNLOCK(disk_thread_lock)
345 }
346 }
347
348
349 void
set_title_label(char * str)350 set_title_label(char * str) {
351
352 gchar default_title[MAXLEN];
353 char tmp[MAXLEN];
354
355 tmp[0] = '\0';
356
357 if (is_file_loaded) {
358 /* Remember current title. */
359 strncpy(playing_app_title, str, MAXLEN-1);
360
361 gtk_label_set_text(GTK_LABEL(label_title), str);
362 if (options.show_sn_title) {
363 if (stop_after_current_song) {
364 strncat(tmp, "[", MAXLEN-1);
365 strncat(tmp, _("STOPPING"), MAXLEN-1);
366 strncat(tmp, "] ", MAXLEN-1);
367 }
368 strncat(tmp, str, MAXLEN-1);
369 strncat(tmp, " - ", MAXLEN-1);
370 strncat(tmp, win_title, MAXLEN-1);
371 gtk_window_set_title(GTK_WINDOW(main_window), tmp);
372 #ifdef HAVE_SYSTRAY
373 if (systray_used) {
374 aqualung_status_icon_set_tooltip_text(systray_icon, tmp);
375 }
376 #endif /* HAVE_SYSTRAY */
377 } else {
378 gtk_window_set_title(GTK_WINDOW(main_window), win_title);
379 #ifdef HAVE_SYSTRAY
380 if (systray_used) {
381 aqualung_status_icon_set_tooltip_text(systray_icon, win_title);
382 }
383 #endif /* HAVE_SYSTRAY */
384 }
385 } else {
386 sprintf(default_title, "Aqualung %s", AQUALUNG_VERSION);
387 gtk_label_set_text(GTK_LABEL(label_title), default_title);
388 gtk_window_set_title(GTK_WINDOW(main_window), win_title);
389 #ifdef HAVE_SYSTRAY
390 if (systray_used) {
391 aqualung_status_icon_set_tooltip_text(systray_icon, win_title);
392 }
393 #endif /* HAVE_SYSTRAY */
394 }
395 }
396
397 void
hide_cover_thumbnail(void)398 hide_cover_thumbnail(void) {
399 cover_show_flag = 0;
400 gtk_widget_hide(cover_image_area);
401 gtk_widget_hide(c_event_box);
402 gtk_widget_hide(cover_align);
403 }
404
405 void
set_format_label(char * format_str)406 set_format_label(char * format_str) {
407
408 if (!is_file_loaded) {
409 gtk_label_set_text(GTK_LABEL(label_format), "");
410 } else {
411 gtk_label_set_text(GTK_LABEL(label_format), format_str);
412 }
413 }
414
415
416 void
format_bps_label(int bps,int format_flags,char * str)417 format_bps_label(int bps, int format_flags, char * str) {
418
419 if (bps == 0) {
420 strcpy(str, "N/A kbit/s");
421 return;
422 }
423
424 if (format_flags & FORMAT_VBR) {
425 sprintf(str, "%.1f kbit/s VBR", bps/1000.0);
426 } else {
427 if (format_flags & FORMAT_UBR) {
428 sprintf(str, "%.1f kbit/s UBR", bps/1000.0);
429 } else {
430 sprintf(str, "%.1f kbit/s", bps/1000.0);
431 }
432 }
433 }
434
435 void
set_bps_label(int bps,int format_flags)436 set_bps_label(int bps, int format_flags) {
437
438 char str[MAXLEN];
439
440 format_bps_label(bps, format_flags, str);
441
442 if (is_file_loaded) {
443 gtk_label_set_text(GTK_LABEL(label_bps), str);
444 } else {
445 gtk_label_set_text(GTK_LABEL(label_bps), "");
446 }
447 }
448
449
450 void
set_samplerate_label(int sr)451 set_samplerate_label(int sr) {
452
453 char str[MAXLEN];
454
455 snprintf(str, MAXLEN-1, "%d Hz", sr);
456
457 if (is_file_loaded) {
458 gtk_label_set_text(GTK_LABEL(label_samplerate), str);
459 } else {
460 gtk_label_set_text(GTK_LABEL(label_samplerate), "");
461 }
462 }
463
464
465 void
set_mono_label(int is_mono)466 set_mono_label(int is_mono) {
467
468 if (is_file_loaded) {
469 if (is_mono) {
470 gtk_label_set_text(GTK_LABEL(label_mono), _("MONO"));
471 } else {
472 gtk_label_set_text(GTK_LABEL(label_mono), _("STEREO"));
473 }
474 } else {
475 gtk_label_set_text(GTK_LABEL(label_mono), "");
476 }
477 }
478
479
480
481 void
set_output_label(int output,int out_SR)482 set_output_label(int output, int out_SR) {
483
484 char str[MAXLEN];
485
486 switch (output) {
487 #ifdef HAVE_PULSE
488 case PULSE_DRIVER:
489 snprintf(str, MAXLEN-1, "%s PulseAudio @ %d Hz", _("Output:"), out_SR);
490 break;
491 #endif /* HAVE_PULSE */
492 #ifdef HAVE_SNDIO
493 case SNDIO_DRIVER:
494 snprintf(str, MAXLEN-1, "%s sndio @ %d Hz", _("Output:"), out_SR);
495 break;
496 #endif /* HAVE_SNDIO */
497 #ifdef HAVE_OSS
498 case OSS_DRIVER:
499 snprintf(str, MAXLEN-1, "%s OSS @ %d Hz", _("Output:"), out_SR);
500 break;
501 #endif /* HAVE_OSS */
502 #ifdef HAVE_ALSA
503 case ALSA_DRIVER:
504 snprintf(str, MAXLEN-1, "%s ALSA @ %d Hz", _("Output:"), out_SR);
505 break;
506 #endif /* HAVE_ALSA */
507 #ifdef HAVE_JACK
508 case JACK_DRIVER:
509 snprintf(str, MAXLEN-1, "%s JACK @ %d Hz", _("Output:"), out_SR);
510 break;
511 #endif /* HAVE_JACK */
512 #ifdef HAVE_WINMM
513 case WIN32_DRIVER:
514 snprintf(str, MAXLEN-1, "%s Win32 @ %d Hz", _("Output:"), out_SR);
515 break;
516 #endif /* HAVE_WINMM */
517 default:
518 strncpy(str, _("No output"), MAXLEN-1);
519 break;
520 }
521
522 gtk_label_set_text(GTK_LABEL(label_output), str);
523 }
524
525
526
527 void
set_src_type_label(int src_type)528 set_src_type_label(int src_type) {
529
530 char str[MAXLEN];
531
532 strcpy(str, _("SRC Type: "));
533 #ifdef HAVE_SRC
534 strcat(str, src_get_name(src_type));
535 #else
536 strcat(str, _("None"));
537 #endif /* HAVE_SRC */
538
539 gtk_label_set_text(GTK_LABEL(label_src_type), str);
540 }
541
542
543 void
refresh_time_displays(void)544 refresh_time_displays(void) {
545
546 char str[MAXLEN];
547
548 if (is_file_loaded) {
549 if (refresh_time_label || options.time_idx[0] != 0) {
550 sample2time(disp_info.sample_rate, disp_pos, str, 0);
551 gtk_label_set_text(GTK_LABEL(time_labels[0]), str);
552
553 }
554
555 if (refresh_time_label || options.time_idx[0] != 1) {
556 if (disp_samples == 0) {
557 strcpy(str, " N/A ");
558 } else {
559 sample2time(disp_info.sample_rate, disp_samples - disp_pos, str, 1);
560 }
561 gtk_label_set_text(GTK_LABEL(time_labels[1]), str);
562
563 }
564
565 if (refresh_time_label || options.time_idx[0] != 2) {
566 if (disp_samples == 0) {
567 strcpy(str, " N/A ");
568 } else {
569 sample2time(disp_info.sample_rate, disp_samples, str, 0);
570 }
571 gtk_label_set_text(GTK_LABEL(time_labels[2]), str);
572
573 }
574 } else {
575 int i;
576 for (i = 0; i < 3; i++) {
577 gtk_label_set_text(GTK_LABEL(time_labels[i]), " 00:00 ");
578 }
579 }
580 }
581
582 #ifdef HAVE_LOOP
583
584 void
loop_bar_update_tooltip(void)585 loop_bar_update_tooltip(void) {
586
587 if (options.enable_tooltips) {
588 char str[MAXLEN];
589
590 if (is_file_loaded) {
591 char start[32];
592 char end[32];
593 sample2time(disp_info.sample_rate, total_samples * options.loop_range_start, start, 0);
594 sample2time(disp_info.sample_rate, total_samples * options.loop_range_end, end, 0);
595 snprintf(str, MAXLEN-1, _("Loop range: %d-%d%% [%s - %s]"),
596 (int)(100 * options.loop_range_start),
597 (int)(100 * options.loop_range_end),
598 start, end);
599 } else {
600 snprintf(str, MAXLEN-1, _("Loop range: %d-%d%%"),
601 (int)(100 * options.loop_range_start),
602 (int)(100 * options.loop_range_end));
603 }
604
605 aqualung_widget_set_tooltip_text(loop_bar, str);
606 }
607 }
608
609 void
loop_range_changed_cb(AqualungLoopBar * bar,float start,float end,gpointer data)610 loop_range_changed_cb(AqualungLoopBar * bar, float start, float end, gpointer data) {
611
612 options.loop_range_start = start;
613 options.loop_range_end = end;
614 loop_bar_update_tooltip();
615 }
616
617 #endif /* HAVE_LOOP */
618
619 void
refresh_displays(void)620 refresh_displays(void) {
621
622 GtkTreePath * p;
623 GtkTreeIter iter;
624 playlist_t * pl;
625
626 refresh_time_displays();
627
628 #ifdef HAVE_LOOP
629 loop_bar_update_tooltip();
630 #endif /* HAVE_LOOP */
631
632 set_format_label(disp_info.format_str);
633 set_samplerate_label(disp_info.sample_rate);
634 set_bps_label(disp_info.bps, disp_info.format_flags);
635 set_mono_label(disp_info.is_mono);
636 set_output_label(output, out_SR);
637 set_src_type_label(options.src_type);
638
639 if ((pl = playlist_get_playing()) == NULL) {
640 if ((pl = playlist_get_current()) == NULL) {
641 set_title_label("");
642 hide_cover_thumbnail();
643 return;
644 }
645 }
646
647 p = playlist_get_playing_path(pl);
648 if (p != NULL) {
649 playlist_data_t * pldata;
650
651 gtk_tree_model_get_iter(GTK_TREE_MODEL(pl->store), &iter, p);
652 gtk_tree_model_get(GTK_TREE_MODEL(pl->store), &iter, PL_COL_DATA, &pldata, -1);
653 gtk_tree_path_free(p);
654
655 if (!httpc_is_url(pldata->file) && !options.use_ext_title_format) {
656 char list_str[MAXLEN];
657 playlist_data_get_display_name(list_str, pldata);
658 set_title_label(list_str);
659 } else if (!is_file_loaded) {
660 char * name;
661 gtk_tree_model_get(GTK_TREE_MODEL(pl->store), &iter, PL_COL_NAME, &name, -1);
662 set_title_label(name);
663 g_free(name);
664 }
665
666 if (is_file_loaded) {
667 if (!options.dont_show_cover) {
668 if (embedded_picture != NULL && (find_cover_filename(pldata->file) == NULL || !options.use_external_cover_first)) {
669 display_cover_from_binary(cover_image_area, c_event_box, cover_align, 48, 48,
670 embedded_picture, embedded_picture_size, TRUE, TRUE);
671 } else {
672 if (options.show_cover_for_ms_tracks_only) {
673 if (IS_PL_COVER(pldata)) {
674 display_cover(cover_image_area, c_event_box, cover_align,
675 48, 48, pldata->file, TRUE, TRUE);
676 } else {
677 hide_cover_thumbnail();
678 }
679 } else {
680 display_cover(cover_image_area, c_event_box, cover_align,
681 48, 48, pldata->file, TRUE, TRUE);
682 }
683 }
684 }
685 }
686 } else if (!is_file_loaded) {
687 set_title_label("");
688 hide_cover_thumbnail();
689 }
690 }
691
692
693 void
zero_displays(void)694 zero_displays(void) {
695
696 disp_info.total_samples = 0;
697 disp_info.sample_rate = 0;
698 disp_info.channels = 2;
699 disp_info.is_mono = 0;
700 disp_info.bps = 0;
701
702 disp_samples = 0;
703 disp_pos = 0;
704
705 refresh_displays();
706 }
707
708
709 void
save_window_position(void)710 save_window_position(void) {
711
712 gtk_window_get_position(GTK_WINDOW(main_window), &options.main_pos_x, &options.main_pos_y);
713
714 if (!options.playlist_is_embedded && options.playlist_on) {
715 gtk_window_get_position(GTK_WINDOW(playlist_window), &options.playlist_pos_x, &options.playlist_pos_y);
716 }
717
718 if (options.browser_on) {
719 gtk_window_get_position(GTK_WINDOW(browser_window), &options.browser_pos_x, &options.browser_pos_y);
720 }
721
722 gtk_window_get_size(GTK_WINDOW(main_window), &options.main_size_x, &options.main_size_y);
723 gtk_window_get_size(GTK_WINDOW(browser_window), &options.browser_size_x, &options.browser_size_y);
724
725 if (!options.playlist_is_embedded) {
726 gtk_window_get_size(GTK_WINDOW(playlist_window), &options.playlist_size_x, &options.playlist_size_y);
727 } else {
728 options.playlist_size_x = playlist_window->allocation.width;
729 options.playlist_size_y = playlist_window->allocation.height;
730 }
731
732 if (!options.hide_comment_pane) {
733 options.browser_paned_pos = gtk_paned_get_position(GTK_PANED(browser_paned));
734 }
735 }
736
737
738 void
restore_window_position(void)739 restore_window_position(void) {
740
741 gtk_window_move(GTK_WINDOW(main_window), options.main_pos_x, options.main_pos_y);
742 gtk_window_move(GTK_WINDOW(browser_window), options.browser_pos_x, options.browser_pos_y);
743 if (!options.playlist_is_embedded) {
744 gtk_window_move(GTK_WINDOW(playlist_window), options.playlist_pos_x, options.playlist_pos_y);
745 }
746
747 gtk_window_resize(GTK_WINDOW(main_window), options.main_size_x, options.main_size_y);
748 gtk_window_resize(GTK_WINDOW(browser_window), options.browser_size_x, options.browser_size_y);
749 if (!options.playlist_is_embedded) {
750 gtk_window_resize(GTK_WINDOW(playlist_window), options.playlist_size_x, options.playlist_size_y);
751 }
752
753 if (!options.hide_comment_pane) {
754 gtk_paned_set_position(GTK_PANED(browser_paned), options.browser_paned_pos);
755 }
756 }
757
758
759 gboolean
main_window_close(GtkWidget * widget,GdkEvent * event,gpointer data)760 main_window_close(GtkWidget * widget, GdkEvent * event, gpointer data) {
761
762 send_cmd = CMD_FINISH;
763 rb_write(rb_gui2disk, &send_cmd, 1);
764 try_waking_disk_thread();
765
766 #ifdef HAVE_CDDA
767 cdda_shutdown();
768 #endif /* HAVE_CDDA */
769
770 if (systray_main_window_on) {
771 save_window_position();
772 }
773
774 save_config();
775
776 #ifdef HAVE_LADSPA
777 save_plugin_data();
778 lrdf_cleanup();
779 #endif /* HAVE_LADSPA */
780
781 #ifdef HAVE_SYSTRAY
782 if (systray_used) {
783 gtk_status_icon_set_visible(GTK_STATUS_ICON(systray_icon), FALSE);
784 }
785 #endif /* HAVE_SYSTRAY */
786
787 if (options.auto_save_playlist) {
788 char playlist_name[MAXLEN];
789
790 snprintf(playlist_name, MAXLEN-1, "%s/%s", options.confdir, "playlist.xml");
791 playlist_save_all(playlist_name);
792 }
793
794 pango_font_description_free(fd_playlist);
795 pango_font_description_free(fd_browser);
796
797 finalize_options();
798
799 gtk_main_quit();
800
801 return FALSE;
802 }
803
804 void
main_window_closing(void)805 main_window_closing(void) {
806
807 if (music_store_changed) {
808 GtkWidget * dialog;
809 int resp;
810
811 dialog = gtk_message_dialog_new(GTK_WINDOW(main_window),
812 GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
813 GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE,
814 _("One or more stores in Music Store have been modified.\n"
815 "Do you want to save them before exiting?"));
816
817 gtk_dialog_add_buttons(GTK_DIALOG(dialog),
818 _("Save"), GTK_RESPONSE_YES,
819 _("Discard changes"), GTK_RESPONSE_NO,
820 _("Do not exit"), GTK_RESPONSE_CANCEL,
821 NULL);
822
823 gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
824 gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_YES);
825 gtk_container_set_border_width(GTK_CONTAINER(dialog), 5);
826 gtk_window_set_title(GTK_WINDOW(dialog), _("Quit"));
827
828 resp = aqualung_dialog_run(GTK_DIALOG(dialog));
829 gtk_widget_destroy(dialog);
830
831 if (resp == GTK_RESPONSE_CANCEL) {
832 return;
833 }
834
835 if (resp == GTK_RESPONSE_YES) {
836 music_store_save_all();
837 }
838 }
839
840 main_window_close(NULL, NULL, NULL);
841 }
842
843 gboolean
main_window_event(GtkWidget * widget,GdkEvent * event,gpointer data)844 main_window_event(GtkWidget * widget, GdkEvent * event, gpointer data) {
845
846 if (event->type == GDK_DELETE) {
847 #ifdef HAVE_SYSTRAY
848 if (systray_used) {
849 hide_all_windows(NULL);
850 } else {
851 main_window_closing();
852 }
853 #else
854 main_window_closing();
855 #endif /* HAVE_SYSTRAY */
856 return TRUE;
857 }
858
859 return FALSE;
860 }
861
862 void
main_window_resize(void)863 main_window_resize(void) {
864
865 if (options.playlist_is_embedded && !options.playlist_on) {
866 gtk_window_resize(GTK_WINDOW(main_window), options.main_size_x,
867 options.main_size_y - 14 - 6 - 6 -
868 playlist_window->allocation.height);
869 }
870
871 if (!options.playlist_is_embedded) {
872 gtk_window_resize(GTK_WINDOW(main_window),
873 options.main_size_x, options.main_size_y - 14 - 6);
874 }
875 }
876
877 /***********************************************************************************/
878
879
880 void
conf__options_cb(gpointer data)881 conf__options_cb(gpointer data) {
882
883 create_options_window();
884 }
885
886
887 void
conf__skin_cb(gpointer data)888 conf__skin_cb(gpointer data) {
889
890 create_skin_window();
891 }
892
893
894 #ifdef HAVE_JACK_MGMT
895 void
conf__jack_cb(gpointer data)896 conf__jack_cb(gpointer data) {
897
898 port_setup_dialog();
899 }
900 #endif /* HAVE_JACK_MGMT */
901
902
903 void
conf__fileinfo_cb(gpointer data)904 conf__fileinfo_cb(gpointer data) {
905
906 playlist_t * pl;
907 GtkTreePath * p;
908 GtkTreeIter iter;
909
910 if (is_file_loaded) {
911 pl = playlist_get_playing();
912 } else {
913 pl = playlist_get_current();
914 }
915 if (pl == NULL) return;
916 p = playlist_get_playing_path(pl);
917 if (p == NULL) return;
918 gtk_tree_model_get_iter(GTK_TREE_MODEL(pl->store), &iter, p);
919 gtk_tree_path_free(p);
920 show_file_info(GTK_TREE_MODEL(pl->store), iter, playlist_model_func, 0, FALSE, TRUE);
921 }
922
923
924 void
conf__about_cb(gpointer data)925 conf__about_cb(gpointer data) {
926
927 create_about_window();
928 }
929
930
931 void
conf__quit_cb(gpointer data)932 conf__quit_cb(gpointer data) {
933
934 main_window_closing();
935 }
936
937
938 gint
vol_bal_timeout_callback(gpointer data)939 vol_bal_timeout_callback(gpointer data) {
940
941 refresh_time_label = 1;
942 vol_bal_timeout_tag = 0;
943 refresh_time_displays();
944
945 return FALSE;
946 }
947
948
949 void
musicstore_toggled(GtkWidget * widget,gpointer data)950 musicstore_toggled(GtkWidget * widget, gpointer data) {
951
952 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
953 show_music_browser();
954 } else {
955 hide_music_browser();
956 }
957 }
958
959
960 void
playlist_toggled(GtkWidget * widget,gpointer data)961 playlist_toggled(GtkWidget * widget, gpointer data) {
962
963 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
964 show_playlist();
965 } else {
966 hide_playlist();
967 }
968 }
969
970
971 #ifdef HAVE_LADSPA
972 void
plugin_toggled(GtkWidget * widget,gpointer data)973 plugin_toggled(GtkWidget * widget, gpointer data) {
974
975 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget))) {
976 show_fxbuilder();
977 } else {
978 hide_fxbuilder();
979 }
980 }
981 #endif /* HAVE_LADSPA */
982
983 void
toggle_stop_after_current_song()984 toggle_stop_after_current_song() {
985
986 if (is_file_loaded) {
987 stop_after_current_song = !stop_after_current_song;
988 set_title_label(playing_app_title);
989 }
990 }
991
992 void
move_song_position_slider(GtkScrollType scroll_type)993 move_song_position_slider(GtkScrollType scroll_type) {
994
995 if (is_file_loaded && allow_seeks && total_samples != 0) {
996 /* 5 seconds step */
997 gdouble step = 5 * 100.0f * disp_info.sample_rate / total_samples;
998 gdouble pos = gtk_adjustment_get_value(GTK_ADJUSTMENT(adj_pos));
999
1000 refresh_scale = 0;
1001 if (scroll_type == GTK_SCROLL_STEP_FORWARD) {
1002 pos += step;
1003 if (pos > 100.0) {
1004 pos = 100.0;
1005 }
1006 gtk_adjustment_set_value(GTK_ADJUSTMENT(adj_pos), pos);
1007 } else if (scroll_type == GTK_SCROLL_STEP_BACKWARD) {
1008 pos -= step;
1009 if (pos < 0) {
1010 pos = 0.0;
1011 }
1012 gtk_adjustment_set_value(GTK_ADJUSTMENT(adj_pos), pos);
1013 }
1014 }
1015 }
1016
1017 void
seek_song(void)1018 seek_song(void) {
1019
1020 if (is_file_loaded && allow_seeks && refresh_scale == 0 && total_samples != 0) {
1021 seek_t seek;
1022
1023 refresh_scale = 1;
1024 send_cmd = CMD_SEEKTO;
1025 seek.seek_to_pos = gtk_adjustment_get_value(GTK_ADJUSTMENT(adj_pos)) / 100.0f * total_samples;
1026 rb_write(rb_gui2disk, &send_cmd, 1);
1027 rb_write(rb_gui2disk, (char *)&seek, sizeof(seek_t));
1028 try_waking_disk_thread();
1029 refresh_scale_suppress = 2;
1030 }
1031 }
1032
1033 void
change_volume_or_balance(GtkWidget * slider_widget,GtkScrollType scroll_type)1034 change_volume_or_balance(GtkWidget * slider_widget, GtkScrollType scroll_type) {
1035
1036 refresh_time_label = 0;
1037 if (vol_bal_timeout_tag) {
1038 g_source_remove(vol_bal_timeout_tag);
1039 }
1040
1041 vol_bal_timeout_tag = aqualung_timeout_add(1000, vol_bal_timeout_callback, NULL);
1042
1043 g_signal_emit_by_name(G_OBJECT(slider_widget), "move-slider",
1044 scroll_type, NULL);
1045 }
1046
1047 gint
main_window_key_pressed(GtkWidget * widget,GdkEventKey * event)1048 main_window_key_pressed(GtkWidget * widget, GdkEventKey * event) {
1049
1050 int playlist_tabs = gtk_notebook_get_n_pages(GTK_NOTEBOOK(playlist_notebook));
1051
1052 if (custom_main_keybinding_expected) {
1053 switch (event->keyval) {
1054 case GDK_Shift_L:
1055 case GDK_Shift_R:
1056 case GDK_Control_L:
1057 case GDK_Control_R:
1058 case GDK_Alt_L:
1059 case GDK_Alt_R:
1060 case GDK_Super_L:
1061 case GDK_Super_R:
1062 return FALSE;
1063 default:
1064 run_custom_main_keybinding(gdk_keyval_name(event->keyval), event->state);
1065 custom_main_keybinding_expected = 0;
1066 return TRUE;
1067 }
1068 }
1069
1070 switch (event->keyval) {
1071 case GDK_KP_Divide:
1072 case GDK_slash:
1073 if (event->state & GDK_MOD1_MASK) { /* ALT + KP_Divide */
1074 change_volume_or_balance(scale_bal, GTK_SCROLL_STEP_BACKWARD);
1075 } else {
1076 change_volume_or_balance(scale_vol, GTK_SCROLL_STEP_BACKWARD);
1077 }
1078 return TRUE;
1079 case GDK_KP_Multiply:
1080 case GDK_asterisk:
1081 if (event->state & GDK_MOD1_MASK) { /* ALT + KP_Multiply */
1082 change_volume_or_balance(scale_bal, GTK_SCROLL_STEP_FORWARD);
1083 } else {
1084 change_volume_or_balance(scale_vol, GTK_SCROLL_STEP_FORWARD);
1085 }
1086 return TRUE;
1087 case GDK_Right:
1088 move_song_position_slider(GTK_SCROLL_STEP_FORWARD);
1089 return TRUE;
1090 case GDK_Left:
1091 move_song_position_slider(GTK_SCROLL_STEP_BACKWARD);
1092 return TRUE;
1093 case GDK_b:
1094 case GDK_B:
1095 case GDK_period:
1096 case GDK_AudioNext:
1097 next_event(NULL, NULL, NULL);
1098 return TRUE;
1099 case GDK_z:
1100 case GDK_Z:
1101 if (event->state & GDK_CONTROL_MASK) {
1102 custom_main_keybinding_expected = 1;
1103 return TRUE;
1104 }
1105 case GDK_y:
1106 case GDK_Y:
1107 case GDK_comma:
1108 case GDK_AudioPrev:
1109 prev_event(NULL, NULL, NULL);
1110 return TRUE;
1111 case GDK_s:
1112 case GDK_S:
1113 if (event->state & GDK_MOD1_MASK) { /* ALT + s */
1114 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(musicstore_toggle),
1115 !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(musicstore_toggle)));
1116 } else {
1117 if (!(event->state & GDK_CONTROL_MASK)) {
1118 stop_event(NULL, NULL, NULL);
1119 } else {
1120 toggle_stop_after_current_song();
1121 }
1122 }
1123 return TRUE;
1124 case GDK_v:
1125 case GDK_V:
1126 if (!(event->state & GDK_CONTROL_MASK)) {
1127 stop_event(NULL, NULL, NULL);
1128 return TRUE;
1129 }
1130 break;
1131 case GDK_AudioStop:
1132 stop_event(NULL, NULL, NULL);
1133 return TRUE;
1134 case GDK_c:
1135 case GDK_C:
1136 case GDK_space:
1137 if (!(event->state & GDK_CONTROL_MASK)) {
1138 if (!options.combine_play_pause) {
1139 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pause_button),
1140 !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(pause_button)));
1141 } else if (is_file_loaded) {
1142 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(play_button),
1143 !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(play_button)));
1144 }
1145 return TRUE;
1146 }
1147 break;
1148 case GDK_p:
1149 case GDK_P:
1150 case GDK_AudioPlay:
1151 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(play_button),
1152 !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(play_button)));
1153 return TRUE;
1154 case GDK_i:
1155 case GDK_I:
1156 if (options.playlist_is_embedded) {
1157 return playlist_window_key_pressed(widget, event);
1158 } else {
1159 conf__fileinfo_cb(NULL);
1160 }
1161 break;
1162 case GDK_BackSpace:
1163 if (allow_seeks && total_samples != 0) {
1164 seek_t seek;
1165
1166 send_cmd = CMD_SEEKTO;
1167 seek.seek_to_pos = 0.0f;
1168 rb_write(rb_gui2disk, &send_cmd, 1);
1169 rb_write(rb_gui2disk, (char *)&seek, sizeof(seek_t));
1170 try_waking_disk_thread();
1171 refresh_scale_suppress = 2;
1172 }
1173
1174 if ((!options.combine_play_pause) && gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(pause_button))) {
1175 gtk_adjustment_set_value(GTK_ADJUSTMENT(adj_pos), 0.0f);
1176 }
1177 return TRUE;
1178 case GDK_l:
1179 case GDK_L:
1180 if (event->state & GDK_MOD1_MASK) { /* ALT + l */
1181 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(playlist_toggle),
1182 !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(playlist_toggle)));
1183 }
1184 return TRUE;
1185 case GDK_x:
1186 case GDK_X:
1187 if (event->state & GDK_CONTROL_MASK) {
1188 break;
1189 }
1190 if (event->state & GDK_MOD1_MASK) { /* ALT + x */
1191 #ifdef HAVE_LADSPA
1192 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(plugin_toggle),
1193 !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(plugin_toggle)));
1194 #endif /* HAVE_LADSPA */
1195 } else {
1196 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(play_button),
1197 !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(play_button)));
1198 }
1199 return TRUE;
1200 case GDK_q:
1201 case GDK_Q:
1202 if (event->state & GDK_CONTROL_MASK) { /* CTRL + q */
1203 main_window_closing();
1204 }
1205 return TRUE;
1206 case GDK_k:
1207 case GDK_K:
1208 if (!options.disable_skin_support_settings) {
1209 create_skin_window();
1210 }
1211 return TRUE;
1212 case GDK_o:
1213 case GDK_O:
1214 create_options_window();
1215 return TRUE;
1216 case GDK_1:
1217 if (event->state & GDK_MOD1_MASK) { /* ALT + 1 */
1218 if(playlist_tabs >= 1) {
1219 gtk_notebook_set_current_page(GTK_NOTEBOOK(playlist_notebook), 1-1);
1220 }
1221 } else {
1222 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(repeat_button))) {
1223 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(repeat_button), FALSE);
1224 } else {
1225 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(repeat_button), TRUE);
1226 }
1227 }
1228 return TRUE;
1229 case GDK_2:
1230 if (event->state & GDK_MOD1_MASK) { /* ALT + 2 */
1231 if(playlist_tabs >= 2) {
1232 gtk_notebook_set_current_page(GTK_NOTEBOOK(playlist_notebook), 2-1);
1233 }
1234 } else {
1235 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(repeat_all_button))) {
1236 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(repeat_all_button), FALSE);
1237 } else {
1238 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(repeat_all_button), TRUE);
1239 }
1240 }
1241 return TRUE;
1242 case GDK_3:
1243 if (event->state & GDK_MOD1_MASK) { /* ALT + 3 */
1244 if(playlist_tabs >= 3) {
1245 gtk_notebook_set_current_page(GTK_NOTEBOOK(playlist_notebook), 3-1);
1246 }
1247 } else {
1248 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(shuffle_button))) {
1249 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(shuffle_button), FALSE);
1250 } else {
1251 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(shuffle_button), TRUE);
1252 }
1253 }
1254 return TRUE;
1255 case GDK_4:
1256 case GDK_5:
1257 case GDK_6:
1258 case GDK_7:
1259 case GDK_8:
1260 case GDK_9:
1261 case GDK_0:
1262 if (event->state & GDK_MOD1_MASK) { /* ALT */
1263
1264 int val = event->keyval - GDK_0;
1265 val = (val == 0) ? 10 : val;
1266
1267 if(playlist_tabs >= val) {
1268 gtk_notebook_set_current_page(GTK_NOTEBOOK(playlist_notebook), val-1);
1269 }
1270 }
1271 return TRUE;
1272 #ifdef HAVE_SYSTRAY
1273 case GDK_Escape:
1274 if (systray_used) {
1275 hide_all_windows(NULL);
1276 }
1277 return TRUE;
1278 #endif /* HAVE_SYSTRAY */
1279
1280 #ifdef HAVE_LOOP
1281 case GDK_less:
1282 if (options.repeat_on && is_file_loaded) {
1283 float pos = (total_samples > 0) ? ((double)sample_pos / total_samples) : 0;
1284 aqualung_loop_bar_adjust_start(AQUALUNG_LOOP_BAR(loop_bar), pos);
1285 }
1286 return TRUE;
1287 case GDK_greater:
1288 if (options.repeat_on && is_file_loaded) {
1289 float pos = (total_samples > 0) ? ((double)sample_pos / total_samples) : 1;
1290 aqualung_loop_bar_adjust_end(AQUALUNG_LOOP_BAR(loop_bar), pos);
1291 }
1292 return TRUE;
1293 #endif /* HAVE_LOOP */
1294 }
1295
1296 if (options.playlist_is_embedded) {
1297 playlist_window_key_pressed(widget, event);
1298 }
1299
1300 return FALSE;
1301 }
1302
1303
1304 gint
main_window_key_released(GtkWidget * widget,GdkEventKey * event)1305 main_window_key_released(GtkWidget * widget, GdkEventKey * event) {
1306
1307 switch (event->keyval) {
1308 case GDK_Right:
1309 case GDK_Left:
1310 seek_song();
1311 break;
1312 }
1313
1314 return FALSE;
1315 }
1316
1317
1318 gint
main_window_focus_out(GtkWidget * widget,GdkEventFocus * event,gpointer data)1319 main_window_focus_out(GtkWidget * widget, GdkEventFocus * event, gpointer data) {
1320
1321 refresh_scale = 1;
1322
1323 return FALSE;
1324 }
1325
1326
1327 gint
main_window_state_changed(GtkWidget * widget,GdkEventWindowState * event,gpointer data)1328 main_window_state_changed(GtkWidget * widget, GdkEventWindowState * event, gpointer data) {
1329
1330 if (!options.united_minimization)
1331 return FALSE;
1332
1333 if (event->new_window_state == GDK_WINDOW_STATE_ICONIFIED) {
1334 if (options.browser_on) {
1335 gtk_window_iconify(GTK_WINDOW(browser_window));
1336 }
1337
1338 if (!options.playlist_is_embedded && options.playlist_on) {
1339 gtk_window_iconify(GTK_WINDOW(playlist_window));
1340 }
1341
1342 if (vol_window) {
1343 gtk_window_iconify(GTK_WINDOW(vol_window));
1344 }
1345 #ifdef HAVE_LADSPA
1346 if (fxbuilder_on) {
1347 GtkTreeIter iter;
1348 gpointer gp_instance;
1349 int i = 0;
1350
1351 gtk_window_iconify(GTK_WINDOW(fxbuilder_window));
1352
1353 while (gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(running_store), &iter, NULL, i) &&
1354 i < MAX_PLUGINS) {
1355 gtk_tree_model_get(GTK_TREE_MODEL(running_store), &iter, 1, &gp_instance, -1);
1356 gtk_widget_hide(((plugin_instance *)gp_instance)->window);
1357 ++i;
1358 }
1359 }
1360 #endif /* HAVE_LADSPA */
1361 }
1362
1363 if (event->new_window_state == 0) {
1364 if (options.browser_on) {
1365 gtk_window_deiconify(GTK_WINDOW(browser_window));
1366 }
1367
1368 if (!options.playlist_is_embedded && options.playlist_on) {
1369 gtk_window_deiconify(GTK_WINDOW(playlist_window));
1370 }
1371
1372 if (vol_window) {
1373 gtk_window_deiconify(GTK_WINDOW(vol_window));
1374 }
1375 #ifdef HAVE_LADSPA
1376 if (fxbuilder_on) {
1377 gtk_window_deiconify(GTK_WINDOW(fxbuilder_window));
1378 }
1379 #endif /* HAVE_LADSPA */
1380 }
1381 return FALSE;
1382 }
1383
1384
1385 gint
main_window_button_pressed(GtkWidget * widget,GdkEventButton * event,gpointer data)1386 main_window_button_pressed(GtkWidget * widget, GdkEventButton * event, gpointer data) {
1387
1388 if (event->button == 3) {
1389 if (options.playlist_is_embedded) {
1390 /* translate and crop event coordinates over playlist widget */
1391 event->x -= playlist_window->allocation.x;
1392 if (event->x > playlist_window->allocation.width) {
1393 event->x = -1;
1394 }
1395 event->y -= playlist_window->allocation.y;
1396 if (event->y > playlist_window->allocation.height) {
1397 event->y = -1;
1398 }
1399 return playlist_window_button_pressed(widget, event, playlist_get_current());
1400 }
1401 gtk_menu_popup(GTK_MENU(conf_menu), NULL, NULL, NULL, NULL,
1402 event->button, event->time);
1403 }
1404
1405 return TRUE;
1406 }
1407
1408
1409 static gint
scale_button_press_event(GtkWidget * widget,GdkEventButton * event)1410 scale_button_press_event(GtkWidget * widget, GdkEventButton * event) {
1411
1412 if (event->button == 3)
1413 return FALSE;
1414
1415 if (!is_file_loaded)
1416 return FALSE;
1417
1418 if (!allow_seeks)
1419 return FALSE;
1420
1421 if (total_samples == 0)
1422 return FALSE;
1423
1424 refresh_scale = 0;
1425 return FALSE;
1426 }
1427
1428
1429 static gint
scale_button_release_event(GtkWidget * widget,GdkEventButton * event)1430 scale_button_release_event(GtkWidget * widget, GdkEventButton * event) {
1431
1432 seek_t seek;
1433
1434 if (is_file_loaded) {
1435
1436 if (!allow_seeks)
1437 return FALSE;
1438
1439 if (total_samples == 0)
1440 return FALSE;
1441
1442 if (refresh_scale == 0) {
1443 refresh_scale = 1;
1444
1445 send_cmd = CMD_SEEKTO;
1446 seek.seek_to_pos = gtk_adjustment_get_value(GTK_ADJUSTMENT(adj_pos))
1447 / 100.0f * total_samples;
1448 rb_write(rb_gui2disk, &send_cmd, 1);
1449 rb_write(rb_gui2disk, (char *)&seek, sizeof(seek_t));
1450 try_waking_disk_thread();
1451 refresh_scale_suppress = 2;
1452 }
1453 }
1454
1455 return FALSE;
1456 }
1457
1458
1459 void
changed_pos(GtkAdjustment * adj,gpointer data)1460 changed_pos(GtkAdjustment * adj, gpointer data) {
1461 static int pos = -1;
1462
1463 if (!is_file_loaded) {
1464 gtk_adjustment_set_value(adj, 0.0f);
1465 }
1466
1467 if (options.enable_tooltips) {
1468 int newpos = (int)gtk_adjustment_get_value(adj);
1469 if (pos != newpos) {
1470 char str[32];
1471 snprintf(str, 31, _("Position: %d%%"), newpos);
1472 aqualung_widget_set_tooltip_text(scale_pos, str);
1473 pos = newpos;
1474 }
1475 }
1476 }
1477
1478
1479 gint
scale_vol_button_press_event(GtkWidget * widget,GdkEventButton * event)1480 scale_vol_button_press_event(GtkWidget * widget, GdkEventButton * event) {
1481
1482 char str[32];
1483 options.vol = gtk_adjustment_get_value(GTK_ADJUSTMENT(adj_vol));
1484
1485 if (event->state & GDK_SHIFT_MASK) { /* SHIFT */
1486 gtk_adjustment_set_value(GTK_ADJUSTMENT(adj_vol), 0);
1487 return TRUE;
1488 }
1489
1490 if (options.vol < -40.5f) {
1491 snprintf(str, 31, _("Mute"));
1492 } else {
1493 snprintf(str, 31, _("%d dB"), (int)options.vol);
1494 }
1495
1496 gtk_label_set_text(GTK_LABEL(time_labels[options.time_idx[0]]), str);
1497
1498 refresh_time_label = 0;
1499
1500 if (event->button == 3) {
1501 return TRUE;
1502 } else {
1503 return FALSE;
1504 }
1505 }
1506
1507
1508 void
changed_vol(GtkAdjustment * adj,gpointer date)1509 changed_vol(GtkAdjustment * adj, gpointer date) {
1510
1511 char str[32];
1512 char str2[32];
1513
1514 options.vol = (int)gtk_adjustment_get_value(GTK_ADJUSTMENT(adj_vol));
1515 gtk_adjustment_set_value(GTK_ADJUSTMENT(adj_vol), options.vol);
1516
1517 if (options.vol < -40.5f) {
1518 snprintf(str, 31, _("Mute"));
1519 } else {
1520 snprintf(str, 31, _("%d dB"), (int)options.vol);
1521 }
1522
1523 if (!refresh_time_label) {
1524 gtk_label_set_text(GTK_LABEL(time_labels[options.time_idx[0]]), str);
1525 }
1526
1527 snprintf(str2, 31, _("Volume: %s"), str);
1528 aqualung_widget_set_tooltip_text(scale_vol, str2);
1529 }
1530
1531
1532 gint
scale_vol_button_release_event(GtkWidget * widget,GdkEventButton * event)1533 scale_vol_button_release_event(GtkWidget * widget, GdkEventButton * event) {
1534
1535 refresh_time_label = 1;
1536 refresh_time_displays();
1537
1538 return FALSE;
1539 }
1540
1541
1542 gint
scale_bal_button_press_event(GtkWidget * widget,GdkEventButton * event)1543 scale_bal_button_press_event(GtkWidget * widget, GdkEventButton * event) {
1544
1545 char str[32];
1546 options.bal = gtk_adjustment_get_value(GTK_ADJUSTMENT(adj_bal));
1547
1548 if (event->state & GDK_SHIFT_MASK) { /* SHIFT */
1549 gtk_adjustment_set_value(GTK_ADJUSTMENT(adj_bal), 0);
1550 return TRUE;
1551 }
1552
1553 if (options.bal != 0.0f) {
1554 if (options.bal > 0.0f) {
1555 snprintf(str, 31, _("%d%% R"), (int)options.bal);
1556 } else {
1557 snprintf(str, 31, _("%d%% L"), -1*(int)options.bal);
1558 }
1559 } else {
1560 snprintf(str, 31, _("C"));
1561 }
1562
1563 gtk_label_set_text(GTK_LABEL(time_labels[options.time_idx[0]]), str);
1564
1565 refresh_time_label = 0;
1566
1567 if (event->button == 3) {
1568 return TRUE;
1569 } else {
1570 return FALSE;
1571 }
1572 }
1573
1574
1575 void
changed_bal(GtkAdjustment * adj,gpointer date)1576 changed_bal(GtkAdjustment * adj, gpointer date) {
1577
1578 char str[32];
1579 char str2[32];
1580
1581 options.bal = (int)gtk_adjustment_get_value(GTK_ADJUSTMENT(adj_bal));
1582 gtk_adjustment_set_value(GTK_ADJUSTMENT(adj_bal), options.bal);
1583
1584 if (options.bal != 0.0f) {
1585 if (options.bal > 0.0f) {
1586 snprintf(str, 31, _("%d%% R"), (int)options.bal);
1587 } else {
1588 snprintf(str, 31, _("%d%% L"), -1*(int)options.bal);
1589 }
1590 } else {
1591 snprintf(str, 31, _("C"));
1592 }
1593
1594 if (!refresh_time_label) {
1595 gtk_label_set_text(GTK_LABEL(time_labels[options.time_idx[0]]), str);
1596 }
1597
1598 snprintf(str2, 31, _("Balance: %s"), str);
1599 aqualung_widget_set_tooltip_text(scale_bal, str2);
1600 }
1601
1602
1603 gint
scale_bal_button_release_event(GtkWidget * widget,GdkEventButton * event)1604 scale_bal_button_release_event(GtkWidget * widget, GdkEventButton * event) {
1605
1606 refresh_time_label = 1;
1607 refresh_time_displays();
1608
1609 return FALSE;
1610 }
1611
1612
1613 void
show_scale_pos(gboolean state)1614 show_scale_pos(gboolean state) {
1615
1616 if (state == FALSE) {
1617 gtk_widget_hide(GTK_WIDGET(scale_pos));
1618 gtk_widget_show(GTK_WIDGET(vbox_sep));
1619 main_window_resize();
1620 } else {
1621 gtk_widget_show(GTK_WIDGET(scale_pos));
1622 gtk_widget_hide(GTK_WIDGET(vbox_sep));
1623 }
1624 }
1625
1626
1627 /******** Cue functions *********/
1628
1629 void
toggle_noeffect(int id,int state)1630 toggle_noeffect(int id, int state) {
1631 switch (id) {
1632 case PLAY:
1633 g_signal_handler_block(G_OBJECT(play_button), play_id);
1634 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(play_button), state);
1635 g_signal_handler_unblock(G_OBJECT(play_button), play_id);
1636 break;
1637 case PAUSE:
1638 g_signal_handler_block(G_OBJECT(pause_button), pause_id);
1639 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pause_button), state);
1640 g_signal_handler_unblock(G_OBJECT(pause_button), pause_id);
1641 break;
1642 default:
1643 printf("error in gui_main.c/toggle_noeffect(): unknown id value %d\n", id);
1644 break;
1645 }
1646 }
1647
1648
1649 void
cue_track_for_playback(GtkTreeStore * store,GtkTreeIter * piter,cue_t * cue)1650 cue_track_for_playback(GtkTreeStore * store, GtkTreeIter * piter, cue_t * cue) {
1651
1652 playlist_data_t * data;
1653
1654 gtk_tree_model_get(GTK_TREE_MODEL(store), piter, PL_COL_DATA, &data, -1);
1655 cue->filename = strdup(data->file);
1656 cue->voladj = options.rva_is_enabled ? data->voladj : 0.0f;
1657 strncpy(current_file, cue->filename, MAXLEN-1);
1658 }
1659
1660
1661 /* retcode for choose_*_track(): 1->success, 0->empty list */
1662 int
choose_first_track(GtkTreeStore * store,GtkTreeIter * piter)1663 choose_first_track(GtkTreeStore * store, GtkTreeIter * piter) {
1664
1665 if (gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), piter)) {
1666 if (gtk_tree_model_iter_has_child(GTK_TREE_MODEL(store), piter)) {
1667 GtkTreeIter iter_parent = *piter;
1668 gtk_tree_model_iter_children(GTK_TREE_MODEL(store), piter, &iter_parent);
1669 }
1670 return 1;
1671 }
1672 return 0;
1673 }
1674
1675
1676 /* get first or last child iter */
1677 void
get_child_iter(GtkTreeStore * store,GtkTreeIter * piter,int first)1678 get_child_iter(GtkTreeStore * store, GtkTreeIter * piter, int first) {
1679
1680 GtkTreeIter iter;
1681 if (first) {
1682 gtk_tree_model_iter_children(GTK_TREE_MODEL(store), &iter, piter);
1683 } else {
1684 int n = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(store), piter);
1685 gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(store), &iter, piter, n-1);
1686 }
1687 *piter = iter;
1688 }
1689
1690
1691 int
choose_prev_track(GtkTreeStore * store,GtkTreeIter * piter)1692 choose_prev_track(GtkTreeStore * store, GtkTreeIter * piter) {
1693
1694 GtkTreePath * p = gtk_tree_model_get_path(GTK_TREE_MODEL(store), piter);
1695
1696 try_again_prev:
1697 if (gtk_tree_path_prev(p)) {
1698 if (gtk_tree_path_get_depth(p) == 1) { /* toplevel */
1699 GtkTreeIter iter;
1700 gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, p);
1701 if (gtk_tree_model_iter_has_child(GTK_TREE_MODEL(store), &iter)) {
1702 get_child_iter(store, &iter, 0/* last */);
1703 }
1704 *piter = iter;
1705 } else {
1706 gtk_tree_model_get_iter(GTK_TREE_MODEL(store), piter, p);
1707 }
1708 gtk_tree_path_free(p);
1709 return 1;
1710 } else {
1711 if (gtk_tree_path_get_depth(p) == 1) { /* toplevel */
1712 GtkTreeIter iter;
1713 int n = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(store), NULL);
1714 if (n) {
1715 gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(store), &iter, NULL, n-1);
1716 if (gtk_tree_model_iter_has_child(GTK_TREE_MODEL(store), &iter)) {
1717 get_child_iter(store, &iter, 0/* last */);
1718 }
1719 *piter = iter;
1720 gtk_tree_path_free(p);
1721 return 1;
1722 } else {
1723 gtk_tree_path_free(p);
1724 return 0;
1725 }
1726 } else {
1727 gtk_tree_path_up(p);
1728 goto try_again_prev;
1729 }
1730 }
1731 }
1732
1733
1734 int
choose_next_track(GtkTreeStore * store,GtkTreeIter * piter)1735 choose_next_track(GtkTreeStore * store, GtkTreeIter * piter) {
1736 GtkTreeIter iter = *piter;
1737
1738 if (gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter)) {
1739 *piter = iter;
1740 if (gtk_tree_model_iter_has_child(GTK_TREE_MODEL(store), piter)) {
1741 get_child_iter(store, piter, 1/* first */);
1742 }
1743 return 1;
1744 } else {
1745 GtkTreePath * p = gtk_tree_model_get_path(GTK_TREE_MODEL(store), piter);
1746
1747 if (gtk_tree_path_get_depth(p) == 1) { /* toplevel */
1748 int n = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(store), NULL);
1749 if (n) {
1750 gtk_tree_model_get_iter_first(GTK_TREE_MODEL(store), piter);
1751 if (gtk_tree_model_iter_has_child(GTK_TREE_MODEL(store), piter)) {
1752 get_child_iter(store, piter, 1/* first */);
1753 }
1754 gtk_tree_path_free(p);
1755 return 1;
1756 } else {
1757 gtk_tree_path_free(p);
1758 return 0;
1759 }
1760 } else {
1761 gtk_tree_path_up(p);
1762 gtk_tree_model_get_iter(GTK_TREE_MODEL(store), piter, p);
1763 gtk_tree_path_free(p);
1764 return choose_next_track(store, piter);
1765 }
1766 }
1767 }
1768
1769
1770 /* simpler case than choose_next_track(); no support for wrap-around at end of list.
1771 * used by the timeout callback for track flow-through */
1772 int
choose_adjacent_track(GtkTreeStore * store,GtkTreeIter * piter)1773 choose_adjacent_track(GtkTreeStore * store, GtkTreeIter * piter) {
1774 GtkTreeIter iter = *piter;
1775
1776 if (gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter)) {
1777 *piter = iter;
1778 if (gtk_tree_model_iter_has_child(GTK_TREE_MODEL(store), piter)) {
1779 get_child_iter(store, piter, 1/* first */);
1780 }
1781 return 1;
1782 } else {
1783 GtkTreePath * p = gtk_tree_model_get_path(GTK_TREE_MODEL(store), piter);
1784 if (gtk_tree_path_get_depth(p) == 1) { /* toplevel */
1785 gtk_tree_path_free(p);
1786 return 0;
1787 } else {
1788 gtk_tree_path_up(p);
1789 gtk_tree_model_get_iter(GTK_TREE_MODEL(store), piter, p);
1790 gtk_tree_path_free(p);
1791 return choose_adjacent_track(store, piter);
1792 }
1793 }
1794 }
1795
1796
1797 /* also used to pick the track numbered n_stop in the flattened tree */
1798 long
count_playlist_tracks(GtkTreeStore * store,GtkTreeIter * piter,long n_stop)1799 count_playlist_tracks(GtkTreeStore * store, GtkTreeIter * piter, long n_stop) {
1800
1801 GtkTreeIter iter;
1802 long i = 0;
1803 long n = 0;
1804
1805 while (gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(store), &iter, NULL, i++)) {
1806 long c = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(store), &iter);
1807 long d = c;
1808 if (!c) ++c;
1809 if (n_stop > -1) {
1810 if (n_stop > c) {
1811 n_stop -= c;
1812 } else {
1813 if (d) {
1814 gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(store),
1815 piter, &iter, n_stop-1);
1816 } else {
1817 *piter = iter;
1818 }
1819 return 0;
1820 }
1821 }
1822 n += c;
1823 }
1824 return n;
1825 }
1826
1827
1828 int
random_toplevel_item(GtkTreeStore * store,GtkTreeIter * piter)1829 random_toplevel_item(GtkTreeStore * store, GtkTreeIter * piter) {
1830
1831 long n_items;
1832 long n;
1833
1834 n_items = gtk_tree_model_iter_n_children(GTK_TREE_MODEL(store), NULL);
1835 if (!n_items) {
1836 return 0;
1837 }
1838
1839 n = (double)rand() * n_items / RAND_MAX;
1840 if (n == n_items)
1841 --n;
1842
1843 gtk_tree_model_iter_nth_child(GTK_TREE_MODEL(store), piter, NULL, n);
1844 return 1;
1845 }
1846
1847
1848 int
random_first_track(GtkTreeStore * store,GtkTreeIter * piter)1849 random_first_track(GtkTreeStore * store, GtkTreeIter * piter) {
1850
1851 if (random_toplevel_item(store, piter)) {
1852 if (gtk_tree_model_iter_has_child(GTK_TREE_MODEL(store), piter)) {
1853 get_child_iter(store, piter, 1/* first */);
1854 }
1855 return 1;
1856 } else {
1857 return 0;
1858 }
1859 }
1860
1861
1862 int
choose_random_track(GtkTreeStore * store,GtkTreeIter * piter)1863 choose_random_track(GtkTreeStore * store, GtkTreeIter * piter) {
1864
1865 long n_items;
1866 long n;
1867
1868 if (options.album_shuffle_mode) {
1869 if (gtk_tree_store_iter_is_valid(store, piter)) {
1870 int d = gtk_tree_store_iter_depth(store, piter);
1871 if (d) {
1872 if (gtk_tree_model_iter_next(GTK_TREE_MODEL(store), piter)) {
1873 return 1;
1874 }
1875 }
1876 }
1877 return random_first_track(store, piter);
1878 } else {
1879 n_items = count_playlist_tracks(store, NULL, -1);
1880 if (n_items) {
1881 n = (double)rand() * n_items / RAND_MAX;
1882 if (n == n_items) {
1883 --n;
1884 }
1885 count_playlist_tracks(store, piter, n+1);
1886 return 1;
1887 }
1888 return 0;
1889 }
1890 }
1891
1892
1893 void
prepare_playback(playlist_t * pl,GtkTreeIter * piter,cue_t * pcue)1894 prepare_playback(playlist_t * pl, GtkTreeIter * piter, cue_t * pcue) {
1895
1896 mark_track(pl, piter);
1897 cue_track_for_playback(pl->store, piter, pcue);
1898 is_file_loaded = 1;
1899 toggle_noeffect(PLAY, TRUE);
1900 }
1901
1902
1903 void
unprepare_playback(void)1904 unprepare_playback(void) {
1905
1906 is_file_loaded = 0;
1907 stop_after_current_song = 0;
1908 current_file[0] = '\0';
1909 zero_displays();
1910 toggle_noeffect(PLAY, FALSE);
1911 }
1912
1913
1914 gint
prev_event(GtkWidget * widget,GdkEvent * event,gpointer data)1915 prev_event(GtkWidget * widget, GdkEvent * event, gpointer data) {
1916
1917 GtkTreeIter iter;
1918 GtkTreePath * p;
1919 char cmd;
1920 cue_t cue;
1921 playlist_t * pl;
1922
1923 if (!allow_seeks)
1924 return FALSE;
1925
1926 if (is_file_loaded) {
1927 pl = playlist_get_playing();
1928 } else {
1929 pl = playlist_get_current();
1930 }
1931
1932 if (pl == NULL) {
1933 return FALSE;
1934 }
1935
1936 if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(shuffle_button))) {
1937 /* normal or repeat mode */
1938 p = playlist_get_playing_path(pl);
1939 if (p != NULL) {
1940 gtk_tree_model_get_iter(GTK_TREE_MODEL(pl->store), &iter, p);
1941 gtk_tree_path_free(p);
1942 unmark_track(pl, &iter);
1943 if (choose_prev_track(pl->store, &iter)) {
1944 mark_track(pl, &iter);
1945 }
1946 } else {
1947 if (choose_first_track(pl->store, &iter)) {
1948 mark_track(pl, &iter);
1949 }
1950 }
1951 } else {
1952 /* shuffle mode */
1953 p = playlist_get_playing_path(pl);
1954 if (p != NULL) {
1955 gtk_tree_model_get_iter(GTK_TREE_MODEL(pl->store), &iter, p);
1956 gtk_tree_path_free(p);
1957 unmark_track(pl, &iter);
1958 }
1959 if (choose_random_track(pl->store, &iter)) {
1960 mark_track(pl, &iter);
1961 }
1962 }
1963
1964 if (is_file_loaded) {
1965 if ((p = playlist_get_playing_path(pl)) == NULL) {
1966 if (is_paused) {
1967 is_paused = 0;
1968 toggle_noeffect(PAUSE, FALSE);
1969 stop_event(NULL, NULL, NULL);
1970 }
1971 return FALSE;
1972 }
1973
1974 gtk_tree_model_get_iter(GTK_TREE_MODEL(pl->store), &iter, p);
1975 gtk_tree_path_free(p);
1976 cue_track_for_playback(pl->store, &iter, &cue);
1977
1978 stop_after_current_song = 0;
1979 if (is_paused) {
1980 is_paused = 0;
1981 toggle_noeffect(PAUSE, FALSE);
1982 toggle_noeffect(PLAY, TRUE);
1983 }
1984
1985 cmd = CMD_CUE;
1986 flush_rb_disk2gui();
1987 rb_write(rb_gui2disk, &cmd, sizeof(char));
1988 rb_write(rb_gui2disk, (void *)&cue, sizeof(cue_t));
1989 try_waking_disk_thread();
1990 }
1991 return FALSE;
1992 }
1993
1994
1995 gint
next_event(GtkWidget * widget,GdkEvent * event,gpointer data)1996 next_event(GtkWidget * widget, GdkEvent * event, gpointer data) {
1997
1998 GtkTreeIter iter;
1999 GtkTreePath * p;
2000 char cmd;
2001 cue_t cue;
2002 playlist_t * pl;
2003
2004 if (!allow_seeks)
2005 return FALSE;
2006
2007 if (is_file_loaded) {
2008 pl = playlist_get_playing();
2009 } else {
2010 pl = playlist_get_current();
2011 }
2012
2013 if (pl == NULL) {
2014 return FALSE;
2015 }
2016
2017 if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(shuffle_button))) {
2018 /* normal or repeat mode */
2019 p = playlist_get_playing_path(pl);
2020 if (p != NULL) {
2021 gtk_tree_model_get_iter(GTK_TREE_MODEL(pl->store), &iter, p);
2022 gtk_tree_path_free(p);
2023 unmark_track(pl, &iter);
2024 if (choose_next_track(pl->store, &iter)) {
2025 mark_track(pl, &iter);
2026 }
2027 } else {
2028 if (choose_first_track(pl->store, &iter)) {
2029 mark_track(pl, &iter);
2030 }
2031 }
2032 } else {
2033 /* shuffle mode */
2034 p = playlist_get_playing_path(pl);
2035 if (p != NULL) {
2036 gtk_tree_model_get_iter(GTK_TREE_MODEL(pl->store), &iter, p);
2037 gtk_tree_path_free(p);
2038 unmark_track(pl, &iter);
2039 }
2040 if (choose_random_track(pl->store, &iter)) {
2041 mark_track(pl, &iter);
2042 }
2043 }
2044
2045 if (is_file_loaded) {
2046 if ((p = playlist_get_playing_path(pl)) == NULL) {
2047 if (is_paused) {
2048 is_paused = 0;
2049 toggle_noeffect(PAUSE, FALSE);
2050 stop_event(NULL, NULL, NULL);
2051 }
2052 return FALSE;
2053 }
2054
2055 gtk_tree_model_get_iter(GTK_TREE_MODEL(pl->store), &iter, p);
2056 gtk_tree_path_free(p);
2057 cue_track_for_playback(pl->store, &iter, &cue);
2058
2059 stop_after_current_song = 0;
2060 if (is_paused) {
2061 is_paused = 0;
2062 toggle_noeffect(PAUSE, FALSE);
2063 toggle_noeffect(PLAY, TRUE);
2064 }
2065
2066 cmd = CMD_CUE;
2067 flush_rb_disk2gui();
2068 rb_write(rb_gui2disk, &cmd, sizeof(char));
2069 rb_write(rb_gui2disk, (void *)&cue, sizeof(cue_t));
2070 try_waking_disk_thread();
2071 }
2072 return FALSE;
2073 }
2074
2075
2076 gint
play_event(GtkWidget * widget,GdkEvent * event,gpointer data)2077 play_event(GtkWidget * widget, GdkEvent * event, gpointer data) {
2078
2079 GtkTreeIter iter;
2080 GtkTreePath * p;
2081 char cmd;
2082 cue_t cue;
2083 playlist_t * pl;
2084
2085 if (is_paused) {
2086 is_paused = 0;
2087 if (!options.combine_play_pause) {
2088 toggle_noeffect(PAUSE, FALSE);
2089 }
2090 send_cmd = CMD_RESUME;
2091 rb_write(rb_gui2disk, &send_cmd, 1);
2092 try_waking_disk_thread();
2093 return FALSE;
2094 }
2095 if (options.combine_play_pause && is_file_loaded) {
2096 return pause_event(widget, event, data);
2097 }
2098
2099 cmd = CMD_CUE;
2100 cue.filename = NULL;
2101
2102 while ((pl = playlist_get_playing()) != NULL) {
2103 playlist_set_playing(pl, 0);
2104 }
2105
2106 if ((pl = playlist_get_current()) == NULL) {
2107 return FALSE;
2108 }
2109
2110 playlist_set_playing(pl, 1);
2111
2112 p = playlist_get_playing_path(pl);
2113 if (p != NULL) {
2114 gtk_tree_model_get_iter(GTK_TREE_MODEL(pl->store), &iter, p);
2115 gtk_tree_path_free(p);
2116 prepare_playback(pl, &iter, &cue);
2117 } else {
2118 if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(shuffle_button))) {
2119 /* normal or repeat mode */
2120 if (choose_first_track(pl->store, &iter)) {
2121 prepare_playback(pl, &iter, &cue);
2122 } else {
2123 unprepare_playback();
2124 }
2125 } else { /* shuffle mode */
2126 if (choose_random_track(pl->store, &iter)) {
2127 prepare_playback(pl, &iter, &cue);
2128 } else {
2129 unprepare_playback();
2130 }
2131 }
2132 }
2133 if (cue.filename == NULL) {
2134 stop_event(NULL, NULL, NULL);
2135 } else {
2136 flush_rb_disk2gui();
2137 rb_write(rb_gui2disk, &cmd, sizeof(char));
2138 rb_write(rb_gui2disk, (void *)&cue, sizeof(cue_t));
2139 try_waking_disk_thread();
2140 }
2141 return FALSE;
2142 }
2143
2144
2145 gint
pause_event(GtkWidget * widget,GdkEvent * event,gpointer data)2146 pause_event(GtkWidget * widget, GdkEvent * event, gpointer data) {
2147
2148 if ((!allow_seeks) || (!is_file_loaded)) {
2149 if (!options.combine_play_pause) {
2150 toggle_noeffect(PAUSE, FALSE);
2151 }
2152 return FALSE;
2153 }
2154
2155 if (!is_paused) {
2156 is_paused = 1;
2157 toggle_noeffect(PLAY, FALSE);
2158 send_cmd = CMD_PAUSE;
2159 rb_write(rb_gui2disk, &send_cmd, 1);
2160
2161 } else {
2162 is_paused = 0;
2163 toggle_noeffect(PLAY, TRUE);
2164 send_cmd = CMD_RESUME;
2165 rb_write(rb_gui2disk, &send_cmd, 1);
2166 }
2167
2168 try_waking_disk_thread();
2169 return FALSE;
2170 }
2171
2172
2173 gint
stop_event(GtkWidget * widget,GdkEvent * event,gpointer data)2174 stop_event(GtkWidget * widget, GdkEvent * event, gpointer data) {
2175
2176 char cmd;
2177 cue_t cue;
2178
2179 is_file_loaded = 0;
2180 stop_after_current_song = 0;
2181 current_file[0] = '\0';
2182 gtk_adjustment_set_value(GTK_ADJUSTMENT(adj_pos), 0.0f);
2183 zero_displays();
2184 toggle_noeffect(PLAY, FALSE);
2185 if (!options.combine_play_pause) {
2186 toggle_noeffect(PAUSE, FALSE);
2187 }
2188
2189 is_paused = 0;
2190 allow_seeks = 1;
2191
2192 cmd = CMD_CUE;
2193 cue.filename = NULL;
2194 flush_rb_disk2gui();
2195 rb_write(rb_gui2disk, &cmd, sizeof(char));
2196 rb_write(rb_gui2disk, (void *)&cue, sizeof(cue_t));
2197 try_waking_disk_thread();
2198
2199 show_scale_pos(TRUE);
2200
2201 /* hide cover */
2202 hide_cover_thumbnail();
2203
2204 if (embedded_picture != NULL) {
2205 free(embedded_picture);
2206 embedded_picture = NULL;
2207 embedded_picture_size = 0;
2208 }
2209
2210 return FALSE;
2211 }
2212
2213
2214 /* called when a track ends without user intervention */
2215 void
decide_next_track(cue_t * pcue)2216 decide_next_track(cue_t * pcue) {
2217
2218 GtkTreePath * p;
2219 GtkTreeIter iter;
2220 playlist_t * pl;
2221
2222 if ((pl = playlist_get_playing()) == NULL) {
2223 unprepare_playback();
2224 return;
2225 }
2226
2227 if (stop_after_current_song) {
2228 unprepare_playback();
2229 return;
2230 }
2231
2232 p = playlist_get_playing_path(pl);
2233 if (p != NULL) { /* there is a marked track in playlist */
2234 if ((!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(shuffle_button))) &&
2235 (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(repeat_button)))) {
2236 /* normal or list repeat mode */
2237 gtk_tree_model_get_iter(GTK_TREE_MODEL(pl->store), &iter, p);
2238 gtk_tree_path_free(p);
2239 unmark_track(pl, &iter);
2240 if (choose_adjacent_track(pl->store, &iter)) {
2241 prepare_playback(pl, &iter, pcue);
2242 } else {
2243 if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(repeat_all_button))) {
2244 /* normal mode */
2245 allow_seeks = 1;
2246 changed_pos(GTK_ADJUSTMENT(adj_pos), NULL);
2247 unprepare_playback();
2248 } else {
2249 /* list repeat mode */
2250 if (choose_first_track(pl->store, &iter)) {
2251 prepare_playback(pl, &iter, pcue);
2252 } else {
2253 allow_seeks = 1;
2254 changed_pos(GTK_ADJUSTMENT(adj_pos), NULL);
2255 unprepare_playback();
2256 }
2257 }
2258 }
2259 } else if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(repeat_button))) {
2260 /* track repeat mode */
2261 gtk_tree_model_get_iter(GTK_TREE_MODEL(pl->store), &iter, p);
2262 gtk_tree_path_free(p);
2263 prepare_playback(pl, &iter, pcue);
2264 } else {
2265 /* shuffle mode */
2266 gtk_tree_model_get_iter(GTK_TREE_MODEL(pl->store), &iter, p);
2267 gtk_tree_path_free(p);
2268 unmark_track(pl, &iter);
2269 if (choose_random_track(pl->store, &iter)) {
2270 prepare_playback(pl, &iter, pcue);
2271 } else {
2272 unprepare_playback();
2273 }
2274 }
2275 } else { /* no marked track in playlist */
2276 if (!gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(shuffle_button))) {
2277 /* normal or repeat mode */
2278 if (choose_first_track(pl->store, &iter)) {
2279 prepare_playback(pl, &iter, pcue);
2280 } else {
2281 allow_seeks = 1;
2282 changed_pos(GTK_ADJUSTMENT(adj_pos), NULL);
2283 unprepare_playback();
2284 }
2285 } else { /* shuffle mode */
2286 if (choose_random_track(pl->store, &iter)) {
2287 prepare_playback(pl, &iter, pcue);
2288 } else {
2289 unprepare_playback();
2290 }
2291 }
2292 }
2293 }
2294
2295
2296 /********************************************/
2297
2298 void
swap_labels(int a,int b)2299 swap_labels(int a, int b) {
2300
2301 GtkWidget * tmp;
2302 int t;
2303
2304 tmp = time_labels[options.time_idx[a]];
2305 time_labels[options.time_idx[a]] = time_labels[options.time_idx[b]] ;
2306 time_labels[options.time_idx[b]] = tmp;
2307
2308 t = options.time_idx[b];
2309 options.time_idx[b] = options.time_idx[a];
2310 options.time_idx[a] = t;
2311 }
2312
2313
2314 gint
time_label0_clicked(GtkWidget * widget,GdkEventButton * event)2315 time_label0_clicked(GtkWidget * widget, GdkEventButton * event) {
2316
2317 switch (event->button) {
2318 case 1:
2319 swap_labels(0, 1);
2320 refresh_time_displays();
2321 break;
2322 case 3:
2323 swap_labels(0, 2);
2324 refresh_time_displays();
2325 break;
2326 }
2327
2328 return TRUE;
2329 }
2330
2331
2332 gint
time_label1_clicked(GtkWidget * widget,GdkEventButton * event)2333 time_label1_clicked(GtkWidget * widget, GdkEventButton * event) {
2334
2335 switch (event->button) {
2336 case 1:
2337 swap_labels(0, 1);
2338 refresh_time_displays();
2339 break;
2340 case 3:
2341 swap_labels(1, 2);
2342 refresh_time_displays();
2343 break;
2344 }
2345
2346 return TRUE;
2347 }
2348
2349
2350 gint
time_label2_clicked(GtkWidget * widget,GdkEventButton * event)2351 time_label2_clicked(GtkWidget * widget, GdkEventButton * event) {
2352
2353 switch (event->button) {
2354 case 1:
2355 swap_labels(1, 2);
2356 refresh_time_displays();
2357 break;
2358 case 3:
2359 swap_labels(0, 2);
2360 refresh_time_displays();
2361 break;
2362 }
2363
2364 return TRUE;
2365 }
2366
2367
2368 gint
scroll_btn_pressed(GtkWidget * widget,GdkEventButton * event)2369 scroll_btn_pressed(GtkWidget * widget, GdkEventButton * event) {
2370
2371 if (event->button != 1)
2372 return FALSE;
2373
2374 x_scroll_start = event->x;
2375 x_scroll_pos = event->x;
2376 scroll_btn = event->button;
2377
2378 return TRUE;
2379 }
2380
2381 gint
scroll_btn_released(GtkWidget * widget,GdkEventButton * event,gpointer * win)2382 scroll_btn_released(GtkWidget * widget, GdkEventButton * event, gpointer * win) {
2383
2384 scroll_btn = 0;
2385 gdk_window_set_cursor(gtk_widget_get_parent_window(GTK_WIDGET(win)), NULL);
2386
2387 return TRUE;
2388 }
2389
2390 gint
scroll_motion_notify(GtkWidget * widget,GdkEventMotion * event,gpointer * win)2391 scroll_motion_notify(GtkWidget * widget, GdkEventMotion * event, gpointer * win) {
2392
2393 int dx = event->x - x_scroll_start;
2394 gboolean dummy;
2395
2396 if (scroll_btn != 1)
2397 return FALSE;
2398
2399 if (!scroll_btn)
2400 return TRUE;
2401
2402 if (dx < -10) {
2403 GtkRange * range = GTK_RANGE(gtk_scrolled_window_get_hscrollbar(GTK_SCROLLED_WINDOW(win)));
2404 g_signal_emit_by_name(G_OBJECT(range), "move-slider", GTK_SCROLL_STEP_RIGHT, &dummy);
2405 x_scroll_start = event->x;
2406 gdk_window_set_cursor(gtk_widget_get_parent_window(GTK_WIDGET(win)),
2407 gdk_cursor_new(GDK_SB_H_DOUBLE_ARROW));
2408 }
2409
2410 if (dx > 10) {
2411 GtkRange * range = GTK_RANGE(gtk_scrolled_window_get_hscrollbar(GTK_SCROLLED_WINDOW(win)));
2412 g_signal_emit_by_name(G_OBJECT(range), "move-slider", GTK_SCROLL_STEP_LEFT, &dummy);
2413 x_scroll_start = event->x;
2414 gdk_window_set_cursor(gtk_widget_get_parent_window(GTK_WIDGET(win)),
2415 gdk_cursor_new(GDK_SB_H_DOUBLE_ARROW));
2416 }
2417
2418 x_scroll_pos = event->x;
2419
2420 return TRUE;
2421 }
2422
2423 #ifdef HAVE_LOOP
2424 void
hide_loop_bar()2425 hide_loop_bar() {
2426 gtk_widget_hide(loop_bar);
2427 main_window_resize();
2428 }
2429 #endif /* HAVE_LOOP */
2430
2431 void
repeat_toggled(GtkWidget * widget,gpointer data)2432 repeat_toggled(GtkWidget * widget, gpointer data) {
2433
2434 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(repeat_button))) {
2435 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(repeat_all_button), FALSE);
2436 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(shuffle_button), FALSE);
2437 options.repeat_on = 1;
2438 } else {
2439 options.repeat_on = 0;
2440 }
2441
2442 #ifdef HAVE_LOOP
2443 if (options.repeat_on) {
2444 gtk_widget_show(loop_bar);
2445 } else {
2446 hide_loop_bar();
2447 }
2448 #endif /* HAVE_LOOP */
2449 }
2450
2451
2452 void
repeat_all_toggled(GtkWidget * widget,gpointer data)2453 repeat_all_toggled(GtkWidget * widget, gpointer data) {
2454
2455 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(repeat_all_button))) {
2456 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(repeat_button), FALSE);
2457 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(shuffle_button), FALSE);
2458 options.repeat_all_on = 1;
2459 } else {
2460 options.repeat_all_on = 0;
2461 }
2462 }
2463
2464
2465 void
shuffle_toggled(GtkWidget * widget,gpointer data)2466 shuffle_toggled(GtkWidget * widget, gpointer data) {
2467
2468 if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(shuffle_button))) {
2469 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(repeat_button), FALSE);
2470 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(repeat_all_button), FALSE);
2471 options.shuffle_on = 1;
2472 } else {
2473 options.shuffle_on = 0;
2474 }
2475 }
2476
2477
2478 void
button_set_content(GtkWidget * button,char * imgpath,char * alt)2479 button_set_content(GtkWidget * button, char * imgpath, char * alt) {
2480
2481 GdkPixbuf * pixbuf;
2482 GtkWidget * widget;
2483
2484 if ((widget = gtk_bin_get_child(GTK_BIN(button))) != NULL) {
2485 gtk_widget_destroy(widget);
2486 }
2487
2488 if ((pixbuf = gdk_pixbuf_new_from_file(imgpath, NULL)) != NULL) {
2489 widget = gtk_image_new_from_pixbuf(pixbuf);
2490 } else {
2491 widget = gtk_label_new(alt);
2492 }
2493
2494 gtk_container_add(GTK_CONTAINER(button), widget);
2495 gtk_widget_show(widget);
2496 }
2497
2498 void
main_buttons_set_content(char * skin_path)2499 main_buttons_set_content(char * skin_path) {
2500
2501 char path[MAXLEN];
2502
2503 sprintf(path, "%s/%s", skin_path, "prev.png");
2504 button_set_content(prev_button, path, "prev");
2505 sprintf(path, "%s/%s", skin_path, "stop.png");
2506 button_set_content(stop_button, path, "stop");
2507 sprintf(path, "%s/%s", skin_path, "next.png");
2508 button_set_content(next_button, path, "next");
2509 if (options.combine_play_pause) {
2510 sprintf(path, "%s/%s", skin_path, "play_pause.png");
2511 button_set_content(play_button, path, "play/pause");
2512 } else {
2513 sprintf(path, "%s/%s", skin_path, "play.png");
2514 button_set_content(play_button, path, "play");
2515 sprintf(path, "%s/%s", skin_path, "pause.png");
2516 button_set_content(pause_button, path, "pause");
2517 }
2518 sprintf(path, "%s/%s", skin_path, "repeat.png");
2519 button_set_content(repeat_button, path, "repeat");
2520 sprintf(path, "%s/%s", skin_path, "repeat_all.png");
2521 button_set_content(repeat_all_button, path, "rep_all");
2522 sprintf(path, "%s/%s", skin_path, "shuffle.png");
2523 button_set_content(shuffle_button, path, "shuffle");
2524
2525 sprintf(path, "%s/%s", skin_path, "pl.png");
2526 button_set_content(playlist_toggle, path, "PL");
2527 sprintf(path, "%s/%s", skin_path, "ms.png");
2528 button_set_content(musicstore_toggle, path, "MS");
2529 #ifdef HAVE_LADSPA
2530 sprintf(path, "%s/%s", skin_path, "fx.png");
2531 button_set_content(plugin_toggle, path, "FX");
2532 #endif /* HAVE_LADSPA */
2533 }
2534
2535
2536 #ifdef HAVE_JACK
2537 void
jack_shutdown_window(void)2538 jack_shutdown_window(void) {
2539
2540 message_dialog(_("JACK connection lost"),
2541 main_window,
2542 GTK_MESSAGE_ERROR,
2543 GTK_BUTTONS_OK,
2544 NULL,
2545 _("JACK has either been shutdown or it "
2546 "disconnected Aqualung. Reason: %s"),
2547 jack_shutdown_reason);
2548 }
2549 #endif /* HAVE_JACK */
2550
2551
2552 void
set_win_title(void)2553 set_win_title(void) {
2554
2555 char str_session_id[32];
2556
2557 strcpy(win_title, "Aqualung");
2558 if (aqualung_session_id > 0) {
2559 sprintf(str_session_id, ".%d", aqualung_session_id);
2560 strcat(win_title, str_session_id);
2561 }
2562 #ifdef HAVE_JACK
2563 if ((output == JACK_DRIVER) && (strcmp(client_name, "aqualung") != 0)) {
2564 strcat(win_title, " [");
2565 strcat(win_title, client_name);
2566 strcat(win_title, "]");
2567 }
2568 #endif /* HAVE_JACK */
2569 }
2570
2571
2572 #ifdef HAVE_SYSTRAY
2573 void
wm_systray_warn_cb(GtkWidget * widget,gpointer data)2574 wm_systray_warn_cb(GtkWidget * widget, gpointer data) {
2575
2576 set_option_from_toggle(widget, &options.wm_systray_warn);
2577 }
2578
2579 void
hide_all_windows(gpointer data)2580 hide_all_windows(gpointer data) {
2581
2582 if (wm_not_systray_capable) {
2583 main_window_closing();
2584 return;
2585 }
2586
2587 if (gtk_status_icon_is_embedded(systray_icon) == FALSE) {
2588
2589 if (!wm_not_systray_capable && options.wm_systray_warn) {
2590
2591 GtkWidget * check = gtk_check_button_new_with_label(_("Warn me if the Window Manager does not support system tray"));
2592
2593 gtk_widget_set_name(check, "check_on_window");
2594 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check), TRUE);
2595 g_signal_connect(G_OBJECT(check), "toggled",
2596 G_CALLBACK(wm_systray_warn_cb), NULL);
2597
2598 message_dialog(_("Warning"),
2599 options.playlist_is_embedded ? main_window : playlist_window,
2600 GTK_MESSAGE_WARNING,
2601 GTK_BUTTONS_OK,
2602 check,
2603 _("Aqualung is compiled with system tray support, but "
2604 "the status icon could not be embedded in the notification "
2605 "area. Your desktop may not have support for a system tray, "
2606 "or it has not been configured correctly."));
2607
2608 wm_not_systray_capable = 1;
2609 } else {
2610 main_window_closing();
2611 }
2612
2613 return;
2614
2615 } else {
2616 options.wm_systray_warn = 1;
2617 }
2618
2619 if (!systray_main_window_on) {
2620 return;
2621 }
2622
2623 systray_main_window_on = 0;
2624
2625 save_window_position();
2626 toplevel_window_foreach(TOP_WIN_TRAY, gtk_widget_hide);
2627
2628 gtk_widget_hide(systray__hide);
2629 gtk_widget_show(systray__show);
2630 }
2631
2632 void
show_all_windows(gpointer data)2633 show_all_windows(gpointer data) {
2634
2635 systray_main_window_on = 1;
2636
2637 toplevel_window_foreach(TOP_WIN_TRAY, gtk_widget_show);
2638 restore_window_position();
2639
2640 gtk_widget_hide(systray__show);
2641 gtk_widget_show(systray__hide);
2642 }
2643 #endif /* HAVE_SYSTRAY */
2644
2645
2646 gboolean
cover_press_button_cb(GtkWidget * widget,GdkEventButton * event,gpointer user_data)2647 cover_press_button_cb (GtkWidget *widget, GdkEventButton *event, gpointer user_data) {
2648
2649 GtkTreePath * p;
2650 GtkTreeIter iter;
2651 playlist_t * pl;
2652
2653 if ((pl = playlist_get_playing()) == NULL) {
2654 return FALSE;
2655 }
2656
2657 if (event->type == GDK_BUTTON_PRESS && event->button == 1) { /* LMB ? */
2658 p = playlist_get_playing_path(pl);
2659 if (p != NULL) {
2660 gtk_tree_model_get_iter(GTK_TREE_MODEL(pl->store), &iter, p);
2661 gtk_tree_path_free(p);
2662 playlist_data_t * pldata;
2663 gtk_tree_model_get(GTK_TREE_MODEL(pl->store), &iter, PL_COL_DATA, &pldata, -1);
2664 if (is_file_loaded) {
2665 if (embedded_picture != NULL && (find_cover_filename(pldata->file) == NULL || !options.use_external_cover_first)) {
2666 display_zoomed_cover_from_binary(main_window, c_event_box, embedded_picture, embedded_picture_size);
2667 } else {
2668 display_zoomed_cover(main_window, c_event_box, pldata->file);
2669 }
2670 }
2671 }
2672 }
2673 return TRUE;
2674 }
2675
2676 void
main_window_set_font(int cond)2677 main_window_set_font(int cond) {
2678
2679 if (cond) {
2680 gtk_widget_modify_font(bigtimer_label, fd_bigtimer);
2681 gtk_widget_modify_font(smalltimer_label_1, fd_smalltimer);
2682 gtk_widget_modify_font(smalltimer_label_2, fd_smalltimer);
2683 gtk_widget_modify_font(label_title, fd_songtitle);
2684 gtk_widget_modify_font(label_mono, fd_songinfo);
2685 gtk_widget_modify_font(label_samplerate, fd_songinfo);
2686 gtk_widget_modify_font(label_bps, fd_songinfo);
2687 gtk_widget_modify_font(label_format, fd_songinfo);
2688 gtk_widget_modify_font(label_output, fd_songinfo);
2689 gtk_widget_modify_font(label_src_type, fd_songinfo);
2690 }
2691 }
2692
2693 void
create_main_window(char * skin_path)2694 create_main_window(char * skin_path) {
2695
2696 GtkWidget * vbox;
2697 GtkWidget * disp_hbox;
2698 GtkWidget * btns_hbox;
2699 GtkWidget * title_hbox;
2700 GtkWidget * info_hbox;
2701 GtkWidget * vb_table;
2702
2703 GtkWidget * conf__separator1;
2704 GtkWidget * conf__separator2;
2705
2706 GtkWidget * time_table;
2707 GtkWidget * time0_viewp;
2708 GtkWidget * time1_viewp;
2709 GtkWidget * time2_viewp;
2710 GtkWidget * time_hbox1;
2711 GtkWidget * time_hbox2;
2712
2713 GtkWidget * disp_vbox;
2714 GtkWidget * title_viewp;
2715 GtkWidget * title_scrolledwin;
2716 GtkWidget * info_viewp;
2717 GtkWidget * info_scrolledwin;
2718 GtkWidget * info_vsep;
2719
2720 GtkWidget * sr_table;
2721
2722 char path[MAXLEN];
2723
2724 set_win_title();
2725 playing_app_title[0] = '\0';
2726
2727 main_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
2728 gtk_widget_set_name(main_window, "main_window");
2729 register_toplevel_window(main_window, TOP_WIN_SKIN | TOP_WIN_TRAY);
2730 gtk_window_set_title(GTK_WINDOW(main_window), win_title);
2731 #ifdef HAVE_SYSTRAY
2732 if (systray_used) {
2733 aqualung_status_icon_set_tooltip_text(systray_icon, win_title);
2734 }
2735 #endif /* HAVE_SYSTRAY */
2736
2737 g_signal_connect(G_OBJECT(main_window), "event", G_CALLBACK(main_window_event), NULL);
2738
2739 g_signal_connect(G_OBJECT(main_window), "key_press_event", G_CALLBACK(main_window_key_pressed), NULL);
2740 g_signal_connect(G_OBJECT(main_window), "key_release_event",
2741 G_CALLBACK(main_window_key_released), NULL);
2742 g_signal_connect(G_OBJECT(main_window), "button_press_event",
2743 G_CALLBACK(main_window_button_pressed), NULL);
2744 g_signal_connect(G_OBJECT(main_window), "focus_out_event",
2745 G_CALLBACK(main_window_focus_out), NULL);
2746 g_signal_connect(G_OBJECT(main_window), "window-state-event",
2747 G_CALLBACK(main_window_state_changed), NULL);
2748
2749 gtk_widget_set_events(main_window, GDK_BUTTON_PRESS_MASK | GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK);
2750 gtk_container_set_border_width(GTK_CONTAINER(main_window), 5);
2751
2752 /* always on top ? */
2753
2754 if (options.main_window_always_on_top) {
2755 gtk_window_set_keep_above (GTK_WINDOW(main_window), TRUE);
2756 }
2757
2758 /* initialize fonts */
2759
2760 fd_playlist = pango_font_description_from_string(options.playlist_font);
2761 fd_browser = pango_font_description_from_string(options.browser_font);
2762 fd_bigtimer = pango_font_description_from_string(options.bigtimer_font);
2763 fd_smalltimer = pango_font_description_from_string(options.smalltimer_font);
2764 fd_songtitle = pango_font_description_from_string(options.songtitle_font);
2765 fd_songinfo = pango_font_description_from_string(options.songinfo_font);
2766 fd_statusbar = pango_font_description_from_string(options.statusbar_font);
2767
2768 conf_menu = gtk_menu_new();
2769 register_toplevel_window(conf_menu, TOP_WIN_SKIN);
2770
2771 if (options.playlist_is_embedded) {
2772 init_plist_menu(conf_menu);
2773 plist_menu = conf_menu;
2774 }
2775
2776 conf__options = gtk_menu_item_new_with_label(_("Settings"));
2777 conf__skin = gtk_menu_item_new_with_label(_("Skin chooser"));
2778 if (!options.playlist_is_embedded) {
2779 conf__fileinfo = gtk_menu_item_new_with_label(_("File info"));
2780 }
2781 conf__separator1 = gtk_separator_menu_item_new();
2782 conf__about = gtk_menu_item_new_with_label(_("About"));
2783 conf__separator2 = gtk_separator_menu_item_new();
2784 conf__quit = gtk_menu_item_new_with_label(_("Quit"));
2785
2786 if (options.playlist_is_embedded) {
2787 gtk_menu_shell_append(GTK_MENU_SHELL(conf_menu), conf__separator1);
2788 }
2789 gtk_menu_shell_append(GTK_MENU_SHELL(conf_menu), conf__options);
2790 gtk_menu_shell_append(GTK_MENU_SHELL(conf_menu), conf__skin);
2791
2792 #ifdef HAVE_JACK_MGMT
2793 if (output == JACK_DRIVER) {
2794 conf__jack = gtk_menu_item_new_with_label(_("JACK port setup"));
2795 gtk_menu_shell_append(GTK_MENU_SHELL(conf_menu), conf__jack);
2796 g_signal_connect_swapped(G_OBJECT(conf__jack), "activate",
2797 G_CALLBACK(conf__jack_cb), NULL);
2798 gtk_widget_show(conf__jack);
2799 }
2800 #endif /* HAVE_JACK_MGMT */
2801
2802 if (!options.playlist_is_embedded) {
2803 gtk_menu_shell_append(GTK_MENU_SHELL(conf_menu), conf__fileinfo);
2804 gtk_menu_shell_append(GTK_MENU_SHELL(conf_menu), conf__separator1);
2805 }
2806 gtk_menu_shell_append(GTK_MENU_SHELL(conf_menu), conf__about);
2807 gtk_menu_shell_append(GTK_MENU_SHELL(conf_menu), conf__separator2);
2808 gtk_menu_shell_append(GTK_MENU_SHELL(conf_menu), conf__quit);
2809
2810 g_signal_connect_swapped(G_OBJECT(conf__options), "activate", G_CALLBACK(conf__options_cb), NULL);
2811 g_signal_connect_swapped(G_OBJECT(conf__skin), "activate", G_CALLBACK(conf__skin_cb), NULL);
2812 g_signal_connect_swapped(G_OBJECT(conf__about), "activate", G_CALLBACK(conf__about_cb), NULL);
2813 g_signal_connect_swapped(G_OBJECT(conf__quit), "activate", G_CALLBACK(conf__quit_cb), NULL);
2814
2815 if (!options.playlist_is_embedded) {
2816 g_signal_connect_swapped(G_OBJECT(conf__fileinfo), "activate", G_CALLBACK(conf__fileinfo_cb), NULL);
2817 gtk_widget_show(conf__fileinfo);
2818 }
2819
2820 gtk_widget_show(conf__options);
2821 if (!options.disable_skin_support_settings) {
2822 gtk_widget_show(conf__skin);
2823 }
2824 gtk_widget_show(conf__separator1);
2825 gtk_widget_show(conf__about);
2826 gtk_widget_show(conf__separator2);
2827 gtk_widget_show(conf__quit);
2828
2829
2830 vbox = gtk_vbox_new(FALSE, 0);
2831 gtk_container_add(GTK_CONTAINER(main_window), vbox);
2832
2833
2834 disp_hbox = gtk_hbox_new(FALSE, 3);
2835 gtk_box_pack_start(GTK_BOX(vbox), disp_hbox, FALSE, FALSE, 0);
2836
2837
2838 time_table = gtk_table_new(2, 2, FALSE);
2839 disp_vbox = gtk_vbox_new(FALSE, 0);
2840
2841 gtk_box_pack_start(GTK_BOX(disp_hbox), time_table, FALSE, FALSE, 0);
2842 gtk_box_pack_start(GTK_BOX(disp_hbox), disp_vbox, TRUE, TRUE, 0);
2843
2844 time0_viewp = gtk_viewport_new(NULL, NULL);
2845 time1_viewp = gtk_viewport_new(NULL, NULL);
2846 time2_viewp = gtk_viewport_new(NULL, NULL);
2847
2848 gtk_widget_set_name(time0_viewp, "time_viewport");
2849 gtk_widget_set_name(time1_viewp, "time_viewport");
2850 gtk_widget_set_name(time2_viewp, "time_viewport");
2851
2852 g_signal_connect(G_OBJECT(time0_viewp), "button_press_event", G_CALLBACK(time_label0_clicked), NULL);
2853 g_signal_connect(G_OBJECT(time1_viewp), "button_press_event", G_CALLBACK(time_label1_clicked), NULL);
2854 g_signal_connect(G_OBJECT(time2_viewp), "button_press_event", G_CALLBACK(time_label2_clicked), NULL);
2855
2856
2857 gtk_table_attach(GTK_TABLE(time_table), time0_viewp, 0, 2, 0, 1,
2858 GTK_FILL | GTK_EXPAND, 0, 0, 0);
2859 gtk_table_attach(GTK_TABLE(time_table), time1_viewp, 0, 1, 1, 2,
2860 GTK_FILL | GTK_EXPAND, 0, 0, 0);
2861 gtk_table_attach(GTK_TABLE(time_table), time2_viewp, 1, 2, 1, 2,
2862 GTK_FILL | GTK_EXPAND, 0, 0, 0);
2863
2864
2865 info_scrolledwin = gtk_scrolled_window_new(NULL, NULL);
2866 gtk_widget_set_size_request(info_scrolledwin, 1, -1); /* MAGIC */
2867 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(info_scrolledwin),
2868 GTK_POLICY_NEVER, GTK_POLICY_NEVER);
2869
2870 info_viewp = gtk_viewport_new(NULL, NULL);
2871 gtk_widget_set_name(info_viewp, "info_viewport");
2872 gtk_container_add(GTK_CONTAINER(info_scrolledwin), info_viewp);
2873 gtk_widget_set_events(info_viewp, GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK);
2874
2875 g_signal_connect(G_OBJECT(info_viewp), "button_press_event",
2876 G_CALLBACK(scroll_btn_pressed), NULL);
2877 g_signal_connect(G_OBJECT(info_viewp), "button_release_event",
2878 G_CALLBACK(scroll_btn_released), (gpointer)info_scrolledwin);
2879 g_signal_connect(G_OBJECT(info_viewp), "motion_notify_event",
2880 G_CALLBACK(scroll_motion_notify), (gpointer)info_scrolledwin);
2881
2882 info_hbox = gtk_hbox_new(FALSE, 0);
2883 gtk_container_set_border_width(GTK_CONTAINER(info_hbox), 1);
2884 gtk_container_add(GTK_CONTAINER(info_viewp), info_hbox);
2885
2886
2887 title_scrolledwin = gtk_scrolled_window_new(NULL, NULL);
2888 gtk_widget_set_size_request(title_scrolledwin, 1, -1); /* MAGIC */
2889 gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(title_scrolledwin),
2890 GTK_POLICY_NEVER, GTK_POLICY_NEVER);
2891
2892 title_viewp = gtk_viewport_new(NULL, NULL);
2893 gtk_widget_set_name(title_viewp, "title_viewport");
2894 gtk_container_add(GTK_CONTAINER(title_scrolledwin), title_viewp);
2895 gtk_widget_set_events(title_viewp, GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK);
2896 g_signal_connect(G_OBJECT(title_viewp), "button_press_event", G_CALLBACK(scroll_btn_pressed), NULL);
2897 g_signal_connect(G_OBJECT(title_viewp), "button_release_event", G_CALLBACK(scroll_btn_released),
2898 (gpointer)title_scrolledwin);
2899 g_signal_connect(G_OBJECT(title_viewp), "motion_notify_event", G_CALLBACK(scroll_motion_notify),
2900 (gpointer)title_scrolledwin);
2901
2902 title_hbox = gtk_hbox_new(FALSE, 0);
2903 gtk_container_set_border_width(GTK_CONTAINER(title_hbox), 1);
2904 gtk_container_add(GTK_CONTAINER(title_viewp), title_hbox);
2905
2906 gtk_box_pack_start(GTK_BOX(disp_vbox), title_scrolledwin, TRUE, FALSE, 0);
2907 gtk_box_pack_start(GTK_BOX(disp_vbox), info_scrolledwin, TRUE, FALSE, 0);
2908
2909 /* labels */
2910 bigtimer_label = time_labels[options.time_idx[0]] = gtk_label_new("");
2911
2912 gtk_widget_set_name(time_labels[options.time_idx[0]], "big_timer_label");
2913 gtk_container_add(GTK_CONTAINER(time0_viewp), time_labels[options.time_idx[0]]);
2914
2915 time_hbox1 = gtk_hbox_new(FALSE, 3);
2916 gtk_container_set_border_width(GTK_CONTAINER(time_hbox1), 2);
2917 gtk_container_add(GTK_CONTAINER(time1_viewp), time_hbox1);
2918
2919 smalltimer_label_1 = time_labels[options.time_idx[1]] = gtk_label_new("");
2920
2921 gtk_widget_set_name(time_labels[options.time_idx[1]], "small_timer_label");
2922 gtk_box_pack_start(GTK_BOX(time_hbox1), time_labels[options.time_idx[1]], TRUE, TRUE, 0);
2923
2924 time_hbox2 = gtk_hbox_new(FALSE, 3);
2925 gtk_container_set_border_width(GTK_CONTAINER(time_hbox2), 2);
2926 gtk_container_add(GTK_CONTAINER(time2_viewp), time_hbox2);
2927
2928 smalltimer_label_2 = time_labels[options.time_idx[2]] = gtk_label_new("");
2929
2930 gtk_widget_set_name(time_labels[options.time_idx[2]], "small_timer_label");
2931 gtk_box_pack_start(GTK_BOX(time_hbox2), time_labels[options.time_idx[2]], TRUE, TRUE, 0);
2932
2933 label_title = gtk_label_new("");
2934 gtk_widget_set_name(label_title, "label_title");
2935 gtk_box_pack_start(GTK_BOX(title_hbox), label_title, FALSE, FALSE, 3);
2936
2937 label_mono = gtk_label_new("");
2938 gtk_box_pack_start(GTK_BOX(info_hbox), label_mono, FALSE, FALSE, 3);
2939 gtk_widget_set_name(label_mono, "label_info");
2940
2941 label_samplerate = gtk_label_new("0");
2942 gtk_widget_set_name(label_samplerate, "label_info");
2943 gtk_box_pack_start(GTK_BOX(info_hbox), label_samplerate, FALSE, FALSE, 3);
2944
2945 label_bps = gtk_label_new("");
2946 gtk_widget_set_name(label_bps, "label_info");
2947 gtk_box_pack_start(GTK_BOX(info_hbox), label_bps, FALSE, FALSE, 3);
2948
2949 label_format = gtk_label_new("");
2950 gtk_widget_set_name(label_format, "label_info");
2951 gtk_box_pack_start(GTK_BOX(info_hbox), label_format, FALSE, FALSE, 3);
2952
2953 info_vsep = gtk_vseparator_new();
2954 gtk_box_pack_start(GTK_BOX(info_hbox), info_vsep, FALSE, FALSE, 3);
2955
2956 label_output = gtk_label_new("");
2957 gtk_widget_set_name(label_output, "label_info");
2958 gtk_box_pack_start(GTK_BOX(info_hbox), label_output, FALSE, FALSE, 3);
2959
2960 label_src_type = gtk_label_new("");
2961 gtk_widget_set_name(label_src_type, "label_info");
2962 gtk_box_pack_start(GTK_BOX(info_hbox), label_src_type, FALSE, FALSE, 3);
2963
2964 main_window_set_font(options.override_skin_settings);
2965
2966 /* Volume and balance slider */
2967 vb_table = gtk_table_new(1, 3, FALSE);
2968 gtk_table_set_col_spacings(GTK_TABLE(vb_table), 3);
2969 gtk_box_pack_start(GTK_BOX(disp_vbox), vb_table, TRUE, FALSE, 0);
2970
2971 adj_vol = gtk_adjustment_new(0.0f, -41.0f, 6.0f, 1.0f, 3.0f, 0.0f);
2972 g_signal_connect(G_OBJECT(adj_vol), "value_changed", G_CALLBACK(changed_vol), NULL);
2973 scale_vol = gtk_hscale_new(GTK_ADJUSTMENT(adj_vol));
2974 gtk_widget_set_name(scale_vol, "scale_vol");
2975 g_signal_connect(G_OBJECT(scale_vol), "button_press_event",
2976 G_CALLBACK(scale_vol_button_press_event), NULL);
2977 g_signal_connect(G_OBJECT(scale_vol), "button_release_event",
2978 G_CALLBACK(scale_vol_button_release_event), NULL);
2979 gtk_widget_set_size_request(scale_vol, -1, 8);
2980 gtk_scale_set_digits(GTK_SCALE(scale_vol), 0);
2981 gtk_scale_set_draw_value(GTK_SCALE(scale_vol), FALSE);
2982 gtk_table_attach(GTK_TABLE(vb_table), scale_vol, 0, 2, 0, 1,
2983 GTK_FILL | GTK_EXPAND, 0, 0, 0);
2984
2985 adj_bal = gtk_adjustment_new(0.0f, -100.0f, 100.0f, 1.0f, 10.0f, 0.0f);
2986 g_signal_connect(G_OBJECT(adj_bal), "value_changed", G_CALLBACK(changed_bal), NULL);
2987 scale_bal = gtk_hscale_new(GTK_ADJUSTMENT(adj_bal));
2988 gtk_scale_set_digits(GTK_SCALE(scale_bal), 0);
2989 gtk_widget_set_size_request(scale_bal, -1, 8);
2990 gtk_widget_set_name(scale_bal, "scale_bal");
2991 g_signal_connect(G_OBJECT(scale_bal), "button_press_event",
2992 G_CALLBACK(scale_bal_button_press_event), NULL);
2993 g_signal_connect(G_OBJECT(scale_bal), "button_release_event",
2994 G_CALLBACK(scale_bal_button_release_event), NULL);
2995 gtk_scale_set_draw_value(GTK_SCALE(scale_bal), FALSE);
2996 gtk_table_attach(GTK_TABLE(vb_table), scale_bal, 2, 3, 0, 1,
2997 GTK_FILL | GTK_EXPAND, 0, 0, 0);
2998
2999 /* Loop bar */
3000
3001 #ifdef HAVE_LOOP
3002 loop_bar = aqualung_loop_bar_new(options.loop_range_start, options.loop_range_end);
3003 g_signal_connect(loop_bar, "range-changed", G_CALLBACK(loop_range_changed_cb), NULL);
3004 gtk_widget_set_size_request(loop_bar, -1, 14);
3005 gtk_box_pack_start(GTK_BOX(vbox), loop_bar, FALSE, FALSE, 3);
3006 #endif /* HAVE_LOOP */
3007
3008
3009 /* Position slider */
3010 adj_pos = gtk_adjustment_new(0, 0, 100, 1, 5, 0);
3011 g_signal_connect(G_OBJECT(adj_pos), "value_changed", G_CALLBACK(changed_pos), NULL);
3012 scale_pos = gtk_hscale_new(GTK_ADJUSTMENT(adj_pos));
3013 gtk_widget_set_name(scale_pos, "scale_pos");
3014 g_signal_connect(G_OBJECT(scale_pos), "button_press_event",
3015 G_CALLBACK(scale_button_press_event), NULL);
3016 g_signal_connect(G_OBJECT(scale_pos), "button_release_event",
3017 G_CALLBACK(scale_button_release_event), NULL);
3018 gtk_scale_set_digits(GTK_SCALE(scale_pos), 0);
3019 gtk_scale_set_draw_value(GTK_SCALE(scale_pos), FALSE);
3020 gtk_range_set_update_policy(GTK_RANGE(scale_pos), GTK_UPDATE_DISCONTINUOUS);
3021 gtk_box_pack_start(GTK_BOX(vbox), scale_pos, FALSE, FALSE, 3);
3022
3023 vbox_sep = gtk_vbox_new (FALSE, 0);
3024 gtk_box_pack_start(GTK_BOX(vbox), vbox_sep, FALSE, FALSE, 2);
3025
3026 gtk_widget_set_can_focus(scale_vol, FALSE);
3027 gtk_widget_set_can_focus(scale_bal, FALSE);
3028 gtk_widget_set_can_focus(scale_pos, FALSE);
3029
3030 /* cover display widget */
3031
3032 cover_align = gtk_alignment_new(0.5f, 0.5f, 0.0f, 0.0f);
3033 gtk_box_pack_start(GTK_BOX(disp_hbox), cover_align, FALSE, FALSE, 0);
3034 cover_image_area = gtk_image_new();
3035 c_event_box = gtk_event_box_new();
3036 gtk_container_add(GTK_CONTAINER(cover_align), c_event_box);
3037 gtk_container_add(GTK_CONTAINER(c_event_box), cover_image_area);
3038 g_signal_connect(G_OBJECT(c_event_box), "button_press_event",
3039 G_CALLBACK(cover_press_button_cb), cover_image_area);
3040
3041 /* Embedded playlist */
3042
3043 if (options.playlist_is_embedded && options.buttons_at_the_bottom) {
3044 playlist_window = gtk_vbox_new(FALSE, 0);
3045 gtk_widget_set_name(playlist_window, "playlist_window");
3046 gtk_box_pack_start(GTK_BOX(vbox), playlist_window, TRUE, TRUE, 3);
3047 }
3048
3049 /* Button box with prev, play, pause, stop, next buttons */
3050
3051 btns_hbox = gtk_hbox_new(FALSE, 0);
3052 gtk_box_pack_start(GTK_BOX(vbox), btns_hbox, FALSE, FALSE, 0);
3053
3054 prev_button = gtk_button_new();
3055 aqualung_widget_set_tooltip_text(prev_button, _("Previous song"));
3056
3057 stop_button = gtk_button_new();
3058 aqualung_widget_set_tooltip_text(stop_button, _("Stop"));
3059
3060 next_button = gtk_button_new();
3061 aqualung_widget_set_tooltip_text(next_button, _("Next song"));
3062
3063 play_button = gtk_toggle_button_new();
3064
3065 if (options.combine_play_pause) {
3066 aqualung_widget_set_tooltip_text(play_button, _("Play/Pause"));
3067 } else {
3068 aqualung_widget_set_tooltip_text(play_button, _("Play"));
3069 pause_button = gtk_toggle_button_new();
3070 aqualung_widget_set_tooltip_text(pause_button, _("Pause"));
3071 }
3072
3073 gtk_widget_set_can_focus(prev_button, FALSE);
3074 gtk_widget_set_can_focus(stop_button, FALSE);
3075 gtk_widget_set_can_focus(next_button, FALSE);
3076 gtk_widget_set_can_focus(play_button, FALSE);
3077 if (!options.combine_play_pause) {
3078 gtk_widget_set_can_focus(pause_button, FALSE);
3079 }
3080
3081 gtk_box_pack_start(GTK_BOX(btns_hbox), prev_button, FALSE, FALSE, 0);
3082 gtk_box_pack_start(GTK_BOX(btns_hbox), play_button, FALSE, FALSE, 0);
3083 if (!options.combine_play_pause) {
3084 gtk_box_pack_start(GTK_BOX(btns_hbox), pause_button, FALSE, FALSE, 0);
3085 }
3086 gtk_box_pack_start(GTK_BOX(btns_hbox), stop_button, FALSE, FALSE, 0);
3087 gtk_box_pack_start(GTK_BOX(btns_hbox), next_button, FALSE, FALSE, 0);
3088
3089 g_signal_connect(prev_button, "clicked", G_CALLBACK(prev_event), NULL);
3090 play_id = g_signal_connect(play_button, "toggled", G_CALLBACK(play_event), NULL);
3091 if (!options.combine_play_pause) {
3092 pause_id = g_signal_connect(pause_button, "toggled", G_CALLBACK(pause_event), NULL);
3093 }
3094 g_signal_connect(stop_button, "clicked", G_CALLBACK(stop_event), NULL);
3095 g_signal_connect(next_button, "clicked", G_CALLBACK(next_event), NULL);
3096
3097
3098 /* toggle buttons for shuffle and repeat */
3099 sr_table = gtk_table_new(2, 2, FALSE);
3100
3101 repeat_button = gtk_toggle_button_new();
3102 aqualung_widget_set_tooltip_text(repeat_button, _("Repeat current song"));
3103 gtk_widget_set_size_request(repeat_button, -1, 1);
3104 gtk_table_attach(GTK_TABLE(sr_table), repeat_button, 0, 1, 0, 1,
3105 GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 0, 0);
3106 g_signal_connect(repeat_button, "toggled", G_CALLBACK(repeat_toggled), NULL);
3107
3108 repeat_all_button = gtk_toggle_button_new();
3109 aqualung_widget_set_tooltip_text(repeat_all_button, _("Repeat all songs"));
3110 gtk_widget_set_size_request(repeat_all_button, -1, 1);
3111 gtk_table_attach(GTK_TABLE(sr_table), repeat_all_button, 0, 1, 1, 2,
3112 GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 0, 0);
3113 g_signal_connect(repeat_all_button, "toggled", G_CALLBACK(repeat_all_toggled), NULL);
3114
3115 shuffle_button = gtk_toggle_button_new();
3116 aqualung_widget_set_tooltip_text(shuffle_button, _("Shuffle songs"));
3117 gtk_widget_set_size_request(shuffle_button, -1, 1);
3118 gtk_table_attach(GTK_TABLE(sr_table), shuffle_button, 1, 2, 0, 2,
3119 GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 0, 0);
3120 g_signal_connect(shuffle_button, "toggled", G_CALLBACK(shuffle_toggled), NULL);
3121
3122 gtk_widget_set_can_focus(repeat_button, FALSE);
3123 gtk_widget_set_can_focus(repeat_all_button, FALSE);
3124 gtk_widget_set_can_focus(shuffle_button, FALSE);
3125
3126 /* toggle buttons for sub-windows visibility */
3127 playlist_toggle = gtk_toggle_button_new();
3128 aqualung_widget_set_tooltip_text(playlist_toggle, _("Toggle playlist"));
3129 gtk_box_pack_end(GTK_BOX(btns_hbox), playlist_toggle, FALSE, FALSE, 0);
3130
3131 musicstore_toggle = gtk_toggle_button_new();
3132 aqualung_widget_set_tooltip_text(musicstore_toggle, _("Toggle music store"));
3133 gtk_box_pack_end(GTK_BOX(btns_hbox), musicstore_toggle, FALSE, FALSE, 3);
3134
3135 g_signal_connect(playlist_toggle, "toggled", G_CALLBACK(playlist_toggled), NULL);
3136 g_signal_connect(musicstore_toggle, "toggled", G_CALLBACK(musicstore_toggled), NULL);
3137
3138 gtk_widget_set_can_focus(playlist_toggle, FALSE);
3139 gtk_widget_set_can_focus(musicstore_toggle, FALSE);
3140
3141 #ifdef HAVE_LADSPA
3142 plugin_toggle = gtk_toggle_button_new();
3143 aqualung_widget_set_tooltip_text(plugin_toggle, _("Toggle LADSPA patch builder"));
3144 gtk_box_pack_end(GTK_BOX(btns_hbox), plugin_toggle, FALSE, FALSE, 0);
3145 g_signal_connect(plugin_toggle, "toggled", G_CALLBACK(plugin_toggled), NULL);
3146 gtk_widget_set_can_focus(plugin_toggle, FALSE);
3147 #endif /* HAVE_LADSPA */
3148
3149 gtk_box_pack_end(GTK_BOX(btns_hbox), sr_table, FALSE, FALSE, 3);
3150
3151 if (options.disable_skin_support_settings) {
3152 sprintf(path, "%s/no_skin", AQUALUNG_SKINDIR);
3153 main_buttons_set_content(path);
3154 } else {
3155 main_buttons_set_content(skin_path);
3156 }
3157 set_buttons_relief();
3158
3159 /* Embedded playlist */
3160 if (options.playlist_is_embedded && !options.buttons_at_the_bottom) {
3161 playlist_window = gtk_vbox_new(FALSE, 0);
3162 gtk_widget_set_name(playlist_window, "playlist_window");
3163 gtk_box_pack_start(GTK_BOX(vbox), playlist_window, TRUE, TRUE, 3);
3164 }
3165
3166 aqualung_tooltips_set_enabled(options.enable_tooltips);
3167 }
3168
3169
3170 void
process_filenames(GSList * list,int enqueue,int start_playback,int has_tab,char * tab_name)3171 process_filenames(GSList * list, int enqueue, int start_playback, int has_tab, char * tab_name) {
3172
3173 int mode;
3174 char * name = NULL;
3175
3176 if (!has_tab) {
3177 if (enqueue) {
3178 mode = PLAYLIST_ENQUEUE;
3179 } else {
3180 mode = PLAYLIST_LOAD;
3181 }
3182 } else {
3183 if (strlen(tab_name) == 0) {
3184 mode = PLAYLIST_LOAD_TAB;
3185 } else {
3186 if (g_utf8_validate(tab_name, -1, NULL)) {
3187 name = g_strdup(tab_name);
3188 } else {
3189 name = g_locale_to_utf8(tab_name, -1, NULL, NULL, NULL);
3190 }
3191 if (name == NULL) {
3192 fprintf(stderr, "process_filenames(): unable to convert tab name to UTF-8\n");
3193 }
3194
3195 if (enqueue) {
3196 mode = PLAYLIST_ENQUEUE;
3197 } else {
3198 mode = PLAYLIST_LOAD;
3199 }
3200 }
3201 }
3202
3203 playlist_load(list, mode, name, start_playback);
3204
3205 if (name != NULL) {
3206 g_free(name);
3207 }
3208 }
3209
3210
3211 /*** Systray support ***/
3212 #ifdef HAVE_SYSTRAY
3213 void
systray_popup_menu_cb(GtkStatusIcon * systray_icon,guint button,guint time,gpointer data)3214 systray_popup_menu_cb(GtkStatusIcon * systray_icon, guint button, guint time, gpointer data) {
3215
3216 if (get_systray_semaphore() == 0) {
3217 gtk_menu_popup(GTK_MENU(systray_menu), NULL, NULL,
3218 gtk_status_icon_position_menu, data,
3219 button, time);
3220 }
3221 }
3222
3223 void
systray__show_cb(gpointer data)3224 systray__show_cb(gpointer data) {
3225
3226 show_all_windows(NULL);
3227 }
3228
3229 void
systray__hide_cb(gpointer data)3230 systray__hide_cb(gpointer data) {
3231
3232 hide_all_windows(NULL);
3233 }
3234
3235 void
systray__play_cb(gpointer data)3236 systray__play_cb(gpointer data) {
3237
3238 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(play_button),
3239 !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(play_button)));
3240 }
3241
3242 void
systray__pause_cb(gpointer data)3243 systray__pause_cb(gpointer data) {
3244
3245 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pause_button),
3246 !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(pause_button)));
3247 }
3248
3249 void
systray__stop_cb(gpointer data)3250 systray__stop_cb(gpointer data) {
3251
3252 stop_event(NULL, NULL, NULL);
3253 }
3254
3255 void
systray__prev_cb(gpointer data)3256 systray__prev_cb(gpointer data) {
3257
3258 prev_event(NULL, NULL, NULL);
3259 }
3260
3261 void
systray__next_cb(gpointer data)3262 systray__next_cb(gpointer data) {
3263
3264 next_event(NULL, NULL, NULL);
3265 }
3266
3267 void
systray__quit_cb(gpointer data)3268 systray__quit_cb(gpointer data) {
3269
3270 main_window_closing();
3271 }
3272
3273 void
systray_activate_cb(GtkStatusIcon * systray_icon,gpointer data)3274 systray_activate_cb(GtkStatusIcon * systray_icon, gpointer data) {
3275
3276 if (get_systray_semaphore() == 0) {
3277 if (!systray_main_window_on) {
3278 systray__show_cb(NULL);
3279 } else {
3280 systray__hide_cb(NULL);
3281 }
3282 }
3283 }
3284
3285 GtkScrollType
reverse_direction(GtkScrollType scroll_type)3286 reverse_direction(GtkScrollType scroll_type) {
3287 switch (scroll_type) {
3288 case GTK_SCROLL_STEP_BACKWARD:
3289 return GTK_SCROLL_STEP_FORWARD;
3290 case GTK_SCROLL_STEP_FORWARD:
3291 return GTK_SCROLL_STEP_BACKWARD;
3292 default:
3293 return scroll_type;
3294 }
3295 }
3296
3297 gboolean
systray_mouse_wheel(int mouse_wheel_option,gboolean vertical_wheel,guint32 time_since_last_event,GtkScrollType scroll_type)3298 systray_mouse_wheel(int mouse_wheel_option, gboolean vertical_wheel,
3299 guint32 time_since_last_event, GtkScrollType scroll_type) {
3300
3301 switch (mouse_wheel_option) {
3302 case SYSTRAY_MW_CMD_VOLUME:
3303 if (time_since_last_event > 100) {
3304 if (vertical_wheel)
3305 scroll_type = reverse_direction(scroll_type);
3306 change_volume_or_balance(scale_vol, scroll_type);
3307 return TRUE;
3308 }
3309 break;
3310 case SYSTRAY_MW_CMD_BALANCE:
3311 if (time_since_last_event > 100) {
3312 if (vertical_wheel)
3313 scroll_type = reverse_direction(scroll_type);
3314 change_volume_or_balance(scale_bal, scroll_type);
3315 return TRUE;
3316 }
3317 break;
3318 case SYSTRAY_MW_CMD_SONG_POSITION:
3319 move_song_position_slider(scroll_type);
3320 seek_song();
3321 return TRUE;
3322 case SYSTRAY_MW_CMD_NEXT_PREV_SONG:
3323 // At most one per second.
3324 if (time_since_last_event > 1000) {
3325 if (scroll_type == GTK_SCROLL_STEP_BACKWARD) {
3326 prev_event(NULL, NULL, NULL);
3327 return TRUE;
3328 } else if (scroll_type == GTK_SCROLL_STEP_FORWARD) {
3329 next_event(NULL, NULL, NULL);
3330 return TRUE;
3331 }
3332 }
3333 break;
3334 }
3335
3336 return FALSE;
3337 }
3338
3339 gboolean
systray_scroll_event_cb(GtkStatusIcon * systray_icon,GdkEventScroll * event,gpointer user_data)3340 systray_scroll_event_cb(GtkStatusIcon * systray_icon,
3341 GdkEventScroll * event,
3342 gpointer user_data) {
3343
3344 gboolean result = FALSE;
3345 guint32 time_since_last_event;
3346
3347 if (!options.use_systray)
3348 return FALSE;
3349
3350 time_since_last_event = event->time - last_systray_scroll_event_time;
3351
3352 switch (event->direction) {
3353 case GDK_SCROLL_LEFT:
3354 result = systray_mouse_wheel(options.systray_mouse_wheel_horizontal,
3355 FALSE, time_since_last_event, GTK_SCROLL_STEP_BACKWARD);
3356 break;
3357 case GDK_SCROLL_RIGHT:
3358 result = systray_mouse_wheel(options.systray_mouse_wheel_horizontal,
3359 FALSE, time_since_last_event, GTK_SCROLL_STEP_FORWARD);
3360 break;
3361 case GDK_SCROLL_UP:
3362 result = systray_mouse_wheel(options.systray_mouse_wheel_vertical,
3363 TRUE, time_since_last_event, GTK_SCROLL_STEP_BACKWARD);
3364 break;
3365 case GDK_SCROLL_DOWN:
3366 result = systray_mouse_wheel(options.systray_mouse_wheel_vertical,
3367 TRUE, time_since_last_event, GTK_SCROLL_STEP_FORWARD);
3368 break;
3369 }
3370
3371 if (result) {
3372 last_systray_scroll_event_time = event->time;
3373 }
3374
3375 return result;
3376 }
3377
3378 gboolean
systray_mouse_button(int mouse_button_option)3379 systray_mouse_button(int mouse_button_option) {
3380
3381 switch (mouse_button_option) {
3382 case SYSTRAY_MB_CMD_PLAY_STOP_SONG:
3383 if (is_file_loaded) {
3384 systray__stop_cb(NULL);
3385 } else {
3386 systray__play_cb(NULL);
3387 }
3388 return TRUE;
3389 case SYSTRAY_MB_CMD_PLAY_PAUSE_SONG:
3390 if (is_file_loaded && !options.combine_play_pause) {
3391 systray__pause_cb(NULL);
3392 } else {
3393 systray__play_cb(NULL);
3394 }
3395 return TRUE;
3396 case SYSTRAY_MB_CMD_PREV_SONG:
3397 systray__prev_cb(NULL);
3398 return TRUE;
3399 case SYSTRAY_MB_CMD_NEXT_SONG:
3400 systray__next_cb(NULL);
3401 return TRUE;
3402 }
3403 return FALSE;
3404 }
3405
3406 gboolean
systray_button_press_event_cb(GtkStatusIcon * systray_icon,GdkEventButton * event,gpointer user_data)3407 systray_button_press_event_cb(GtkStatusIcon * systray_icon,
3408 GdkEventButton * event,
3409 gpointer user_data) {
3410
3411 int i;
3412
3413 if (!options.use_systray)
3414 return FALSE;
3415
3416 if (event->type == GDK_BUTTON_PRESS) {
3417 for (i = 0; i < options.systray_mouse_buttons_count; i++) {
3418 if (options.systray_mouse_buttons[i].button_nr == event->button) {
3419 return systray_mouse_button(options.systray_mouse_buttons[i].command);
3420 }
3421 }
3422 }
3423
3424 return FALSE;
3425 }
3426
3427 /* returns a hbox with a stock image and label in it */
3428 GtkWidget *
create_systray_menu_item(const gchar * stock_id,char * text)3429 create_systray_menu_item(const gchar * stock_id, char * text) {
3430
3431 GtkWidget * hbox;
3432 GtkWidget * widget;
3433
3434 hbox = gtk_hbox_new(FALSE, 5);
3435 gtk_widget_show(hbox);
3436 widget = gtk_image_new_from_stock(stock_id, GTK_ICON_SIZE_MENU);
3437 gtk_widget_show(widget);
3438 gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, TRUE, 2);
3439 widget = gtk_label_new(text);
3440 gtk_widget_show(widget);
3441 gtk_box_pack_start(GTK_BOX(hbox), widget, FALSE, TRUE, 2);
3442
3443 return hbox;
3444 }
3445
3446 void
setup_systray(void)3447 setup_systray(void) {
3448
3449 char path[MAXLEN];
3450
3451 GtkWidget * systray__separator1;
3452 GtkWidget * systray__separator2;
3453
3454 sprintf(path, "%s/icon_64.png", AQUALUNG_DATADIR);
3455 systray_icon = gtk_status_icon_new_from_file(path);
3456
3457 g_signal_connect_swapped(G_OBJECT(systray_icon), "activate",
3458 G_CALLBACK(systray_activate_cb), NULL);
3459 g_signal_connect_swapped(G_OBJECT(systray_icon), "popup-menu",
3460 G_CALLBACK(systray_popup_menu_cb), (gpointer)systray_icon);
3461 g_signal_connect(G_OBJECT(systray_icon), "scroll-event",
3462 G_CALLBACK(systray_scroll_event_cb), NULL);
3463 g_signal_connect(G_OBJECT(systray_icon), "button-press-event",
3464 G_CALLBACK(systray_button_press_event_cb), NULL);
3465
3466 systray_menu = gtk_menu_new();
3467 register_toplevel_window(systray_menu, TOP_WIN_SKIN);
3468
3469 systray__show = gtk_menu_item_new_with_label(_("Show Aqualung"));
3470 systray__hide = gtk_menu_item_new_with_label(_("Hide Aqualung"));
3471
3472 systray__separator1 = gtk_separator_menu_item_new();
3473
3474 systray__play = gtk_menu_item_new();
3475 gtk_container_add(GTK_CONTAINER(systray__play),
3476 create_systray_menu_item(GTK_STOCK_MEDIA_PLAY,
3477 options.combine_play_pause ? _("Play/Pause") : _("Play")));
3478
3479 if (!options.combine_play_pause) {
3480 systray__pause = gtk_menu_item_new();
3481 gtk_container_add(GTK_CONTAINER(systray__pause),
3482 create_systray_menu_item(GTK_STOCK_MEDIA_PAUSE, _("Pause")));
3483 }
3484
3485 systray__stop = gtk_menu_item_new();
3486 gtk_container_add(GTK_CONTAINER(systray__stop),
3487 create_systray_menu_item(GTK_STOCK_MEDIA_STOP, _("Stop")));
3488
3489 systray__prev = gtk_menu_item_new();
3490 gtk_container_add(GTK_CONTAINER(systray__prev),
3491 create_systray_menu_item(GTK_STOCK_MEDIA_PREVIOUS, _("Previous")));
3492
3493 systray__next = gtk_menu_item_new();
3494 gtk_container_add(GTK_CONTAINER(systray__next),
3495 create_systray_menu_item(GTK_STOCK_MEDIA_NEXT, _("Next")));
3496
3497 systray__separator2 = gtk_separator_menu_item_new();
3498
3499 systray__quit = gtk_menu_item_new();
3500 gtk_container_add(GTK_CONTAINER(systray__quit),
3501 create_systray_menu_item(GTK_STOCK_STOP, _("Quit")));
3502
3503 gtk_menu_shell_append(GTK_MENU_SHELL(systray_menu), systray__show);
3504 gtk_menu_shell_append(GTK_MENU_SHELL(systray_menu), systray__hide);
3505 gtk_menu_shell_append(GTK_MENU_SHELL(systray_menu), systray__separator1);
3506 gtk_menu_shell_append(GTK_MENU_SHELL(systray_menu), systray__play);
3507 if (!options.combine_play_pause) {
3508 gtk_menu_shell_append(GTK_MENU_SHELL(systray_menu), systray__pause);
3509 }
3510 gtk_menu_shell_append(GTK_MENU_SHELL(systray_menu), systray__stop);
3511 gtk_menu_shell_append(GTK_MENU_SHELL(systray_menu), systray__prev);
3512 gtk_menu_shell_append(GTK_MENU_SHELL(systray_menu), systray__next);
3513 gtk_menu_shell_append(GTK_MENU_SHELL(systray_menu), systray__separator2);
3514 gtk_menu_shell_append(GTK_MENU_SHELL(systray_menu), systray__quit);
3515
3516 g_signal_connect_swapped(G_OBJECT(systray__show), "activate", G_CALLBACK(systray__show_cb), NULL);
3517 g_signal_connect_swapped(G_OBJECT(systray__hide), "activate", G_CALLBACK(systray__hide_cb), NULL);
3518 g_signal_connect_swapped(G_OBJECT(systray__play), "activate", G_CALLBACK(systray__play_cb), NULL);
3519 if (!options.combine_play_pause) {
3520 g_signal_connect_swapped(G_OBJECT(systray__pause), "activate", G_CALLBACK(systray__pause_cb), NULL);
3521 }
3522 g_signal_connect_swapped(G_OBJECT(systray__stop), "activate", G_CALLBACK(systray__stop_cb), NULL);
3523 g_signal_connect_swapped(G_OBJECT(systray__prev), "activate", G_CALLBACK(systray__prev_cb), NULL);
3524 g_signal_connect_swapped(G_OBJECT(systray__next), "activate", G_CALLBACK(systray__next_cb), NULL);
3525 g_signal_connect_swapped(G_OBJECT(systray__quit), "activate", G_CALLBACK(systray__quit_cb), NULL);
3526
3527 gtk_widget_show(systray_menu);
3528 gtk_widget_show(systray__hide);
3529 gtk_widget_show(systray__separator1);
3530 gtk_widget_show(systray__play);
3531 if (!options.combine_play_pause) {
3532 gtk_widget_show(systray__pause);
3533 }
3534 gtk_widget_show(systray__stop);
3535 gtk_widget_show(systray__prev);
3536 gtk_widget_show(systray__next);
3537
3538 gtk_widget_show(systray__separator2);
3539 gtk_widget_show(systray__quit);
3540 }
3541 #endif /* HAVE_SYSTRAY */
3542
3543 void
create_gui(int argc,char ** argv,int optind,int enqueue,unsigned long rate,unsigned long rb_audio_size)3544 create_gui(int argc, char ** argv, int optind, int enqueue,
3545 unsigned long rate, unsigned long rb_audio_size) {
3546
3547 char path[MAXLEN];
3548 GList * glist = NULL;
3549 GdkPixbuf * pixbuf = NULL;
3550
3551 srand(time(0));
3552 sample_pos = 0;
3553 out_SR = rate;
3554 rb_size = rb_audio_size;
3555
3556 gdk_threads_enter();
3557 gtk_init(&argc, &argv);
3558 #ifdef HAVE_LADSPA
3559 lrdf_init();
3560 #endif /* HAVE_LADSPA */
3561
3562 load_config();
3563
3564 if (options.title_format[0] == '\0')
3565 sprintf(options.title_format, "%%a: %%t [%%r]");
3566 if (options.skin[0] == '\0') {
3567 sprintf(options.skin, "%s/plain", AQUALUNG_SKINDIR);
3568 options.main_pos_x = 280;
3569 options.main_pos_y = 30;
3570 options.main_size_x = 380;
3571 options.main_size_y = 380;
3572 options.browser_pos_x = 30;
3573 options.browser_pos_y = 30;
3574 options.browser_size_x = 240;
3575 options.browser_size_y = 380;
3576 options.browser_on = 1;
3577 options.playlist_pos_x = 300;
3578 options.playlist_pos_y = 180;
3579 options.playlist_size_x = 400;
3580 options.playlist_size_y = 500;
3581 options.playlist_on = 1;
3582 }
3583
3584 if (options.cddb_server[0] == '\0') {
3585 sprintf(options.cddb_server, "freedb.org");
3586 }
3587
3588 if (options.src_type == -1) {
3589 options.src_type = 4;
3590 }
3591
3592 if (options.disable_skin_support_settings) {
3593 sprintf(path, "%s/no_skin/rc", AQUALUNG_SKINDIR);
3594 } else {
3595 sprintf(path, "%s/rc", options.skin);
3596 }
3597 gtk_rc_parse(path);
3598
3599 #ifdef HAVE_SYSTRAY
3600 if (options.use_systray) {
3601 systray_used = 1;
3602 setup_systray();
3603 }
3604 #endif /* HAVE_SYSTRAY */
3605
3606 create_main_window(options.skin);
3607
3608 vol_prev = -101.0f;
3609 gtk_adjustment_set_value(GTK_ADJUSTMENT(adj_vol), options.vol);
3610 bal_prev = -101.0f;
3611 gtk_adjustment_set_value(GTK_ADJUSTMENT(adj_bal), options.bal);
3612
3613 create_playlist();
3614 playlist_auto_save_reset();
3615
3616 create_music_browser();
3617
3618 #ifdef HAVE_LADSPA
3619 create_fxbuilder();
3620 load_plugin_data();
3621 #endif /* HAVE_LADSPA */
3622
3623 #ifdef HAVE_CDDA
3624 create_cdda_node();
3625 cdda_scanner_start();
3626 #endif /* HAVE_CDDA */
3627
3628 #ifdef HAVE_PODCAST
3629 create_podcast_node();
3630 store_podcast_load();
3631 store_podcast_updater_start();
3632 #endif /* HAVE_PODCAST */
3633
3634 music_store_load_all();
3635
3636 options_store_watcher_start();
3637
3638 sprintf(path, "%s/icon_16.png", AQUALUNG_DATADIR);
3639 if ((pixbuf = gdk_pixbuf_new_from_file(path, NULL)) != NULL) {
3640 glist = g_list_append(glist, gdk_pixbuf_new_from_file(path, NULL));
3641 }
3642
3643 sprintf(path, "%s/icon_24.png", AQUALUNG_DATADIR);
3644 if ((pixbuf = gdk_pixbuf_new_from_file(path, NULL)) != NULL) {
3645 glist = g_list_append(glist, gdk_pixbuf_new_from_file(path, NULL));
3646 }
3647
3648 sprintf(path, "%s/icon_32.png", AQUALUNG_DATADIR);
3649 if ((pixbuf = gdk_pixbuf_new_from_file(path, NULL)) != NULL) {
3650 glist = g_list_append(glist, gdk_pixbuf_new_from_file(path, NULL));
3651 }
3652
3653 sprintf(path, "%s/icon_48.png", AQUALUNG_DATADIR);
3654 if ((pixbuf = gdk_pixbuf_new_from_file(path, NULL)) != NULL) {
3655 glist = g_list_append(glist, gdk_pixbuf_new_from_file(path, NULL));
3656 }
3657
3658 sprintf(path, "%s/icon_64.png", AQUALUNG_DATADIR);
3659 if ((pixbuf = gdk_pixbuf_new_from_file(path, NULL)) != NULL) {
3660 glist = g_list_append(glist, gdk_pixbuf_new_from_file(path, NULL));
3661 }
3662
3663 if (glist != NULL) {
3664 gtk_window_set_default_icon_list(glist);
3665 g_list_free(glist);
3666 }
3667
3668 if (options.repeat_on) {
3669 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(repeat_button), TRUE);
3670 }
3671
3672 if (options.repeat_all_on) {
3673 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(repeat_all_button), TRUE);
3674 }
3675
3676 if (options.shuffle_on) {
3677 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(shuffle_button), TRUE);
3678 }
3679
3680 if (playlist_state != -1) {
3681 options.playlist_on = playlist_state;
3682 }
3683
3684 if (browser_state != -1) {
3685 options.browser_on = browser_state;
3686 }
3687
3688 if (options.browser_on) {
3689 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(musicstore_toggle), TRUE);
3690 }
3691
3692 if (options.playlist_on) {
3693 if (options.playlist_is_embedded) {
3694 g_signal_handlers_block_by_func(G_OBJECT(playlist_toggle), playlist_toggled, NULL);
3695 }
3696 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(playlist_toggle), TRUE);
3697 if (options.playlist_is_embedded) {
3698 g_signal_handlers_unblock_by_func(G_OBJECT(playlist_toggle), playlist_toggled, NULL);
3699 }
3700 }
3701
3702 restore_window_position();
3703
3704 gtk_widget_show_all(main_window);
3705
3706 #ifdef HAVE_SYSTRAY
3707 if (options.use_systray && options.systray_start_minimized) {
3708 toplevel_window_foreach(TOP_WIN_TRAY, gtk_widget_hide);
3709 systray_main_window_on = 0;
3710 }
3711 #endif /* HAVE_SYSTRAY */
3712
3713 hide_cover_thumbnail();
3714
3715 gtk_widget_hide(vbox_sep);
3716
3717 if (options.playlist_is_embedded) {
3718 if (!options.playlist_on) {
3719 hide_playlist();
3720 }
3721 }
3722
3723 #ifdef HAVE_LOOP
3724 if (!options.repeat_on) {
3725 hide_loop_bar();
3726 }
3727 #endif /* HAVE_LOOP */
3728
3729
3730 /* update sliders' tooltips */
3731 if (options.enable_tooltips) {
3732 changed_vol(GTK_ADJUSTMENT(adj_vol), NULL);
3733 changed_bal(GTK_ADJUSTMENT(adj_bal), NULL);
3734 changed_pos(GTK_ADJUSTMENT(adj_pos), NULL);
3735 }
3736
3737 zero_displays();
3738 if (options.auto_save_playlist) {
3739 /* start playback only if no files to be loaded on command line */
3740 int start_playback = (argv[optind] == NULL) && immediate_start;
3741 char file[MAXLEN];
3742
3743 snprintf(file, MAXLEN-1, "%s/%s", options.confdir, "playlist.xml");
3744 if (g_file_test(file, G_FILE_TEST_EXISTS) == TRUE) {
3745 GSList * list = g_slist_append(NULL, strdup(file));
3746 playlist_load(list, PLAYLIST_LOAD_TAB, NULL, start_playback);
3747 }
3748 }
3749
3750 /* read command line filenames */
3751 {
3752 int i;
3753 GSList * list = NULL;
3754
3755 for (i = optind; argv[i] != NULL; i++) {
3756 list = g_slist_append(list, strdup(argv[i]));
3757 }
3758
3759 if (list != NULL) {
3760 process_filenames(list, enqueue, immediate_start, (tab_name != NULL), tab_name);
3761 }
3762 }
3763
3764 /* ensure that at least one playlist has been created */
3765 playlist_ensure_tab_exists();
3766
3767 playlist_set_color();
3768
3769 /* activate jack client and connect ports */
3770 #ifdef HAVE_JACK
3771 if (output == JACK_DRIVER) {
3772 jack_client_start();
3773 }
3774 #endif /* HAVE_JACK */
3775
3776 /* set timeout function */
3777 timeout_tag = aqualung_timeout_add(TIMEOUT_PERIOD, timeout_callback, NULL);
3778
3779 /* re-apply skin to override possible WM theme */
3780 if (!options.disable_skin_support_settings) {
3781 apply_skin(options.skin);
3782 }
3783 }
3784
3785
3786 void
adjust_remote_volume(char * str)3787 adjust_remote_volume(char * str) {
3788
3789 char * endptr = NULL;
3790 int val = gtk_adjustment_get_value(GTK_ADJUSTMENT(adj_vol));
3791
3792 switch (str[0]) {
3793 case 'm':
3794 case 'M':
3795 val = -41;
3796 break;
3797 case '=':
3798 val = strtol(str + 1, &endptr, 10);
3799 if (endptr[0] != '\0') {
3800 fprintf(stderr, "Cannot convert to integer value: %s\n", str + 1);
3801 return;
3802 }
3803 break;
3804 default:
3805 val += strtol(str, &endptr, 10);
3806 if (endptr[0] != '\0') {
3807 fprintf(stderr, "Cannot convert to integer value: %s\n", str);
3808 return;
3809 }
3810 break;
3811 }
3812
3813 gtk_adjustment_set_value(GTK_ADJUSTMENT(adj_vol), val);
3814 }
3815
3816
3817 void
process_metablock(metadata_t * meta)3818 process_metablock(metadata_t * meta) {
3819
3820 char buf[MAXLEN];
3821 char tmp[MAXLEN];
3822 playlist_t * pl;
3823 file_decoder_t * fdec = (file_decoder_t *)meta->fdec;
3824 char * artist = NULL;
3825 char * album = NULL;
3826 char * title = NULL;
3827 char * icy_name = NULL;
3828 char * icy_descr = NULL;
3829 meta_frame_t * frame;
3830
3831 frame = metadata_get_frame_by_type(meta, META_FIELD_APIC, NULL);
3832 if (frame != NULL) {
3833 if (embedded_picture != NULL) {
3834 free(embedded_picture);
3835 }
3836 embedded_picture_size = frame->length;
3837 embedded_picture = malloc(embedded_picture_size);
3838 if (embedded_picture == NULL) {
3839 embedded_picture_size = 0;
3840 } else {
3841 memcpy(embedded_picture, frame->data, embedded_picture_size);
3842 }
3843 } else {
3844 if (embedded_picture != NULL) {
3845 free(embedded_picture);
3846 embedded_picture = NULL;
3847 }
3848 embedded_picture_size = 0;
3849 }
3850
3851 if ((!httpc_is_url(fdec->filename)) && !options.use_ext_title_format) {
3852 return;
3853 }
3854
3855 buf[0] = '\0';
3856 tmp[0] = '\0';
3857
3858 // Abuse artist variable
3859 if ((artist = application_title_format(fdec)) != NULL) {
3860 strncpy(buf, artist, MAXLEN-1);
3861 free(artist);
3862 artist = NULL;
3863 }
3864
3865 if (buf[0] == '\0') {
3866 metadata_get_artist(meta, &artist);
3867 metadata_get_album(meta, &album);
3868 metadata_get_title(meta, &title);
3869 metadata_get_icy_name(meta, &icy_name);
3870
3871 if ((artist && !is_all_wspace(artist)) ||
3872 (album && !is_all_wspace(album)) ||
3873 (title && !is_all_wspace(title))) {
3874 make_title_string(tmp, options.title_format, artist, album, title);
3875 if (icy_name != NULL) {
3876 snprintf(buf, MAXLEN-1, "%s (%s)", tmp, icy_name);
3877 }
3878 } else if (icy_name != NULL) {
3879 strncpy(buf, icy_name, MAXLEN-1);
3880 }
3881 }
3882
3883 if (buf[0] != '\0') {
3884 set_title_label(buf);
3885 } else {
3886 set_title_label(fdec->filename);
3887 }
3888
3889 if (icy_name == NULL) {
3890 return;
3891 }
3892
3893 buf[0] = '\0';
3894
3895 metadata_get_icy_descr(meta, &icy_descr);
3896
3897 if (icy_descr != NULL) {
3898 snprintf(buf, MAXLEN-1, "%s (%s)", icy_name, icy_descr);
3899 } else {
3900 strncpy(buf, icy_name, MAXLEN-1);
3901 }
3902
3903 /* set playlist_str for playlist entry */
3904 if ((pl = playlist_get_playing()) != NULL) {
3905 GtkTreePath * p = playlist_get_playing_path(pl);
3906 if (p != NULL) {
3907 GtkTreeIter iter;
3908 playlist_data_t * data;
3909
3910 gtk_tree_model_get_iter(GTK_TREE_MODEL(pl->store), &iter, p);
3911 gtk_tree_model_get(GTK_TREE_MODEL(pl->store), &iter, PL_COL_DATA, &data, -1);
3912
3913 free_strdup(&data->title, buf);
3914 gtk_tree_store_set(pl->store, &iter, PL_COL_NAME, buf, -1);
3915
3916 gtk_tree_path_free(p);
3917 }
3918 }
3919 }
3920
3921 void
flush_rb_disk2gui(void)3922 flush_rb_disk2gui(void) {
3923
3924 char recv_cmd;
3925
3926 while (rb_read_space(rb_disk2gui)) {
3927 rb_read(rb_disk2gui, &recv_cmd, 1);
3928 }
3929 }
3930
3931 gint
timeout_callback(gpointer data)3932 timeout_callback(gpointer data) {
3933
3934 char cmd;
3935 cue_t cue;
3936 static double left_gain_shadow;
3937 static double right_gain_shadow;
3938 char rcmd;
3939 static char cmdbuf[MAXLEN];
3940 int rcv_count;
3941 static GSList * file_list = NULL;
3942 #ifdef HAVE_JACK
3943 static int jack_popup_beenthere = 0;
3944 #endif /* HAVE_JACK */
3945 metadata_t * meta;
3946
3947
3948 while (rb_read_space(rb_disk2gui)) {
3949 rb_read(rb_disk2gui, &recv_cmd, 1);
3950 switch (recv_cmd) {
3951
3952 case CMD_FILEREQ:
3953 cmd = CMD_CUE;
3954 cue.filename = NULL;
3955 cue.voladj = 0.0f;
3956
3957 if (!is_file_loaded)
3958 break; /* ignore leftover filereq message */
3959
3960 decide_next_track(&cue);
3961
3962 if (cue.filename != NULL) {
3963 rb_write(rb_gui2disk, &cmd, sizeof(char));
3964 rb_write(rb_gui2disk, (void *)&cue, sizeof(cue_t));
3965 } else {
3966 send_cmd = CMD_STOPWOFL;
3967 rb_write(rb_gui2disk, &send_cmd, sizeof(char));
3968 }
3969
3970 try_waking_disk_thread();
3971 break;
3972
3973 case CMD_FILEINFO:
3974 while (rb_read_space(rb_disk2gui) < sizeof(fileinfo_t))
3975 ;
3976 if (fileinfo.format_str != NULL) { /* free previous format_str, if there is one */
3977 free(fileinfo.format_str);
3978 fileinfo.format_str = NULL;
3979 }
3980 rb_read(rb_disk2gui, (char *)&fileinfo, sizeof(fileinfo_t));
3981
3982 sample_pos = 0;
3983 total_samples = fileinfo.total_samples;
3984 status.samples_left = fileinfo.total_samples;
3985 status.sample_pos = 0;
3986 status.sample_offset = 0;
3987 fresh_new_file = fresh_new_file_prev = 0;
3988 run_hooks_fdec("track_change", fdec);
3989 break;
3990
3991 case CMD_STATUS:
3992 while (rb_read_space(rb_disk2gui) < sizeof(status_t))
3993 ;
3994 rb_read(rb_disk2gui, (char *)&status, sizeof(status_t));
3995
3996 sample_pos = total_samples - status.samples_left;
3997 #ifdef HAVE_LOOP
3998 if (options.repeat_on &&
3999 (sample_pos < total_samples * options.loop_range_start ||
4000 sample_pos > total_samples * options.loop_range_end)) {
4001
4002 seek_t seek;
4003
4004 send_cmd = CMD_SEEKTO;
4005 seek.seek_to_pos = options.loop_range_start * total_samples;
4006 rb_write(rb_gui2disk, &send_cmd, 1);
4007 rb_write(rb_gui2disk, (char *)&seek, sizeof(seek_t));
4008 try_waking_disk_thread();
4009 refresh_scale_suppress = 2;
4010 }
4011 #endif /* HAVE_LOOP */
4012
4013 if ((is_file_loaded) && (status.samples_left < 2*status.sample_offset)) {
4014 allow_seeks = 0;
4015 } else {
4016 allow_seeks = 1;
4017 }
4018
4019 /* treat files with unknown length */
4020 if (total_samples == 0) {
4021 allow_seeks = 1;
4022 sample_pos = status.sample_pos - status.sample_offset;
4023 }
4024
4025 if ((!fresh_new_file) && (sample_pos > status.sample_offset)) {
4026 fresh_new_file = 1;
4027 }
4028
4029 if (fresh_new_file && !fresh_new_file_prev) {
4030 disp_info = fileinfo;
4031 disp_samples = total_samples;
4032 if (sample_pos > status.sample_offset) {
4033 disp_pos = sample_pos - status.sample_offset;
4034 } else {
4035 disp_pos = 0;
4036 }
4037 refresh_displays();
4038 } else {
4039 if (sample_pos > status.sample_offset) {
4040 disp_pos = sample_pos - status.sample_offset;
4041 } else {
4042 disp_pos = 0;
4043 }
4044
4045 if (disp_info.sample_rate != status.sample_rate) {
4046 disp_info.sample_rate = status.sample_rate;
4047 refresh_displays();
4048 }
4049
4050 if (is_file_loaded) {
4051 refresh_time_displays();
4052 }
4053 }
4054
4055 fresh_new_file_prev = fresh_new_file;
4056
4057 if (refresh_scale && !refresh_scale_suppress) {
4058 if (total_samples == 0) {
4059 gtk_adjustment_set_value(GTK_ADJUSTMENT(adj_pos), 0.0f);
4060 } else {
4061 gtk_adjustment_set_value(GTK_ADJUSTMENT(adj_pos),
4062 100.0 * sample_pos / total_samples);
4063 run_hooks("track_position_change");
4064 }
4065 }
4066
4067 if (refresh_scale_suppress > 0) {
4068 --refresh_scale_suppress;
4069 }
4070
4071 show_scale_pos(!total_samples ? FALSE : TRUE);
4072 break;
4073
4074 case CMD_METABLOCK:
4075 while (rb_read_space(rb_disk2gui) < sizeof(metadata_t *))
4076 ;
4077 rb_read(rb_disk2gui, (char *)&meta, sizeof(metadata_t *));
4078
4079 process_metablock(meta);
4080 break;
4081
4082 default:
4083 fprintf(stderr, "gui: unexpected command %d recv'd from disk\n", recv_cmd);
4084 break;
4085 }
4086 }
4087 /* update volume & balance if necessary */
4088 if ((options.vol != vol_prev) || (options.bal != bal_prev)) {
4089 vol_prev = options.vol;
4090 vol_lin = (options.vol < -40.5f) ? 0 : db2lin(options.vol);
4091 bal_prev = options.bal;
4092 if (options.bal >= 0.0f) {
4093 left_gain_shadow = vol_lin * db2lin(-0.4f * options.bal);
4094 right_gain_shadow = vol_lin;
4095 } else {
4096 left_gain_shadow = vol_lin;
4097 right_gain_shadow = vol_lin * db2lin(0.4f * options.bal);
4098 }
4099 left_gain = left_gain_shadow;
4100 right_gain = right_gain_shadow;
4101 }
4102
4103 /* receive and execute remote commands, if any */
4104 rcv_count = 0;
4105 while (((rcmd = receive_message(aqualung_socket_fd, cmdbuf)) != 0) && (rcv_count < MAX_RCV_COUNT)) {
4106 switch (rcmd) {
4107 case RCMD_BACK:
4108 prev_event(NULL, NULL, NULL);
4109 break;
4110 case RCMD_PAUSE:
4111 if (!options.combine_play_pause) {
4112 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(pause_button),
4113 !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(pause_button)));
4114 break;
4115 }
4116 case RCMD_PLAY:
4117 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(play_button),
4118 !gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(play_button)));
4119 break;
4120 case RCMD_STOP:
4121 stop_event(NULL, NULL, NULL);
4122 break;
4123 case RCMD_FWD:
4124 next_event(NULL, NULL, NULL);
4125 break;
4126 case RCMD_ADD_FILE:
4127 file_list = g_slist_append(file_list, strdup(cmdbuf));
4128 break;
4129 case RCMD_ADD_COMMIT:
4130 process_filenames(file_list, cmdbuf[0], cmdbuf[1], cmdbuf[2], cmdbuf+3);
4131 file_list = NULL;
4132 break;
4133 case RCMD_CUSTOM:
4134 run_custom_remote_command(cmdbuf);
4135 break;
4136 case RCMD_VOLADJ:
4137 adjust_remote_volume(cmdbuf);
4138 break;
4139 case RCMD_QUIT:
4140 main_window_closing();
4141 break;
4142 default:
4143 fprintf(stderr, "Unrecognized remote command received: %i\n", (int)rcmd);
4144 }
4145 ++rcv_count;
4146 }
4147
4148 /* check for JACK shutdown condition */
4149 #ifdef HAVE_JACK
4150 if (output == JACK_DRIVER) {
4151 if (jack_is_shutdown) {
4152 if (is_file_loaded) {
4153 stop_event(NULL, NULL, NULL);
4154 }
4155 if (!jack_popup_beenthere) {
4156 jack_shutdown_window();
4157 #ifdef HAVE_JACK_MGMT
4158 if (ports_window) {
4159 ports_clicked_close(NULL, NULL);
4160 }
4161 gtk_widget_set_sensitive(conf__jack, FALSE);
4162 #endif /* HAVE_JACK_MGMT */
4163 jack_client_close(jack_client);
4164 jack_popup_beenthere = 1;
4165 }
4166 }
4167 }
4168 #endif /* HAVE_JACK */
4169
4170 return TRUE;
4171 }
4172
4173
4174 void
run_gui(void)4175 run_gui(void) {
4176
4177 gtk_main();
4178 gdk_threads_leave();
4179
4180 return;
4181 }
4182
4183
4184 void
set_buttons_relief(void)4185 set_buttons_relief(void) {
4186
4187 GtkWidget *rbuttons_table[] = {
4188 prev_button, stop_button, next_button, play_button,
4189 pause_button, repeat_button, repeat_all_button, shuffle_button,
4190 #ifdef HAVE_LADSPA
4191 plugin_toggle,
4192 #endif /* HAVE_LADSPA */
4193 playlist_toggle, musicstore_toggle
4194 };
4195
4196 gint i, n;
4197 i = sizeof(rbuttons_table)/sizeof(GtkWidget*);
4198
4199 for (n = 0; n < i; n++) {
4200 if ((rbuttons_table[n] != pause_button) || !options.combine_play_pause) {
4201 gtk_button_set_relief(GTK_BUTTON(rbuttons_table[n]),
4202 (options.disable_buttons_relief) ? GTK_RELIEF_NONE : GTK_RELIEF_NORMAL);
4203 }
4204 }
4205 }
4206
4207 // vim: shiftwidth=8:tabstop=8:softtabstop=8 :
4208
4209