1 /*
2  * Copyright (c) 2011 Tim van der Molen <tim@kariliq.nl>
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 #include <pthread.h>
18 #include <stdlib.h>
19 #include <string.h>
20 
21 #include "siren.h"
22 
23 static int		 queue_search_entry(const void *, const char *);
24 
25 static pthread_mutex_t	 queue_menu_mtx = PTHREAD_MUTEX_INITIALIZER;
26 static struct format	*queue_altformat;
27 static struct format	*queue_format;
28 static struct menu	*queue_menu;
29 static unsigned int	 queue_duration;
30 
31 void
queue_activate_entry(void)32 queue_activate_entry(void)
33 {
34 	struct track *t;
35 
36 	XPTHREAD_MUTEX_LOCK(&queue_menu_mtx);
37 	if ((t = menu_get_selected_entry_data(queue_menu)) != NULL) {
38 		queue_duration -= t->duration;
39 		menu_remove_selected_entry(queue_menu);
40 	}
41 	XPTHREAD_MUTEX_UNLOCK(&queue_menu_mtx);
42 
43 	if (t != NULL) {
44 		player_play_track(t);
45 		queue_print();
46 	}
47 }
48 
49 void
queue_add_dir(const char * path)50 queue_add_dir(const char *path)
51 {
52 	struct dir		*d;
53 	struct dir_entry	*de;
54 	struct track		*t;
55 
56 	if ((d = dir_open(path)) == NULL) {
57 		msg_err("%s", path);
58 		return;
59 	}
60 
61 	while ((de = dir_get_entry(d)) != NULL)
62 		switch (de->type) {
63 		case FILE_TYPE_DIRECTORY:
64 			if (strcmp(de->name, ".") && strcmp(de->name, ".."))
65 				queue_add_dir(de->path);
66 			break;
67 		case FILE_TYPE_REGULAR:
68 			if ((t = track_get(de->path, NULL)) != NULL)
69 				queue_add_track(t);
70 			break;
71 		default:
72 			msg_errx("%s: Unsupported file type", de->path);
73 			break;
74 		}
75 
76 	dir_close(d);
77 }
78 
79 void
queue_add_track(struct track * t)80 queue_add_track(struct track *t)
81 {
82 	XPTHREAD_MUTEX_LOCK(&queue_menu_mtx);
83 	menu_insert_tail(queue_menu, t);
84 	queue_duration += t->duration;
85 	XPTHREAD_MUTEX_UNLOCK(&queue_menu_mtx);
86 	queue_print();
87 }
88 
89 void
queue_copy_entry(enum view_id view)90 queue_copy_entry(enum view_id view)
91 {
92 	struct track *t;
93 
94 	if (view == VIEW_ID_QUEUE)
95 		return;
96 
97 	XPTHREAD_MUTEX_LOCK(&queue_menu_mtx);
98 	if ((t = menu_get_selected_entry_data(queue_menu)) != NULL)
99 		view_add_track(view, t);
100 	XPTHREAD_MUTEX_UNLOCK(&queue_menu_mtx);
101 }
102 
103 void
queue_delete_all_entries(void)104 queue_delete_all_entries(void)
105 {
106 	XPTHREAD_MUTEX_LOCK(&queue_menu_mtx);
107 	menu_remove_all_entries(queue_menu);
108 	queue_duration = 0;
109 	XPTHREAD_MUTEX_UNLOCK(&queue_menu_mtx);
110 	queue_print();
111 }
112 
113 void
queue_delete_entry(void)114 queue_delete_entry(void)
115 {
116 	struct track *t;
117 
118 	XPTHREAD_MUTEX_LOCK(&queue_menu_mtx);
119 	if ((t = menu_get_selected_entry_data(queue_menu)) != NULL) {
120 		queue_duration -= t->duration;
121 		menu_remove_selected_entry(queue_menu);
122 	}
123 	XPTHREAD_MUTEX_UNLOCK(&queue_menu_mtx);
124 	queue_print();
125 }
126 
127 void
queue_end(void)128 queue_end(void)
129 {
130 	menu_free(queue_menu);
131 }
132 
133 static void
queue_get_entry_text(const void * e,char * buf,size_t bufsize)134 queue_get_entry_text(const void *e, char *buf, size_t bufsize)
135 {
136 	const struct track *t;
137 
138 	t = e;
139 	format_track_snprintf(buf, bufsize, queue_format, queue_altformat, t);
140 }
141 
142 struct track *
queue_get_next_track(void)143 queue_get_next_track(void)
144 {
145 	struct menu_entry	*me;
146 	struct track		*t;
147 
148 	XPTHREAD_MUTEX_LOCK(&queue_menu_mtx);
149 	if ((me = menu_get_first_entry(queue_menu)) == NULL)
150 		t = NULL;
151 	else {
152 		t = menu_get_entry_data(me);
153 		queue_duration -= t->duration;
154 		menu_remove_entry(queue_menu, me);
155 	}
156 	XPTHREAD_MUTEX_UNLOCK(&queue_menu_mtx);
157 
158 	if (t != NULL)
159 		queue_print();
160 
161 	return t;
162 }
163 
164 void
queue_init(void)165 queue_init(void)
166 {
167 	queue_menu = menu_init(NULL, queue_get_entry_text, queue_search_entry);
168 }
169 
170 void
queue_move_entry_down(void)171 queue_move_entry_down(void)
172 {
173 	struct menu_entry *e;
174 
175 	XPTHREAD_MUTEX_LOCK(&queue_menu_mtx);
176 	if ((e = menu_get_selected_entry(queue_menu)) != NULL)
177 		menu_move_entry_down(queue_menu, e);
178 	XPTHREAD_MUTEX_UNLOCK(&queue_menu_mtx);
179 	queue_print();
180 }
181 
182 void
queue_move_entry_up(void)183 queue_move_entry_up(void)
184 {
185 	struct menu_entry *e;
186 
187 	XPTHREAD_MUTEX_LOCK(&queue_menu_mtx);
188 	if ((e = menu_get_selected_entry(queue_menu)) != NULL)
189 		menu_move_entry_up(queue_menu, e);
190 	XPTHREAD_MUTEX_UNLOCK(&queue_menu_mtx);
191 	queue_print();
192 }
193 
194 void
queue_print(void)195 queue_print(void)
196 {
197 	if (view_get_id() != VIEW_ID_QUEUE)
198 		return;
199 
200 	XPTHREAD_MUTEX_LOCK(&queue_menu_mtx);
201 	screen_view_title_printf("Queue: %u track%s (%u:%02u:%02u)",
202 	    menu_get_nentries(queue_menu),
203 	    menu_get_nentries(queue_menu) == 1 ? "" : "s",
204 	    HOURS(queue_duration),
205 	    HMINS(queue_duration),
206 	    MSECS(queue_duration));
207 	option_lock();
208 	queue_format = option_get_format("queue-format");
209 	queue_altformat = option_get_format("queue-format-alt");
210 	menu_print(queue_menu);
211 	option_unlock();
212 	XPTHREAD_MUTEX_UNLOCK(&queue_menu_mtx);
213 }
214 
215 void
queue_scroll_down(enum menu_scroll scroll)216 queue_scroll_down(enum menu_scroll scroll)
217 {
218 	XPTHREAD_MUTEX_LOCK(&queue_menu_mtx);
219 	menu_scroll_down(queue_menu, scroll);
220 	XPTHREAD_MUTEX_UNLOCK(&queue_menu_mtx);
221 	queue_print();
222 }
223 
224 void
queue_scroll_up(enum menu_scroll scroll)225 queue_scroll_up(enum menu_scroll scroll)
226 {
227 	XPTHREAD_MUTEX_LOCK(&queue_menu_mtx);
228 	menu_scroll_up(queue_menu, scroll);
229 	XPTHREAD_MUTEX_UNLOCK(&queue_menu_mtx);
230 	queue_print();
231 }
232 
233 static int
queue_search_entry(const void * e,const char * search)234 queue_search_entry(const void *e, const char *search)
235 {
236 	const struct track *t;
237 
238 	t = e;
239 	return track_search(t, search);
240 }
241 
242 void
queue_search_next(const char * search)243 queue_search_next(const char *search)
244 {
245 	XPTHREAD_MUTEX_LOCK(&queue_menu_mtx);
246 	menu_search_next(queue_menu, search);
247 	XPTHREAD_MUTEX_UNLOCK(&queue_menu_mtx);
248 	queue_print();
249 }
250 
251 void
queue_search_prev(const char * search)252 queue_search_prev(const char *search)
253 {
254 	XPTHREAD_MUTEX_LOCK(&queue_menu_mtx);
255 	menu_search_prev(queue_menu, search);
256 	XPTHREAD_MUTEX_UNLOCK(&queue_menu_mtx);
257 	queue_print();
258 }
259 
260 void
queue_select_first_entry(void)261 queue_select_first_entry(void)
262 {
263 	XPTHREAD_MUTEX_LOCK(&queue_menu_mtx);
264 	menu_select_first_entry(queue_menu);
265 	XPTHREAD_MUTEX_UNLOCK(&queue_menu_mtx);
266 	queue_print();
267 }
268 
269 void
queue_select_last_entry(void)270 queue_select_last_entry(void)
271 {
272 	XPTHREAD_MUTEX_LOCK(&queue_menu_mtx);
273 	menu_select_last_entry(queue_menu);
274 	XPTHREAD_MUTEX_UNLOCK(&queue_menu_mtx);
275 	queue_print();
276 }
277 
278 void
queue_select_next_entry(void)279 queue_select_next_entry(void)
280 {
281 	XPTHREAD_MUTEX_LOCK(&queue_menu_mtx);
282 	menu_select_next_entry(queue_menu);
283 	XPTHREAD_MUTEX_UNLOCK(&queue_menu_mtx);
284 	queue_print();
285 }
286 
287 void
queue_select_prev_entry(void)288 queue_select_prev_entry(void)
289 {
290 	XPTHREAD_MUTEX_LOCK(&queue_menu_mtx);
291 	menu_select_prev_entry(queue_menu);
292 	XPTHREAD_MUTEX_UNLOCK(&queue_menu_mtx);
293 	queue_print();
294 }
295 
296 /* Recalculate the duration. */
297 void
queue_update(void)298 queue_update(void)
299 {
300 	struct menu_entry	*e;
301 	struct track		*t;
302 
303 	XPTHREAD_MUTEX_LOCK(&queue_menu_mtx);
304 	queue_duration = 0;
305 	MENU_FOR_EACH_ENTRY(queue_menu, e) {
306 		t = menu_get_entry_data(e);
307 		queue_duration += t->duration;
308 	}
309 	XPTHREAD_MUTEX_UNLOCK(&queue_menu_mtx);
310 }
311