1 /* Audacious - Cross-platform multimedia player
2 * Copyright (C) 2005-2011 Audacious development team.
3 *
4 * BMP - Cross-platform multimedia player
5 * Copyright (C) 2003-2004 BMP development team.
6 *
7 * Based on XMMS:
8 * Copyright (C) 1998-2003 XMMS development team.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; under version 3 of the License.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses>.
21 *
22 * The Audacious team does not consider modular code linking to
23 * Audacious or using our public API to be a derived work.
24 */
25
26 #include <math.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <sys/time.h>
30
31 #include <gdk/gdkkeysyms.h>
32 #include <gtk/gtk.h>
33
34 #include <libaudcore/audstrings.h>
35 #include <libaudcore/drct.h>
36 #include <libaudcore/hook.h>
37 #include <libaudcore/i18n.h>
38 #include <libaudcore/mainloop.h>
39 #include <libaudcore/plugins.h>
40 #include <libaudcore/runtime.h>
41 #include <libaudgui/libaudgui.h>
42
43 #include "actions-mainwin.h"
44 #include "actions-playlist.h"
45 #include "dnd.h"
46 #include "menus.h"
47 #include "plugin.h"
48 #include "skins_cfg.h"
49 #include "equalizer.h"
50 #include "main.h"
51 #include "vis-callbacks.h"
52 #include "playlistwin.h"
53 #include "button.h"
54 #include "hslider.h"
55 #include "menurow.h"
56 #include "monostereo.h"
57 #include "number.h"
58 #include "playlist-widget.h"
59 #include "playstatus.h"
60 #include "textbox.h"
61 #include "window.h"
62 #include "vis.h"
63 #include "skins_util.h"
64 #include "view.h"
65
66 #include "../ui-common/menu-ops.h"
67
68 #define SEEK_THRESHOLD 200 /* milliseconds */
69 #define SEEK_SPEED 50 /* milliseconds per pixel */
70
71 class MainWindow : public Window
72 {
73 public:
MainWindow(bool shaded)74 MainWindow (bool shaded) :
75 Window (WINDOW_MAIN, & config.player_x, & config.player_y,
76 shaded ? MAINWIN_SHADED_WIDTH : skin.hints.mainwin_width,
77 shaded ? MAINWIN_SHADED_HEIGHT : skin.hints.mainwin_height, shaded) {}
78
79 private:
80 void draw (cairo_t * cr);
81 bool button_press (GdkEventButton * event);
82 bool scroll (GdkEventScroll * event);
83 bool motion (GdkEventMotion * event);
84 bool leave ();
85
86 QueuedFunc m_popup_timer;
87 bool m_popup_shown = false;
88 };
89
90 Window * mainwin;
91
92 Button * mainwin_eq, * mainwin_pl;
93 TextBox * mainwin_info;
94 MenuRow * mainwin_menurow;
95
96 SkinnedVis * mainwin_vis;
97 SmallVis * mainwin_svis;
98
99 static bool seeking = false;
100 static int seek_start, seek_time;
101
102 static TextBox * locked_textbox = nullptr;
103 static String locked_old_text;
104
105 static QueuedFunc status_message_timeout;
106 static QueuedFunc mainwin_volume_release_timeout;
107
108 static Button * mainwin_menubtn, * mainwin_minimize, * mainwin_shade, * mainwin_close;
109 static Button * mainwin_shaded_menubtn, * mainwin_shaded_minimize, * mainwin_shaded_shade, * mainwin_shaded_close;
110
111 static Button * mainwin_rew, * mainwin_fwd;
112 static Button * mainwin_eject;
113 static Button * mainwin_play, * mainwin_pause, * mainwin_stop;
114 static Button * mainwin_shuffle, * mainwin_repeat;
115
116 static TextBox * mainwin_stime_min, * mainwin_stime_sec;
117 static TextBox * mainwin_rate_text, * mainwin_freq_text, * mainwin_othertext;
118
119 static PlayStatus * mainwin_playstatus;
120 static SkinnedNumber * mainwin_minus_num, * mainwin_10min_num, * mainwin_min_num;
121 static SkinnedNumber * mainwin_10sec_num, * mainwin_sec_num;
122 static HSlider * mainwin_position, * mainwin_sposition;
123
124 static HSlider * mainwin_volume, * mainwin_balance;
125 static MonoStereo * mainwin_monostereo;
126
127 static Button * mainwin_srew, * mainwin_splay, * mainwin_spause;
128 static Button * mainwin_sstop, * mainwin_sfwd, * mainwin_seject, * mainwin_about;
129
130 static void mainwin_position_motion_cb ();
131 static void mainwin_position_release_cb ();
132 static void seek_timeout (void * rewind);
133
134 /* always returns a 6-character string */
format_time(int time,int length)135 static StringBuf format_time (int time, int length)
136 {
137 bool zero = aud_get_bool ("leading_zero");
138 bool remaining = aud_get_bool ("skins", "show_remaining_time");
139
140 if (remaining && length > 0)
141 {
142 time = (length - time) / 1000;
143 time = aud::clamp(0, time, 359999); // 99:59:59
144
145 if (time < 60)
146 return str_printf (zero ? "-00:%02d" : " -0:%02d", time);
147 else if (time < 6000)
148 return str_printf (zero ? "%03d:%02d" : "%3d:%02d", -time / 60, time % 60);
149 else
150 return str_printf ("%3d:%02d", -time / 3600, time / 60 % 60);
151 }
152 else
153 {
154 time /= 1000;
155 time = aud::clamp(0, time, 3599999); // 999:59:59
156
157 if (time < 6000)
158 return str_printf (zero ? " %02d:%02d" : " %2d:%02d", time / 60, time % 60);
159 else if (time < 60000)
160 return str_printf ("%3d:%02d", time / 60, time % 60);
161 else
162 return str_printf ("%3d:%02d", time / 3600, time / 60 % 60);
163 }
164 }
165
mainwin_menubtn_cb()166 static void mainwin_menubtn_cb ()
167 {
168 int x, y;
169 mainwin->getPosition (& x, & y);
170 menu_popup (UI_MENU_MAIN, x + 6 * config.scale,
171 y + MAINWIN_SHADED_HEIGHT * config.scale, false, false, 1, GDK_CURRENT_TIME);
172 }
173
mainwin_minimize_cb()174 static void mainwin_minimize_cb ()
175 {
176 gtk_window_iconify ((GtkWindow *) mainwin->gtk ());
177 }
178
mainwin_shade_toggle()179 static void mainwin_shade_toggle ()
180 {
181 view_set_player_shaded (! aud_get_bool ("skins", "player_shaded"));
182 }
183
mainwin_lock_info_text(const char * text)184 static void mainwin_lock_info_text (const char * text)
185 {
186 if (! locked_textbox)
187 {
188 locked_textbox = skin.hints.mainwin_othertext_is_status ? mainwin_othertext : mainwin_info;
189 locked_old_text = locked_textbox->get_text ();
190 }
191
192 locked_textbox->set_text (text);
193 }
194
mainwin_release_info_text()195 static void mainwin_release_info_text ()
196 {
197 if (locked_textbox)
198 {
199 locked_textbox->set_text (locked_old_text);
200 locked_textbox = nullptr;
201 locked_old_text = String ();
202 }
203 }
204
set_info_text(TextBox * textbox,const char * text)205 static void set_info_text (TextBox * textbox, const char * text)
206 {
207 if (textbox == locked_textbox)
208 locked_old_text = String (text);
209 else
210 textbox->set_text (text);
211 }
212
213 #define mainwin_set_info_text(t) set_info_text (mainwin_info, (t))
214 #define mainwin_set_othertext(t) set_info_text (mainwin_othertext, (t))
215
mainwin_show_status_message(const char * message)216 void mainwin_show_status_message (const char * message)
217 {
218 mainwin_lock_info_text (message);
219 status_message_timeout.queue (1000, mainwin_release_info_text);
220 }
221
mainwin_set_song_title(const char * title)222 static void mainwin_set_song_title (const char * title)
223 {
224 StringBuf buf;
225
226 if (title)
227 buf = str_printf (_("%s - Audacious"), title);
228 else
229 buf = str_copy (_("Audacious"));
230
231 int instance = aud_get_instance ();
232 if (instance != 1)
233 str_append_printf (buf, " (%d)", instance);
234
235 mainwin->setWindowTitle ((const char *) buf);
236 mainwin_set_info_text (title ? title : "");
237 }
238
title_change()239 static void title_change ()
240 {
241 if (aud_drct_get_ready ())
242 mainwin_set_song_title (aud_drct_get_title ());
243 else
244 mainwin_set_song_title ("Buffering ...");
245 }
246
setup_widget(Widget * widget,int x,int y,bool show)247 static void setup_widget (Widget * widget, int x, int y, bool show)
248 {
249 int width, height;
250
251 /* use get_size_request(), not get_preferred_size() */
252 /* get_preferred_size() will return 0x0 for hidden widgets */
253 gtk_widget_get_size_request (widget->gtk (), & width, & height);
254
255 width /= config.scale;
256 height /= config.scale;
257
258 /* hide widgets that are outside the window boundary */
259 if (x < 0 || x + width > skin.hints.mainwin_width ||
260 y < 0 || y + height > skin.hints.mainwin_height)
261 show = false;
262
263 widget->setVisible (show);
264 mainwin->move_widget (false, widget, x, y);
265 }
266
mainwin_refresh_hints()267 void mainwin_refresh_hints ()
268 {
269 const SkinHints * p = & skin.hints;
270
271 mainwin_menurow->setVisible (p->mainwin_menurow_visible);
272 mainwin_rate_text->setVisible (p->mainwin_streaminfo_visible);
273 mainwin_freq_text->setVisible (p->mainwin_streaminfo_visible);
274 mainwin_monostereo->setVisible (p->mainwin_streaminfo_visible);
275
276 mainwin_info->set_width (p->mainwin_text_width);
277
278 setup_widget (mainwin_vis, p->mainwin_vis_x, p->mainwin_vis_y, p->mainwin_vis_visible);
279 setup_widget (mainwin_info, p->mainwin_text_x, p->mainwin_text_y, p->mainwin_text_visible);
280 setup_widget (mainwin_othertext, p->mainwin_infobar_x, p->mainwin_infobar_y, p->mainwin_othertext_visible);
281
282 bool playing = aud_drct_get_playing ();
283 bool can_seek = aud_drct_get_length () > 0;
284
285 setup_widget (mainwin_minus_num, p->mainwin_number_0_x, p->mainwin_number_0_y, playing);
286 setup_widget (mainwin_10min_num, p->mainwin_number_1_x, p->mainwin_number_1_y, playing);
287 setup_widget (mainwin_min_num, p->mainwin_number_2_x, p->mainwin_number_2_y, playing);
288 setup_widget (mainwin_10sec_num, p->mainwin_number_3_x, p->mainwin_number_3_y, playing);
289 setup_widget (mainwin_sec_num, p->mainwin_number_4_x, p->mainwin_number_4_y, playing);
290 setup_widget (mainwin_position, p->mainwin_position_x, p->mainwin_position_y, can_seek);
291
292 setup_widget (mainwin_playstatus, p->mainwin_playstatus_x, p->mainwin_playstatus_y, true);
293 setup_widget (mainwin_volume, p->mainwin_volume_x, p->mainwin_volume_y, true);
294 setup_widget (mainwin_balance, p->mainwin_balance_x, p->mainwin_balance_y, true);
295 setup_widget (mainwin_rew, p->mainwin_previous_x, p->mainwin_previous_y, true);
296 setup_widget (mainwin_play, p->mainwin_play_x, p->mainwin_play_y, true);
297 setup_widget (mainwin_pause, p->mainwin_pause_x, p->mainwin_pause_y, true);
298 setup_widget (mainwin_stop, p->mainwin_stop_x, p->mainwin_stop_y, true);
299 setup_widget (mainwin_fwd, p->mainwin_next_x, p->mainwin_next_y, true);
300 setup_widget (mainwin_eject, p->mainwin_eject_x, p->mainwin_eject_y, true);
301 setup_widget (mainwin_eq, p->mainwin_eqbutton_x, p->mainwin_eqbutton_y, true);
302 setup_widget (mainwin_pl, p->mainwin_plbutton_x, p->mainwin_plbutton_y, true);
303 setup_widget (mainwin_shuffle, p->mainwin_shuffle_x, p->mainwin_shuffle_y, true);
304 setup_widget (mainwin_repeat, p->mainwin_repeat_x, p->mainwin_repeat_y, true);
305 setup_widget (mainwin_about, p->mainwin_about_x, p->mainwin_about_y, true);
306 setup_widget (mainwin_minimize, p->mainwin_minimize_x, p->mainwin_minimize_y, true);
307 setup_widget (mainwin_shade, p->mainwin_shade_x, p->mainwin_shade_y, true);
308 setup_widget (mainwin_close, p->mainwin_close_x, p->mainwin_close_y, true);
309
310 if (aud_get_bool ("skins", "player_shaded"))
311 mainwin->resize (MAINWIN_SHADED_WIDTH, MAINWIN_SHADED_HEIGHT);
312 else
313 mainwin->resize (p->mainwin_width, p->mainwin_height);
314
315 mainwin_vis->set_colors ();
316 }
317
318 /* note that the song info is not translated since it is displayed using
319 * the skinned bitmap font, which supports only the English alphabet */
mainwin_set_song_info(int bitrate,int samplerate,int channels)320 static void mainwin_set_song_info (int bitrate, int samplerate, int channels)
321 {
322 char scratch[32];
323 int length;
324
325 if (bitrate > 0)
326 {
327 if (bitrate < 1000000)
328 snprintf (scratch, sizeof scratch, "%3d", bitrate / 1000);
329 else
330 snprintf (scratch, sizeof scratch, "%2dH", bitrate / 100000);
331
332 mainwin_rate_text->set_text (scratch);
333 }
334 else
335 mainwin_rate_text->set_text (nullptr);
336
337 if (samplerate > 0)
338 {
339 snprintf (scratch, sizeof scratch, "%2d", samplerate / 1000);
340 mainwin_freq_text->set_text (scratch);
341 }
342 else
343 mainwin_freq_text->set_text (nullptr);
344
345 mainwin_monostereo->set_num_channels (channels);
346
347 if (bitrate > 0)
348 snprintf (scratch, sizeof scratch, "%d kbps", bitrate / 1000);
349 else
350 scratch[0] = 0;
351
352 if (samplerate > 0)
353 {
354 length = strlen (scratch);
355 snprintf (scratch + length, sizeof scratch - length, "%s%d kHz", length ?
356 ", " : "", samplerate / 1000);
357 }
358
359 if (channels > 0)
360 {
361 length = strlen (scratch);
362 snprintf (scratch + length, sizeof scratch - length, "%s%s", length ?
363 ", " : "", channels > 2 ? "surround" : channels > 1 ? "stereo" : "mono");
364 }
365
366 mainwin_set_othertext (scratch);
367 }
368
info_change()369 static void info_change ()
370 {
371 int bitrate, samplerate, channels;
372 aud_drct_get_info (bitrate, samplerate, channels);
373 mainwin_set_song_info (bitrate, samplerate, channels);
374 }
375
playback_pause()376 static void playback_pause ()
377 {
378 mainwin_playstatus->set_status (STATUS_PAUSE);
379 }
380
playback_unpause()381 static void playback_unpause ()
382 {
383 mainwin_playstatus->set_status (STATUS_PLAY);
384 }
385
mainwin_playback_begin()386 void mainwin_playback_begin ()
387 {
388 mainwin_update_song_info ();
389
390 mainwin_stime_min->show ();
391 mainwin_stime_sec->show ();
392 mainwin_minus_num->show ();
393 mainwin_10min_num->show ();
394 mainwin_min_num->show ();
395 mainwin_10sec_num->show ();
396 mainwin_sec_num->show ();
397
398 if (aud_drct_get_length () > 0)
399 {
400 mainwin_position->show ();
401 mainwin_sposition->show ();
402 }
403
404 if (aud_drct_get_paused ())
405 playback_pause ();
406 else
407 playback_unpause ();
408
409 title_change ();
410 info_change ();
411 }
412
mainwin_playback_stop()413 static void mainwin_playback_stop ()
414 {
415 seeking = false;
416 timer_remove (TimerRate::Hz10, seek_timeout);
417
418 mainwin_set_song_title (nullptr);
419
420 mainwin_vis->clear ();
421 mainwin_svis->clear ();
422
423 mainwin_minus_num->hide ();
424 mainwin_10min_num->hide ();
425 mainwin_min_num->hide ();
426 mainwin_10sec_num->hide ();
427 mainwin_sec_num->hide ();
428 mainwin_stime_min->hide ();
429 mainwin_stime_sec->hide ();
430 mainwin_position->hide ();
431 mainwin_sposition->hide ();
432
433 mainwin_position->set_pressed (false);
434 mainwin_sposition->set_pressed (false);
435
436 /* clear sampling parameter displays */
437 mainwin_rate_text->set_text (nullptr);
438 mainwin_freq_text->set_text (nullptr);
439 mainwin_monostereo->set_num_channels (0);
440 mainwin_set_othertext ("");
441
442 mainwin_playstatus->set_status (STATUS_STOP);
443
444 playlistwin_hide_timer();
445 }
446
record_toggled()447 static void record_toggled ()
448 {
449 if (aud_drct_get_record_enabled ())
450 {
451 if (aud_get_bool ("record"))
452 mainwin_show_status_message (_("Recording on"));
453 else
454 mainwin_show_status_message (_("Recording off"));
455 }
456 }
457
repeat_toggled()458 static void repeat_toggled ()
459 {
460 mainwin_repeat->set_active (aud_get_bool ("repeat"));
461 }
462
shuffle_toggled()463 static void shuffle_toggled ()
464 {
465 mainwin_shuffle->set_active (aud_get_bool ("shuffle"));
466 }
467
no_advance_toggled()468 static void no_advance_toggled ()
469 {
470 if (aud_get_bool ("no_playlist_advance"))
471 mainwin_show_status_message (_("Single mode."));
472 else
473 mainwin_show_status_message (_("Playlist mode."));
474 }
475
stop_after_song_toggled()476 static void stop_after_song_toggled ()
477 {
478 if (aud_get_bool ("stop_after_current_song"))
479 mainwin_show_status_message (_("Stopping after song."));
480 }
481
scroll(GdkEventScroll * event)482 bool MainWindow::scroll (GdkEventScroll * event)
483 {
484 switch (event->direction)
485 {
486 case GDK_SCROLL_UP:
487 mainwin_set_volume_diff (aud_get_int ("volume_delta"));
488 break;
489 case GDK_SCROLL_DOWN:
490 mainwin_set_volume_diff (-aud_get_int ("volume_delta"));
491 break;
492 case GDK_SCROLL_LEFT:
493 aud_drct_seek (aud_drct_get_time () - aud_get_int ("step_size") * 1000);
494 break;
495 case GDK_SCROLL_RIGHT:
496 aud_drct_seek (aud_drct_get_time () + aud_get_int ("step_size") * 1000);
497 break;
498 default:
499 break;
500 }
501
502 return true;
503 }
504
button_press(GdkEventButton * event)505 bool MainWindow::button_press (GdkEventButton * event)
506 {
507 if (event->button == 1 && event->type == GDK_2BUTTON_PRESS &&
508 event->window == gtk_widget_get_window (gtk ()) &&
509 event->y < 14 * config.scale)
510 {
511 mainwin_shade_toggle ();
512 return true;
513 }
514
515 if (event->button == 3 && event->type == GDK_BUTTON_PRESS)
516 {
517 menu_popup (UI_MENU_MAIN, event->x_root, event->y_root, false, false,
518 event->button, event->time);
519 return true;
520 }
521
522 return Window::button_press (event);
523 }
524
motion(GdkEventMotion * event)525 bool MainWindow::motion (GdkEventMotion * event)
526 {
527 if (is_shaded () &&
528 event->x >= 79 * config.scale &&
529 event->x <= 157 * config.scale &&
530 aud_get_bool ("show_filepopup_for_tuple"))
531 {
532 if (! m_popup_shown)
533 {
534 m_popup_timer.queue (aud_get_int ("filepopup_delay") * 100,
535 audgui_infopopup_show_current);
536 m_popup_shown = true;
537 }
538 }
539 else if (m_popup_shown)
540 {
541 audgui_infopopup_hide ();
542 m_popup_timer.stop ();
543 m_popup_shown = false;
544 }
545
546 return Window::motion (event);
547 }
548
leave()549 bool MainWindow::leave ()
550 {
551 if (m_popup_shown)
552 {
553 audgui_infopopup_hide ();
554 m_popup_timer.stop ();
555 m_popup_shown = false;
556 }
557
558 return Window::leave ();
559 }
560
mainwin_playback_rpress(Button * button,GdkEventButton * event)561 static void mainwin_playback_rpress (Button * button, GdkEventButton * event)
562 {
563 menu_popup (UI_MENU_PLAYBACK, event->x_root, event->y_root, false, false,
564 event->button, event->time);
565 }
566
keypress(GdkEventKey * event)567 bool Window::keypress (GdkEventKey * event)
568 {
569 if (playlistwin_list->handle_keypress (event))
570 return true;
571
572 switch (event->keyval)
573 {
574 case GDK_KEY_Left:
575 case GDK_KEY_KP_Left:
576 case GDK_KEY_KP_7:
577 aud_drct_seek (aud_drct_get_time () - aud_get_int ("step_size") * 1000);
578 break;
579 case GDK_KEY_Right:
580 case GDK_KEY_KP_Right:
581 case GDK_KEY_KP_9:
582 aud_drct_seek (aud_drct_get_time () + aud_get_int ("step_size") * 1000);
583 break;
584 case GDK_KEY_KP_4:
585 aud_drct_pl_prev ();
586 break;
587 case GDK_KEY_KP_6:
588 aud_drct_pl_next ();
589 break;
590 case GDK_KEY_KP_Insert:
591 audgui_jump_to_track ();
592 break;
593 case GDK_KEY_space:
594 aud_drct_pause ();
595 break;
596 case GDK_KEY_Tab: /* GtkUIManager does not handle tab, apparently. */
597 if (event->state & GDK_SHIFT_MASK)
598 pl_prev ();
599 else
600 pl_next ();
601
602 break;
603 case GDK_KEY_ISO_Left_Tab:
604 pl_prev ();
605 break;
606 default:
607 return false;
608 }
609
610 return true;
611 }
612
mainwin_drag_data_received(GtkWidget * widget,GdkDragContext * context,int x,int y,GtkSelectionData * selection_data,unsigned info,unsigned time,void *)613 void mainwin_drag_data_received (GtkWidget * widget, GdkDragContext * context,
614 int x, int y, GtkSelectionData * selection_data, unsigned info, unsigned time, void *)
615 {
616 g_return_if_fail (selection_data != nullptr);
617
618 const char * data = (const char *) gtk_selection_data_get_data (selection_data);
619 g_return_if_fail (data);
620
621 if (str_has_prefix_nocase (data, "file:///"))
622 {
623 if (str_has_suffix_nocase (data, ".wsz\r\n") || str_has_suffix_nocase
624 (data, ".zip\r\n"))
625 {
626 on_skin_view_drag_data_received (0, context, x, y, selection_data, info, time, 0);
627 return;
628 }
629 }
630
631 audgui_urilist_open (data);
632 }
633
time_now()634 static int time_now ()
635 {
636 struct timeval tv;
637 gettimeofday (& tv, nullptr);
638 return (tv.tv_sec % (24 * 3600) * 1000 + tv.tv_usec / 1000);
639 }
640
time_diff(int a,int b)641 static int time_diff (int a, int b)
642 {
643 if (a > 18 * 3600 * 1000 && b < 6 * 3600 * 1000) /* detect midnight */
644 b += 24 * 3600 * 1000;
645 return (b > a) ? b - a : 0;
646 }
647
seek_timeout(void * rewind)648 static void seek_timeout (void * rewind)
649 {
650 int held = time_diff (seek_time, time_now ());
651 if (held < SEEK_THRESHOLD)
652 return;
653
654 int position;
655 if (aud::from_ptr<bool> (rewind))
656 position = seek_start - held / SEEK_SPEED;
657 else
658 position = seek_start + held / SEEK_SPEED;
659
660 position = aud::clamp (position, 0, 219);
661 mainwin_position->set_pos (position);
662 mainwin_position_motion_cb ();
663 }
664
seek_press(GdkEventButton * event,bool rewind)665 static void seek_press (GdkEventButton * event, bool rewind)
666 {
667 if (event->button != 1 || seeking)
668 return;
669
670 seeking = true;
671 seek_start = mainwin_position->get_pos ();
672 seek_time = time_now ();
673 timer_add (TimerRate::Hz10, seek_timeout, aud::to_ptr (rewind));
674 }
675
seek_release(GdkEventButton * event,bool rewind)676 static void seek_release (GdkEventButton * event, bool rewind)
677 {
678 if (event->button != 1 || ! seeking)
679 return;
680
681 if (! aud_drct_get_playing () || time_diff (seek_time, time_now ()) <
682 SEEK_THRESHOLD)
683 {
684 if (rewind)
685 aud_drct_pl_prev ();
686 else
687 aud_drct_pl_next ();
688 }
689 else
690 mainwin_position_release_cb ();
691
692 seeking = false;
693 timer_remove (TimerRate::Hz10, seek_timeout);
694 }
695
mainwin_rew_press(Button * button,GdkEventButton * event)696 static void mainwin_rew_press (Button * button, GdkEventButton * event)
697 { seek_press (event, true); }
mainwin_rew_release(Button * button,GdkEventButton * event)698 static void mainwin_rew_release (Button * button, GdkEventButton * event)
699 { seek_release (event, true); }
mainwin_fwd_press(Button * button,GdkEventButton * event)700 static void mainwin_fwd_press (Button * button, GdkEventButton * event)
701 { seek_press (event, false); }
mainwin_fwd_release(Button * button,GdkEventButton * event)702 static void mainwin_fwd_release (Button * button, GdkEventButton * event)
703 { seek_release (event, false); }
704
mainwin_shuffle_cb(Button * button,GdkEventButton * event)705 static void mainwin_shuffle_cb (Button * button, GdkEventButton * event)
706 { aud_set_bool ("shuffle", button->get_active ()); }
mainwin_repeat_cb(Button * button,GdkEventButton * event)707 static void mainwin_repeat_cb (Button * button, GdkEventButton * event)
708 { aud_set_bool ("repeat", button->get_active ()); }
mainwin_eq_cb(Button * button,GdkEventButton * event)709 static void mainwin_eq_cb (Button * button, GdkEventButton * event)
710 { view_set_show_equalizer (button->get_active ()); }
mainwin_pl_cb(Button * button,GdkEventButton * event)711 static void mainwin_pl_cb (Button * button, GdkEventButton * event)
712 { view_set_show_playlist (button->get_active ()); }
713
mainwin_spos_set_knob()714 static void mainwin_spos_set_knob ()
715 {
716 int pos = mainwin_sposition->get_pos ();
717 int x = (pos < 6) ? 17 : (pos < 9) ? 20 : 23;
718 mainwin_sposition->set_knob (x, 36, x, 36);
719 }
720
mainwin_spos_motion_cb()721 static void mainwin_spos_motion_cb ()
722 {
723 mainwin_spos_set_knob ();
724
725 int pos = mainwin_sposition->get_pos ();
726 int length = aud_drct_get_length ();
727 int time = (pos - 1) * length / 12;
728
729 StringBuf buf = format_time (time, length);
730
731 mainwin_stime_min->set_text (buf);
732 mainwin_stime_sec->set_text (buf + 4);
733 }
734
mainwin_spos_release_cb()735 static void mainwin_spos_release_cb ()
736 {
737 mainwin_spos_set_knob ();
738
739 int pos = mainwin_sposition->get_pos ();
740 aud_drct_seek (aud_drct_get_length () * (pos - 1) / 12);
741 }
742
mainwin_position_motion_cb()743 static void mainwin_position_motion_cb ()
744 {
745 int length = aud_drct_get_length () / 1000;
746 int pos = mainwin_position->get_pos ();
747 int time = pos * length / 219;
748
749 mainwin_lock_info_text (str_printf (_("Seek to %d:%-2.2d / %d:%-2.2d"),
750 time / 60, time % 60, length / 60, length % 60));
751 }
752
mainwin_position_release_cb()753 static void mainwin_position_release_cb ()
754 {
755 int length = aud_drct_get_length ();
756 int pos = mainwin_position->get_pos ();
757 int time = (int64_t) pos * length / 219;
758
759 aud_drct_seek(time);
760 mainwin_release_info_text();
761 }
762
mainwin_adjust_volume_motion(int v)763 void mainwin_adjust_volume_motion (int v)
764 {
765 aud_drct_set_volume_main (v);
766 mainwin_lock_info_text (str_printf (_("Volume: %d%%"), v));
767 }
768
mainwin_adjust_volume_release()769 void mainwin_adjust_volume_release ()
770 {
771 mainwin_release_info_text ();
772 }
773
mainwin_adjust_balance_motion(int b)774 void mainwin_adjust_balance_motion (int b)
775 {
776 aud_drct_set_volume_balance (b);
777
778 if (b < 0)
779 mainwin_lock_info_text (str_printf (_("Balance: %d%% left"), -b));
780 else if (b == 0)
781 mainwin_lock_info_text (_("Balance: center"));
782 else
783 mainwin_lock_info_text (str_printf (_("Balance: %d%% right"), b));
784 }
785
mainwin_adjust_balance_release()786 void mainwin_adjust_balance_release ()
787 {
788 mainwin_release_info_text ();
789 }
790
mainwin_volume_set_frame()791 static void mainwin_volume_set_frame ()
792 {
793 int pos = mainwin_volume->get_pos ();
794 int frame = (pos * 27 + 25) / 51;
795 mainwin_volume->set_frame (0, 15 * frame);
796 }
797
mainwin_set_volume_slider(int percent)798 void mainwin_set_volume_slider (int percent)
799 {
800 mainwin_volume->set_pos ((percent * 51 + 50) / 100);
801 mainwin_volume_set_frame ();
802 }
803
mainwin_volume_motion_cb()804 static void mainwin_volume_motion_cb ()
805 {
806 mainwin_volume_set_frame ();
807 int pos = mainwin_volume->get_pos ();
808 int vol = (pos * 100 + 25) / 51;
809
810 mainwin_adjust_volume_motion (vol);
811 equalizerwin_set_volume_slider (vol);
812 }
813
mainwin_volume_release_cb()814 static void mainwin_volume_release_cb ()
815 {
816 mainwin_volume_set_frame ();
817 mainwin_adjust_volume_release ();
818 }
819
mainwin_balance_set_frame()820 static void mainwin_balance_set_frame ()
821 {
822 int pos = mainwin_balance->get_pos ();
823 int frame = (abs (pos - 12) * 27 + 6) / 12;
824 mainwin_balance->set_frame (9, 15 * frame);
825 }
826
mainwin_set_balance_slider(int percent)827 void mainwin_set_balance_slider (int percent)
828 {
829 if (percent > 0)
830 mainwin_balance->set_pos (12 + (percent * 12 + 50) / 100);
831 else
832 mainwin_balance->set_pos (12 + (percent * 12 - 50) / 100);
833
834 mainwin_balance_set_frame ();
835 }
836
mainwin_balance_motion_cb()837 static void mainwin_balance_motion_cb ()
838 {
839 mainwin_balance_set_frame ();
840 int pos = mainwin_balance->get_pos ();
841
842 int bal;
843 if (pos > 12)
844 bal = ((pos - 12) * 100 + 6) / 12;
845 else
846 bal = ((pos - 12) * 100 - 6) / 12;
847
848 mainwin_adjust_balance_motion (bal);
849 equalizerwin_set_balance_slider (bal);
850 }
851
mainwin_balance_release_cb()852 static void mainwin_balance_release_cb ()
853 {
854 mainwin_balance_set_frame ();
855 mainwin_adjust_volume_release ();
856 }
857
mainwin_set_volume_diff(int diff)858 void mainwin_set_volume_diff (int diff)
859 {
860 int vol = aud_drct_get_volume_main ();
861
862 vol = aud::clamp (vol + diff, 0, 100);
863 mainwin_adjust_volume_motion (vol);
864 mainwin_set_volume_slider (vol);
865 equalizerwin_set_volume_slider (vol);
866
867 mainwin_volume_release_timeout.queue (700, mainwin_volume_release_cb);
868 }
869
mainwin_mr_change(MenuRowItem i)870 void mainwin_mr_change (MenuRowItem i)
871 {
872 switch (i)
873 {
874 case MENUROW_OPTIONS:
875 mainwin_lock_info_text (_("Options Menu"));
876 break;
877 case MENUROW_ALWAYS:
878 if (aud_get_bool ("skins", "always_on_top"))
879 mainwin_lock_info_text (_("Disable 'Always On Top'"));
880 else
881 mainwin_lock_info_text (_("Enable 'Always On Top'"));
882 break;
883 case MENUROW_FILEINFOBOX:
884 mainwin_lock_info_text (_("File Info Box"));
885 break;
886 case MENUROW_SCALE:
887 mainwin_lock_info_text (_("Double Size"));
888 break;
889 case MENUROW_VISUALIZATION:
890 mainwin_lock_info_text (_("Visualizations"));
891 break;
892 default:
893 break;
894 }
895 }
896
mainwin_mr_release(MenuRowItem i,GdkEventButton * event)897 void mainwin_mr_release (MenuRowItem i, GdkEventButton * event)
898 {
899 switch (i)
900 {
901 case MENUROW_OPTIONS:
902 menu_popup (UI_MENU_VIEW, event->x_root, event->y_root, false, false, 1, event->time);
903 break;
904 case MENUROW_ALWAYS:
905 view_set_on_top (! aud_get_bool ("skins", "always_on_top"));
906 break;
907 case MENUROW_FILEINFOBOX:
908 audgui_infowin_show_current ();
909 break;
910 case MENUROW_SCALE:
911 view_set_double_size (! aud_get_bool ("skins", "double_size"));
912 break;
913 case MENUROW_VISUALIZATION:
914 audgui_show_prefs_for_plugin_type (PluginType::Vis);
915 break;
916 default:
917 break;
918 }
919
920 mainwin_release_info_text();
921 }
922
change_timer_mode_cb(GdkEventButton * event)923 bool change_timer_mode_cb (GdkEventButton * event)
924 {
925 if (event->type != GDK_BUTTON_PRESS || event->button != 1)
926 return false;
927
928 view_set_show_remaining (! aud_get_bool ("skins", "show_remaining_time"));
929 return true;
930 }
931
mainwin_info_button_press(GdkEventButton * event)932 static bool mainwin_info_button_press (GdkEventButton * event)
933 {
934 if (event->type == GDK_BUTTON_PRESS && event->button == 3)
935 {
936 menu_popup (UI_MENU_PLAYBACK, event->x_root, event->y_root, false,
937 false, event->button, event->time);
938 return true;
939 }
940
941 if (event->type == GDK_2BUTTON_PRESS && event->button == 1)
942 {
943 audgui_infowin_show_current ();
944 return true;
945 }
946
947 return false;
948 }
949
mainwin_create_widgets()950 static void mainwin_create_widgets ()
951 {
952 mainwin_menubtn = new Button (9, 9, 0, 0, 0, 9, SKIN_TITLEBAR, SKIN_TITLEBAR);
953 mainwin->put_widget (false, mainwin_menubtn, 6, 3);
954 mainwin_menubtn->on_release ((ButtonCB) mainwin_menubtn_cb);
955
956 mainwin_minimize = new Button (9, 9, 9, 0, 9, 9, SKIN_TITLEBAR, SKIN_TITLEBAR);
957 mainwin->put_widget (false, mainwin_minimize, 244, 3);
958 mainwin_minimize->on_release ((ButtonCB) mainwin_minimize_cb);
959
960 mainwin_shade = new Button (9, 9, 0, 18, 9, 18, SKIN_TITLEBAR, SKIN_TITLEBAR);
961 mainwin->put_widget (false, mainwin_shade, 254, 3);
962 mainwin_shade->on_release ((ButtonCB) mainwin_shade_toggle);
963
964 mainwin_close = new Button (9, 9, 18, 0, 18, 9, SKIN_TITLEBAR, SKIN_TITLEBAR);
965 mainwin->put_widget (false, mainwin_close, 264, 3);
966 mainwin_close->on_release ((ButtonCB) skins_close);
967
968 mainwin_rew = new Button (23, 18, 0, 0, 0, 18, SKIN_CBUTTONS, SKIN_CBUTTONS);
969 mainwin->put_widget (false, mainwin_rew, 16, 88);
970 mainwin_rew->on_press (mainwin_rew_press);
971 mainwin_rew->on_release (mainwin_rew_release);
972 mainwin_rew->on_rpress (mainwin_playback_rpress);
973
974 mainwin_fwd = new Button (22, 18, 92, 0, 92, 18, SKIN_CBUTTONS, SKIN_CBUTTONS);
975 mainwin->put_widget (false, mainwin_fwd, 108, 88);
976 mainwin_fwd->on_press (mainwin_fwd_press);
977 mainwin_fwd->on_release (mainwin_fwd_release);
978 mainwin_fwd->on_rpress (mainwin_playback_rpress);
979
980 mainwin_play = new Button (23, 18, 23, 0, 23, 18, SKIN_CBUTTONS, SKIN_CBUTTONS);
981 mainwin->put_widget (false, mainwin_play, 39, 88);
982 mainwin_play->on_release ((ButtonCB) aud_drct_play);
983 mainwin_play->on_rpress (mainwin_playback_rpress);
984
985 mainwin_pause = new Button (23, 18, 46, 0, 46, 18, SKIN_CBUTTONS, SKIN_CBUTTONS);
986 mainwin->put_widget (false, mainwin_pause, 62, 88);
987 mainwin_pause->on_release ((ButtonCB) aud_drct_pause);
988 mainwin_pause->on_rpress (mainwin_playback_rpress);
989
990 mainwin_stop = new Button (23, 18, 69, 0, 69, 18, SKIN_CBUTTONS, SKIN_CBUTTONS);
991 mainwin->put_widget (false, mainwin_stop, 85, 88);
992 mainwin_stop->on_release ((ButtonCB) aud_drct_stop);
993 mainwin_stop->on_rpress (mainwin_playback_rpress);
994
995 mainwin_eject = new Button (22, 16, 114, 0, 114, 16, SKIN_CBUTTONS, SKIN_CBUTTONS);
996 mainwin->put_widget (false, mainwin_eject, 136, 89);
997 mainwin_eject->on_release ((ButtonCB) action_play_file);
998
999 mainwin_shuffle = new Button (46, 15, 28, 0, 28, 15, 28, 30, 28, 45, SKIN_SHUFREP, SKIN_SHUFREP);
1000 mainwin->put_widget (false, mainwin_shuffle, 164, 89);
1001 mainwin_shuffle->set_active (aud_get_bool ("shuffle"));
1002 mainwin_shuffle->on_release (mainwin_shuffle_cb);
1003
1004 mainwin_repeat = new Button (28, 15, 0, 0, 0, 15, 0, 30, 0, 45, SKIN_SHUFREP, SKIN_SHUFREP);
1005 mainwin->put_widget (false, mainwin_repeat, 210, 89);
1006 mainwin_repeat->set_active (aud_get_bool ("repeat"));
1007 mainwin_repeat->on_release (mainwin_repeat_cb);
1008
1009 mainwin_eq = new Button (23, 12, 0, 61, 46, 61, 0, 73, 46, 73, SKIN_SHUFREP, SKIN_SHUFREP);
1010 mainwin->put_widget (false, mainwin_eq, 219, 58);
1011 mainwin_eq->on_release (mainwin_eq_cb);
1012
1013 mainwin_pl = new Button (23, 12, 23, 61, 69, 61, 23, 73, 69, 73, SKIN_SHUFREP, SKIN_SHUFREP);
1014 mainwin->put_widget (false, mainwin_pl, 242, 58);
1015 mainwin_pl->on_release (mainwin_pl_cb);
1016
1017 String font;
1018 if (! config.mainwin_use_bitmapfont)
1019 font = aud_get_str ("skins", "mainwin_font");
1020
1021 bool shaded = aud_get_bool ("skins", "mainwin_shaded");
1022 mainwin_info = new TextBox (153, font, ! shaded && config.autoscroll);
1023 mainwin->put_widget (false, mainwin_info, 112, 27);
1024 mainwin_info->on_press (mainwin_info_button_press);
1025
1026 mainwin_othertext = new TextBox (153, nullptr, false);
1027 mainwin->put_widget (false, mainwin_othertext, 112, 43);
1028
1029 mainwin_rate_text = new TextBox (15, nullptr, false);
1030 mainwin->put_widget (false, mainwin_rate_text, 111, 43);
1031
1032 mainwin_freq_text = new TextBox (10, nullptr, false);
1033 mainwin->put_widget (false, mainwin_freq_text, 156, 43);
1034
1035 mainwin_menurow = new MenuRow;
1036 mainwin->put_widget (false, mainwin_menurow, 10, 22);
1037
1038 mainwin_volume = new HSlider (0, 51, SKIN_VOLUME, 68, 13, 0, 0, 14, 11, 15, 422, 0, 422);
1039 mainwin->put_widget (false, mainwin_volume, 107, 57);
1040 mainwin_volume->on_move (mainwin_volume_motion_cb);
1041 mainwin_volume->on_release (mainwin_volume_release_cb);
1042
1043 mainwin_balance = new HSlider (0, 24, SKIN_BALANCE, 38, 13, 9, 0, 14, 11, 15, 422, 0, 422);
1044 mainwin->put_widget (false, mainwin_balance, 177, 57);
1045 mainwin_balance->on_move (mainwin_balance_motion_cb);
1046 mainwin_balance->on_release (mainwin_balance_release_cb);
1047
1048 mainwin_monostereo = new MonoStereo;
1049 mainwin->put_widget (false, mainwin_monostereo, 212, 41);
1050
1051 mainwin_playstatus = new PlayStatus;
1052 mainwin->put_widget (false, mainwin_playstatus, 24, 28);
1053
1054 mainwin_minus_num = new SkinnedNumber;
1055 mainwin->put_widget (false, mainwin_minus_num, 36, 26);
1056
1057 mainwin_10min_num = new SkinnedNumber;
1058 mainwin->put_widget (false, mainwin_10min_num, 48, 26);
1059
1060 mainwin_min_num = new SkinnedNumber;
1061 mainwin->put_widget (false, mainwin_min_num, 60, 26);
1062
1063 mainwin_10sec_num = new SkinnedNumber;
1064 mainwin->put_widget (false, mainwin_10sec_num, 78, 26);
1065
1066 mainwin_sec_num = new SkinnedNumber;
1067 mainwin->put_widget (false, mainwin_sec_num, 90, 26);
1068
1069 mainwin_about = new Button (20, 25);
1070 mainwin->put_widget (false, mainwin_about, 247, 83);
1071 mainwin_about->on_release ((ButtonCB) audgui_show_about_window);
1072
1073 mainwin_vis = new SkinnedVis;
1074 mainwin->put_widget (false, mainwin_vis, 24, 43);
1075
1076 mainwin_position = new HSlider (0, 219, SKIN_POSBAR, 248, 10, 0, 0, 29, 10, 248, 0, 278, 0);
1077 mainwin->put_widget (false, mainwin_position, 16, 72);
1078 mainwin_position->on_move (mainwin_position_motion_cb);
1079 mainwin_position->on_release (mainwin_position_release_cb);
1080
1081 /* shaded */
1082
1083 mainwin_shaded_menubtn = new Button (9, 9, 0, 0, 0, 9, SKIN_TITLEBAR, SKIN_TITLEBAR);
1084 mainwin->put_widget (true, mainwin_shaded_menubtn, 6, 3);
1085 mainwin_shaded_menubtn->on_release ((ButtonCB) mainwin_menubtn_cb);
1086
1087 mainwin_shaded_minimize = new Button (9, 9, 9, 0, 9, 9, SKIN_TITLEBAR, SKIN_TITLEBAR);
1088 mainwin->put_widget (true, mainwin_shaded_minimize, 244, 3);
1089 mainwin_shaded_minimize->on_release ((ButtonCB) mainwin_minimize_cb);
1090
1091 mainwin_shaded_shade = new Button (9, 9, 0, 27, 9, 27, SKIN_TITLEBAR, SKIN_TITLEBAR);
1092 mainwin->put_widget (true, mainwin_shaded_shade, 254, 3);
1093 mainwin_shaded_shade->on_release ((ButtonCB) mainwin_shade_toggle);
1094
1095 mainwin_shaded_close = new Button (9, 9, 18, 0, 18, 9, SKIN_TITLEBAR, SKIN_TITLEBAR);
1096 mainwin->put_widget (true, mainwin_shaded_close, 264, 3);
1097 mainwin_shaded_close->on_release ((ButtonCB) skins_close);
1098
1099 mainwin_srew = new Button (8, 7);
1100 mainwin->put_widget (true, mainwin_srew, 169, 4);
1101 mainwin_srew->on_release ((ButtonCB) aud_drct_pl_prev);
1102
1103 mainwin_splay = new Button (10, 7);
1104 mainwin->put_widget (true, mainwin_splay, 177, 4);
1105 mainwin_splay->on_release ((ButtonCB) aud_drct_play);
1106
1107 mainwin_spause = new Button (10, 7);
1108 mainwin->put_widget (true, mainwin_spause, 187, 4);
1109 mainwin_spause->on_release ((ButtonCB) aud_drct_pause);
1110
1111 mainwin_sstop = new Button (9, 7);
1112 mainwin->put_widget (true, mainwin_sstop, 197, 4);
1113 mainwin_sstop->on_release ((ButtonCB) aud_drct_stop);
1114
1115 mainwin_sfwd = new Button (8, 7);
1116 mainwin->put_widget (true, mainwin_sfwd, 206, 4);
1117 mainwin_sfwd->on_release ((ButtonCB) aud_drct_pl_next);
1118
1119 mainwin_seject = new Button (9, 7);
1120 mainwin->put_widget (true, mainwin_seject, 216, 4);
1121 mainwin_seject->on_release ((ButtonCB) action_play_file);
1122
1123 mainwin_svis = new SmallVis ();
1124 mainwin->put_widget (true, mainwin_svis, 79, 5);
1125
1126 mainwin_sposition = new HSlider (1, 13, SKIN_TITLEBAR, 17, 7, 0, 36, 3, 7, 17, 36, 17, 36);
1127 mainwin->put_widget (true, mainwin_sposition, 226, 4);
1128 mainwin_sposition->on_move (mainwin_spos_motion_cb);
1129 mainwin_sposition->on_release (mainwin_spos_release_cb);
1130
1131 mainwin_stime_min = new TextBox (15, nullptr, false);
1132 mainwin->put_widget (true, mainwin_stime_min, 130, 4);
1133 mainwin_stime_min->on_press (change_timer_mode_cb);
1134
1135 mainwin_stime_sec = new TextBox (10, nullptr, false);
1136 mainwin->put_widget (true, mainwin_stime_sec, 147, 4);
1137 mainwin_stime_sec->on_press (change_timer_mode_cb);
1138 }
1139
state_cb(GtkWidget * widget,GdkEventWindowState * event,void *)1140 static gboolean state_cb (GtkWidget * widget, GdkEventWindowState * event, void *)
1141 {
1142 if (event->changed_mask & GDK_WINDOW_STATE_STICKY)
1143 view_set_sticky (!! (event->new_window_state & GDK_WINDOW_STATE_STICKY));
1144
1145 if (event->changed_mask & GDK_WINDOW_STATE_ABOVE)
1146 view_set_on_top (!! (event->new_window_state & GDK_WINDOW_STATE_ABOVE));
1147
1148 return true;
1149 }
1150
draw(cairo_t * cr)1151 void MainWindow::draw (cairo_t * cr)
1152 {
1153 int width = is_shaded () ? MAINWIN_SHADED_WIDTH : skin.hints.mainwin_width;
1154 int height = is_shaded () ? MAINWIN_SHADED_HEIGHT : skin.hints.mainwin_height;
1155
1156 skin_draw_pixbuf (cr, SKIN_MAIN, 0, 0, 0, 0, width, height);
1157 skin_draw_mainwin_titlebar (cr, is_shaded (), true);
1158 }
1159
mainwin_create_window()1160 static void mainwin_create_window ()
1161 {
1162 bool shaded = aud_get_bool ("skins", "player_shaded");
1163
1164 mainwin = new MainWindow (shaded);
1165
1166 GtkWidget * w = mainwin->gtk ();
1167 drag_dest_set (w);
1168
1169 g_signal_connect (w, "drag-data-received", (GCallback) mainwin_drag_data_received, nullptr);
1170 g_signal_connect (w, "window-state-event", (GCallback) state_cb, nullptr);
1171
1172 hook_associate ("playback begin", (HookFunction) mainwin_playback_begin, nullptr);
1173 hook_associate ("playback ready", (HookFunction) mainwin_playback_begin, nullptr);
1174 hook_associate ("playback seek", (HookFunction) mainwin_update_song_info, nullptr);
1175 hook_associate ("playback stop", (HookFunction) mainwin_playback_stop, nullptr);
1176 hook_associate ("playback pause", (HookFunction) playback_pause, nullptr);
1177 hook_associate ("playback unpause", (HookFunction) playback_unpause, nullptr);
1178 hook_associate ("title change", (HookFunction) title_change, nullptr);
1179 hook_associate ("info change", (HookFunction) info_change, nullptr);
1180 hook_associate ("set record", (HookFunction) record_toggled, nullptr);
1181 hook_associate ("set repeat", (HookFunction) repeat_toggled, nullptr);
1182 hook_associate ("set shuffle", (HookFunction) shuffle_toggled, nullptr);
1183 hook_associate ("set no_playlist_advance", (HookFunction) no_advance_toggled, nullptr);
1184 hook_associate ("set stop_after_current_song", (HookFunction) stop_after_song_toggled, nullptr);
1185 }
1186
mainwin_unhook()1187 void mainwin_unhook ()
1188 {
1189 seeking = false;
1190 timer_remove (TimerRate::Hz10, seek_timeout);
1191
1192 status_message_timeout.stop ();
1193 mainwin_volume_release_timeout.stop ();
1194
1195 hook_dissociate ("playback begin", (HookFunction) mainwin_playback_begin);
1196 hook_dissociate ("playback ready", (HookFunction) mainwin_playback_begin);
1197 hook_dissociate ("playback seek", (HookFunction) mainwin_update_song_info);
1198 hook_dissociate ("playback stop", (HookFunction) mainwin_playback_stop);
1199 hook_dissociate ("playback pause", (HookFunction) playback_pause);
1200 hook_dissociate ("playback unpause", (HookFunction) playback_unpause);
1201 hook_dissociate ("title change", (HookFunction) title_change);
1202 hook_dissociate ("info change", (HookFunction) info_change);
1203 hook_dissociate ("set record", (HookFunction) record_toggled);
1204 hook_dissociate ("set repeat", (HookFunction) repeat_toggled);
1205 hook_dissociate ("set shuffle", (HookFunction) shuffle_toggled);
1206 hook_dissociate ("set no_playlist_advance", (HookFunction) no_advance_toggled);
1207 hook_dissociate ("set stop_after_current_song", (HookFunction) stop_after_song_toggled);
1208
1209 start_stop_visual (true);
1210
1211 locked_textbox = nullptr;
1212 locked_old_text = String ();
1213 }
1214
mainwin_create()1215 void mainwin_create ()
1216 {
1217 mainwin_create_window ();
1218 mainwin_create_widgets ();
1219 mainwin_set_song_title (nullptr);
1220 }
1221
mainwin_update_volume()1222 static void mainwin_update_volume ()
1223 {
1224 int volume = aud_drct_get_volume_main ();
1225 int balance = aud_drct_get_volume_balance ();
1226
1227 mainwin_set_volume_slider (volume);
1228 mainwin_set_balance_slider (balance);
1229 equalizerwin_set_volume_slider (volume);
1230 equalizerwin_set_balance_slider (balance);
1231 }
1232
mainwin_update_time_display(int time,int length)1233 static void mainwin_update_time_display (int time, int length)
1234 {
1235 StringBuf scratch = format_time (time, length);
1236
1237 mainwin_minus_num->set (scratch[0]);
1238 mainwin_10min_num->set (scratch[1]);
1239 mainwin_min_num->set (scratch[2]);
1240 mainwin_10sec_num->set (scratch[4]);
1241 mainwin_sec_num->set (scratch[5]);
1242
1243 if (! mainwin_sposition->get_pressed ())
1244 {
1245 mainwin_stime_min->set_text (scratch);
1246 mainwin_stime_sec->set_text (scratch + 4);
1247 }
1248
1249 playlistwin_set_time (scratch, scratch + 4);
1250 }
1251
mainwin_update_time_slider(int time,int length)1252 static void mainwin_update_time_slider (int time, int length)
1253 {
1254 mainwin_position->setVisible (length > 0);
1255 mainwin_sposition->setVisible (length > 0);
1256
1257 if (length > 0 && ! seeking)
1258 {
1259 if (time < length)
1260 {
1261 mainwin_position->set_pos (time * (int64_t) 219 / length);
1262 mainwin_sposition->set_pos (1 + time * (int64_t) 12 / length);
1263 }
1264 else
1265 {
1266 mainwin_position->set_pos (219);
1267 mainwin_sposition->set_pos (13);
1268 }
1269
1270 mainwin_spos_set_knob ();
1271 }
1272 }
1273
mainwin_update_song_info()1274 void mainwin_update_song_info ()
1275 {
1276 mainwin_update_volume ();
1277
1278 if (! aud_drct_get_playing ())
1279 return;
1280
1281 int time = 0, length = 0;
1282 if (aud_drct_get_ready ())
1283 {
1284 time = aud_drct_get_time ();
1285 length = aud_drct_get_length ();
1286 }
1287
1288 mainwin_update_time_display (time, length);
1289 mainwin_update_time_slider (time, length);
1290 }
1291