1 /*
2     gtkui hotkey handlers
3     Copyright (C) 2009-2013 Alexey Yakovenko and other contributors
4 
5     This software is provided 'as-is', without any express or implied
6     warranty.  In no event will the authors be held liable for any damages
7     arising from the use of this software.
8 
9     Permission is granted to anyone to use this software for any purpose,
10     including commercial applications, and to alter it and redistribute it
11     freely, subject to the following restrictions:
12 
13     1. The origin of this software must not be misrepresented; you must not
14      claim that you wrote the original software. If you use this software
15      in a product, an acknowledgment in the product documentation would be
16      appreciated but is not required.
17 
18     2. Altered source versions must be plainly marked as such, and must not be
19      misrepresented as being the original software.
20 
21     3. This notice may not be removed or altered from any source distribution.
22 */
23 #ifdef HAVE_CONFIG_H
24 #  include <config.h>
25 #endif
26 
27 #include <stdlib.h>
28 #include <string.h>
29 #include <gtk/gtk.h>
30 #include <unistd.h>
31 #include "../../gettext.h"
32 #include "../../deadbeef.h"
33 #include "gtkui.h"
34 #include "progress.h"
35 #include "ddblistview.h"
36 #include "search.h"
37 #include "support.h"
38 #include "wingeom.h"
39 #include "interface.h"
40 #include "trkproperties.h"
41 #include "callbacks.h"
42 #include <sys/stat.h>
43 
44 // disable custom title function, until we have new title formatting (0.7)
45 #define DISABLE_CUSTOM_TITLE
46 
47 extern GtkWidget *mainwin;
48 extern DB_functions_t *deadbeef;
49 
50 static gboolean
file_filter_func(const GtkFileFilterInfo * filter_info,gpointer data)51 file_filter_func (const GtkFileFilterInfo *filter_info, gpointer data) {
52     // get ext
53     const char *p = strrchr (filter_info->filename, '.');
54     if (!p) {
55         return FALSE;
56     }
57     p++;
58 
59     // get beginning of fname
60     const char *fn = strrchr (filter_info->filename, '/');
61     if (!fn) {
62         fn = filter_info->filename;
63     }
64     else {
65         fn++;
66     }
67 
68 
69     DB_decoder_t **codecs = deadbeef->plug_get_decoder_list ();
70     for (int i = 0; codecs[i]; i++) {
71         if (codecs[i]->exts && codecs[i]->insert) {
72             const char **exts = codecs[i]->exts;
73             for (int e = 0; exts[e]; e++) {
74                 if (!strcasecmp (exts[e], p)) {
75                     return TRUE;
76                 }
77             }
78         }
79         if (codecs[i]->prefixes && codecs[i]->insert) {
80             const char **prefixes = codecs[i]->prefixes;
81             for (int e = 0; prefixes[e]; e++) {
82                 if (!strncasecmp (prefixes[e], fn, strlen(prefixes[e])) && *(fn + strlen (prefixes[e])) == '.') {
83                     return TRUE;
84                 }
85             }
86         }
87     }
88 #if 0
89     if (!strcasecmp (p, "pls")) {
90         return TRUE;
91     }
92     if (!strcasecmp (p, "m3u")) {
93         return TRUE;
94     }
95 #endif
96 
97     // test container (vfs) formats
98     DB_vfs_t **vfsplugs = deadbeef->plug_get_vfs_list ();
99     for (int i = 0; vfsplugs[i]; i++) {
100         if (vfsplugs[i]->is_container) {
101             if (vfsplugs[i]->is_container (filter_info->filename)) {
102                 return TRUE;
103             }
104         }
105     }
106 
107     return FALSE;
108 }
109 
110 static GtkFileFilter *
set_file_filter(GtkWidget * dlg,const char * name)111 set_file_filter (GtkWidget *dlg, const char *name) {
112     if (!name) {
113         name = _("Supported sound formats");
114     }
115 
116     GtkFileFilter* flt;
117     flt = gtk_file_filter_new ();
118     gtk_file_filter_set_name (flt, name);
119 
120     gtk_file_filter_add_custom (flt, GTK_FILE_FILTER_FILENAME, file_filter_func, NULL, NULL);
121     gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dlg), flt);
122     gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (dlg), flt);
123     flt = gtk_file_filter_new ();
124     gtk_file_filter_set_name (flt, _("All files (*)"));
125     gtk_file_filter_add_pattern (flt, "*");
126     gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dlg), flt);
127     return flt;
128 }
129 
130 gboolean
action_open_files_handler_cb(void * userdata)131 action_open_files_handler_cb (void *userdata) {
132     GtkWidget *dlg = gtk_file_chooser_dialog_new (_("Open file(s)..."), GTK_WINDOW (mainwin), GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_OK, NULL);
133 
134     set_file_filter (dlg, NULL);
135 
136     gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dlg), TRUE);
137     // restore folder
138     deadbeef->conf_lock ();
139     gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dlg), deadbeef->conf_get_str_fast ("filechooser.lastdir", ""));
140     deadbeef->conf_unlock ();
141     int response = gtk_dialog_run (GTK_DIALOG (dlg));
142     // store folder
143     gchar *folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dlg));
144     if (folder) {
145         deadbeef->conf_set_str ("filechooser.lastdir", folder);
146         g_free (folder);
147     }
148     if (response == GTK_RESPONSE_OK)
149     {
150         deadbeef->pl_clear ();
151         GSList *lst = gtk_file_chooser_get_filenames (GTK_FILE_CHOOSER (dlg));
152         gtk_widget_destroy (dlg);
153         if (lst) {
154             gtkui_open_files (lst);
155         }
156     }
157     else {
158         gtk_widget_destroy (dlg);
159     }
160     return FALSE;
161 }
162 
163 int
action_open_files_handler(struct DB_plugin_action_s * action,int ctx)164 action_open_files_handler (struct DB_plugin_action_s *action, int ctx) {
165     gdk_threads_add_idle (action_open_files_handler_cb, NULL);
166     return 0;
167 }
168 
169 gboolean
action_add_files_handler_cb(void * user_data)170 action_add_files_handler_cb (void *user_data) {
171     GtkWidget *dlg = gtk_file_chooser_dialog_new (_("Add file(s) to playlist..."), GTK_WINDOW (mainwin), GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_OK, NULL);
172 
173     set_file_filter (dlg, NULL);
174 
175     gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dlg), TRUE);
176 
177     // restore folder
178     deadbeef->conf_lock ();
179     gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dlg), deadbeef->conf_get_str_fast ("filechooser.lastdir", ""));
180     deadbeef->conf_unlock ();
181     int response = gtk_dialog_run (GTK_DIALOG (dlg));
182     // store folder
183     gchar *folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dlg));
184     if (folder) {
185         deadbeef->conf_set_str ("filechooser.lastdir", folder);
186         g_free (folder);
187     }
188     if (response == GTK_RESPONSE_OK)
189     {
190         GSList *lst = gtk_file_chooser_get_filenames (GTK_FILE_CHOOSER (dlg));
191         gtk_widget_destroy (dlg);
192         if (lst) {
193             gtkui_add_files (lst);
194         }
195     }
196     else {
197         gtk_widget_destroy (dlg);
198     }
199     return FALSE;
200 }
201 
202 int
action_add_files_handler(struct DB_plugin_action_s * action,int ctx)203 action_add_files_handler (struct DB_plugin_action_s *action, int ctx) {
204     gdk_threads_add_idle (action_add_files_handler_cb, NULL);
205     return 0;
206 }
207 
208 static void
on_follow_symlinks_toggled(GtkToggleButton * togglebutton,gpointer user_data)209 on_follow_symlinks_toggled         (GtkToggleButton *togglebutton,
210                                         gpointer         user_data)
211 {
212     deadbeef->conf_set_int ("add_folders_follow_symlinks", gtk_toggle_button_get_active (togglebutton));
213 }
214 
215 gboolean
action_add_folders_handler_cb(void * user_data)216 action_add_folders_handler_cb (void *user_data) {
217     GtkWidget *dlg = gtk_file_chooser_dialog_new (_("Add folder(s) to playlist..."), GTK_WINDOW (mainwin), GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_OK, NULL);
218 
219     GtkWidget *box = gtk_hbox_new (FALSE, 8);
220     gtk_widget_show (box);
221 
222     GtkWidget *check = gtk_check_button_new_with_mnemonic (_("Follow symlinks"));
223     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check), deadbeef->conf_get_int ("add_folders_follow_symlinks", 0));
224     g_signal_connect ((gpointer) check, "toggled",
225             G_CALLBACK (on_follow_symlinks_toggled),
226             NULL);
227     gtk_widget_show (check);
228     gtk_box_pack_start (GTK_BOX (box), check, FALSE, FALSE, 0);
229 
230     gtk_file_chooser_set_extra_widget (GTK_FILE_CHOOSER (dlg), box);
231 
232 // gtk devs broke this in 3.6 - thanks guys
233 //  set_file_filter (dlg, NULL);
234 
235     gtk_file_chooser_set_select_multiple (GTK_FILE_CHOOSER (dlg), TRUE);
236     // restore folder
237     deadbeef->conf_lock ();
238     gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dlg), deadbeef->conf_get_str_fast ("filechooser.lastdir", ""));
239     deadbeef->conf_unlock ();
240     int response = gtk_dialog_run (GTK_DIALOG (dlg));
241     // store folder
242     gchar *folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dlg));
243     if (folder) {
244         deadbeef->conf_set_str ("filechooser.lastdir", folder);
245         g_free (folder);
246     }
247     if (response == GTK_RESPONSE_OK)
248     {
249         //gchar *folder = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dlg));
250         GSList *lst = gtk_file_chooser_get_filenames (GTK_FILE_CHOOSER (dlg));
251         gtk_widget_destroy (dlg);
252         if (lst) {
253             gtkui_add_dirs (lst);
254         }
255     }
256     else {
257         gtk_widget_destroy (dlg);
258     }
259     return FALSE;
260 }
261 
262 int
action_add_folders_handler(struct DB_plugin_action_s * action,int ctx)263 action_add_folders_handler (struct DB_plugin_action_s *action, int ctx) {
264     gdk_threads_add_idle (action_add_folders_handler_cb, NULL);
265     return 0;
266 }
267 
268 gboolean
action_quit_handler_cb(void * user_data)269 action_quit_handler_cb (void *user_data) {
270     gtkui_quit ();
271     return FALSE;
272 }
273 
274 int
action_quit_handler(DB_plugin_action_t * act,int ctx)275 action_quit_handler (DB_plugin_action_t *act, int ctx) {
276     g_idle_add (action_quit_handler_cb, NULL);
277     return 0;
278 }
279 
280 gboolean
action_deselect_all_handler_cb(void * user_data)281 action_deselect_all_handler_cb (void *user_data) {
282     deadbeef->pl_lock ();
283     DB_playItem_t *it = deadbeef->pl_get_first (PL_MAIN);
284     while (it) {
285         if (deadbeef->pl_is_selected (it)) {
286             deadbeef->pl_set_selected (it, 0);
287         }
288         DB_playItem_t *next = deadbeef->pl_get_next (it, PL_MAIN);
289         deadbeef->pl_item_unref (it);
290         it = next;
291     }
292     deadbeef->pl_unlock ();
293     deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, DDB_PLAYLIST_CHANGE_SELECTION, 0);
294     DdbListview *pl = DDB_LISTVIEW (lookup_widget (searchwin, "searchlist"));
295     if (pl) {
296         ddb_listview_refresh (pl, DDB_REFRESH_LIST);
297     }
298     return FALSE;
299 }
300 
301 int
action_deselect_all_handler(struct DB_plugin_action_s * action,int ctx)302 action_deselect_all_handler (struct DB_plugin_action_s *action, int ctx) {
303     g_idle_add (action_deselect_all_handler_cb, NULL);
304     return 0;
305 }
306 
307 gboolean
action_select_all_handler_cb(void * user_data)308 action_select_all_handler_cb (void *user_data) {
309     deadbeef->pl_select_all ();
310     deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, DDB_PLAYLIST_CHANGE_SELECTION, 0);
311     DdbListview *pl = DDB_LISTVIEW (lookup_widget (searchwin, "searchlist"));
312     if (pl) {
313         ddb_listview_refresh (pl, DDB_REFRESH_LIST);
314     }
315     return FALSE;
316 }
317 
318 int
action_select_all_handler(struct DB_plugin_action_s * action,int ctx)319 action_select_all_handler (struct DB_plugin_action_s *action, int ctx) {
320     g_idle_add (action_select_all_handler_cb, NULL);
321     return 0;
322 }
323 
324 gboolean
action_new_playlist_handler_cb(void * user_data)325 action_new_playlist_handler_cb (void *user_data) {
326     int pl = gtkui_add_new_playlist ();
327     if (pl != -1) {
328         deadbeef->plt_set_curr_idx (pl);
329         deadbeef->conf_set_int ("playlist.current", pl);
330     }
331     return FALSE;
332 }
333 
334 int
action_new_playlist_handler(struct DB_plugin_action_s * action,int ctx)335 action_new_playlist_handler (struct DB_plugin_action_s *action, int ctx) {
336     gdk_threads_add_idle (action_new_playlist_handler_cb, NULL);
337     return 0;
338 }
339 
340 int
action_remove_current_playlist_handler(struct DB_plugin_action_s * action,int ctx)341 action_remove_current_playlist_handler (struct DB_plugin_action_s *action, int ctx) {
342     int idx = deadbeef->plt_get_curr_idx ();
343     if (idx != -1) {
344         deadbeef->plt_remove (idx);
345     }
346     return 0;
347 }
348 
349 gboolean
action_toggle_mainwin_handler_cb(void * user_data)350 action_toggle_mainwin_handler_cb (void *user_data) {
351     mainwin_toggle_visible ();
352     return FALSE;
353 }
354 
355 int
action_toggle_mainwin_handler(struct DB_plugin_action_s * action,int ctx)356 action_toggle_mainwin_handler (struct DB_plugin_action_s *action, int ctx) {
357     g_idle_add (action_toggle_mainwin_handler_cb, NULL);
358     return 0;
359 }
360 
361 gboolean
action_show_mainwin_handler_cb(void * user_data)362 action_show_mainwin_handler_cb (void *user_data) {
363     int iconified = gdk_window_get_state(gtk_widget_get_window(mainwin)) & GDK_WINDOW_STATE_ICONIFIED;
364     if (!(gtk_widget_get_visible (mainwin) && !iconified)) {
365         wingeom_restore (mainwin, "mainwin", 40, 40, 500, 300, 0);
366         if (iconified) {
367             gtk_window_deiconify (GTK_WINDOW(mainwin));
368         }
369         else {
370             gtk_window_present (GTK_WINDOW (mainwin));
371         }
372     }
373     return FALSE;
374 }
375 
376 int
action_show_mainwin_handler(struct DB_plugin_action_s * action,int ctx)377 action_show_mainwin_handler (struct DB_plugin_action_s *action, int ctx) {
378     g_idle_add (action_show_mainwin_handler_cb, NULL);
379     return 0;
380 }
381 
382 gboolean
action_hide_mainwin_handler_cb(void * user_data)383 action_hide_mainwin_handler_cb (void *user_data) {
384     int iconified = gdk_window_get_state(gtk_widget_get_window(mainwin)) & GDK_WINDOW_STATE_ICONIFIED;
385     if (gtk_widget_get_visible (mainwin) && !iconified) {
386         gtk_widget_hide (mainwin);
387     }
388     return FALSE;
389 }
390 
391 int
action_hide_mainwin_handler(struct DB_plugin_action_s * action,int ctx)392 action_hide_mainwin_handler (struct DB_plugin_action_s *action, int ctx) {
393     g_idle_add (action_hide_mainwin_handler_cb, NULL);
394     return 0;
395 }
396 
397 static void
on_toggle_set_custom_title(GtkToggleButton * togglebutton,gpointer user_data)398 on_toggle_set_custom_title (GtkToggleButton *togglebutton, gpointer user_data) {
399     gboolean active = gtk_toggle_button_get_active (togglebutton);
400     deadbeef->conf_set_int ("gtkui.location_set_custom_title", active);
401 
402     GtkWidget *ct = lookup_widget (GTK_WIDGET (user_data), "custom_title");
403     gtk_widget_set_sensitive (ct, active);
404 
405     deadbeef->conf_save ();
406 }
407 
408 gboolean
action_add_location_handler_cb(void * user_data)409 action_add_location_handler_cb (void *user_data) {
410     GtkWidget *dlg = create_addlocationdlg ();
411 
412     GtkWidget *sct = lookup_widget (dlg, "set_custom_title");
413     GtkWidget *ct = lookup_widget (dlg, "custom_title");
414 
415 #ifndef DISABLE_CUSTOM_TITLE
416     if (deadbeef->conf_get_int ("gtkui.location_set_custom_title", 0)) {
417         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (sct), TRUE);
418         gtk_widget_set_sensitive (ct, TRUE);
419     }
420     else
421 #endif
422     {
423         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (sct), FALSE);
424         gtk_widget_set_sensitive (ct, FALSE);
425     }
426 
427 #ifndef DISABLE_CUSTOM_TITLE
428     g_signal_connect ((gpointer) sct, "toggled",
429             G_CALLBACK (on_toggle_set_custom_title),
430             dlg);
431 #endif
432 
433     gtk_dialog_set_default_response (GTK_DIALOG (dlg), GTK_RESPONSE_OK);
434     int res = gtk_dialog_run (GTK_DIALOG (dlg));
435     if (res == GTK_RESPONSE_OK) {
436         GtkEntry *entry = GTK_ENTRY (lookup_widget (dlg, "addlocation_entry"));
437         if (entry) {
438             const char *text = gtk_entry_get_text (entry);
439             if (text) {
440                 ddb_playlist_t *plt = deadbeef->plt_get_curr ();
441                 if (!deadbeef->plt_add_files_begin (plt, 0)) {
442                     DB_playItem_t *tail = deadbeef->plt_get_last (plt, PL_MAIN);
443                     DB_playItem_t *it = deadbeef->plt_insert_file2 (0, plt, tail, text, NULL, NULL, NULL);
444 #ifndef DISABLE_CUSTOM_TITLE
445                     if (it && deadbeef->conf_get_int ("gtkui.location_set_custom_title", 0)) {
446                         deadbeef->pl_replace_meta (it, ":CUSTOM_TITLE", gtk_entry_get_text (GTK_ENTRY (ct)));
447                     }
448 #endif
449                     if (tail) {
450                         deadbeef->pl_item_unref (tail);
451                     }
452                     deadbeef->plt_add_files_end (plt, 0);
453                     playlist_refresh ();
454                 }
455                 if (plt) {
456                     deadbeef->plt_unref (plt);
457                 }
458             }
459         }
460     }
461     gtk_widget_destroy (dlg);
462     return FALSE;
463 }
464 
465 int
action_add_location_handler(DB_plugin_action_t * act,int ctx)466 action_add_location_handler (DB_plugin_action_t *act, int ctx) {
467     gdk_threads_add_idle (action_add_location_handler_cb, NULL);
468     return 0;
469 }
470 
471 static GtkWidget *helpwindow;
472 
473 gboolean
action_show_help_handler_cb(void * user_data)474 action_show_help_handler_cb (void *user_data) {
475     char fname[PATH_MAX];
476     snprintf (fname, sizeof (fname), "%s/%s", deadbeef->get_doc_dir (), _("help.txt"));
477     gtkui_show_info_window (fname, _("Help"), &helpwindow);
478     return FALSE;
479 }
480 
481 int
action_show_help_handler(DB_plugin_action_t * act,int ctx)482 action_show_help_handler (DB_plugin_action_t *act, int ctx) {
483     gdk_threads_add_idle (action_show_help_handler_cb, NULL);
484     return 0;
485 }
486 
487 int
action_remove_from_playlist_handler(DB_plugin_action_t * act,int ctx)488 action_remove_from_playlist_handler (DB_plugin_action_t *act, int ctx) {
489     if (ctx == DDB_ACTION_CTX_SELECTION) {
490         ddb_playlist_t *plt = deadbeef->plt_get_curr ();
491         if (plt) {
492             int cursor = deadbeef->plt_delete_selected (plt);
493             if (cursor != -1) {
494                 DB_playItem_t *it = deadbeef->plt_get_item_for_idx (plt, cursor, PL_MAIN);
495                 if (it) {
496                     deadbeef->pl_set_selected (it, 1);
497                     deadbeef->pl_item_unref (it);
498                 }
499             }
500             deadbeef->plt_save_config (plt);
501             deadbeef->plt_unref (plt);
502             deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, DDB_PLAYLIST_CHANGE_CONTENT, 0);
503         }
504     }
505     else if (ctx == DDB_ACTION_CTX_PLAYLIST) {
506         ddb_playlist_t *plt_curr = deadbeef->plt_get_curr ();
507         ddb_playlist_t *plt = deadbeef->action_get_playlist ();
508         deadbeef->plt_clear (plt);
509         deadbeef->plt_save_config (plt);
510         if (plt == plt_curr) {
511             deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, DDB_PLAYLIST_CHANGE_CONTENT, 0);
512         }
513         deadbeef->plt_unref (plt);
514         deadbeef->plt_unref (plt_curr);
515     }
516     else if (ctx == DDB_ACTION_CTX_NOWPLAYING) {
517         int success = 0;
518         deadbeef->pl_lock ();
519         DB_playItem_t *it = deadbeef->streamer_get_playing_track ();
520         if (it) {
521             ddb_playlist_t *plt = deadbeef->plt_get_curr ();
522             if (plt) {
523                 int idx = deadbeef->plt_get_item_idx (plt, it, PL_MAIN);
524                 if (idx != -1) {
525                     deadbeef->plt_remove_item (plt, it);
526                     deadbeef->pl_save_current ();
527                     deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, DDB_PLAYLIST_CHANGE_CONTENT, 0);
528                 }
529                 deadbeef->plt_unref (plt);
530             }
531             deadbeef->pl_item_unref (it);
532         }
533         deadbeef->pl_unlock ();
534     }
535     return 0;
536 }
537 
538 void
delete_and_remove_track(const char * uri,ddb_playlist_t * plt,ddb_playItem_t * it)539 delete_and_remove_track (const char *uri, ddb_playlist_t *plt, ddb_playItem_t *it) {
540     int res = unlink (uri);
541 
542     // check if file exists
543     struct stat buf;
544     memset (&buf, 0, sizeof (buf));
545     int stat_res = stat (uri, &buf);
546     if (stat_res != 0) {
547         deadbeef->plt_remove_item (plt, it);
548     }
549 }
550 
551 gboolean
action_delete_from_disk_handler_cb(void * data)552 action_delete_from_disk_handler_cb (void *data) {
553     int ctx = (intptr_t)data;
554     if (deadbeef->conf_get_int ("gtkui.delete_files_ask", 1)) {
555         GtkWidget *dlg = gtk_message_dialog_new (GTK_WINDOW (mainwin), GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_YES_NO, _("Delete files from disk"));
556         gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dlg), _("Files will be lost. Proceed?\n(This dialog can be turned off in GTKUI plugin settings)"));
557         gtk_window_set_title (GTK_WINDOW (dlg), _("Warning"));
558 
559         int response = gtk_dialog_run (GTK_DIALOG (dlg));
560         gtk_widget_destroy (dlg);
561         if (response != GTK_RESPONSE_YES) {
562             return FALSE;
563         }
564     }
565 
566     ddb_playlist_t *plt = deadbeef->plt_get_curr ();
567     if (!plt) {
568         return FALSE;
569     }
570     deadbeef->pl_lock ();
571 
572     if (ctx == DDB_ACTION_CTX_SELECTION) {
573         DB_playItem_t *it = deadbeef->plt_get_first (plt, PL_MAIN);
574         while (it) {
575             const char *uri = deadbeef->pl_find_meta (it, ":URI");
576             if (deadbeef->pl_is_selected (it) && deadbeef->is_local_file (uri)) {
577                 delete_and_remove_track (uri, plt, it);
578             }
579             DB_playItem_t *next = deadbeef->pl_get_next (it, PL_MAIN);
580             deadbeef->pl_item_unref (it);
581             it = next;
582         }
583 
584         deadbeef->pl_save_current ();
585     }
586     else if (ctx == DDB_ACTION_CTX_PLAYLIST) {
587         DB_playItem_t *it = deadbeef->plt_get_first (plt, PL_MAIN);
588         while (it) {
589             const char *uri = deadbeef->pl_find_meta (it, ":URI");
590             if (deadbeef->is_local_file (uri)) {
591                 delete_and_remove_track (uri, plt, it);
592 // FIXME: this dialog should allow something like "cancel" and "ignore all", then
593 // it will be usable
594 //                else {
595 //                    GtkWidget *dlg = gtk_message_dialog_new (GTK_WINDOW (mainwin), GTK_DIALOG_MODAL, GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, _("Can't delete the file. Perhaps it doesn't exist, read-only, or part of read-only VFS, or all of the above."));
596 //                    gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dlg), uri);
597 //                    gtk_window_set_title (GTK_WINDOW (dlg), _("Warning"));
598 //
599 //                    int response = gtk_dialog_run (GTK_DIALOG (dlg));
600 //                    gtk_widget_destroy (dlg);
601 //                }
602             }
603             DB_playItem_t *next = deadbeef->pl_get_next (it, PL_MAIN);
604             deadbeef->pl_item_unref (it);
605             it = next;
606         }
607 
608         deadbeef->pl_save_current ();
609     }
610     else if (ctx == DDB_ACTION_CTX_NOWPLAYING) {
611         DB_playItem_t *it = deadbeef->streamer_get_playing_track ();
612         if (it) {
613             const char *uri = deadbeef->pl_find_meta (it, ":URI");
614             if (deadbeef->is_local_file (uri)) {
615                 int idx = deadbeef->plt_get_item_idx (plt, it, PL_MAIN);
616                 if (idx != -1) {
617                     delete_and_remove_track (uri, plt, it);
618                 }
619             }
620             deadbeef->pl_item_unref (it);
621         }
622     }
623     deadbeef->pl_unlock ();
624     deadbeef->plt_unref (plt);
625 
626     deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, DDB_PLAYLIST_CHANGE_CONTENT, 0);
627     return FALSE;
628 }
629 
630 int
action_delete_from_disk_handler(DB_plugin_action_t * act,int ctx)631 action_delete_from_disk_handler (DB_plugin_action_t *act, int ctx) {
632     gdk_threads_add_idle (action_delete_from_disk_handler_cb, (void *)(intptr_t)ctx);
633     return 0;
634 }
635 
636 typedef struct {
637     int ctx;
638     ddb_playlist_t *plt;
639 } trkproperties_action_ctx_t;
640 
641 gboolean
action_show_track_properties_handler_cb(void * data)642 action_show_track_properties_handler_cb (void *data) {
643     trkproperties_action_ctx_t *ctx = data;
644     show_track_properties_dlg (ctx->ctx, ctx->plt);
645     deadbeef->plt_unref (ctx->plt);
646     free (data);
647     return FALSE;
648 }
649 
650 int
action_show_track_properties_handler(DB_plugin_action_t * act,int ctx)651 action_show_track_properties_handler (DB_plugin_action_t *act, int ctx) {
652     trkproperties_action_ctx_t *data = calloc (1, sizeof (trkproperties_action_ctx_t));
653     data->ctx = ctx;
654     data->plt = deadbeef->action_get_playlist ();
655     gdk_threads_add_idle (action_show_track_properties_handler_cb, data);
656     return 0;
657 }
658 
659 gboolean
action_find_handler_cb(void * data)660 action_find_handler_cb (void *data) {
661     search_start ();
662     return FALSE;
663 }
664 
665 int
action_find_handler(DB_plugin_action_t * act,int ctx)666 action_find_handler (DB_plugin_action_t *act, int ctx) {
667     gdk_threads_add_idle (action_find_handler_cb, NULL);
668     return 0;
669 }
670 
671 gboolean
action_scroll_follows_playback_handler_cb(void * data)672 action_scroll_follows_playback_handler_cb (void *data) {
673     int val = 1 - deadbeef->conf_get_int ("playlist.scroll.followplayback", 1);
674     deadbeef->conf_set_int ("playlist.scroll.followplayback", val);
675     gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (lookup_widget (mainwin, "scroll_follows_playback")), val);
676     return FALSE;
677 }
678 
679 int
action_scroll_follows_playback_handler(DB_plugin_action_t * act,int ctx)680 action_scroll_follows_playback_handler (DB_plugin_action_t *act, int ctx) {
681     g_idle_add (action_scroll_follows_playback_handler_cb, NULL);
682     return 0;
683 }
684 
685 gboolean
action_cursor_follows_playback_handler_cb(void * data)686 action_cursor_follows_playback_handler_cb (void *data) {
687     int val = 1 - deadbeef->conf_get_int ("playlist.scroll.cursorfollowplayback", 1);
688     deadbeef->conf_set_int ("playlist.scroll.cursorfollowplayback", val);
689     gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (lookup_widget (mainwin, "cursor_follows_playback")), val);
690     return FALSE;
691 }
692 
693 int
action_cursor_follows_playback_handler(DB_plugin_action_t * act,int ctx)694 action_cursor_follows_playback_handler (DB_plugin_action_t *act, int ctx) {
695     g_idle_add (action_cursor_follows_playback_handler_cb, NULL);
696     return 0;
697 }
698 
699 static gboolean
playlist_filter_func(const GtkFileFilterInfo * filter_info,gpointer data)700 playlist_filter_func (const GtkFileFilterInfo *filter_info, gpointer data) {
701     // get ext
702     const char *p = strrchr (filter_info->filename, '.');
703     if (!p) {
704         return FALSE;
705     }
706     p++;
707     DB_playlist_t **plug = deadbeef->plug_get_playlist_list ();
708     for (int i = 0; plug[i]; i++) {
709         if (plug[i]->extensions && plug[i]->load) {
710             const char **exts = plug[i]->extensions;
711             if (exts) {
712                 for (int e = 0; exts[e]; e++) {
713                     if (!strcasecmp (exts[e], p)) {
714                         return TRUE;
715                     }
716                 }
717             }
718         }
719     }
720     return FALSE;
721 }
722 
723 static void
load_playlist_thread(void * data)724 load_playlist_thread (void *data) {
725     char *fname = data;
726     ddb_playlist_t *plt = deadbeef->plt_get_curr ();
727     if (plt) {
728         if (!deadbeef->plt_add_files_begin (plt, 0)) {
729             deadbeef->plt_clear (plt);
730             int abort = 0;
731             DB_playItem_t *it = deadbeef->plt_load2 (0, plt, NULL, fname, &abort, NULL, NULL);
732             deadbeef->plt_save_config (plt);
733             deadbeef->plt_add_files_end (plt, 0);
734         }
735         deadbeef->plt_unref (plt);
736     }
737     g_free (fname);
738     deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, DDB_PLAYLIST_CHANGE_CONTENT, 0);
739 }
740 
741 
742 gboolean
action_load_playlist_handler_cb(void * data)743 action_load_playlist_handler_cb (void *data) {
744     GtkWidget *dlg = gtk_file_chooser_dialog_new (_("Load Playlist"), GTK_WINDOW (mainwin), GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_OK, NULL);
745 
746     // restore folder
747     deadbeef->conf_lock ();
748     gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dlg), deadbeef->conf_get_str_fast ("filechooser.playlist.lastdir", ""));
749     deadbeef->conf_unlock ();
750 
751     GtkFileFilter* flt;
752     flt = gtk_file_filter_new ();
753     gtk_file_filter_set_name (flt, "Supported playlist formats");
754     gtk_file_filter_add_custom (flt, GTK_FILE_FILTER_FILENAME, playlist_filter_func, NULL, NULL);
755     gtk_file_filter_add_pattern (flt, "*.dbpl");
756     gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dlg), flt);
757     gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (dlg), flt);
758     flt = gtk_file_filter_new ();
759     gtk_file_filter_set_name (flt, _("Other files (*)"));
760     gtk_file_filter_add_pattern (flt, "*");
761     gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dlg), flt);
762 
763     int res = gtk_dialog_run (GTK_DIALOG (dlg));
764     // store folder
765     gchar *folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dlg));
766     if (folder) {
767         deadbeef->conf_set_str ("filechooser.playlist.lastdir", folder);
768         g_free (folder);
769     }
770     if (res == GTK_RESPONSE_OK)
771     {
772         gchar *fname = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dlg));
773         gtk_widget_destroy (dlg);
774         if (fname) {
775             uintptr_t tid = deadbeef->thread_start (load_playlist_thread, fname);
776             deadbeef->thread_detach (tid);
777         }
778     }
779     else {
780         gtk_widget_destroy (dlg);
781     }
782     return FALSE;
783 }
784 
785 int
action_load_playlist_handler(DB_plugin_action_t * act,int ctx)786 action_load_playlist_handler (DB_plugin_action_t *act, int ctx) {
787     gdk_threads_add_idle (action_load_playlist_handler_cb, NULL);
788     return 0;
789 }
790 
791 gboolean
action_save_playlist_handler_cb(void * data)792 action_save_playlist_handler_cb (void *data) {
793     GtkWidget *dlg = gtk_file_chooser_dialog_new (_("Save Playlist As"), GTK_WINDOW (mainwin), GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_OK, NULL);
794 
795     gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dlg), TRUE);
796     gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dlg), "untitled.dbpl");
797     // restore folder
798     deadbeef->conf_lock ();
799     gtk_file_chooser_set_current_folder_uri (GTK_FILE_CHOOSER (dlg), deadbeef->conf_get_str_fast ("filechooser.playlist.lastdir", ""));
800     deadbeef->conf_unlock ();
801 
802     GtkFileFilter* flt;
803     flt = gtk_file_filter_new ();
804     gtk_file_filter_set_name (flt, _("DeaDBeeF playlist files (*.dbpl)"));
805     gtk_file_filter_add_pattern (flt, "*.dbpl");
806     gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dlg), flt);
807     DB_playlist_t **plug = deadbeef->plug_get_playlist_list ();
808     for (int i = 0; plug[i]; i++) {
809         if (plug[i]->extensions && plug[i]->load) {
810             const char **exts = plug[i]->extensions;
811             if (exts && plug[i]->save) {
812                 for (int e = 0; exts[e]; e++) {
813                     char s[100];
814                     flt = gtk_file_filter_new ();
815                     gtk_file_filter_set_name (flt, exts[e]);
816                     snprintf (s, sizeof (s), "*.%s", exts[e]);
817                     gtk_file_filter_add_pattern (flt, s);
818                     gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dlg), flt);
819                 }
820             }
821         }
822     }
823 
824     int res = gtk_dialog_run (GTK_DIALOG (dlg));
825     // store folder
826     gchar *folder = gtk_file_chooser_get_current_folder_uri (GTK_FILE_CHOOSER (dlg));
827     if (folder) {
828         deadbeef->conf_set_str ("filechooser.playlist.lastdir", folder);
829         g_free (folder);
830     }
831     if (res == GTK_RESPONSE_OK)
832     {
833         gchar *fname = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dlg));
834         gtk_widget_destroy (dlg);
835 
836         if (fname) {
837             ddb_playlist_t *plt = deadbeef->plt_get_curr ();
838             if (plt) {
839                 int res = deadbeef->plt_save (plt, NULL, NULL, fname, NULL, NULL, NULL);
840                 if (res >= 0 && strlen (fname) < 1024) {
841                     deadbeef->conf_set_str ("gtkui.last_playlist_save_name", fname);
842                 }
843                 deadbeef->plt_unref (plt);
844             }
845             g_free (fname);
846         }
847     }
848     else {
849         gtk_widget_destroy (dlg);
850     }
851     return FALSE;
852 }
853 
854 int
action_save_playlist_handler(DB_plugin_action_t * act,int ctx)855 action_save_playlist_handler (DB_plugin_action_t *act, int ctx) {
856     gdk_threads_add_idle (action_save_playlist_handler_cb, NULL);
857     return 0;
858 }
859 
860 gboolean
action_toggle_menu_handler_cb(void * data)861 action_toggle_menu_handler_cb (void *data) {
862     GtkWidget *menu = lookup_widget (mainwin, "menubar");
863     int val = 1-deadbeef->conf_get_int ("gtkui.show_menu", 1);
864     val ? gtk_widget_show (menu) : gtk_widget_hide (menu);
865     deadbeef->conf_set_int ("gtkui.show_menu", val);
866     return FALSE;
867 }
868 
869 int
action_toggle_menu_handler(DB_plugin_action_t * act,int ctx)870 action_toggle_menu_handler (DB_plugin_action_t *act, int ctx) {
871     g_idle_add (action_toggle_menu_handler_cb, NULL);
872     return 0;
873 }
874 
875 gboolean
action_toggle_statusbar_handler_cb(void * data)876 action_toggle_statusbar_handler_cb (void *data) {
877     GtkWidget *sb = lookup_widget (mainwin, "statusbar");
878     if (sb) {
879         int val = 1 - deadbeef->conf_get_int ("gtkui.statusbar.visible", 1);
880         deadbeef->conf_set_int ("gtkui.statusbar.visible", val);
881         gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (lookup_widget (mainwin, "view_status_bar")), val);
882         val ? gtk_widget_show (sb) : gtk_widget_hide (sb);
883         deadbeef->conf_save ();
884     }
885     return FALSE;
886 }
887 
888 int
action_toggle_statusbar_handler(DB_plugin_action_t * act,int ctx)889 action_toggle_statusbar_handler (DB_plugin_action_t *act, int ctx) {
890     g_idle_add (action_toggle_statusbar_handler_cb, NULL);
891     return 0;
892 }
893 
894 gboolean
action_toggle_designmode_handler_cb(void * data)895 action_toggle_designmode_handler_cb (void *data) {
896     GtkWidget *menuitem = lookup_widget (mainwin, "design_mode1");
897     gboolean act = gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menuitem));
898     act = !act;
899     gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menuitem), act);
900     return FALSE;
901 }
902 
903 int
action_toggle_designmode_handler(DB_plugin_action_t * act,int ctx)904 action_toggle_designmode_handler (DB_plugin_action_t *act, int ctx) {
905     g_idle_add (action_toggle_designmode_handler_cb, NULL);
906     return 0;
907 }
908 
909 gboolean
action_preferences_handler_cb(void * data)910 action_preferences_handler_cb (void *data) {
911     gtkui_run_preferences_dlg ();
912     return FALSE;
913 }
914 
915 int
action_preferences_handler(DB_plugin_action_t * act,int ctx)916 action_preferences_handler (DB_plugin_action_t *act, int ctx) {
917     gdk_threads_add_idle (action_preferences_handler_cb, NULL);
918     return 0;
919 }
920 
921 gboolean
action_sort_custom_handler_cb(void * data)922 action_sort_custom_handler_cb (void *data) {
923     GtkWidget *dlg = create_sortbydlg ();
924     gtk_dialog_set_default_response (GTK_DIALOG (dlg), GTK_RESPONSE_OK);
925 
926     GtkComboBox *combo = GTK_COMBO_BOX (lookup_widget (dlg, "sortorder"));
927     GtkEntry *entry = GTK_ENTRY (lookup_widget (dlg, "sortfmt"));
928 
929     gtk_combo_box_set_active (combo, deadbeef->conf_get_int ("gtkui.sortby_order", 0));
930     deadbeef->conf_lock ();
931     gtk_entry_set_text (entry, deadbeef->conf_get_str_fast ("gtkui.sortby_fmt_v2", ""));
932     deadbeef->conf_unlock ();
933 
934     int r = gtk_dialog_run (GTK_DIALOG (dlg));
935 
936     if (r == GTK_RESPONSE_OK) {
937         GtkComboBox *combo = GTK_COMBO_BOX (lookup_widget (dlg, "sortorder"));
938         GtkEntry *entry = GTK_ENTRY (lookup_widget (dlg, "sortfmt"));
939         int order = gtk_combo_box_get_active (combo);
940         const char *fmt = gtk_entry_get_text (entry);
941 
942         deadbeef->conf_set_int ("gtkui.sortby_order", order);
943         deadbeef->conf_set_str ("gtkui.sortby_fmt_v2", fmt);
944 
945         ddb_playlist_t *plt = deadbeef->plt_get_curr ();
946         deadbeef->plt_sort_v2 (plt, PL_MAIN, -1, fmt, order == 0 ? DDB_SORT_ASCENDING : DDB_SORT_DESCENDING);
947         deadbeef->plt_save_config (plt);
948         deadbeef->plt_unref (plt);
949 
950         deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, DDB_PLAYLIST_CHANGE_CONTENT, 0);
951     }
952 
953     gtk_widget_destroy (dlg);
954     dlg = NULL;
955     return FALSE;
956 }
957 
958 int
action_sort_custom_handler(DB_plugin_action_t * act,int ctx)959 action_sort_custom_handler (DB_plugin_action_t *act, int ctx) {
960     gdk_threads_add_idle (action_sort_custom_handler_cb, NULL);
961     return 0;
962 }
963 
964 int
action_crop_selected_handler(DB_plugin_action_t * act,int ctx)965 action_crop_selected_handler (DB_plugin_action_t *act, int ctx) {
966     deadbeef->pl_crop_selected ();
967     deadbeef->pl_save_current ();
968     deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, DDB_PLAYLIST_CHANGE_CONTENT, 0);
969     return 0;
970 }
971 
972 gboolean
action_toggle_eq_handler_cb(void * data)973 action_toggle_eq_handler_cb (void *data) {
974     GtkWidget *menuitem = lookup_widget (mainwin, "view_eq");
975     gboolean act = gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menuitem));
976     act = !act;
977     gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menuitem), act);
978     return FALSE;
979 }
980 
981 int
action_toggle_eq_handler(DB_plugin_action_t * act,int ctx)982 action_toggle_eq_handler (DB_plugin_action_t *act, int ctx) {
983     g_idle_add (action_toggle_eq_handler_cb, NULL);
984     return 0;
985 }
986 
987 gboolean
action_show_eq_handler_cb(void * data)988 action_show_eq_handler_cb (void *data) {
989     GtkWidget *menuitem = lookup_widget (mainwin, "view_eq");
990     gboolean act = gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menuitem));
991     if (!act) {
992         gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menuitem), 1);
993     }
994     return FALSE;
995 }
996 
997 int
action_show_eq_handler(DB_plugin_action_t * act,int ctx)998 action_show_eq_handler(DB_plugin_action_t *act, int ctx) {
999     g_idle_add (action_show_eq_handler_cb, NULL);
1000     return 0;
1001 }
1002 
1003 gboolean
action_hide_eq_handler_cb(void * data)1004 action_hide_eq_handler_cb (void *data) {
1005     GtkWidget *menuitem = lookup_widget (mainwin, "view_eq");
1006     gboolean act = gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menuitem));
1007     if (act) {
1008         gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (menuitem), 0);
1009     }
1010     return FALSE;
1011 }
1012 
1013 int
action_hide_eq_handler(DB_plugin_action_t * act,int ctx)1014 action_hide_eq_handler(DB_plugin_action_t *act, int ctx) {
1015     g_idle_add (action_hide_eq_handler_cb, NULL);
1016     return 0;
1017 }
1018 
1019 gboolean
action_playback_loop_off_handler_cb(void * data)1020 action_playback_loop_off_handler_cb (void *data) {
1021     gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (lookup_widget (mainwin, "loop_disable")), 1);
1022     return FALSE;
1023 }
1024 
1025 int
action_playback_loop_off_handler(DB_plugin_action_t * act,int ctx)1026 action_playback_loop_off_handler(DB_plugin_action_t *act, int ctx) {
1027     g_idle_add (action_playback_loop_off_handler_cb, NULL);
1028     return 0;
1029 }
1030 
1031 gboolean
action_playback_loop_single_handler_cb(void * data)1032 action_playback_loop_single_handler_cb (void *data) {
1033     gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (lookup_widget (mainwin, "loop_single")), 1);
1034     return FALSE;
1035 }
1036 
1037 int
action_playback_loop_single_handler(DB_plugin_action_t * act,int ctx)1038 action_playback_loop_single_handler(DB_plugin_action_t *act, int ctx) {
1039     g_idle_add (action_playback_loop_single_handler_cb, NULL);
1040     return 0;
1041 }
1042 
1043 gboolean
action_playback_loop_all_handler_cb(void * data)1044 action_playback_loop_all_handler_cb (void *data) {
1045     gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (lookup_widget (mainwin, "loop_all")), 1);
1046     return FALSE;
1047 }
1048 
1049 int
action_playback_loop_all_handler(DB_plugin_action_t * act,int ctx)1050 action_playback_loop_all_handler(DB_plugin_action_t *act, int ctx) {
1051     g_idle_add (action_playback_loop_all_handler_cb, NULL);
1052     return 0;
1053 }
1054 
1055 gboolean
action_playback_order_random_handler_cb(void * data)1056 action_playback_order_random_handler_cb (void *data) {
1057     gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (lookup_widget (mainwin, "order_random")), 1);
1058     return FALSE;
1059 }
1060 
1061 int
action_playback_order_random_handler(DB_plugin_action_t * act,int ctx)1062 action_playback_order_random_handler(DB_plugin_action_t *act, int ctx) {
1063     g_idle_add (action_playback_order_random_handler_cb, NULL);
1064     return 0;
1065 }
1066 
1067 gboolean
action_playback_order_shuffle_albums_handler_cb(void * data)1068 action_playback_order_shuffle_albums_handler_cb (void *data) {
1069     gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (lookup_widget (mainwin, "order_shuffle_albums")), 1);
1070     return FALSE;
1071 }
1072 
1073 int
action_playback_order_shuffle_albums_handler(DB_plugin_action_t * act,int ctx)1074 action_playback_order_shuffle_albums_handler(DB_plugin_action_t *act, int ctx) {
1075     g_idle_add (action_playback_order_shuffle_albums_handler_cb, NULL);
1076     return 0;
1077 }
1078 
1079 gboolean
action_playback_order_shuffle_handler_cb(void * data)1080 action_playback_order_shuffle_handler_cb (void *data) {
1081     gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (lookup_widget (mainwin, "order_shuffle")), 1);
1082     return FALSE;
1083 }
1084 
1085 int
action_playback_order_shuffle_handler(DB_plugin_action_t * act,int ctx)1086 action_playback_order_shuffle_handler(DB_plugin_action_t *act, int ctx) {
1087     g_idle_add (action_playback_order_shuffle_handler_cb, NULL);
1088     return 0;
1089 }
1090 
1091 gboolean
action_playback_order_linear_handler_cb(void * data)1092 action_playback_order_linear_handler_cb (void *data) {
1093     gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (lookup_widget (mainwin, "order_linear")), 1);
1094     return FALSE;
1095 }
1096 
1097 int
action_playback_order_linear_handler(DB_plugin_action_t * act,int ctx)1098 action_playback_order_linear_handler(DB_plugin_action_t *act, int ctx) {
1099     g_idle_add (action_playback_order_linear_handler_cb, NULL);
1100     return 0;
1101 }
1102 
1103 gboolean
action_playback_order_cycle_handler_cb(void * data)1104 action_playback_order_cycle_handler_cb (void *data) {
1105     int ord = deadbeef->conf_get_int ("playback.order", PLAYBACK_ORDER_LINEAR);
1106     switch (ord) {
1107     case PLAYBACK_ORDER_LINEAR:
1108         gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (lookup_widget (mainwin, "order_shuffle")), 1);
1109         break;
1110     case PLAYBACK_ORDER_SHUFFLE_TRACKS:
1111         gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (lookup_widget (mainwin, "order_shuffle_albums")), 1);
1112         break;
1113     case PLAYBACK_ORDER_SHUFFLE_ALBUMS:
1114         gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (lookup_widget (mainwin, "order_random")), 1);
1115         break;
1116     case PLAYBACK_ORDER_RANDOM:
1117         gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (lookup_widget (mainwin, "order_linear")), 1);
1118         break;
1119     }
1120     return FALSE;
1121 }
1122 
1123 int
action_playback_order_cycle_handler(DB_plugin_action_t * act,int ctx)1124 action_playback_order_cycle_handler(DB_plugin_action_t *act, int ctx) {
1125     g_idle_add (action_playback_order_cycle_handler_cb, NULL);
1126     return 0;
1127 }
1128 
1129 gboolean
action_playback_loop_cycle_handler_cb(void * data)1130 action_playback_loop_cycle_handler_cb (void *data) {
1131     int ord = deadbeef->conf_get_int ("playback.loop", PLAYBACK_MODE_LOOP_ALL);
1132     switch (ord) {
1133     case PLAYBACK_MODE_LOOP_ALL:
1134         gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (lookup_widget (mainwin, "loop_single")), 1);
1135         break;
1136     case PLAYBACK_MODE_LOOP_SINGLE:
1137         gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (lookup_widget (mainwin, "loop_disable")), 1);
1138         break;
1139     case PLAYBACK_MODE_NOLOOP:
1140         gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (lookup_widget (mainwin, "loop_all")), 1);
1141         break;
1142     }
1143     return FALSE;
1144 }
1145 
1146 int
action_playback_loop_cycle_handler(DB_plugin_action_t * act,int ctx)1147 action_playback_loop_cycle_handler(DB_plugin_action_t *act, int ctx) {
1148     g_idle_add (action_playback_loop_cycle_handler_cb, NULL);
1149     return 0;
1150 }
1151