Project

General

Profile

main.cc

skins-qt/main.cc (proposed) - Jim Turner, December 10, 2019 16:11

 
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 <libaudcore/audstrings.h>
32
#include <libaudcore/drct.h>
33
#include <libaudcore/hook.h>
34
#include <libaudcore/i18n.h>
35
#include <libaudcore/mainloop.h>
36
#include <libaudcore/plugins.h>
37
#include <libaudcore/runtime.h>
38
#include <libaudqt/libaudqt.h>
39

    
40
#include "../ui-common/dialogs-qt.h"
41

    
42
#include "actions-mainwin.h"
43
#include "actions-playlist.h"
44
#include "dnd.h"
45
#include "menus.h"
46
#include "plugin.h"
47
#include "skins_cfg.h"
48
#include "equalizer.h"
49
#include "main.h"
50
#include "vis-callbacks.h"
51
#include "playlistwin.h"
52
#include "button.h"
53
#include "hslider.h"
54
#include "menurow.h"
55
#include "monostereo.h"
56
#include "number.h"
57
#include "playlist-widget.h"
58
#include "playstatus.h"
59
#include "textbox.h"
60
#include "window.h"
61
#include "vis.h"
62
#include "skins_util.h"
63
#include "view.h"
64

    
65
#define SEEK_THRESHOLD 200 /* milliseconds */
66
#define SEEK_SPEED 50 /* milliseconds per pixel */
67

    
68
class MainWindow : public Window
69
{
70
public:
71
    MainWindow (bool shaded) :
72
        Window (WINDOW_MAIN, & config.player_x, & config.player_y,
73
         shaded ? MAINWIN_SHADED_WIDTH : skin.hints.mainwin_width,
74
         shaded ? MAINWIN_SHADED_HEIGHT : skin.hints.mainwin_height, shaded),
75
        m_dialogs (this) {}
76

    
77
private:
78
    DialogWindows m_dialogs;
79
    int m_scroll_delta_x = 0;
80
    int m_scroll_delta_y = 0;
81

    
82
    void draw (QPainter & cr);
83
    bool button_press (QMouseEvent * event);
84
    void enterEvent (QEvent * event);
85
    Playlist m_playlist;
86
    int m_popup_pos = -1;
87
    bool scroll (QWheelEvent * event);
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 */
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

    
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);
172
}
173

    
174
static void mainwin_minimize_cb ()
175
{
176
    mainwin->showMinimized ();
177
}
178

    
179
static void mainwin_shade_toggle ()
180
{
181
    view_set_player_shaded (! aud_get_bool ("skins", "player_shaded"));
182
}
183

    
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

    
195
static void mainwin_release_info_text (void * = nullptr)
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

    
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

    
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, nullptr);
220
}
221

    
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

    
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

    
247
static void setup_widget (Widget * widget, int x, int y, bool show)
248
{
249
    widget->setVisible (show);
250
    mainwin->move_widget (false, widget, x, y);
251
}
252

    
253
void mainwin_refresh_hints ()
254
{
255
    const SkinHints * p = & skin.hints;
256

    
257
    mainwin_menurow->setVisible (p->mainwin_menurow_visible);
258
    mainwin_rate_text->setVisible (p->mainwin_streaminfo_visible);
259
    mainwin_freq_text->setVisible (p->mainwin_streaminfo_visible);
260
    mainwin_monostereo->setVisible (p->mainwin_streaminfo_visible);
261

    
262
    mainwin_info->set_width (p->mainwin_text_width);
263

    
264
    setup_widget (mainwin_vis, p->mainwin_vis_x, p->mainwin_vis_y, p->mainwin_vis_visible);
265
    setup_widget (mainwin_info, p->mainwin_text_x, p->mainwin_text_y, p->mainwin_text_visible);
266
    setup_widget (mainwin_othertext, p->mainwin_infobar_x, p->mainwin_infobar_y, p->mainwin_othertext_visible);
267

    
268
    bool playing = aud_drct_get_playing ();
269
    bool can_seek = aud_drct_get_length () > 0;
270

    
271
    setup_widget (mainwin_minus_num, p->mainwin_number_0_x, p->mainwin_number_0_y, playing);
272
    setup_widget (mainwin_10min_num, p->mainwin_number_1_x, p->mainwin_number_1_y, playing);
273
    setup_widget (mainwin_min_num, p->mainwin_number_2_x, p->mainwin_number_2_y, playing);
274
    setup_widget (mainwin_10sec_num, p->mainwin_number_3_x, p->mainwin_number_3_y, playing);
275
    setup_widget (mainwin_sec_num, p->mainwin_number_4_x, p->mainwin_number_4_y, playing);
276
    setup_widget (mainwin_position, p->mainwin_position_x, p->mainwin_position_y, can_seek);
277

    
278
    setup_widget (mainwin_playstatus, p->mainwin_playstatus_x, p->mainwin_playstatus_y, true);
279
    setup_widget (mainwin_volume, p->mainwin_volume_x, p->mainwin_volume_y, true);
280
    setup_widget (mainwin_balance, p->mainwin_balance_x, p->mainwin_balance_y, true);
281
    setup_widget (mainwin_rew, p->mainwin_previous_x, p->mainwin_previous_y, true);
282
    setup_widget (mainwin_play, p->mainwin_play_x, p->mainwin_play_y, true);
283
    setup_widget (mainwin_pause, p->mainwin_pause_x, p->mainwin_pause_y, true);
284
    setup_widget (mainwin_stop, p->mainwin_stop_x, p->mainwin_stop_y, true);
285
    setup_widget (mainwin_fwd, p->mainwin_next_x, p->mainwin_next_y, true);
286
    setup_widget (mainwin_eject, p->mainwin_eject_x, p->mainwin_eject_y, true);
287
    setup_widget (mainwin_eq, p->mainwin_eqbutton_x, p->mainwin_eqbutton_y, true);
288
    setup_widget (mainwin_pl, p->mainwin_plbutton_x, p->mainwin_plbutton_y, true);
289
    setup_widget (mainwin_shuffle, p->mainwin_shuffle_x, p->mainwin_shuffle_y, true);
290
    setup_widget (mainwin_repeat, p->mainwin_repeat_x, p->mainwin_repeat_y, true);
291
    setup_widget (mainwin_about, p->mainwin_about_x, p->mainwin_about_y, true);
292
    setup_widget (mainwin_minimize, p->mainwin_minimize_x, p->mainwin_minimize_y, true);
293
    setup_widget (mainwin_shade, p->mainwin_shade_x, p->mainwin_shade_y, true);
294
    setup_widget (mainwin_close, p->mainwin_close_x, p->mainwin_close_y, true);
295

    
296
    if (aud_get_bool ("skins", "player_shaded"))
297
        mainwin->resize (MAINWIN_SHADED_WIDTH, MAINWIN_SHADED_HEIGHT);
298
    else
299
        mainwin->resize (p->mainwin_width, p->mainwin_height);
300

    
301
    mainwin_vis->set_colors ();
302
}
303

    
304
/* note that the song info is not translated since it is displayed using
305
 * the skinned bitmap font, which supports only the English alphabet */
306
static void mainwin_set_song_info (int bitrate, int samplerate, int channels)
307
{
308
    char scratch[32];
309
    int length;
310

    
311
    if (bitrate > 0)
312
    {
313
        if (bitrate < 1000000)
314
            snprintf (scratch, sizeof scratch, "%3d", bitrate / 1000);
315
        else
316
            snprintf (scratch, sizeof scratch, "%2dH", bitrate / 100000);
317

    
318
        mainwin_rate_text->set_text (scratch);
319
    }
320
    else
321
        mainwin_rate_text->set_text (nullptr);
322

    
323
    if (samplerate > 0)
324
    {
325
        snprintf (scratch, sizeof scratch, "%2d", samplerate / 1000);
326
        mainwin_freq_text->set_text (scratch);
327
    }
328
    else
329
        mainwin_freq_text->set_text (nullptr);
330

    
331
    mainwin_monostereo->set_num_channels (channels);
332

    
333
    if (bitrate > 0)
334
        snprintf (scratch, sizeof scratch, "%d kbps", bitrate / 1000);
335
    else
336
        scratch[0] = 0;
337

    
338
    if (samplerate > 0)
339
    {
340
        length = strlen (scratch);
341
        snprintf (scratch + length, sizeof scratch - length, "%s%d kHz", length ?
342
         ", " : "", samplerate / 1000);
343
    }
344

    
345
    if (channels > 0)
346
    {
347
        length = strlen (scratch);
348
        snprintf (scratch + length, sizeof scratch - length, "%s%s", length ?
349
         ", " : "", channels > 2 ? "surround" : channels > 1 ? "stereo" : "mono");
350
    }
351

    
352
    mainwin_set_othertext (scratch);
353
}
354

    
355
static void info_change ()
356
{
357
    int bitrate, samplerate, channels;
358
    aud_drct_get_info (bitrate, samplerate, channels);
359
    mainwin_set_song_info (bitrate, samplerate, channels);
360
}
361

    
362
static void playback_pause ()
363
{
364
    mainwin_playstatus->set_status (STATUS_PAUSE);
365
}
366

    
367
static void playback_unpause ()
368
{
369
    mainwin_playstatus->set_status (STATUS_PLAY);
370
}
371

    
372
void mainwin_playback_begin ()
373
{
374
    mainwin_update_song_info ();
375

    
376
    mainwin_stime_min->show ();
377
    mainwin_stime_sec->show ();
378
    mainwin_minus_num->show ();
379
    mainwin_10min_num->show ();
380
    mainwin_min_num->show ();
381
    mainwin_10sec_num->show ();
382
    mainwin_sec_num->show ();
383

    
384
    if (aud_drct_get_length () > 0)
385
    {
386
        mainwin_position->show ();
387
        mainwin_sposition->show ();
388
    }
389

    
390
    if (aud_drct_get_paused ())
391
        playback_pause ();
392
    else
393
        playback_unpause ();
394

    
395
    title_change ();
396
    info_change ();
397
}
398

    
399
static void mainwin_playback_stop ()
400
{
401
    seeking = false;
402
    timer_remove (TimerRate::Hz10, seek_timeout);
403

    
404
    mainwin_set_song_title (nullptr);
405

    
406
    mainwin_vis->clear ();
407
    mainwin_svis->clear ();
408

    
409
    mainwin_minus_num->hide ();
410
    mainwin_10min_num->hide ();
411
    mainwin_min_num->hide ();
412
    mainwin_10sec_num->hide ();
413
    mainwin_sec_num->hide ();
414
    mainwin_stime_min->hide ();
415
    mainwin_stime_sec->hide ();
416
    mainwin_position->hide ();
417
    mainwin_sposition->hide ();
418

    
419
    mainwin_position->set_pressed (false);
420
    mainwin_sposition->set_pressed (false);
421

    
422
    /* clear sampling parameter displays */
423
    mainwin_rate_text->set_text (nullptr);
424
    mainwin_freq_text->set_text (nullptr);
425
    mainwin_monostereo->set_num_channels (0);
426
    mainwin_set_othertext ("");
427

    
428
    mainwin_playstatus->set_status (STATUS_STOP);
429

    
430
    playlistwin_hide_timer();
431
}
432

    
433
static void record_toggled ()
434
{
435
    if (aud_drct_get_record_enabled ())
436
    {
437
        if (aud_get_bool ("record"))
438
            mainwin_show_status_message (_("Recording on"));
439
        else
440
            mainwin_show_status_message (_("Recording off"));
441
    }
442
}
443

    
444
static void repeat_toggled ()
445
{
446
    mainwin_repeat->set_active (aud_get_bool ("repeat"));
447
}
448

    
449
static void shuffle_toggled ()
450
{
451
    mainwin_shuffle->set_active (aud_get_bool ("shuffle"));
452
}
453

    
454
static void no_advance_toggled ()
455
{
456
    if (aud_get_bool ("no_playlist_advance"))
457
        mainwin_show_status_message (_("Single mode."));
458
    else
459
        mainwin_show_status_message (_("Playlist mode."));
460
}
461

    
462
static void stop_after_song_toggled ()
463
{
464
    if (aud_get_bool ("stop_after_current_song"))
465
        mainwin_show_status_message (_("Stopping after song."));
466
}
467

    
468
bool MainWindow::scroll (QWheelEvent * event)
469
{
470
    m_scroll_delta_x += event->angleDelta ().x ();
471
    m_scroll_delta_y += event->angleDelta ().y ();
472

    
473
    /* we want discrete steps here */
474
    int steps_x = m_scroll_delta_x / 120;
475
    int steps_y = m_scroll_delta_y / 120;
476

    
477
    if (steps_x != 0)
478
    {
479
        m_scroll_delta_x -= 120 * steps_x;
480
        int step_size = aud_get_int ("step_size");
481
        aud_drct_seek (aud_drct_get_time () - steps_x * step_size * 1000);
482
    }
483

    
484
    if (steps_y != 0)
485
    {
486
        m_scroll_delta_y -= 120 * steps_y;
487
        int volume_delta = aud_get_int ("volume_delta");
488
        aud_drct_set_volume_main (aud_drct_get_volume_main () + steps_y * volume_delta);
489
    }
490

    
491
    return true;
492
}
493

    
494
bool MainWindow::button_press (QMouseEvent * event)
495
{
496
    if (event->button () == Qt::LeftButton &&
497
     event->type () == QEvent::MouseButtonDblClick &&
498
     event->y () < 14 * config.scale)
499
    {
500
        mainwin_shade_toggle ();
501
        return true;
502
    }
503

    
504
    if (event->button () == Qt::RightButton && event->type () == QEvent::MouseButtonPress)
505
    {
506
        menu_popup (UI_MENU_MAIN, event->globalX (), event->globalY (), false, false);
507
        return true;
508
    }
509

    
510
    return Window::button_press (event);
511
}
512

    
513
void MainWindow::enterEvent (QEvent * event)
514
{
515
    if (is_shaded ())
516
    {
517
        QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
518
        int mousey = mouseEvent->y ();
519
        if (mousey > 78 && mousey < 165)
520
        {
521
            if (aud_get_bool (nullptr, "show_filepopup_for_tuple"))
522
                   {
523
                              m_playlist = Playlist::active_playlist ();
524
                m_popup_pos = m_playlist.get_position ();
525
                if (m_popup_pos >= 0)
526
                    audqt::infopopup_show (m_playlist, m_popup_pos);
527
            }
528
        }
529
    }
530
}
531

    
532
static void mainwin_playback_rpress (Button * button, QMouseEvent * event)
533
{
534
    menu_popup (UI_MENU_PLAYBACK, event->globalX (), event->globalY (), false, false);
535
}
536

    
537
bool Window::keypress (QKeyEvent * event)
538
{
539
    if (playlistwin_list->handle_keypress (event))
540
        return true;
541

    
542
    switch (event->key ())
543
    {
544
        case Qt::Key_Left:
545
            aud_drct_seek (aud_drct_get_time () - 5000);
546
            break;
547
        case Qt::Key_Right:
548
            aud_drct_seek (aud_drct_get_time () + 5000);
549
            break;
550
        case Qt::Key_Space:
551
            aud_drct_pause ();
552
            break;
553
        default:
554
            return false;
555
    }
556

    
557
    return true;
558
}
559

    
560
#if 0
561
void mainwin_drag_data_received (GtkWidget * widget, GdkDragContext * context,
562
 int x, int y, GtkSelectionData * selection_data, unsigned info, unsigned time, void *)
563
{
564
    g_return_if_fail (selection_data != nullptr);
565

566
    const char * data = (const char *) gtk_selection_data_get_data (selection_data);
567
    g_return_if_fail (data);
568

569
    if (str_has_prefix_nocase (data, "file:///"))
570
    {
571
        if (str_has_suffix_nocase (data, ".wsz\r\n") || str_has_suffix_nocase
572
         (data, ".zip\r\n"))
573
        {
574
            on_skin_view_drag_data_received (0, context, x, y, selection_data, info, time, 0);
575
            return;
576
        }
577
    }
578

579
    audgui_urilist_open (data);
580
}
581
#endif
582

    
583
static int time_now ()
584
{
585
    struct timeval tv;
586
    gettimeofday (& tv, nullptr);
587
    return (tv.tv_sec % (24 * 3600) * 1000 + tv.tv_usec / 1000);
588
}
589

    
590
static int time_diff (int a, int b)
591
{
592
    if (a > 18 * 3600 * 1000 && b < 6 * 3600 * 1000) /* detect midnight */
593
        b += 24 * 3600 * 1000;
594
    return (b > a) ? b - a : 0;
595
}
596

    
597
static void seek_timeout (void * rewind)
598
{
599
    int held = time_diff (seek_time, time_now ());
600
    if (held < SEEK_THRESHOLD)
601
        return;
602

    
603
    int position;
604
    if (aud::from_ptr<bool> (rewind))
605
        position = seek_start - held / SEEK_SPEED;
606
    else
607
        position = seek_start + held / SEEK_SPEED;
608

    
609
    position = aud::clamp (position, 0, 219);
610
    mainwin_position->set_pos (position);
611
    mainwin_position_motion_cb ();
612
}
613

    
614
static void seek_press (QMouseEvent * event, bool rewind)
615
{
616
    if (event->button () != Qt::LeftButton || seeking)
617
        return;
618

    
619
    seeking = true;
620
    seek_start = mainwin_position->get_pos ();
621
    seek_time = time_now ();
622
    timer_add (TimerRate::Hz10, seek_timeout, aud::to_ptr (rewind));
623
}
624

    
625
static void seek_release (QMouseEvent * event, bool rewind)
626
{
627
    if (event->button () != Qt::LeftButton || ! seeking)
628
        return;
629

    
630
    if (! aud_drct_get_playing () || time_diff (seek_time, time_now ()) <
631
     SEEK_THRESHOLD)
632
    {
633
        if (rewind)
634
            aud_drct_pl_prev ();
635
        else
636
            aud_drct_pl_next ();
637
    }
638
    else
639
        mainwin_position_release_cb ();
640

    
641
    seeking = false;
642
    timer_remove (TimerRate::Hz10, seek_timeout);
643
}
644

    
645
static void mainwin_rew_press (Button * button, QMouseEvent * event)
646
    { seek_press (event, true); }
647
static void mainwin_rew_release (Button * button, QMouseEvent * event)
648
    { seek_release (event, true); }
649
static void mainwin_fwd_press (Button * button, QMouseEvent * event)
650
    { seek_press (event, false); }
651
static void mainwin_fwd_release (Button * button, QMouseEvent * event)
652
    { seek_release (event, false); }
653

    
654
static void mainwin_shuffle_cb (Button * button, QMouseEvent * event)
655
    { aud_set_bool ("shuffle", button->get_active ()); }
656
static void mainwin_repeat_cb (Button * button, QMouseEvent * event)
657
    { aud_set_bool ("repeat", button->get_active ()); }
658
static void mainwin_eq_cb (Button * button, QMouseEvent * event)
659
    { view_set_show_equalizer (button->get_active ()); }
660
static void mainwin_pl_cb (Button * button, QMouseEvent * event)
661
    { view_set_show_playlist (button->get_active ()); }
662

    
663
static void mainwin_spos_set_knob ()
664
{
665
    int pos = mainwin_sposition->get_pos ();
666
    int x = (pos < 6) ? 17 : (pos < 9) ? 20 : 23;
667
    mainwin_sposition->set_knob (x, 36, x, 36);
668
}
669

    
670
static void mainwin_spos_motion_cb ()
671
{
672
    mainwin_spos_set_knob ();
673

    
674
    int pos = mainwin_sposition->get_pos ();
675
    int length = aud_drct_get_length ();
676
    int time = (pos - 1) * length / 12;
677

    
678
    StringBuf buf = format_time (time, length);
679

    
680
    mainwin_stime_min->set_text (buf);
681
    mainwin_stime_sec->set_text (buf + 4);
682
}
683

    
684
static void mainwin_spos_release_cb ()
685
{
686
    mainwin_spos_set_knob ();
687

    
688
    int pos = mainwin_sposition->get_pos ();
689
    aud_drct_seek (aud_drct_get_length () * (pos - 1) / 12);
690
}
691

    
692
static void mainwin_position_motion_cb ()
693
{
694
    int length = aud_drct_get_length () / 1000;
695
    int pos = mainwin_position->get_pos ();
696
    int time = pos * length / 219;
697

    
698
    mainwin_lock_info_text (str_printf (_("Seek to %d:%-2.2d / %d:%-2.2d"),
699
     time / 60, time % 60, length / 60, length % 60));
700
}
701

    
702
static void mainwin_position_release_cb ()
703
{
704
    int length = aud_drct_get_length ();
705
    int pos = mainwin_position->get_pos ();
706
    int time = (int64_t) pos * length / 219;
707

    
708
    aud_drct_seek(time);
709
    mainwin_release_info_text();
710
}
711

    
712
void mainwin_adjust_volume_motion (int v)
713
{
714
    aud_drct_set_volume_main (v);
715
    mainwin_lock_info_text (str_printf (_("Volume: %d%%"), v));
716
}
717

    
718
void mainwin_adjust_volume_release ()
719
{
720
    mainwin_release_info_text ();
721
}
722

    
723
void mainwin_adjust_balance_motion (int b)
724
{
725
    aud_drct_set_volume_balance (b);
726

    
727
    if (b < 0)
728
        mainwin_lock_info_text (str_printf (_("Balance: %d%% left"), -b));
729
    else if (b == 0)
730
        mainwin_lock_info_text (_("Balance: center"));
731
    else
732
        mainwin_lock_info_text (str_printf (_("Balance: %d%% right"), b));
733
}
734

    
735
void mainwin_adjust_balance_release ()
736
{
737
    mainwin_release_info_text ();
738
}
739

    
740
static void mainwin_volume_set_frame ()
741
{
742
    int pos = mainwin_volume->get_pos ();
743
    int frame = (pos * 27 + 25) / 51;
744
    mainwin_volume->set_frame (0, 15 * frame);
745
}
746

    
747
void mainwin_set_volume_slider (int percent)
748
{
749
    mainwin_volume->set_pos ((percent * 51 + 50) / 100);
750
    mainwin_volume_set_frame ();
751
}
752

    
753
static void mainwin_volume_motion_cb ()
754
{
755
    mainwin_volume_set_frame ();
756
    int pos = mainwin_volume->get_pos ();
757
    int vol = (pos * 100 + 25) / 51;
758

    
759
    mainwin_adjust_volume_motion (vol);
760
    equalizerwin_set_volume_slider (vol);
761
}
762

    
763
static void mainwin_volume_release_cb ()
764
{
765
    mainwin_volume_set_frame ();
766
    mainwin_adjust_volume_release ();
767
}
768

    
769
static void mainwin_balance_set_frame ()
770
{
771
    int pos = mainwin_balance->get_pos ();
772
    int frame = (abs (pos - 12) * 27 + 6) / 12;
773
    mainwin_balance->set_frame (9, 15 * frame);
774
}
775

    
776
void mainwin_set_balance_slider (int percent)
777
{
778
    if (percent > 0)
779
        mainwin_balance->set_pos (12 + (percent * 12 + 50) / 100);
780
    else
781
        mainwin_balance->set_pos (12 + (percent * 12 - 50) / 100);
782

    
783
    mainwin_balance_set_frame ();
784
}
785

    
786
static void mainwin_balance_motion_cb ()
787
{
788
    mainwin_balance_set_frame ();
789
    int pos = mainwin_balance->get_pos ();
790

    
791
    int bal;
792
    if (pos > 12)
793
        bal = ((pos - 12) * 100 + 6) / 12;
794
    else
795
        bal = ((pos - 12) * 100 - 6) / 12;
796

    
797
    mainwin_adjust_balance_motion (bal);
798
    equalizerwin_set_balance_slider (bal);
799
}
800

    
801
static void mainwin_balance_release_cb ()
802
{
803
    mainwin_balance_set_frame ();
804
    mainwin_adjust_volume_release ();
805
}
806

    
807
void mainwin_set_volume_diff (int diff)
808
{
809
    int vol = aud_drct_get_volume_main ();
810

    
811
    vol = aud::clamp (vol + diff, 0, 100);
812
    mainwin_adjust_volume_motion (vol);
813
    mainwin_set_volume_slider (vol);
814
    equalizerwin_set_volume_slider (vol);
815

    
816
    mainwin_volume_release_timeout.queue (700,
817
     [] (void *) { mainwin_volume_release_cb (); }, nullptr);
818
}
819

    
820
void mainwin_mr_change (MenuRowItem i)
821
{
822
    switch (i)
823
    {
824
        case MENUROW_OPTIONS:
825
            mainwin_lock_info_text (_("Options Menu"));
826
            break;
827
        case MENUROW_ALWAYS:
828
            if (aud_get_bool ("skins", "always_on_top"))
829
                mainwin_lock_info_text (_("Disable 'Always On Top'"));
830
            else
831
                mainwin_lock_info_text (_("Enable 'Always On Top'"));
832
            break;
833
        case MENUROW_FILEINFOBOX:
834
            mainwin_lock_info_text (_("File Info Box"));
835
            break;
836
        case MENUROW_SCALE:
837
            mainwin_lock_info_text (_("Double Size"));
838
            break;
839
        case MENUROW_VISUALIZATION:
840
            mainwin_lock_info_text (_("Visualizations"));
841
            break;
842
        default:
843
            break;
844
    }
845
}
846

    
847
void mainwin_mr_release (MenuRowItem i, QMouseEvent * event)
848
{
849
    switch (i)
850
    {
851
        case MENUROW_OPTIONS:
852
            menu_popup (UI_MENU_VIEW, event->globalX (), event->globalY (), false, false);
853
            break;
854
        case MENUROW_ALWAYS:
855
            view_set_on_top (! aud_get_bool ("skins", "always_on_top"));
856
            break;
857
        case MENUROW_FILEINFOBOX:
858
            audqt::infowin_show_current ();
859
            break;
860
        case MENUROW_SCALE:
861
            view_set_double_size (! aud_get_bool ("skins", "double_size"));
862
            break;
863
        case MENUROW_VISUALIZATION:
864
            audqt::prefswin_show_plugin_page (PluginType::Vis);
865
            break;
866
        default:
867
            break;
868
    }
869

    
870
    mainwin_release_info_text();
871
}
872

    
873
bool change_timer_mode_cb (QMouseEvent * event)
874
{
875
    if (event->type () != QEvent::MouseButtonPress || event->button () != Qt::LeftButton)
876
        return false;
877

    
878
    view_set_show_remaining (! aud_get_bool ("skins", "show_remaining_time"));
879
    return true;
880
}
881

    
882
static bool mainwin_info_button_press (QMouseEvent * event)
883
{
884
    if (event->type () == QEvent::MouseButtonPress && event->button () == Qt::RightButton)
885
    {
886
        menu_popup (UI_MENU_PLAYBACK, event->globalX (), event->globalY (), false, false);
887
        return true;
888
    }
889

    
890
    if (event->type () == QEvent::MouseButtonDblClick && event->button () == Qt::LeftButton)
891
    {
892
        audqt::infowin_show_current ();
893
        return true;
894
    }
895

    
896
    return false;
897
}
898

    
899
static void mainwin_create_widgets ()
900
{
901
    mainwin_menubtn = new Button (9, 9, 0, 0, 0, 9, SKIN_TITLEBAR, SKIN_TITLEBAR);
902
    mainwin->put_widget (false, mainwin_menubtn, 6, 3);
903
    mainwin_menubtn->on_release ((ButtonCB) mainwin_menubtn_cb);
904

    
905
    mainwin_minimize = new Button (9, 9, 9, 0, 9, 9, SKIN_TITLEBAR, SKIN_TITLEBAR);
906
    mainwin->put_widget (false, mainwin_minimize, 244, 3);
907
    mainwin_minimize->on_release ((ButtonCB) mainwin_minimize_cb);
908

    
909
    mainwin_shade = new Button (9, 9, 0, 18, 9, 18, SKIN_TITLEBAR, SKIN_TITLEBAR);
910
    mainwin->put_widget (false, mainwin_shade, 254, 3);
911
    mainwin_shade->on_release ((ButtonCB) mainwin_shade_toggle);
912

    
913
    mainwin_close = new Button (9, 9, 18, 0, 18, 9, SKIN_TITLEBAR, SKIN_TITLEBAR);
914
    mainwin->put_widget (false, mainwin_close, 264, 3);
915
    mainwin_close->on_release ((ButtonCB) skins_close);
916

    
917
    mainwin_rew = new Button (23, 18, 0, 0, 0, 18, SKIN_CBUTTONS, SKIN_CBUTTONS);
918
    mainwin->put_widget (false, mainwin_rew, 16, 88);
919
    mainwin_rew->on_press (mainwin_rew_press);
920
    mainwin_rew->on_release (mainwin_rew_release);
921
    mainwin_rew->on_rpress (mainwin_playback_rpress);
922

    
923
    mainwin_fwd = new Button (22, 18, 92, 0, 92, 18, SKIN_CBUTTONS, SKIN_CBUTTONS);
924
    mainwin->put_widget (false, mainwin_fwd, 108, 88);
925
    mainwin_fwd->on_press (mainwin_fwd_press);
926
    mainwin_fwd->on_release (mainwin_fwd_release);
927
    mainwin_fwd->on_rpress (mainwin_playback_rpress);
928

    
929
    mainwin_play = new Button (23, 18, 23, 0, 23, 18, SKIN_CBUTTONS, SKIN_CBUTTONS);
930
    mainwin->put_widget (false, mainwin_play, 39, 88);
931
    mainwin_play->on_release ((ButtonCB) aud_drct_play);
932
    mainwin_play->on_rpress (mainwin_playback_rpress);
933

    
934
    mainwin_pause = new Button (23, 18, 46, 0, 46, 18, SKIN_CBUTTONS, SKIN_CBUTTONS);
935
    mainwin->put_widget (false, mainwin_pause, 62, 88);
936
    mainwin_pause->on_release ((ButtonCB) aud_drct_pause);
937
    mainwin_pause->on_rpress (mainwin_playback_rpress);
938

    
939
    mainwin_stop = new Button (23, 18, 69, 0, 69, 18, SKIN_CBUTTONS, SKIN_CBUTTONS);
940
    mainwin->put_widget (false, mainwin_stop, 85, 88);
941
    mainwin_stop->on_release ((ButtonCB) aud_drct_stop);
942
    mainwin_stop->on_rpress (mainwin_playback_rpress);
943

    
944
    mainwin_eject = new Button (22, 16, 114, 0, 114, 16, SKIN_CBUTTONS, SKIN_CBUTTONS);
945
    mainwin->put_widget (false, mainwin_eject, 136, 89);
946
    mainwin_eject->on_release ((ButtonCB) action_play_file);
947

    
948
    mainwin_shuffle = new Button (46, 15, 28, 0, 28, 15, 28, 30, 28, 45, SKIN_SHUFREP, SKIN_SHUFREP);
949
    mainwin->put_widget (false, mainwin_shuffle, 164, 89);
950
    mainwin_shuffle->set_active (aud_get_bool ("shuffle"));
951
    mainwin_shuffle->on_release (mainwin_shuffle_cb);
952

    
953
    mainwin_repeat = new Button (28, 15, 0, 0, 0, 15, 0, 30, 0, 45, SKIN_SHUFREP, SKIN_SHUFREP);
954
    mainwin->put_widget (false, mainwin_repeat, 210, 89);
955
    mainwin_repeat->set_active (aud_get_bool ("repeat"));
956
    mainwin_repeat->on_release (mainwin_repeat_cb);
957

    
958
    mainwin_eq = new Button (23, 12, 0, 61, 46, 61, 0, 73, 46, 73, SKIN_SHUFREP, SKIN_SHUFREP);
959
    mainwin->put_widget (false, mainwin_eq, 219, 58);
960
    mainwin_eq->on_release (mainwin_eq_cb);
961

    
962
    mainwin_pl = new Button (23, 12, 23, 61, 69, 61, 23, 73, 69, 73, SKIN_SHUFREP, SKIN_SHUFREP);
963
    mainwin->put_widget (false, mainwin_pl, 242, 58);
964
    mainwin_pl->on_release (mainwin_pl_cb);
965

    
966
    String font;
967
    if (! config.mainwin_use_bitmapfont)
968
        font = aud_get_str ("skins", "mainwin_font");
969

    
970
    bool shaded = aud_get_bool ("skins", "mainwin_shaded");
971
    mainwin_info = new TextBox (153, font, ! shaded && config.autoscroll);
972
    mainwin->put_widget (false, mainwin_info, 112, 27);
973
    mainwin_info->on_press (mainwin_info_button_press);
974

    
975
    mainwin_othertext = new TextBox (153, nullptr, false);
976
    mainwin->put_widget (false, mainwin_othertext, 112, 43);
977

    
978
    mainwin_rate_text = new TextBox (15, nullptr, false);
979
    mainwin->put_widget (false, mainwin_rate_text, 111, 43);
980

    
981
    mainwin_freq_text = new TextBox (10, nullptr, false);
982
    mainwin->put_widget (false, mainwin_freq_text, 156, 43);
983

    
984
    mainwin_menurow = new MenuRow;
985
    mainwin->put_widget (false, mainwin_menurow, 10, 22);
986

    
987
    mainwin_volume = new HSlider (0, 51, SKIN_VOLUME, 68, 13, 0, 0, 14, 11, 15, 422, 0, 422);
988
    mainwin->put_widget (false, mainwin_volume, 107, 57);
989
    mainwin_volume->on_move (mainwin_volume_motion_cb);
990
    mainwin_volume->on_release (mainwin_volume_release_cb);
991

    
992
    mainwin_balance = new HSlider (0, 24, SKIN_BALANCE, 38, 13, 9, 0, 14, 11, 15, 422, 0, 422);
993
    mainwin->put_widget (false, mainwin_balance, 177, 57);
994
    mainwin_balance->on_move (mainwin_balance_motion_cb);
995
    mainwin_balance->on_release (mainwin_balance_release_cb);
996

    
997
    mainwin_monostereo = new MonoStereo;
998
    mainwin->put_widget (false, mainwin_monostereo, 212, 41);
999

    
1000
    mainwin_playstatus = new PlayStatus;
1001
    mainwin->put_widget (false, mainwin_playstatus, 24, 28);
1002

    
1003
    mainwin_minus_num = new SkinnedNumber;
1004
    mainwin->put_widget (false, mainwin_minus_num, 36, 26);
1005

    
1006
    mainwin_10min_num = new SkinnedNumber;
1007
    mainwin->put_widget (false, mainwin_10min_num, 48, 26);
1008

    
1009
    mainwin_min_num = new SkinnedNumber;
1010
    mainwin->put_widget (false, mainwin_min_num, 60, 26);
1011

    
1012
    mainwin_10sec_num = new SkinnedNumber;
1013
    mainwin->put_widget (false, mainwin_10sec_num, 78, 26);
1014

    
1015
    mainwin_sec_num = new SkinnedNumber;
1016
    mainwin->put_widget (false, mainwin_sec_num, 90, 26);
1017

    
1018
    mainwin_about = new Button (20, 25);
1019
    mainwin->put_widget (false, mainwin_about, 247, 83);
1020
    mainwin_about->on_release ((ButtonCB) audqt::aboutwindow_show);
1021

    
1022
    mainwin_vis = new SkinnedVis;
1023
    mainwin->put_widget (false, mainwin_vis, 24, 43);
1024

    
1025
    mainwin_position = new HSlider (0, 219, SKIN_POSBAR, 248, 10, 0, 0, 29, 10, 248, 0, 278, 0);
1026
    mainwin->put_widget (false, mainwin_position, 16, 72);
1027
    mainwin_position->on_move (mainwin_position_motion_cb);
1028
    mainwin_position->on_release (mainwin_position_release_cb);
1029

    
1030
    /* shaded */
1031

    
1032
    mainwin_shaded_menubtn = new Button (9, 9, 0, 0, 0, 9, SKIN_TITLEBAR, SKIN_TITLEBAR);
1033
    mainwin->put_widget (true, mainwin_shaded_menubtn, 6, 3);
1034
    mainwin_shaded_menubtn->on_release ((ButtonCB) mainwin_menubtn_cb);
1035

    
1036
    mainwin_shaded_minimize = new Button (9, 9, 9, 0, 9, 9, SKIN_TITLEBAR, SKIN_TITLEBAR);
1037
    mainwin->put_widget (true, mainwin_shaded_minimize, 244, 3);
1038
    mainwin_shaded_minimize->on_release ((ButtonCB) mainwin_minimize_cb);
1039

    
1040
    mainwin_shaded_shade = new Button (9, 9, 0, 27, 9, 27, SKIN_TITLEBAR, SKIN_TITLEBAR);
1041
    mainwin->put_widget (true, mainwin_shaded_shade, 254, 3);
1042
    mainwin_shaded_shade->on_release ((ButtonCB) mainwin_shade_toggle);
1043

    
1044
    mainwin_shaded_close = new Button (9, 9, 18, 0, 18, 9, SKIN_TITLEBAR, SKIN_TITLEBAR);
1045
    mainwin->put_widget (true, mainwin_shaded_close, 264, 3);
1046
    mainwin_shaded_close->on_release ((ButtonCB) skins_close);
1047

    
1048
    mainwin_srew = new Button (8, 7);
1049
    mainwin->put_widget (true, mainwin_srew, 169, 4);
1050
    mainwin_srew->on_release ((ButtonCB) aud_drct_pl_prev);
1051

    
1052
    mainwin_splay = new Button (10, 7);
1053
    mainwin->put_widget (true, mainwin_splay, 177, 4);
1054
    mainwin_splay->on_release ((ButtonCB) aud_drct_play);
1055

    
1056
    mainwin_spause = new Button (10, 7);
1057
    mainwin->put_widget (true, mainwin_spause, 187, 4);
1058
    mainwin_spause->on_release ((ButtonCB) aud_drct_pause);
1059

    
1060
    mainwin_sstop = new Button (9, 7);
1061
    mainwin->put_widget (true, mainwin_sstop, 197, 4);
1062
    mainwin_sstop->on_release ((ButtonCB) aud_drct_stop);
1063

    
1064
    mainwin_sfwd = new Button (8, 7);
1065
    mainwin->put_widget (true, mainwin_sfwd, 206, 4);
1066
    mainwin_sfwd->on_release ((ButtonCB) aud_drct_pl_next);
1067

    
1068
    mainwin_seject = new Button (9, 7);
1069
    mainwin->put_widget (true, mainwin_seject, 216, 4);
1070
    mainwin_seject->on_release ((ButtonCB) action_play_file);
1071

    
1072
    mainwin_svis = new SmallVis ();
1073
    mainwin->put_widget (true, mainwin_svis, 79, 5);
1074

    
1075
    mainwin_sposition = new HSlider (1, 13, SKIN_TITLEBAR, 17, 7, 0, 36, 3, 7, 17, 36, 17, 36);
1076
    mainwin->put_widget (true, mainwin_sposition, 226, 4);
1077
    mainwin_sposition->on_move (mainwin_spos_motion_cb);
1078
    mainwin_sposition->on_release (mainwin_spos_release_cb);
1079

    
1080
    mainwin_stime_min = new TextBox (15, nullptr, false);
1081
    mainwin->put_widget (true, mainwin_stime_min, 130, 4);
1082
    mainwin_stime_min->on_press (change_timer_mode_cb);
1083

    
1084
    mainwin_stime_sec = new TextBox (10, nullptr, false);
1085
    mainwin->put_widget (true, mainwin_stime_sec, 147, 4);
1086
    mainwin_stime_sec->on_press (change_timer_mode_cb);
1087
}
1088

    
1089
#if 0
1090
static gboolean state_cb (GtkWidget * widget, GdkEventWindowState * event, void *)
1091
{
1092
    if (event->changed_mask & GDK_WINDOW_STATE_STICKY)
1093
        view_set_sticky (!! (event->new_window_state & GDK_WINDOW_STATE_STICKY));
1094

1095
    if (event->changed_mask & GDK_WINDOW_STATE_ABOVE)
1096
        view_set_on_top (!! (event->new_window_state & GDK_WINDOW_STATE_ABOVE));
1097

1098
    return true;
1099
}
1100
#endif
1101

    
1102
void MainWindow::draw (QPainter & cr)
1103
{
1104
    int width = is_shaded () ? MAINWIN_SHADED_WIDTH : skin.hints.mainwin_width;
1105
    int height = is_shaded () ? MAINWIN_SHADED_HEIGHT : skin.hints.mainwin_height;
1106

    
1107
    skin_draw_pixbuf (cr, SKIN_MAIN, 0, 0, 0, 0, width, height);
1108
    skin_draw_mainwin_titlebar (cr, is_shaded (), true);
1109
}
1110

    
1111
static void mainwin_create_window ()
1112
{
1113
    bool shaded = aud_get_bool ("skins", "player_shaded");
1114

    
1115
    mainwin = new MainWindow (shaded);
1116

    
1117
#if 0
1118
    GtkWidget * w = mainwin->gtk ();
1119
    drag_dest_set (w);
1120

1121
    g_signal_connect (w, "drag-data-received", (GCallback) mainwin_drag_data_received, nullptr);
1122
    g_signal_connect (w, "window-state-event", (GCallback) state_cb, nullptr);
1123
#endif
1124

    
1125
    hook_associate ("playback begin", (HookFunction) mainwin_playback_begin, nullptr);
1126
    hook_associate ("playback ready", (HookFunction) mainwin_playback_begin, nullptr);
1127
    hook_associate ("playback seek", (HookFunction) mainwin_update_song_info, nullptr);
1128
    hook_associate ("playback stop", (HookFunction) mainwin_playback_stop, nullptr);
1129
    hook_associate ("playback pause", (HookFunction) playback_pause, nullptr);
1130
    hook_associate ("playback unpause", (HookFunction) playback_unpause, nullptr);
1131
    hook_associate ("title change", (HookFunction) title_change, nullptr);
1132
    hook_associate ("info change", (HookFunction) info_change, nullptr);
1133
    hook_associate ("set record", (HookFunction) record_toggled, nullptr);
1134
    hook_associate ("set repeat", (HookFunction) repeat_toggled, nullptr);
1135
    hook_associate ("set shuffle", (HookFunction) shuffle_toggled, nullptr);
1136
    hook_associate ("set no_playlist_advance", (HookFunction) no_advance_toggled, nullptr);
1137
    hook_associate ("set stop_after_current_song", (HookFunction) stop_after_song_toggled, nullptr);
1138
}
1139

    
1140
void mainwin_unhook ()
1141
{
1142
    seeking = false;
1143
    timer_remove (TimerRate::Hz10, seek_timeout);
1144

    
1145
    status_message_timeout.stop ();
1146
    mainwin_volume_release_timeout.stop ();
1147

    
1148
    hook_dissociate ("playback begin", (HookFunction) mainwin_playback_begin);
1149
    hook_dissociate ("playback ready", (HookFunction) mainwin_playback_begin);
1150
    hook_dissociate ("playback seek", (HookFunction) mainwin_update_song_info);
1151
    hook_dissociate ("playback stop", (HookFunction) mainwin_playback_stop);
1152
    hook_dissociate ("playback pause", (HookFunction) playback_pause);
1153
    hook_dissociate ("playback unpause", (HookFunction) playback_unpause);
1154
    hook_dissociate ("title change", (HookFunction) title_change);
1155
    hook_dissociate ("info change", (HookFunction) info_change);
1156
    hook_dissociate ("set record", (HookFunction) record_toggled);
1157
    hook_dissociate ("set repeat", (HookFunction) repeat_toggled);
1158
    hook_dissociate ("set shuffle", (HookFunction) shuffle_toggled);
1159
    hook_dissociate ("set no_playlist_advance", (HookFunction) no_advance_toggled);
1160
    hook_dissociate ("set stop_after_current_song", (HookFunction) stop_after_song_toggled);
1161

    
1162
    start_stop_visual (true);
1163

    
1164
    locked_textbox = nullptr;
1165
    locked_old_text = String ();
1166
}
1167

    
1168
void mainwin_create ()
1169
{
1170
    mainwin_create_window ();
1171
    mainwin_create_widgets ();
1172
    mainwin_set_song_title (nullptr);
1173
}
1174

    
1175
static void mainwin_update_volume ()
1176
{
1177
    int volume = aud_drct_get_volume_main ();
1178
    int balance = aud_drct_get_volume_balance ();
1179

    
1180
    mainwin_set_volume_slider (volume);
1181
    mainwin_set_balance_slider (balance);
1182
    equalizerwin_set_volume_slider (volume);
1183
    equalizerwin_set_balance_slider (balance);
1184
}
1185

    
1186
static void mainwin_update_time_display (int time, int length)
1187
{
1188
    StringBuf scratch = format_time (time, length);
1189

    
1190
    mainwin_minus_num->set (scratch[0]);
1191
    mainwin_10min_num->set (scratch[1]);
1192
    mainwin_min_num->set (scratch[2]);
1193
    mainwin_10sec_num->set (scratch[4]);
1194
    mainwin_sec_num->set (scratch[5]);
1195

    
1196
    if (! mainwin_sposition->get_pressed ())
1197
    {
1198
        mainwin_stime_min->set_text (scratch);
1199
        mainwin_stime_sec->set_text (scratch + 4);
1200
    }
1201

    
1202
    playlistwin_set_time (scratch, scratch + 4);
1203
}
1204

    
1205
static void mainwin_update_time_slider (int time, int length)
1206
{
1207
    mainwin_position->setVisible (length > 0);
1208
    mainwin_sposition->setVisible (length > 0);
1209

    
1210
    if (length > 0 && ! seeking)
1211
    {
1212
        if (time < length)
1213
        {
1214
            mainwin_position->set_pos (time * (int64_t) 219 / length);
1215
            mainwin_sposition->set_pos (1 + time * (int64_t) 12 / length);
1216
        }
1217
        else
1218
        {
1219
            mainwin_position->set_pos (219);
1220
            mainwin_sposition->set_pos (13);
1221
        }
1222

    
1223
        mainwin_spos_set_knob ();
1224
    }
1225
}
1226

    
1227
void mainwin_update_song_info ()
1228
{
1229
    mainwin_update_volume ();
1230

    
1231
    if (! aud_drct_get_playing ())
1232
        return;
1233

    
1234
    int time = 0, length = 0;
1235
    if (aud_drct_get_ready ())
1236
    {
1237
        time = aud_drct_get_time ();
1238
        length = aud_drct_get_length ();
1239
    }
1240

    
1241
    mainwin_update_time_display (time, length);
1242
    mainwin_update_time_slider (time, length);
1243
}