1 /*
2     DeaDBeeF -- the music player
3     Copyright (C) 2009-2015 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 
24 #ifdef HAVE_CONFIG_H
25 #  include <config.h>
26 #endif
27 
28 #include <gtk/gtk.h>
29 #include <math.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33 #include <assert.h>
34 #include <ctype.h>
35 #include <gdk/gdkkeysyms.h>
36 #ifndef __APPLE__
37 #include <X11/Xlib.h>
38 #endif
39 #include "../../gettext.h"
40 
41 #include "callbacks.h"
42 #include "interface.h"
43 #include "support.h"
44 
45 #include "ddblistview.h"
46 #include "ddbtabstrip.h"
47 #include "ddbvolumebar.h"
48 #include "ddbseekbar.h"
49 #include "search.h"
50 #include "progress.h"
51 #include "gtkui.h"
52 #include "../libparser/parser.h"
53 #include "drawing.h"
54 #include "eq.h"
55 #include "wingeom.h"
56 #include "widgets.h"
57 #include "../hotkeys/hotkeys.h"
58 #include "actionhandlers.h"
59 #include "actions.h"
60 
61 //#define trace(...) { fprintf (stderr, __VA_ARGS__); }
62 #define trace(fmt,...)
63 
64 #define SELECTED(it) (deadbeef->pl_is_selected(it))
65 #define SELECT(it, sel) (deadbeef->pl_set_selected(it,sel))
66 #define VSELECT(it, sel) {deadbeef->pl_set_selected(it,sel);gtk_pl_redraw_item_everywhere (it);}
67 #define PL_NEXT(it, iter) (deadbeef->pl_get_next(it, iter))
68 
69 DdbListview *last_playlist;
70 extern DB_functions_t *deadbeef; // defined in gtkui.c
71 
72 
73 void
on_open_activate(GtkMenuItem * menuitem,gpointer user_data)74 on_open_activate                       (GtkMenuItem     *menuitem,
75                                         gpointer         user_data)
76 {
77     gdk_threads_add_idle (action_open_files_handler_cb, NULL);
78 }
79 
80 
81 void
on_add_files_activate(GtkMenuItem * menuitem,gpointer user_data)82 on_add_files_activate                  (GtkMenuItem     *menuitem,
83                                         gpointer         user_data)
84 {
85     gdk_threads_add_idle (action_add_files_handler_cb, NULL);
86 }
87 
88 void
on_add_folders_activate(GtkMenuItem * menuitem,gpointer user_data)89 on_add_folders_activate                (GtkMenuItem     *menuitem,
90                                         gpointer         user_data)
91 {
92     gdk_threads_add_idle (action_add_folders_handler_cb, NULL);
93 }
94 
95 
96 void
on_quit_activate(GtkMenuItem * menuitem,gpointer user_data)97 on_quit_activate                      (GtkMenuItem     *menuitem,
98                                         gpointer         user_data)
99 {
100     gdk_threads_add_idle (action_quit_handler_cb, NULL);
101 }
102 
103 
104 
105 void
on_select_all1_activate(GtkMenuItem * menuitem,gpointer user_data)106 on_select_all1_activate                (GtkMenuItem     *menuitem,
107                                         gpointer         user_data)
108 {
109     gdk_threads_add_idle (action_select_all_handler_cb, NULL);
110 }
111 
112 
113 
114 
115 
116 void
on_stopbtn_clicked(GtkButton * button,gpointer user_data)117 on_stopbtn_clicked                     (GtkButton       *button,
118                                         gpointer         user_data)
119 {
120     deadbeef->sendmessage (DB_EV_STOP, 0, 0, 0);
121 }
122 
123 
124 void
on_playbtn_clicked(GtkButton * button,gpointer user_data)125 on_playbtn_clicked                     (GtkButton       *button,
126                                         gpointer         user_data)
127 {
128     // NOTE: this function is a copy of action_play_cb
129     DB_output_t *output = deadbeef->get_output ();
130     if (output->state () == OUTPUT_STATE_PAUSED) {
131         ddb_playlist_t *plt = deadbeef->plt_get_curr ();
132         int cur = deadbeef->plt_get_cursor (plt, PL_MAIN);
133         if (cur != -1) {
134             ddb_playItem_t *it = deadbeef->plt_get_item_for_idx (plt, cur, PL_MAIN);
135             ddb_playItem_t *it_playing = deadbeef->streamer_get_playing_track ();
136 
137             if (it) {
138                 deadbeef->pl_item_unref (it);
139             }
140             if (it_playing) {
141                 deadbeef->pl_item_unref (it_playing);
142             }
143             if (it != it_playing) {
144                 deadbeef->sendmessage (DB_EV_PLAY_NUM, 0, cur, 0);
145             }
146             else {
147                 deadbeef->sendmessage (DB_EV_PLAY_CURRENT, 0, 0, 0);
148             }
149         }
150         else {
151             deadbeef->sendmessage (DB_EV_PLAY_CURRENT, 0, 0, 0);
152         }
153         deadbeef->plt_unref (plt);
154     }
155     else {
156         ddb_playlist_t *plt = deadbeef->plt_get_curr ();
157         int cur = -1;
158         if (plt) {
159             cur = deadbeef->plt_get_cursor (plt, PL_MAIN);
160             deadbeef->plt_unref (plt);
161         }
162         if (cur == -1) {
163             cur = 0;
164         }
165         deadbeef->sendmessage (DB_EV_PLAY_NUM, 0, cur, 0);
166     }
167 }
168 
169 
170 void
on_pausebtn_clicked(GtkButton * button,gpointer user_data)171 on_pausebtn_clicked                    (GtkButton       *button,
172                                         gpointer         user_data)
173 {
174     deadbeef->sendmessage (DB_EV_TOGGLE_PAUSE, 0, 0, 0);
175 }
176 
177 
178 void
on_prevbtn_clicked(GtkButton * button,gpointer user_data)179 on_prevbtn_clicked                     (GtkButton       *button,
180                                         gpointer         user_data)
181 {
182     deadbeef->sendmessage (DB_EV_PREV, 0, 0, 0);
183 }
184 
185 
186 void
on_nextbtn_clicked(GtkButton * button,gpointer user_data)187 on_nextbtn_clicked                     (GtkButton       *button,
188                                         gpointer         user_data)
189 {
190     deadbeef->sendmessage (DB_EV_NEXT, 0, 0, 0);
191 }
192 
193 
194 void
on_playrand_clicked(GtkButton * button,gpointer user_data)195 on_playrand_clicked                    (GtkButton       *button,
196                                         gpointer         user_data)
197 {
198     deadbeef->sendmessage (DB_EV_PLAY_RANDOM, 0, 0, 0);
199 }
200 
201 gboolean
on_mainwin_key_press_event(GtkWidget * widget,GdkEventKey * event,gpointer user_data)202 on_mainwin_key_press_event             (GtkWidget       *widget,
203                                         GdkEventKey     *event,
204                                         gpointer         user_data)
205 {
206     // local hotkeys
207     GdkModifierType consumed;
208     guint accel_key;
209     gdk_keymap_translate_keyboard_state (gdk_keymap_get_default (), event->hardware_keycode, event->state, 0, &accel_key, NULL, NULL, &consumed);
210     if (accel_key == GDK_ISO_Left_Tab)
211         accel_key = GDK_Tab;
212     int mods = event->state & gtk_accelerator_get_default_mod_mask ();
213     mods &= ~(consumed&~GDK_SHIFT_MASK);
214     int lower = gdk_keyval_to_lower (accel_key);
215     if (lower != accel_key) {
216         accel_key = lower;
217     }
218     trace ("pressed: keycode: %x, mods: %x, hw: %x, translated: %x\n", event->keyval, mods, event->hardware_keycode, accel_key);
219 
220     DB_plugin_t *hkplug = deadbeef->plug_get_for_id ("hotkeys");
221     if (hkplug) {
222         int ctx;
223         DB_plugin_action_t *act = ((DB_hotkeys_plugin_t *)hkplug)->get_action_for_keycombo (accel_key, mods, 0, &ctx);
224         if (act && act->callback2) {
225             trace ("executing action %s in ctx %d\n", act->name, ctx);
226             act->callback2 (act, ctx);
227             return TRUE;
228         }
229         else if (act && act->callback) {
230             gtkui_exec_action_14 (act, -1);
231         }
232     }
233     trace ("action not found\n");
234     return FALSE;
235 }
236 
237 
238 void
on_order_linear_activate(GtkMenuItem * menuitem,gpointer user_data)239 on_order_linear_activate               (GtkMenuItem     *menuitem,
240                                         gpointer         user_data)
241 {
242     deadbeef->conf_set_int ("playback.order", PLAYBACK_ORDER_LINEAR);
243     deadbeef->sendmessage (DB_EV_CONFIGCHANGED, 0, 0, 0);
244 }
245 
246 
247 void
on_order_shuffle_activate(GtkMenuItem * menuitem,gpointer user_data)248 on_order_shuffle_activate              (GtkMenuItem     *menuitem,
249                                         gpointer         user_data)
250 {
251     deadbeef->conf_set_int ("playback.order", PLAYBACK_ORDER_SHUFFLE_TRACKS);
252     deadbeef->sendmessage (DB_EV_CONFIGCHANGED, 0, 0, 0);
253 }
254 
255 void
on_order_shuffle_albums_activate(GtkMenuItem * menuitem,gpointer user_data)256 on_order_shuffle_albums_activate       (GtkMenuItem     *menuitem,
257                                         gpointer         user_data)
258 {
259     deadbeef->conf_set_int ("playback.order", PLAYBACK_ORDER_SHUFFLE_ALBUMS);
260     deadbeef->sendmessage (DB_EV_CONFIGCHANGED, 0, 0, 0);
261 }
262 
263 void
on_order_random_activate(GtkMenuItem * menuitem,gpointer user_data)264 on_order_random_activate               (GtkMenuItem     *menuitem,
265                                         gpointer         user_data)
266 {
267     deadbeef->conf_set_int ("playback.order", PLAYBACK_ORDER_RANDOM);
268     deadbeef->sendmessage (DB_EV_CONFIGCHANGED, 0, 0, 0);
269 }
270 
271 
272 void
on_loop_all_activate(GtkMenuItem * menuitem,gpointer user_data)273 on_loop_all_activate                   (GtkMenuItem     *menuitem,
274                                         gpointer         user_data)
275 {
276     deadbeef->conf_set_int ("playback.loop", 0);
277     deadbeef->sendmessage (DB_EV_CONFIGCHANGED, 0, 0, 0);
278 }
279 
280 
281 void
on_loop_single_activate(GtkMenuItem * menuitem,gpointer user_data)282 on_loop_single_activate                (GtkMenuItem     *menuitem,
283                                         gpointer         user_data)
284 {
285     deadbeef->conf_set_int ("playback.loop", 2);
286     deadbeef->sendmessage (DB_EV_CONFIGCHANGED, 0, 0, 0);
287 }
288 
289 
290 void
on_loop_disable_activate(GtkMenuItem * menuitem,gpointer user_data)291 on_loop_disable_activate               (GtkMenuItem     *menuitem,
292                                         gpointer         user_data)
293 {
294     deadbeef->conf_set_int ("playback.loop", 1);
295     deadbeef->sendmessage (DB_EV_CONFIGCHANGED, 0, 0, 0);
296 }
297 
298 void
on_searchlist_realize(GtkWidget * widget,gpointer user_data)299 on_searchlist_realize                  (GtkWidget       *widget,
300                                         gpointer         user_data)
301 {
302 }
303 
304 gboolean
on_mainwin_delete_event(GtkWidget * widget,GdkEvent * event,gpointer user_data)305 on_mainwin_delete_event                (GtkWidget       *widget,
306                                         GdkEvent        *event,
307                                         gpointer         user_data)
308 {
309     int conf_close_send_to_tray = deadbeef->conf_get_int ("close_send_to_tray", 0);
310     if (conf_close_send_to_tray) {
311         gtk_widget_hide (widget);
312     }
313     else {
314         gtkui_quit ();
315     }
316     return TRUE;
317 }
318 
319 gboolean
on_mainwin_configure_event(GtkWidget * widget,GdkEventConfigure * event,gpointer user_data)320 on_mainwin_configure_event             (GtkWidget       *widget,
321                                         GdkEventConfigure *event,
322                                         gpointer         user_data)
323 {
324     wingeom_save (widget, "mainwin");
325     return FALSE;
326 }
327 
328 
329 void
on_scroll_follows_playback_activate(GtkMenuItem * menuitem,gpointer user_data)330 on_scroll_follows_playback_activate    (GtkMenuItem     *menuitem,
331                                         gpointer         user_data)
332 {
333     deadbeef->conf_set_int ("playlist.scroll.followplayback", gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menuitem)));
334     deadbeef->sendmessage (DB_EV_CONFIGCHANGED, 0, 0, 0);
335 }
336 
337 
338 void
on_find_activate(GtkMenuItem * menuitem,gpointer user_data)339 on_find_activate                       (GtkMenuItem     *menuitem,
340                                         gpointer         user_data)
341 {
342     search_start ();
343 }
344 
345 void
on_help1_activate(GtkMenuItem * menuitem,gpointer user_data)346 on_help1_activate                      (GtkMenuItem     *menuitem,
347                                         gpointer         user_data)
348 {
349     gdk_threads_add_idle (action_show_help_handler_cb, NULL);
350 }
351 
352 static GtkWidget *aboutwindow;
353 
354 void
on_about1_activate(GtkMenuItem * menuitem,gpointer user_data)355 on_about1_activate                     (GtkMenuItem     *menuitem,
356                                         gpointer         user_data)
357 {
358     char s[200];
359     snprintf (s, sizeof (s), _("About DeaDBeeF %s"), VERSION);
360     char fname[PATH_MAX];
361     snprintf (fname, sizeof (fname), "%s/%s", deadbeef->get_doc_dir (), "about.txt");
362     gtkui_show_info_window (fname, s, &aboutwindow);
363 }
364 
365 static GtkWidget *changelogwindow;
366 
367 void
on_changelog1_activate(GtkMenuItem * menuitem,gpointer user_data)368 on_changelog1_activate                 (GtkMenuItem     *menuitem,
369                                         gpointer         user_data)
370 {
371     char s[200];
372     snprintf (s, sizeof (s), _("DeaDBeeF %s ChangeLog"), VERSION);
373     char fname[PATH_MAX];
374     snprintf (fname, sizeof (fname), "%s/%s", deadbeef->get_doc_dir (), "ChangeLog");
375     gtkui_show_info_window (fname, s, &changelogwindow);
376 }
377 
378 static GtkWidget *gplwindow;
379 
380 void
on_gpl1_activate(GtkMenuItem * menuitem,gpointer user_data)381 on_gpl1_activate                       (GtkMenuItem     *menuitem,
382                                         gpointer         user_data)
383 {
384     char fname[PATH_MAX];
385     snprintf (fname, sizeof (fname), "%s/%s", deadbeef->get_doc_dir (), "COPYING.GPLv2");
386     gtkui_show_info_window (fname, "GNU GENERAL PUBLIC LICENSE Version 2", &gplwindow);
387 }
388 
389 static GtkWidget *lgplwindow;
390 
391 void
on_lgpl1_activate(GtkMenuItem * menuitem,gpointer user_data)392 on_lgpl1_activate                      (GtkMenuItem     *menuitem,
393                                         gpointer         user_data)
394 {
395     char fname[PATH_MAX];
396     snprintf (fname, sizeof (fname), "%s/%s", deadbeef->get_doc_dir (), "COPYING.LGPLv2.1");
397     gtkui_show_info_window (fname, "GNU LESSER GENERAL PUBLIC LICENSE Version 2.1", &lgplwindow);
398 }
399 
400 gboolean
on_helpwindow_key_press_event(GtkWidget * widget,GdkEventKey * event,gpointer user_data)401 on_helpwindow_key_press_event          (GtkWidget       *widget,
402                                         GdkEventKey     *event,
403                                         gpointer         user_data)
404 {
405     if (event->keyval == GDK_Escape) {
406         GtkWidget **pwindow = (GtkWidget **)g_object_get_data (G_OBJECT (widget), "pointer");
407         if (pwindow) {
408             *pwindow = NULL;
409         }
410         gtk_widget_hide (widget);
411         gtk_widget_destroy (widget);
412     }
413     return FALSE;
414 }
415 
416 // defined in plcommon.c
417 extern int editcolumn_title_changed;
418 
419 void
on_editcolumn_title_changed(GtkEditable * editable,gpointer user_data)420 on_editcolumn_title_changed            (GtkEditable     *editable,
421                                         gpointer         user_data)
422 {
423     editcolumn_title_changed = 1;
424 }
425 
426 void
on_column_id_changed(GtkComboBox * combobox,gpointer user_data)427 on_column_id_changed                   (GtkComboBox     *combobox,
428                                         gpointer         user_data)
429 {
430     GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (combobox));
431     if (!toplevel) {
432         trace ("failed to get toplevel widget for column id combobox\n");
433         return;
434     }
435     int act = gtk_combo_box_get_active (combobox);
436     GtkWidget *fmt = lookup_widget (toplevel, "format");
437     if (!fmt) {
438         trace ("failed to get column format widget\n");
439         return;
440     }
441     gtk_widget_set_sensitive (fmt, act >= 10 ? TRUE : FALSE);
442 
443     if (!editcolumn_title_changed) {
444         GtkWidget *title= lookup_widget (toplevel, "title");
445         if (title) {
446             gtk_entry_set_text (GTK_ENTRY (title), gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (combobox)));
447             editcolumn_title_changed = 0;
448         }
449     }
450 }
451 
452 
453 gboolean
on_mainwin_window_state_event(GtkWidget * widget,GdkEventWindowState * event,gpointer user_data)454 on_mainwin_window_state_event          (GtkWidget       *widget,
455                                         GdkEventWindowState *event,
456                                         gpointer         user_data)
457 {
458     wingeom_save_max (event, widget, "mainwin");
459     return FALSE;
460 }
461 
462 
463 void
on_toggle_status_bar_activate(GtkMenuItem * menuitem,gpointer user_data)464 on_toggle_status_bar_activate          (GtkMenuItem     *menuitem,
465                                         gpointer         user_data)
466 {
467     GtkWidget *sb = lookup_widget (mainwin, "statusbar");
468     if (sb) {
469         if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menuitem))) {
470             deadbeef->conf_set_int ("gtkui.statusbar.visible", 0);
471             gtk_widget_hide (sb);
472         }
473         else {
474             deadbeef->conf_set_int ("gtkui.statusbar.visible", 1);
475             gtk_widget_show (sb);
476         }
477     }
478     deadbeef->sendmessage (DB_EV_CONFIGCHANGED, 0, 0, 0);
479 }
480 
481 void
on_stop_after_current_activate(GtkMenuItem * menuitem,gpointer user_data)482 on_stop_after_current_activate         (GtkMenuItem     *menuitem,
483                                         gpointer         user_data)
484 {
485     deadbeef->conf_set_int ("playlist.stop_after_current", gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menuitem)));
486     deadbeef->sendmessage (DB_EV_CONFIGCHANGED, 0, 0, 0);
487 }
488 
489 void
on_stop_after_album_activate(GtkMenuItem * menuitem,gpointer user_data)490 on_stop_after_album_activate           (GtkMenuItem     *menuitem,
491                                         gpointer         user_data)
492 {
493     deadbeef->conf_set_int ("playlist.stop_after_album", gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menuitem)));
494     deadbeef->sendmessage (DB_EV_CONFIGCHANGED, 0, 0, 0);
495 }
496 
497 void
on_cursor_follows_playback_activate(GtkMenuItem * menuitem,gpointer user_data)498 on_cursor_follows_playback_activate    (GtkMenuItem     *menuitem,
499                                         gpointer         user_data)
500 {
501     deadbeef->conf_set_int ("playlist.scroll.cursorfollowplayback", gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menuitem)));
502     deadbeef->sendmessage (DB_EV_CONFIGCHANGED, 0, 0, 0);
503 }
504 
505 GtkWidget*
create_ddb_listview_widget(gchar * widget_name,gchar * string1,gchar * string2,gint int1,gint int2)506 create_ddb_listview_widget (gchar *widget_name, gchar *string1, gchar *string2,
507                 gint int1, gint int2)
508 {
509     return ddb_listview_new ();
510 }
511 
512 
513 GtkWidget*
create_tabstrip_widget(gchar * widget_name,gchar * string1,gchar * string2,gint int1,gint int2)514 create_tabstrip_widget (gchar *widget_name, gchar *string1, gchar *string2,
515                 gint int1, gint int2)
516 {
517     return ddb_tabstrip_new ();
518 }
519 
520 
521 GtkWidget*
create_volumebar_widget(gchar * widget_name,gchar * string1,gchar * string2,gint int1,gint int2)522 create_volumebar_widget (gchar *widget_name, gchar *string1, gchar *string2,
523                 gint int1, gint int2)
524 {
525     return ddb_volumebar_new ();
526 }
527 
528 
529 
530 void
on_mainwin_realize(GtkWidget * widget,gpointer user_data)531 on_mainwin_realize                     (GtkWidget       *widget,
532                                         gpointer         user_data)
533 {
534     gtkui_init_theme_colors ();
535 }
536 
537 void
on_toggle_eq(GtkMenuItem * menuitem,gpointer user_data)538 on_toggle_eq                           (GtkMenuItem     *menuitem,
539                                         gpointer         user_data)
540 {
541     if (!gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menuitem))) {
542         deadbeef->conf_set_int ("gtkui.eq.visible", 0);
543         eq_window_hide ();
544     }
545     else {
546         deadbeef->conf_set_int ("gtkui.eq.visible", 1);
547         eq_window_show ();
548     }
549     deadbeef->sendmessage (DB_EV_CONFIGCHANGED, 0, 0, 0);
550 }
551 
552 
553 
554 void
on_deselect_all1_activate(GtkMenuItem * menuitem,gpointer user_data)555 on_deselect_all1_activate              (GtkMenuItem     *menuitem,
556                                         gpointer         user_data)
557 {
558     action_deselect_all_handler_cb (NULL);
559 }
560 
561 
562 void
on_invert_selection1_activate(GtkMenuItem * menuitem,gpointer user_data)563 on_invert_selection1_activate          (GtkMenuItem     *menuitem,
564                                         gpointer         user_data)
565 {
566     deadbeef->pl_lock ();
567     DB_playItem_t *it = deadbeef->pl_get_first (PL_MAIN);
568     while (it) {
569         if (deadbeef->pl_is_selected (it)) {
570             deadbeef->pl_set_selected (it, 0);
571         }
572         else {
573             deadbeef->pl_set_selected (it, 1);
574         }
575         DB_playItem_t *next = deadbeef->pl_get_next (it, PL_MAIN);
576         deadbeef->pl_item_unref (it);
577         it = next;
578     }
579     deadbeef->pl_unlock ();
580     deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, DDB_PLAYLIST_CHANGE_SELECTION, 0);
581 }
582 
583 
584 void
on_new_playlist1_activate(GtkMenuItem * menuitem,gpointer user_data)585 on_new_playlist1_activate              (GtkMenuItem     *menuitem,
586                                         gpointer         user_data)
587 {
588     action_new_playlist_handler_cb (NULL);
589 }
590 
591 gboolean
on_mainwin_button_press_event(GtkWidget * widget,GdkEventButton * event,gpointer user_data)592 on_mainwin_button_press_event          (GtkWidget       *widget,
593                                         GdkEventButton  *event,
594                                         gpointer         user_data)
595 {
596     GtkWidget *statusbar = lookup_widget (mainwin, "statusbar");
597     GtkAllocation c;
598     gtk_widget_get_allocation (statusbar, &c);
599     if (event->x >= c.x && event->x < c.x + c.width
600             && event->y >= c.y && event->y < c.y + c.height) {
601         if (event->type == GDK_2BUTTON_PRESS) {
602             deadbeef->sendmessage (DB_EV_TRACKFOCUSCURRENT, 0, 0, 0);
603         }
604     }
605 
606     return FALSE;
607 }
608 
609 
610 GtkWidget*
create_seekbar(gchar * widget_name,gchar * string1,gchar * string2,gint int1,gint int2)611 create_seekbar (gchar *widget_name, gchar *string1, gchar *string2,
612                 gint int1, gint int2)
613 {
614     return GTK_WIDGET (ddb_seekbar_new ());
615 }
616 
617 
618 void
on_jump_to_current_track1_activate(GtkMenuItem * menuitem,gpointer user_data)619 on_jump_to_current_track1_activate     (GtkMenuItem     *menuitem,
620                                         gpointer         user_data)
621 {
622     deadbeef->sendmessage (DB_EV_TRACKFOCUSCURRENT, 0, 0, 0);
623 }
624 
625 static GtkWidget *translatorswindow;
626 
627 void
on_translators1_activate(GtkMenuItem * menuitem,gpointer user_data)628 on_translators1_activate               (GtkMenuItem     *menuitem,
629                                         gpointer         user_data)
630 {
631     char s[200];
632     snprintf (s, sizeof (s), _("DeaDBeeF Translators"));
633     char fname[PATH_MAX];
634     snprintf (fname, sizeof (fname), "%s/%s", deadbeef->get_doc_dir (), "translators.txt");
635     gtkui_show_info_window (fname, s, &translatorswindow);
636 }
637 
638 
639 GtkWidget*
title_formatting_help_link_create(gchar * widget_name,gchar * string1,gchar * string2,gint int1,gint int2)640 title_formatting_help_link_create (gchar *widget_name, gchar *string1, gchar *string2,
641                 gint int1, gint int2)
642 {
643     GtkWidget *link = gtk_link_button_new_with_label ("http://github.com/Alexey-Yakovenko/deadbeef/wiki/Title-formatting-2.0", "Help");
644     return link;
645 }
646 
647 
648 
649 void
on_sortfmt_activate(GtkEntry * entry,gpointer user_data)650 on_sortfmt_activate                    (GtkEntry        *entry,
651                                         gpointer         user_data)
652 {
653     GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (entry));
654     gtk_dialog_response (GTK_DIALOG (toplevel), GTK_RESPONSE_OK);
655 }
656 
657 
658 
659 GtkWidget*
create_plugin_weblink(gchar * widget_name,gchar * string1,gchar * string2,gint int1,gint int2)660 create_plugin_weblink (gchar *widget_name, gchar *string1, gchar *string2,
661                 gint int1, gint int2)
662 {
663     GtkWidget *link = gtk_link_button_new_with_label ("", "WWW");
664     gtk_widget_set_sensitive (link, FALSE);
665     return link;
666 }
667 
668 void
on_sort_by_title_activate(GtkMenuItem * menuitem,gpointer user_data)669 on_sort_by_title_activate              (GtkMenuItem     *menuitem,
670                                         gpointer         user_data)
671 {
672     ddb_playlist_t *plt = deadbeef->plt_get_curr ();
673     deadbeef->plt_sort_v2 (plt, PL_MAIN, -1, "%title%", DDB_SORT_ASCENDING);
674     deadbeef->plt_save_config (plt);
675     deadbeef->plt_unref (plt);
676 
677     deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, DDB_PLAYLIST_CHANGE_CONTENT, 0);
678 }
679 
680 
681 void
on_sort_by_track_nr_activate(GtkMenuItem * menuitem,gpointer user_data)682 on_sort_by_track_nr_activate           (GtkMenuItem     *menuitem,
683                                         gpointer         user_data)
684 {
685     ddb_playlist_t *plt = deadbeef->plt_get_curr ();
686     deadbeef->plt_sort_v2 (plt, PL_MAIN, -1, "%tracknumber%", DDB_SORT_ASCENDING);
687     deadbeef->plt_save_config (plt);
688     deadbeef->plt_unref (plt);
689 
690     deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, DDB_PLAYLIST_CHANGE_CONTENT, 0);
691 }
692 
693 
694 void
on_sort_by_album_activate(GtkMenuItem * menuitem,gpointer user_data)695 on_sort_by_album_activate              (GtkMenuItem     *menuitem,
696                                         gpointer         user_data)
697 {
698     ddb_playlist_t *plt = deadbeef->plt_get_curr ();
699     deadbeef->plt_sort_v2 (plt, PL_MAIN, -1, "%album%", DDB_SORT_ASCENDING);
700     deadbeef->plt_save_config (plt);
701     deadbeef->plt_unref (plt);
702 
703     deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, DDB_PLAYLIST_CHANGE_CONTENT, 0);
704 }
705 
706 
707 void
on_sort_by_artist_activate(GtkMenuItem * menuitem,gpointer user_data)708 on_sort_by_artist_activate             (GtkMenuItem     *menuitem,
709                                         gpointer         user_data)
710 {
711     ddb_playlist_t *plt = deadbeef->plt_get_curr ();
712     deadbeef->plt_sort_v2 (plt, PL_MAIN, -1, "%artist%", DDB_SORT_ASCENDING);
713     deadbeef->plt_save_config (plt);
714     deadbeef->plt_unref (plt);
715 
716     deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, DDB_PLAYLIST_CHANGE_CONTENT, 0);
717 }
718 
719 
720 void
on_sort_by_date_activate(GtkMenuItem * menuitem,gpointer user_data)721 on_sort_by_date_activate               (GtkMenuItem     *menuitem,
722                                         gpointer         user_data)
723 {
724     ddb_playlist_t *plt = deadbeef->plt_get_curr ();
725     deadbeef->plt_sort_v2 (plt, PL_MAIN, -1, "%year%", DDB_SORT_ASCENDING);
726     deadbeef->plt_save_config (plt);
727     deadbeef->plt_unref (plt);
728     deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, DDB_PLAYLIST_CHANGE_CONTENT, 0);
729 }
730 
731 
732 void
on_sort_by_random_activate(GtkMenuItem * menuitem,gpointer user_data)733 on_sort_by_random_activate               (GtkMenuItem     *menuitem,
734                                         gpointer         user_data)
735 {
736     ddb_playlist_t *plt = deadbeef->plt_get_curr ();
737     deadbeef->plt_sort_v2 (plt, PL_MAIN, -1, NULL, DDB_SORT_RANDOM);
738     deadbeef->plt_save_config (plt);
739     deadbeef->plt_unref (plt);
740 
741     deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, DDB_PLAYLIST_CHANGE_CONTENT, 0);
742 }
743 
744 
745 void
on_sort_by_custom_activate(GtkMenuItem * menuitem,gpointer user_data)746 on_sort_by_custom_activate             (GtkMenuItem     *menuitem,
747                                         gpointer         user_data)
748 {
749     gdk_threads_add_idle (action_sort_custom_handler_cb, NULL);
750 }
751 
752 void
on_design_mode1_activate(GtkMenuItem * menuitem,gpointer user_data)753 on_design_mode1_activate               (GtkMenuItem     *menuitem,
754                                         gpointer         user_data)
755 {
756     gboolean act = gtk_check_menu_item_get_active (GTK_CHECK_MENU_ITEM (menuitem));
757     w_set_design_mode (act ? 1 : 0);
758 }
759 
760 void
on_preferences_activate(GtkMenuItem * menuitem,gpointer user_data)761 on_preferences_activate                (GtkMenuItem     *menuitem,
762                                         gpointer         user_data)
763 {
764     gdk_threads_add_idle (action_preferences_handler_cb, NULL);
765 }
766 
767 
768 gboolean
on_prefwin_key_press_event(GtkWidget * widget,GdkEventKey * event,gpointer user_data)769 on_prefwin_key_press_event             (GtkWidget       *widget,
770                                         GdkEventKey     *event,
771                                         gpointer         user_data)
772 {
773     if (gtkui_hotkey_grabbing) {
774         on_hotkeys_set_key_key_press_event (widget, event, user_data);
775         return TRUE;
776     }
777     return FALSE;
778 }
779 
780