Project

General

Profile

dbus-server.cc

Jim Turner, November 21, 2015 18:54

 
1
/*
2
 * dbus-server.c
3
 * Copyright 2013 John Lindgren
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions are met:
7
 *
8
 * 1. Redistributions of source code must retain the above copyright notice,
9
 *    this list of conditions, and the following disclaimer.
10
 *
11
 * 2. Redistributions in binary form must reproduce the above copyright notice,
12
 *    this list of conditions, and the following disclaimer in the documentation
13
 *    provided with the distribution.
14
 *
15
 * This software is provided "as is" and without any warranty, express or
16
 * implied. In no event shall the authors be liable for any damages arising from
17
 * the use of this software.
18
 */
19

    
20
#include <libaudcore/drct.h>
21
#include <libaudcore/equalizer.h>
22
#include <libaudcore/interface.h>
23
#include <libaudcore/playlist.h>
24
#include <libaudcore/runtime.h>
25
#include <libaudcore/tuple.h>
26

    
27
#include "aud-dbus.h"
28
#include "main.h"
29

    
30
typedef ObjAudacious Obj;
31
typedef GDBusMethodInvocation Invoc;
32

    
33
#define FINISH(name) \
34
 obj_audacious_complete_##name (obj, invoc)
35

    
36
#define FINISH2(name, ...) \
37
 obj_audacious_complete_##name (obj, invoc, __VA_ARGS__)
38

    
39
static int current_playlist ()
40
{
41
    int list = aud_playlist_get_playing ();
42
    return (list >= 0) ? list : aud_playlist_get_active ();
43
}
44

    
45
#define CURRENT current_playlist ()
46

    
47
static Index<PlaylistAddItem> strv_to_index (const char * const * strv)
48
{
49
    Index<PlaylistAddItem> index;
50
    while (* strv)
51
        index.append (String (* strv ++));
52

    
53
    return index;
54
}
55

    
56
static gboolean do_add (Obj * obj, Invoc * invoc, const char * file)
57
{
58
    aud_playlist_entry_insert (CURRENT, -1, file, Tuple (), false);
59
    FINISH (add);
60
    return true;
61
}
62

    
63
static gboolean do_add_list (Obj * obj, Invoc * invoc, const char * const * filenames)
64
{
65
    aud_playlist_entry_insert_batch (CURRENT, -1, strv_to_index (filenames), false);
66
    FINISH (add_list);
67
    return true;
68
}
69

    
70
static gboolean do_add_url (Obj * obj, Invoc * invoc, const char * url)
71
{
72
    aud_playlist_entry_insert (CURRENT, -1, url, Tuple (), false);
73
    FINISH (add_url);
74
    return true;
75
}
76

    
77
static gboolean do_advance (Obj * obj, Invoc * invoc)
78
{
79
    aud_drct_pl_next ();
80
    FINISH (advance);
81
    return true;
82
}
83

    
84
static gboolean do_auto_advance (Obj * obj, Invoc * invoc)
85
{
86
    FINISH2 (auto_advance, ! aud_get_bool (nullptr, "no_playlist_advance"));
87
    return true;
88
}
89

    
90
static gboolean do_balance (Obj * obj, Invoc * invoc)
91
{
92
    FINISH2 (balance, aud_drct_get_volume_balance ());
93
    return true;
94
}
95

    
96
static gboolean do_clear (Obj * obj, Invoc * invoc)
97
{
98
    int playlist = CURRENT;
99
    aud_playlist_entry_delete (playlist, 0, aud_playlist_entry_count (playlist));
100
    FINISH (clear);
101
    return true;
102
}
103

    
104
static gboolean do_delete (Obj * obj, Invoc * invoc, unsigned pos)
105
{
106
    aud_playlist_entry_delete (CURRENT, pos, 1);
107
    FINISH (delete);
108
    return true;
109
}
110

    
111
static gboolean do_delete_active_playlist (Obj * obj, Invoc * invoc)
112
{
113
    aud_playlist_delete (CURRENT);
114
    FINISH (delete_active_playlist);
115
    return true;
116
}
117

    
118
static gboolean do_eject (Obj * obj, Invoc * invoc)
119
{
120
    if (! aud_get_headless_mode ())
121
        aud_ui_show_filebrowser (true);
122

    
123
    FINISH (eject);
124
    return true;
125
}
126

    
127
static gboolean do_equalizer_activate (Obj * obj, Invoc * invoc, gboolean active)
128
{
129
    aud_set_bool (nullptr, "equalizer_active", active);
130
    FINISH (equalizer_activate);
131
    return true;
132
}
133

    
134
static gboolean do_get_active_playlist (Obj * obj, Invoc * invoc)
135
{
136
    FINISH2 (get_active_playlist, CURRENT);
137
    return true;
138
}
139

    
140
static gboolean do_get_active_playlist_name (Obj * obj, Invoc * invoc)
141
{
142
    String title = aud_playlist_get_title (CURRENT);
143
    FINISH2 (get_active_playlist_name, title ? title : "");
144
    return true;
145
}
146

    
147
static gboolean do_get_eq (Obj * obj, Invoc * invoc)
148
{
149
    double preamp = aud_get_double (nullptr, "equalizer_preamp");
150
    double bands[AUD_EQ_NBANDS];
151
    aud_eq_get_bands (bands);
152

    
153
    GVariant * var = g_variant_new_fixed_array (G_VARIANT_TYPE_DOUBLE, bands,
154
     AUD_EQ_NBANDS, sizeof (double));
155
    FINISH2 (get_eq, preamp, var);
156
    return true;
157
}
158

    
159
static gboolean do_get_eq_band (Obj * obj, Invoc * invoc, int band)
160
{
161
    FINISH2 (get_eq_band, aud_eq_get_band (band));
162
    return true;
163
}
164

    
165
static gboolean do_get_eq_preamp (Obj * obj, Invoc * invoc)
166
{
167
    FINISH2 (get_eq_preamp, aud_get_double (nullptr, "equalizer_preamp"));
168
    return true;
169
}
170

    
171
static gboolean do_get_info (Obj * obj, Invoc * invoc)
172
{
173
    int bitrate, samplerate, channels;
174
    aud_drct_get_info (bitrate, samplerate, channels);
175
    FINISH2 (get_info, bitrate, samplerate, channels);
176
    return true;
177
}
178

    
179
static gboolean do_get_playqueue_length (Obj * obj, Invoc * invoc)
180
{
181
    FINISH2 (get_playqueue_length, aud_playlist_queue_count (CURRENT));
182
    return true;
183
}
184

    
185
static gboolean do_get_tuple_fields (Obj * obj, Invoc * invoc)
186
{
187
    const char * fields[Tuple::n_fields + 1];
188

    
189
    for (auto f : Tuple::all_fields ())
190
        fields[f] = Tuple::field_get_name (f);
191

    
192
    fields[Tuple::n_fields] = nullptr;
193

    
194
    FINISH2 (get_tuple_fields, fields);
195
    return true;
196
}
197

    
198
static gboolean do_info (Obj * obj, Invoc * invoc)
199
{
200
    int bitrate, samplerate, channels;
201
    aud_drct_get_info (bitrate, samplerate, channels);
202
    FINISH2 (info, bitrate, samplerate, channels);
203
    return true;
204
}
205

    
206
static gboolean do_jump (Obj * obj, Invoc * invoc, unsigned pos)
207
{
208
    aud_playlist_set_position (CURRENT, pos);
209
    FINISH (jump);
210
    return true;
211
}
212

    
213
static gboolean do_length (Obj * obj, Invoc * invoc)
214
{
215
    FINISH2 (length, aud_playlist_entry_count (CURRENT));
216
    return true;
217
}
218

    
219
static gboolean do_main_win_visible (Obj * obj, Invoc * invoc)
220
{
221
    FINISH2 (main_win_visible, ! aud_get_headless_mode () && aud_ui_is_shown ());
222
    return true;
223
}
224

    
225
static gboolean do_new_playlist (Obj * obj, Invoc * invoc)
226
{
227
    int playlist = CURRENT + 1;
228
    aud_playlist_insert (playlist);
229
    aud_playlist_set_active (playlist);
230
    aud_drct_stop ();
231
    FINISH (new_playlist);
232
    return true;
233
}
234

    
235
static gboolean do_number_of_playlists (Obj * obj, Invoc * invoc)
236
{
237
    FINISH2 (number_of_playlists, aud_playlist_count ());
238
    return true;
239
}
240

    
241
static gboolean do_open_list (Obj * obj, Invoc * invoc, const char * const * filenames)
242
{
243
    aud_drct_pl_open_list (strv_to_index (filenames));
244
    FINISH (open_list);
245
    return true;
246
}
247

    
248
static gboolean do_open_list_to_temp (Obj * obj, Invoc * invoc, const char * const * filenames)
249
{
250
    aud_drct_pl_open_temp_list (strv_to_index (filenames));
251
    FINISH (open_list_to_temp);
252
    return true;
253
}
254

    
255
static gboolean do_pause (Obj * obj, Invoc * invoc)
256
{
257
    aud_drct_pause ();
258
    FINISH (pause);
259
    return true;
260
}
261

    
262
static gboolean do_paused (Obj * obj, Invoc * invoc)
263
{
264
    FINISH2 (paused, aud_drct_get_paused ());
265
    return true;
266
}
267

    
268
static gboolean do_play (Obj * obj, Invoc * invoc)
269
{
270
    aud_drct_play ();
271
    FINISH (play);
272
    return true;
273
}
274

    
275
static gboolean do_play_active_playlist (Obj * obj, Invoc * invoc)
276
{
277
    aud_playlist_play (CURRENT);
278
    FINISH (play_active_playlist);
279
    return true;
280
}
281

    
282
static gboolean do_play_pause (Obj * obj, Invoc * invoc)
283
{
284
    aud_drct_play_pause ();
285
    FINISH (play_pause);
286
    return true;
287
}
288

    
289
static gboolean do_playing (Obj * obj, Invoc * invoc)
290
{
291
    FINISH2 (playing, aud_drct_get_playing ());
292
    return true;
293
}
294

    
295
static gboolean do_playlist_add (Obj * obj, Invoc * invoc, const char * list)
296
{
297
    aud_playlist_entry_insert (CURRENT, -1, list, Tuple (), false);
298
    FINISH (playlist_add);
299
    return true;
300
}
301

    
302
static gboolean do_playlist_enqueue_to_temp (Obj * obj, Invoc * invoc, const char * url)
303
{
304
    aud_drct_pl_open_temp (url);
305
    FINISH (playlist_enqueue_to_temp);
306
    return true;
307
}
308

    
309
static gboolean do_playlist_ins_url_string (Obj * obj, Invoc * invoc, const char * url, int pos)
310
{
311
    aud_playlist_entry_insert (CURRENT, pos, url, Tuple (), false);
312
    FINISH (playlist_ins_url_string);
313
    return true;
314
}
315

    
316
static gboolean do_playqueue_add (Obj * obj, Invoc * invoc, int pos)
317
{
318
    aud_playlist_queue_insert (CURRENT, -1, pos);
319
    FINISH (playqueue_add);
320
    return true;
321
}
322

    
323
static gboolean do_playqueue_clear (Obj * obj, Invoc * invoc)
324
{
325
    int playlist = CURRENT;
326
    aud_playlist_queue_delete (playlist, 0, aud_playlist_queue_count (playlist));
327
    FINISH (playqueue_clear);
328
    return true;
329
}
330

    
331
static gboolean do_playqueue_is_queued (Obj * obj, Invoc * invoc, int pos)
332
{
333
    bool queued = (aud_playlist_queue_find_entry (CURRENT, pos) >= 0);
334
    FINISH2 (playqueue_is_queued, queued);
335
    return true;
336
}
337

    
338
static gboolean do_playqueue_remove (Obj * obj, Invoc * invoc, int pos)
339
{
340
    int playlist = CURRENT;
341
    int qpos = aud_playlist_queue_find_entry (playlist, pos);
342

    
343
    if (qpos >= 0)
344
        aud_playlist_queue_delete (playlist, qpos, 1);
345

    
346
    FINISH (playqueue_remove);
347
    return true;
348
}
349

    
350
static gboolean do_position (Obj * obj, Invoc * invoc)
351
{
352
    FINISH2 (position, aud_playlist_get_position (CURRENT));
353
    return true;
354
}
355

    
356
static gboolean do_queue_get_list_pos (Obj * obj, Invoc * invoc, unsigned qpos)
357
{
358
    FINISH2 (queue_get_list_pos, aud_playlist_queue_get_entry (CURRENT, qpos));
359
    return true;
360
}
361

    
362
static gboolean do_queue_get_queue_pos (Obj * obj, Invoc * invoc, unsigned pos)
363
{
364
    FINISH2 (queue_get_queue_pos, aud_playlist_queue_find_entry (CURRENT, pos));
365
    return true;
366
}
367

    
368
static gboolean do_quit (Obj * obj, Invoc * invoc)
369
{
370
    aud_quit ();
371
    FINISH (quit);
372
    return true;
373
}
374

    
375
static gboolean do_repeat (Obj * obj, Invoc * invoc)
376
{
377
    FINISH2 (repeat, aud_get_bool (nullptr, "repeat"));
378
    return true;
379
}
380

    
381
static gboolean do_reverse (Obj * obj, Invoc * invoc)
382
{
383
    aud_drct_pl_prev ();
384
    FINISH (reverse);
385
    return true;
386
}
387

    
388
static gboolean do_record (Obj * obj, Invoc * invoc)
389
{
390
    aud_drct_enable_record (!aud_drct_get_record_enabled ());
391
    FINISH (record);
392
    return true;
393
}
394

    
395
static gboolean do_seek (Obj * obj, Invoc * invoc, unsigned pos)
396
{
397
    aud_drct_seek (pos);
398
    FINISH (seek);
399
    return true;
400
}
401

    
402
static gboolean do_set_active_playlist (Obj * obj, Invoc * invoc, int playlist)
403
{
404
    aud_playlist_set_active (playlist);
405

    
406
    // check that the requested playlist exists before switching playback
407
    if (aud_playlist_get_active () == playlist && aud_drct_get_playing ())
408
        aud_playlist_play (playlist, aud_drct_get_paused ());
409

    
410
    FINISH (set_active_playlist);
411
    return true;
412
}
413

    
414
static gboolean do_set_active_playlist_name (Obj * obj, Invoc * invoc, const char * title)
415
{
416
    aud_playlist_set_title (CURRENT, title);
417
    FINISH (set_active_playlist_name);
418
    return true;
419
}
420

    
421
static gboolean do_set_eq (Obj * obj, Invoc * invoc, double preamp, GVariant * var)
422
{
423
    if (! g_variant_is_of_type (var, G_VARIANT_TYPE ("ad")))
424
        return false;
425

    
426
    size_t nbands = 0;
427
    const double * bands = (double *) g_variant_get_fixed_array (var, & nbands, sizeof (double));
428

    
429
    if (nbands != AUD_EQ_NBANDS)
430
        return false;
431

    
432
    aud_set_double (nullptr, "equalizer_preamp", preamp);
433
    aud_eq_set_bands (bands);
434
    FINISH (set_eq);
435
    return true;
436
}
437

    
438
static gboolean do_set_eq_band (Obj * obj, Invoc * invoc, int band, double value)
439
{
440
    aud_eq_set_band (band, value);
441
    FINISH (set_eq_band);
442
    return true;
443
}
444

    
445
static gboolean do_set_eq_preamp (Obj * obj, Invoc * invoc, double preamp)
446
{
447
    aud_set_double (nullptr, "equalizer_preamp", preamp);
448
    FINISH (set_eq_preamp);
449
    return true;
450
}
451

    
452
static gboolean do_set_volume (Obj * obj, Invoc * invoc, int vl, int vr)
453
{
454
    aud_drct_set_volume ({vl, vr});
455
    FINISH (set_volume);
456
    return true;
457
}
458

    
459
static gboolean do_show_about_box (Obj * obj, Invoc * invoc, gboolean show)
460
{
461
    if (! aud_get_headless_mode ())
462
    {
463
        if (show)
464
            aud_ui_show_about_window ();
465
        else
466
            aud_ui_hide_about_window ();
467
    }
468

    
469
    FINISH (show_about_box);
470
    return true;
471
}
472

    
473
static gboolean do_show_filebrowser (Obj * obj, Invoc * invoc, gboolean show)
474
{
475
    if (! aud_get_headless_mode ())
476
    {
477
        if (show)
478
            aud_ui_show_filebrowser (false);
479
        else
480
            aud_ui_hide_filebrowser ();
481
    }
482

    
483
    FINISH (show_filebrowser);
484
    return true;
485
}
486

    
487
static gboolean do_show_jtf_box (Obj * obj, Invoc * invoc, gboolean show)
488
{
489
    if (! aud_get_headless_mode ())
490
    {
491
        if (show)
492
            aud_ui_show_jump_to_song ();
493
        else
494
            aud_ui_hide_jump_to_song ();
495
    }
496

    
497
    FINISH (show_jtf_box);
498
    return true;
499
}
500

    
501
static gboolean do_show_main_win (Obj * obj, Invoc * invoc, gboolean show)
502
{
503
    if (! aud_get_headless_mode ())
504
        aud_ui_show (show);
505

    
506
    FINISH (show_main_win);
507
    return true;
508
}
509

    
510
static gboolean do_show_prefs_box (Obj * obj, Invoc * invoc, gboolean show)
511
{
512
    if (! aud_get_headless_mode ())
513
    {
514
        if (show)
515
            aud_ui_show_prefs_window ();
516
        else
517
            aud_ui_hide_prefs_window ();
518
    }
519

    
520
    FINISH (show_prefs_box);
521
    return true;
522
}
523

    
524
static gboolean do_shuffle (Obj * obj, Invoc * invoc)
525
{
526
    FINISH2 (shuffle, aud_get_bool (nullptr, "shuffle"));
527
    return true;
528
}
529

    
530
static gboolean do_song_filename (Obj * obj, Invoc * invoc, unsigned pos)
531
{
532
    String filename = aud_playlist_entry_get_filename (CURRENT, pos);
533
    FINISH2 (song_filename, filename ? filename : "");
534
    return true;
535
}
536

    
537
static gboolean do_song_frames (Obj * obj, Invoc * invoc, unsigned pos)
538
{
539
    Tuple tuple = aud_playlist_entry_get_tuple (CURRENT, pos);
540
    FINISH2 (song_frames, aud::max (0, tuple.get_int (Tuple::Length)));
541
    return true;
542
}
543

    
544
static gboolean do_song_length (Obj * obj, Invoc * invoc, unsigned pos)
545
{
546
    Tuple tuple = aud_playlist_entry_get_tuple (CURRENT, pos);
547
    int length = aud::max (0, tuple.get_int (Tuple::Length));
548
    FINISH2 (song_length, length / 1000);
549
    return true;
550
}
551

    
552
static gboolean do_song_title (Obj * obj, Invoc * invoc, unsigned pos)
553
{
554
    Tuple tuple = aud_playlist_entry_get_tuple (CURRENT, pos);
555
    String title = tuple.get_str (Tuple::FormattedTitle);
556
    FINISH2 (song_title, title ? title : "");
557
    return true;
558
}
559

    
560
static gboolean do_song_tuple (Obj * obj, Invoc * invoc, unsigned pos, const char * key)
561
{
562
    Tuple::Field field = Tuple::field_by_name (key);
563
    Tuple tuple;
564
    GVariant * var = nullptr;
565

    
566
    if (field >= 0)
567
        tuple = aud_playlist_entry_get_tuple (CURRENT, pos);
568

    
569
    if (tuple)
570
    {
571
        switch (tuple.get_value_type (field))
572
        {
573
        case Tuple::String:
574
            var = g_variant_new_string (tuple.get_str (field));
575
            break;
576

    
577
        case Tuple::Int:
578
            var = g_variant_new_int32 (tuple.get_int (field));
579
            break;
580

    
581
        default:
582
            break;
583
        }
584
    }
585

    
586
    if (! var)
587
        var = g_variant_new_string ("");
588

    
589
    FINISH2 (song_tuple, g_variant_new_variant (var));
590
    return true;
591
}
592

    
593
static gboolean do_status (Obj * obj, Invoc * invoc)
594
{
595
    const char * status = "stopped";
596
    if (aud_drct_get_playing ())
597
        status = aud_drct_get_paused () ? "paused" : "playing";
598

    
599
    FINISH2 (status, status);
600
    return true;
601
}
602

    
603
static gboolean do_stop (Obj * obj, Invoc * invoc)
604
{
605
    aud_drct_stop ();
606
    FINISH (stop);
607
    return true;
608
}
609

    
610
static gboolean do_stop_after (Obj * obj, Invoc * invoc)
611
{
612
    FINISH2 (stop_after, aud_get_bool (nullptr, "stop_after_current_song"));
613
    return true;
614
}
615

    
616
static gboolean do_stopped (Obj * obj, Invoc * invoc)
617
{
618
    FINISH2 (stopped, ! aud_drct_get_playing ());
619
    return true;
620
}
621

    
622
static gboolean do_time (Obj * obj, Invoc * invoc)
623
{
624
    FINISH2 (time, aud_drct_get_time ());
625
    return true;
626
}
627

    
628
static gboolean do_toggle_auto_advance (Obj * obj, Invoc * invoc)
629
{
630
    aud_set_bool (nullptr, "no_playlist_advance", ! aud_get_bool (nullptr, "no_playlist_advance"));
631
    FINISH (toggle_auto_advance);
632
    return true;
633
}
634

    
635
static gboolean do_toggle_repeat (Obj * obj, Invoc * invoc)
636
{
637
    aud_set_bool (nullptr, "repeat", ! aud_get_bool (nullptr, "repeat"));
638
    FINISH (toggle_repeat);
639
    return true;
640
}
641

    
642
static gboolean do_toggle_shuffle (Obj * obj, Invoc * invoc)
643
{
644
    aud_set_bool (nullptr, "shuffle", ! aud_get_bool (nullptr, "shuffle"));
645
    FINISH (toggle_shuffle);
646
    return true;
647
}
648

    
649
static gboolean do_toggle_stop_after (Obj * obj, Invoc * invoc)
650
{
651
    aud_set_bool (nullptr, "stop_after_current_song", ! aud_get_bool (nullptr, "stop_after_current_song"));
652
    FINISH (toggle_stop_after);
653
    return true;
654
}
655

    
656
static gboolean do_version (Obj * obj, Invoc * invoc)
657
{
658
    FINISH2 (version, VERSION);
659
    return true;
660
}
661

    
662
static gboolean do_volume (Obj * obj, Invoc * invoc)
663
{
664
    StereoVolume volume = aud_drct_get_volume ();
665
    FINISH2 (volume, volume.left, volume.right);
666
    return true;
667
}
668

    
669
static const struct
670
{
671
    const char * signal;
672
    GCallback callback;
673
}
674
handlers[] =
675
{
676
    {"handle-add", (GCallback) do_add},
677
    {"handle-add-list", (GCallback) do_add_list},
678
    {"handle-add-url", (GCallback) do_add_url},
679
    {"handle-advance", (GCallback) do_advance},
680
    {"handle-auto-advance", (GCallback) do_auto_advance},
681
    {"handle-balance", (GCallback) do_balance},
682
    {"handle-clear", (GCallback) do_clear},
683
    {"handle-delete", (GCallback) do_delete},
684
    {"handle-delete-active-playlist", (GCallback) do_delete_active_playlist},
685
    {"handle-eject", (GCallback) do_eject},
686
    {"handle-equalizer-activate", (GCallback) do_equalizer_activate},
687
    {"handle-get-active-playlist", (GCallback) do_get_active_playlist},
688
    {"handle-get-active-playlist-name", (GCallback) do_get_active_playlist_name},
689
    {"handle-get-eq", (GCallback) do_get_eq},
690
    {"handle-get-eq-band", (GCallback) do_get_eq_band},
691
    {"handle-get-eq-preamp", (GCallback) do_get_eq_preamp},
692
    {"handle-get-info", (GCallback) do_get_info},
693
    {"handle-get-playqueue-length", (GCallback) do_get_playqueue_length},
694
    {"handle-get-tuple-fields", (GCallback) do_get_tuple_fields},
695
    {"handle-info", (GCallback) do_info},
696
    {"handle-jump", (GCallback) do_jump},
697
    {"handle-length", (GCallback) do_length},
698
    {"handle-main-win-visible", (GCallback) do_main_win_visible},
699
    {"handle-new-playlist", (GCallback) do_new_playlist},
700
    {"handle-number-of-playlists", (GCallback) do_number_of_playlists},
701
    {"handle-open-list", (GCallback) do_open_list},
702
    {"handle-open-list-to-temp", (GCallback) do_open_list_to_temp},
703
    {"handle-pause", (GCallback) do_pause},
704
    {"handle-paused", (GCallback) do_paused},
705
    {"handle-play", (GCallback) do_play},
706
    {"handle-play-active-playlist", (GCallback) do_play_active_playlist},
707
    {"handle-play-pause", (GCallback) do_play_pause},
708
    {"handle-playing", (GCallback) do_playing},
709
    {"handle-playlist-add", (GCallback) do_playlist_add},
710
    {"handle-playlist-enqueue-to-temp", (GCallback) do_playlist_enqueue_to_temp},
711
    {"handle-playlist-ins-url-string", (GCallback) do_playlist_ins_url_string},
712
    {"handle-playqueue-add", (GCallback) do_playqueue_add},
713
    {"handle-playqueue-clear", (GCallback) do_playqueue_clear},
714
    {"handle-playqueue-is-queued", (GCallback) do_playqueue_is_queued},
715
    {"handle-playqueue-remove", (GCallback) do_playqueue_remove},
716
    {"handle-position", (GCallback) do_position},
717
    {"handle-queue-get-list-pos", (GCallback) do_queue_get_list_pos},
718
    {"handle-queue-get-queue-pos", (GCallback) do_queue_get_queue_pos},
719
    {"handle-quit", (GCallback) do_quit},
720
    {"handle-repeat", (GCallback) do_repeat},
721
    {"handle-reverse", (GCallback) do_reverse},
722
    {"handle-record", (GCallback) do_record},
723
    {"handle-seek", (GCallback) do_seek},
724
    {"handle-set-active-playlist", (GCallback) do_set_active_playlist},
725
    {"handle-set-active-playlist-name", (GCallback) do_set_active_playlist_name},
726
    {"handle-set-eq", (GCallback) do_set_eq},
727
    {"handle-set-eq-band", (GCallback) do_set_eq_band},
728
    {"handle-set-eq-preamp", (GCallback) do_set_eq_preamp},
729
    {"handle-set-volume", (GCallback) do_set_volume},
730
    {"handle-show-about-box", (GCallback) do_show_about_box},
731
    {"handle-show-filebrowser", (GCallback) do_show_filebrowser},
732
    {"handle-show-jtf-box", (GCallback) do_show_jtf_box},
733
    {"handle-show-main-win", (GCallback) do_show_main_win},
734
    {"handle-show-prefs-box", (GCallback) do_show_prefs_box},
735
    {"handle-shuffle", (GCallback) do_shuffle},
736
    {"handle-song-filename", (GCallback) do_song_filename},
737
    {"handle-song-frames", (GCallback) do_song_frames},
738
    {"handle-song-length", (GCallback) do_song_length},
739
    {"handle-song-title", (GCallback) do_song_title},
740
    {"handle-song-tuple", (GCallback) do_song_tuple},
741
    {"handle-status", (GCallback) do_status},
742
    {"handle-stop", (GCallback) do_stop},
743
    {"handle-stop-after", (GCallback) do_stop_after},
744
    {"handle-stopped", (GCallback) do_stopped},
745
    {"handle-time", (GCallback) do_time},
746
    {"handle-toggle-auto-advance", (GCallback) do_toggle_auto_advance},
747
    {"handle-toggle-repeat", (GCallback) do_toggle_repeat},
748
    {"handle-toggle-shuffle", (GCallback) do_toggle_shuffle},
749
    {"handle-toggle-stop-after", (GCallback) do_toggle_stop_after},
750
    {"handle-version", (GCallback) do_version},
751
    {"handle-volume", (GCallback) do_volume}
752
};
753

    
754
static GMainLoop * mainloop = nullptr;
755
static unsigned owner_id = 0;
756

    
757
static GDBusInterfaceSkeleton * skeleton = nullptr;
758

    
759
static void name_acquired (GDBusConnection *, const char *, void *)
760
{
761
    AUDINFO ("Owned D-Bus name (org.atheme.audacious) on session bus.\n");
762

    
763
    g_main_loop_quit (mainloop);
764
}
765

    
766
static void name_lost (GDBusConnection *, const char *, void *)
767
{
768
    AUDINFO ("Owning D-Bus name (org.atheme.audacious) failed, already taken?\n");
769

    
770
    g_bus_unown_name (owner_id);
771
    owner_id = 0;
772

    
773
    g_main_loop_quit (mainloop);
774
}
775

    
776
StartupType dbus_server_init ()
777
{
778
    GError * error = nullptr;
779
    GDBusConnection * bus = g_bus_get_sync (G_BUS_TYPE_SESSION, nullptr, & error);
780
    GMainContext * context;
781

    
782
    if (! bus)
783
        goto ERROR;
784

    
785
    skeleton = (GDBusInterfaceSkeleton *) obj_audacious_skeleton_new ();
786

    
787
    for (auto & handler : handlers)
788
        g_signal_connect (skeleton, handler.signal, handler.callback, nullptr);
789

    
790
    if (! g_dbus_interface_skeleton_export (skeleton, bus, "/org/atheme/audacious", & error))
791
        goto ERROR;
792

    
793
    context = g_main_context_new ();
794
    g_main_context_push_thread_default (context);
795

    
796
    owner_id = g_bus_own_name (G_BUS_TYPE_SESSION, "org.atheme.audacious",
797
     (GBusNameOwnerFlags) 0, nullptr, name_acquired, name_lost, nullptr, nullptr);
798

    
799
    mainloop = g_main_loop_new (context, true);
800
    g_main_loop_run (mainloop);
801
    g_main_loop_unref (mainloop);
802
    mainloop = nullptr;
803

    
804
    g_main_context_pop_thread_default (context);
805
    g_main_context_unref (context);
806

    
807
    if (owner_id)
808
        return StartupType::Server;
809

    
810
    dbus_server_cleanup ();
811
    return StartupType::Client;
812

    
813
ERROR:
814
    if (error)
815
    {
816
        AUDERR ("D-Bus error: %s\n", error->message);
817
        g_error_free (error);
818
    }
819

    
820
    dbus_server_cleanup ();
821
    return StartupType::Unknown;
822
}
823

    
824
void dbus_server_cleanup ()
825
{
826
    if (owner_id)
827
    {
828
        g_bus_unown_name (owner_id);
829
        owner_id = 0;
830
    }
831

    
832
    if (skeleton)
833
    {
834
        g_object_unref (skeleton);
835
        skeleton = nullptr;
836
    }
837
}