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 #include "../../deadbeef.h"
25 #include <gtk/gtk.h>
26 #include <stdlib.h>
27 #include <ctype.h>
28 #include <string.h>
29 #include "gtkui.h"
30 #include "ddblistview.h"
31 #include "progress.h"
32 #include "support.h"
33
34 //void
35 //gtkpl_add_dir (DdbListview *ps, char *folder) {
36 // ddb_playlist_t *plt = deadbeef->plt_get_curr ();
37 // gtkui_original_plt_add_dir (plt, folder, gtkui_add_file_info_cb, NULL);
38 // deadbeef->plt_unref (plt);
39 // g_free (folder);
40 //}
41
42 static void
gtkpl_adddir_cb(gpointer data,gpointer userdata)43 gtkpl_adddir_cb (gpointer data, gpointer userdata) {
44 ddb_playlist_t *plt = deadbeef->plt_get_curr ();
45 deadbeef->plt_add_dir2 (0, plt, data, NULL, NULL);
46 deadbeef->plt_unref (plt);
47 g_free (data);
48 }
49
50 void
gtkpl_add_dirs(GSList * lst)51 gtkpl_add_dirs (GSList *lst) {
52 ddb_playlist_t *plt = deadbeef->plt_get_curr ();
53 int empty = 0 == deadbeef->plt_get_item_count (plt, PL_MAIN);
54 if (deadbeef->plt_add_files_begin (plt, 0) < 0) {
55 deadbeef->plt_unref (plt);
56 g_slist_free (lst);
57 return;
58 }
59 deadbeef->pl_lock ();
60 if (g_slist_length (lst) == 1
61 && deadbeef->conf_get_int ("gtkui.name_playlist_from_folder", 1)) {
62 char t[1000];
63 if (!deadbeef->plt_get_title (plt, t, sizeof (t))) {
64 char *def = _("New Playlist");
65 if (!strncmp (t, def, strlen (def)) || empty) {
66 const char *folder = strrchr ((char*)lst->data, '/');
67 if (!folder) {
68 folder = lst->data;
69 }
70 deadbeef->plt_set_title (plt, folder+1);
71 }
72 }
73 }
74 deadbeef->pl_unlock ();
75 g_slist_foreach(lst, gtkpl_adddir_cb, NULL);
76 g_slist_free (lst);
77 deadbeef->plt_add_files_end (plt, 0);
78 deadbeef->plt_unref (plt);
79 }
80
81 static void
gtkpl_addfile_cb(gpointer data,gpointer userdata)82 gtkpl_addfile_cb (gpointer data, gpointer userdata) {
83 ddb_playlist_t *plt = deadbeef->plt_get_curr ();
84 deadbeef->plt_add_file2 (0, plt, data, NULL, 0);
85 deadbeef->plt_unref (plt);
86 g_free (data);
87 }
88
89 void
gtkpl_add_files(GSList * lst)90 gtkpl_add_files (GSList *lst) {
91 ddb_playlist_t *plt = deadbeef->plt_get_curr ();
92 if (deadbeef->plt_add_files_begin (plt, 0) < 0) {
93 g_slist_free (lst);
94 deadbeef->plt_unref (plt);
95 return;
96 }
97 g_slist_foreach(lst, gtkpl_addfile_cb, NULL);
98 g_slist_free (lst);
99 deadbeef->plt_add_files_end (plt, 0);
100 deadbeef->plt_save_config (plt);
101 deadbeef->plt_unref (plt);
102 deadbeef->conf_save ();
103 }
104
105 static void
add_dirs_worker(void * data)106 add_dirs_worker (void *data) {
107 GSList *lst = (GSList *)data;
108 gtkpl_add_dirs (lst);
109 deadbeef->pl_save_current ();
110 deadbeef->conf_save ();
111 }
112
113 void
gtkui_add_dirs(GSList * lst)114 gtkui_add_dirs (GSList *lst) {
115 intptr_t tid = deadbeef->thread_start (add_dirs_worker, lst);
116 deadbeef->thread_detach (tid);
117 }
118
119 static void
add_files_worker(void * data)120 add_files_worker (void *data) {
121 GSList *lst = (GSList *)data;
122 gtkpl_add_files (lst);
123 }
124
125 void
gtkui_add_files(struct _GSList * lst)126 gtkui_add_files (struct _GSList *lst) {
127 intptr_t tid = deadbeef->thread_start (add_files_worker, lst);
128 deadbeef->thread_detach (tid);
129 }
130
131 static void
open_files_worker(void * data)132 open_files_worker (void *data) {
133 GSList *lst = (GSList *)data;
134 gtkpl_add_files (lst);
135 deadbeef->pl_save_current ();
136 deadbeef->pl_set_cursor (PL_MAIN, 0);
137 deadbeef->conf_save ();
138 deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, DDB_PLAYLIST_CHANGE_CONTENT, 0);
139 deadbeef->sendmessage (DB_EV_PLAY_NUM, 0, 0, 0);
140 }
141
142 void
gtkui_open_files(struct _GSList * lst)143 gtkui_open_files (struct _GSList *lst) {
144 deadbeef->pl_clear ();
145 deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, DDB_PLAYLIST_CHANGE_CONTENT, 0);
146
147 intptr_t tid = deadbeef->thread_start (open_files_worker, lst);
148 deadbeef->thread_detach (tid);
149 }
150
151 void
strcopy_special(char * dest,const char * src,int len)152 strcopy_special (char *dest, const char *src, int len) {
153 while (len > 0) {
154 if (*src == '%' && len >= 3) {
155 int charcode = 0;
156 int byte;
157 byte = tolower (src[2]);
158 if (byte >= '0' && byte <= '9') {
159 charcode = byte - '0';
160 }
161 else if (byte >= 'a' && byte <= 'f') {
162 charcode = byte - 'a' + 10;
163 }
164 else {
165 charcode = '?';
166 }
167 if (charcode != '?') {
168 byte = tolower (src[1]);
169 if (byte >= '0' && byte <= '9') {
170 charcode |= (byte - '0') << 4;
171 }
172 else if (byte >= 'a' && byte <= 'f') {
173 charcode |= (byte - 'a' + 10) << 4;
174 }
175 else {
176 charcode = '?';
177 }
178 }
179 *dest = charcode;
180 dest++;
181 src += 3;
182 len -= 3;
183 continue;
184 }
185 else {
186 *dest++ = *src++;
187 len--;
188 }
189 }
190 *dest = 0;
191 }
192
193 static gboolean
set_dnd_cursor_idle(gpointer data)194 set_dnd_cursor_idle (gpointer data) {
195 if (!data) {
196 deadbeef->pl_set_cursor (PL_MAIN, -1);
197 deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, DDB_PLAYLIST_CHANGE_CONTENT, 0);
198 return FALSE;
199 }
200 int cursor = deadbeef->pl_get_idx_of (DB_PLAYITEM (data));
201 deadbeef->pl_set_cursor (PL_MAIN, cursor);
202 deadbeef->sendmessage (DB_EV_PLAYLISTCHANGED, 0, DDB_PLAYLIST_CHANGE_CONTENT, 0);
203 return FALSE;
204 }
205
206 void
gtkpl_add_fm_dropped_files(DB_playItem_t * drop_before,char * ptr,int length)207 gtkpl_add_fm_dropped_files (DB_playItem_t *drop_before, char *ptr, int length) {
208 ddb_playlist_t *plt = deadbeef->plt_get_curr ();
209 if (deadbeef->plt_add_files_begin (plt, 0) < 0) {
210 free (ptr);
211 deadbeef->plt_unref (plt);
212 return;
213 }
214
215 DdbListviewIter first = NULL;
216 DdbListviewIter after = NULL;
217 if (drop_before) {
218 after = deadbeef->pl_get_prev (drop_before, PL_MAIN);
219 }
220 else {
221 after = deadbeef->pl_get_last (PL_MAIN);
222 }
223 const uint8_t *p = (const uint8_t*)ptr;
224 while (*p) {
225 const uint8_t *pe = p;
226 while (*pe && *pe > ' ') {
227 pe++;
228 }
229 if (pe - p < 4096 && pe - p > 7) {
230 char fname[(int)(pe - p)+1];
231 strcopy_special (fname, p, pe-p);
232 //strncpy (fname, p, pe - p);
233 //fname[pe - p] = 0;
234 int abort = 0;
235 DdbListviewIter inserted = deadbeef->plt_insert_dir2 (0, plt, after, fname, &abort, NULL, NULL);
236 if (!inserted && !abort) {
237 inserted = deadbeef->plt_insert_file2 (0, plt, after, fname, &abort, NULL, NULL);
238 if (!inserted && !abort) {
239 inserted = deadbeef->plt_load2 (0, plt, after, fname, &abort, NULL, NULL);
240 }
241 }
242 if (inserted) {
243 if (!first) {
244 first = inserted;
245 }
246 if (after) {
247 deadbeef->pl_item_unref (after);
248 }
249 after = inserted;
250 deadbeef->pl_item_ref (after);
251 }
252 }
253 p = pe;
254 // skip whitespace
255 while (*p && *p <= ' ') {
256 p++;
257 }
258 }
259 if (after) {
260 deadbeef->pl_item_unref (after);
261 }
262 free (ptr);
263
264 deadbeef->plt_add_files_end (plt, 0);
265 deadbeef->plt_save_config (plt);
266 deadbeef->plt_unref (plt);
267 g_idle_add (set_dnd_cursor_idle, first);
268 }
269
270 struct fmdrop_data {
271 char *mem;
272 int length;
273 DB_playItem_t *drop_before;
274 };
275
276 static void
fmdrop_worker(void * ctx)277 fmdrop_worker (void *ctx) {
278 struct fmdrop_data *data = (struct fmdrop_data *)ctx;
279 gtkpl_add_fm_dropped_files (data->drop_before, data->mem, data->length);
280 if (data->drop_before) {
281 deadbeef->pl_item_unref (data->drop_before);
282 }
283 free (data);
284 }
285
286 void
gtkui_receive_fm_drop(DB_playItem_t * before,char * mem,int length)287 gtkui_receive_fm_drop (DB_playItem_t *before, char *mem, int length) {
288 struct fmdrop_data *data = malloc (sizeof (struct fmdrop_data));
289 if (!data) {
290 fprintf (stderr, "gtkui_receive_fm_drop: malloc failed\n");
291 return;
292 }
293 data->mem = mem;
294 data->length = length;
295 if (before) {
296 deadbeef->pl_item_ref (before);
297 }
298 data->drop_before = before;
299 // since it happens in separate thread, we need to addref
300 intptr_t tid = deadbeef->thread_start (fmdrop_worker, data);
301 deadbeef->thread_detach (tid);
302 }
303