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