1 /*
2     DeaDBeeF -- the music player
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 #include "../../deadbeef.h"
24 #include <gtk/gtk.h>
25 #ifdef HAVE_CONFIG_H
26 #include "../../config.h"
27 #endif
28 #include "../../gettext.h"
29 #include <string.h>
30 #include <stdlib.h>
31 #include "gtkui.h"
32 #include "interface.h"
33 #include "support.h"
34 
35 #define GLADE_HOOKUP_OBJECT_NO_REF(component,widget,name) \
36   g_object_set_data (G_OBJECT (component), name, widget)
37 
38 // selected playlist for the context menu
39 static int pltmenu_idx;
40 
41 void
plt_get_title_wrapper(int plt,char * buffer,int len)42 plt_get_title_wrapper (int plt, char *buffer, int len) {
43     if (plt == -1) {
44         strcpy (buffer, "");
45         return;
46     }
47     ddb_playlist_t *p = deadbeef->plt_get_for_idx (plt);
48     deadbeef->plt_get_title (p, buffer, len);
49     deadbeef->plt_unref (p);
50     char *end;
51     if (!g_utf8_validate (buffer, -1, (const gchar **)&end)) {
52         *end = 0;
53     }
54 }
55 
56 static void
on_rename_playlist1_activate(GtkMenuItem * menuitem,gpointer user_data)57 on_rename_playlist1_activate           (GtkMenuItem     *menuitem,
58                                         gpointer         user_data)
59 {
60     GtkWidget *dlg = create_entrydialog ();
61     gtk_dialog_set_default_response (GTK_DIALOG (dlg), GTK_RESPONSE_OK);
62     gtk_window_set_title (GTK_WINDOW (dlg), _("Edit playlist"));
63     GtkWidget *e;
64     e = lookup_widget (dlg, "title_label");
65     gtk_label_set_text (GTK_LABEL(e), _("Title:"));
66     e = lookup_widget (dlg, "title");
67     char t[1000];
68     plt_get_title_wrapper (pltmenu_idx, t, sizeof (t));
69     gtk_entry_set_text (GTK_ENTRY (e), t);
70     int res = gtk_dialog_run (GTK_DIALOG (dlg));
71     if (res == GTK_RESPONSE_OK) {
72         const char *text = gtk_entry_get_text (GTK_ENTRY (e));
73         deadbeef->pl_lock ();
74         ddb_playlist_t *p = deadbeef->plt_get_for_idx (pltmenu_idx);
75         deadbeef->plt_set_title (p, text);
76         deadbeef->plt_unref (p);
77         deadbeef->pl_unlock ();
78     }
79     gtk_widget_destroy (dlg);
80 }
81 
82 static void
on_remove_playlist1_activate(GtkMenuItem * menuitem,gpointer user_data)83 on_remove_playlist1_activate           (GtkMenuItem     *menuitem,
84                                         gpointer         user_data)
85 {
86     if (pltmenu_idx != -1) {
87         deadbeef->plt_remove (pltmenu_idx);
88         search_refresh ();
89         int playlist = deadbeef->plt_get_curr_idx ();
90         deadbeef->conf_set_int ("playlist.current", playlist);
91     }
92 }
93 
94 static void
on_add_new_playlist1_activate(GtkMenuItem * menuitem,gpointer user_data)95 on_add_new_playlist1_activate          (GtkMenuItem     *menuitem,
96                                         gpointer         user_data)
97 {
98     int playlist = gtkui_add_new_playlist ();
99     if (playlist != -1) {
100         gtkui_playlist_set_curr (playlist);
101     }
102 }
103 
104 static void
on_actionitem_activate(GtkMenuItem * menuitem,DB_plugin_action_t * action)105 on_actionitem_activate (GtkMenuItem     *menuitem,
106                            DB_plugin_action_t *action)
107 {
108     if (action->callback) {
109         ddb_playlist_t *plt = NULL;
110         if (pltmenu_idx != -1) {
111             plt = deadbeef->plt_get_for_idx (pltmenu_idx);
112         }
113         action->callback (action, plt);
114         if (plt) {
115             deadbeef->plt_unref (plt);
116         }
117     }
118     else {
119         ddb_playlist_t *plt = NULL;
120         if (pltmenu_idx != -1) {
121             plt = deadbeef->plt_get_for_idx (pltmenu_idx);
122             if (plt) {
123                 deadbeef->action_set_playlist (plt);
124                 deadbeef->plt_unref (plt);
125                 action->callback2 (action, DDB_ACTION_CTX_PLAYLIST);
126                 deadbeef->action_set_playlist (NULL);
127             }
128         }
129     }
130 }
131 
132 static GtkWidget*
find_popup(GtkWidget * widget,const gchar * widget_name)133 find_popup                          (GtkWidget       *widget,
134                                         const gchar     *widget_name)
135 {
136   GtkWidget *parent, *found_widget;
137 
138   for (;;)
139     {
140       if (GTK_IS_MENU (widget))
141         parent = gtk_menu_get_attach_widget (GTK_MENU (widget));
142       else
143         parent = gtk_widget_get_parent (widget);
144       if (!parent)
145         parent = (GtkWidget*) g_object_get_data (G_OBJECT (widget), "GladeParentKey");
146       if (parent == NULL)
147         break;
148       widget = parent;
149     }
150 
151   found_widget = (GtkWidget*) g_object_get_data (G_OBJECT (widget),
152                                                  widget_name);
153   return found_widget;
154 }
155 
156 static void
add_tab_actions(GtkWidget * menu)157 add_tab_actions (GtkWidget *menu) {
158     DB_plugin_t **plugins = deadbeef->plug_get_list();
159     int i;
160 
161     int added_entries = 0;
162 
163     int hide_remove_from_disk = deadbeef->conf_get_int ("gtkui.hide_remove_from_disk", 0);
164 
165     for (i = 0; plugins[i]; i++)
166     {
167         if (!plugins[i]->get_actions)
168             continue;
169 
170         DB_plugin_action_t *actions = plugins[i]->get_actions (NULL);
171         DB_plugin_action_t *action;
172 
173         int count = 0;
174         for (action = actions; action; action = action->next)
175         {
176             char *tmp = NULL;
177             if (!(action->flags & DB_ACTION_MULTIPLE_TRACKS))
178                 continue;
179 
180             if (action->name && !strcmp (action->name, "delete_from_disk") && hide_remove_from_disk) {
181                 continue;
182             }
183 
184             // create submenus (separated with '/')
185             const char *prev = action->title;
186             while (*prev && *prev == '/') {
187                 prev++;
188             }
189 
190             GtkWidget *popup = NULL;
191 
192             for (;;) {
193                 const char *slash = strchr (prev, '/');
194                 if (slash && *(slash-1) != '\\') {
195                     char name[slash-prev+1];
196                     // replace \/ with /
197                     const char *p = prev;
198                     char *t = name;
199                     while (*p && p < slash) {
200                         if (*p == '\\' && *(p+1) == '/') {
201                             *t++ = '/';
202                             p += 2;
203                         }
204                         else {
205                             *t++ = *p++;
206                         }
207                     }
208                     *t = 0;
209 
210                     // add popup
211                     GtkWidget *prev_menu = popup ? popup : menu;
212 
213                     popup = find_popup (prev_menu, name);
214                     if (!popup) {
215                         GtkWidget *item = gtk_image_menu_item_new_with_mnemonic (_(name));
216                         gtk_widget_show (item);
217                         gtk_container_add (GTK_CONTAINER (prev_menu), item);
218                         popup = gtk_menu_new ();
219                         GLADE_HOOKUP_OBJECT_NO_REF (prev_menu, popup, name);
220                         gtk_menu_item_set_submenu (GTK_MENU_ITEM (item), popup);
221                     }
222                 }
223                 else {
224                     break;
225                 }
226                 prev = slash+1;
227             }
228 
229 
230             count++;
231             added_entries++;
232             GtkWidget *actionitem;
233 
234             // replace \/ with /
235             const char *p = popup ? prev : action->title;
236             char title[strlen (p)+1];
237             char *t = title;
238             while (*p) {
239                 if (*p == '\\' && *(p+1) == '/') {
240                     *t++ = '/';
241                     p += 2;
242                 }
243                 else {
244                     *t++ = *p++;
245                 }
246             }
247             *t = 0;
248 
249             actionitem = gtk_menu_item_new_with_mnemonic (_(title));
250             gtk_widget_show (actionitem);
251             gtk_container_add (popup ? GTK_CONTAINER (popup) : GTK_CONTAINER (menu), actionitem);
252 
253             g_signal_connect ((gpointer) actionitem, "activate",
254                     G_CALLBACK (on_actionitem_activate),
255                     action);
256         }
257     }
258 }
259 
260 GtkWidget*
gtkui_create_pltmenu(int plt_idx)261 gtkui_create_pltmenu (int plt_idx) {
262     GtkWidget *plmenu;
263     GtkWidget *rename_playlist1;
264     GtkWidget *remove_playlist1;
265     GtkWidget *add_new_playlist1;
266     GtkWidget *separator11;
267     GtkWidget *load_playlist1;
268     GtkWidget *save_playlist1;
269     GtkWidget *save_all_playlists1;
270 
271     plmenu = gtk_menu_new ();
272     pltmenu_idx = plt_idx;
273 
274     rename_playlist1 = gtk_menu_item_new_with_mnemonic (_("Rename Playlist"));
275     if (pltmenu_idx == -1) {
276         gtk_widget_set_sensitive (rename_playlist1, FALSE);
277     }
278     gtk_widget_show (rename_playlist1);
279     gtk_container_add (GTK_CONTAINER (plmenu), rename_playlist1);
280 
281     remove_playlist1 = gtk_menu_item_new_with_mnemonic (_("Remove Playlist"));
282     if (pltmenu_idx == -1) {
283         gtk_widget_set_sensitive (remove_playlist1, FALSE);
284     }
285     gtk_widget_show (remove_playlist1);
286     gtk_container_add (GTK_CONTAINER (plmenu), remove_playlist1);
287 
288     add_new_playlist1 = gtk_menu_item_new_with_mnemonic (_("Add New Playlist"));
289     gtk_widget_show (add_new_playlist1);
290     gtk_container_add (GTK_CONTAINER (plmenu), add_new_playlist1);
291 
292     g_signal_connect ((gpointer) rename_playlist1, "activate",
293             G_CALLBACK (on_rename_playlist1_activate),
294             NULL);
295     g_signal_connect ((gpointer) remove_playlist1, "activate",
296             G_CALLBACK (on_remove_playlist1_activate),
297             NULL);
298     g_signal_connect ((gpointer) add_new_playlist1, "activate",
299             G_CALLBACK (on_add_new_playlist1_activate),
300             NULL);
301 
302     add_tab_actions (plmenu);
303 
304     return plmenu;
305 }
306 
307