skin tags: fix the id3 track/disc numbers in conditionals
[maemo-rb.git] / apps / shortcuts.c
blobee8454485d859771a76341f58777e70da1e6ed92
1 /***************************************************************************
3 * __________ __ ___.
4 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
5 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
6 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
7 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
8 * \/ \/ \/ \/ \/
10 * Copyright (C) 2011 Jonathan Gordon
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include <stdbool.h>
23 #include <stdlib.h>
24 #include "config.h"
25 #include "system.h"
26 #include "powermgmt.h"
27 #include "power.h"
28 #include "action.h"
29 #include "ata_idle_notify.h"
30 #include "debug_menu.h"
31 #include "core_alloc.h"
32 #include "list.h"
33 #include "settings.h"
34 #include "settings_list.h"
35 #include "lang.h"
36 #include "menu.h"
37 #include "misc.h"
38 #include "tree.h"
39 #include "splash.h"
40 #include "filefuncs.h"
41 #include "filetypes.h"
42 #include "shortcuts.h"
43 #include "onplay.h"
44 #include "screens.h"
45 #include "talk.h"
46 #include "yesno.h"
49 #define MAX_SHORTCUT_NAME 32
50 #define SHORTCUTS_FILENAME ROCKBOX_DIR "/shortcuts.txt"
51 static const char * const type_strings[SHORTCUT_TYPE_COUNT] = {
52 [SHORTCUT_SETTING] = "setting",
53 [SHORTCUT_FILE] = "file",
54 [SHORTCUT_DEBUGITEM] = "debug",
55 [SHORTCUT_BROWSER] = "browse",
56 [SHORTCUT_PLAYLISTMENU] = "playlist menu",
57 [SHORTCUT_SEPARATOR] = "separator",
58 [SHORTCUT_SHUTDOWN] = "shutdown",
59 [SHORTCUT_TIME] = "time",
62 struct shortcut {
63 enum shortcut_type type;
64 char name[MAX_SHORTCUT_NAME];
65 char talk_clip[MAX_PATH];
66 int icon;
67 union {
68 char path[MAX_PATH];
69 const struct settings_list *setting;
70 struct {
71 #if CONFIG_RTC
72 bool talktime;
73 #endif
74 int sleep_timeout;
75 } timedata;
76 } u;
78 #define SHORTCUTS_PER_HANDLE 32
79 struct shortcut_handle {
80 struct shortcut shortcuts[SHORTCUTS_PER_HANDLE];
81 int next_handle;
83 static int first_handle = 0;
84 static int shortcut_count = 0;
86 static void reset_shortcuts(void)
88 int current_handle = first_handle;
89 struct shortcut_handle *h = NULL;
90 while (current_handle > 0)
92 int next;
93 h = core_get_data(current_handle);
94 next = h->next_handle;
95 core_free(current_handle);
96 current_handle = next;
98 first_handle = 0;
99 shortcut_count = 0;
102 static struct shortcut* get_shortcut(int index)
104 int handle_count, handle_index;
105 int current_handle = first_handle;
106 struct shortcut_handle *h = NULL;
108 if (first_handle == 0)
110 first_handle = core_alloc("shortcuts_head", sizeof(struct shortcut_handle));
111 if (first_handle <= 0)
112 return NULL;
113 h = core_get_data(first_handle);
114 h->next_handle = 0;
115 current_handle = first_handle;
118 handle_count = index/SHORTCUTS_PER_HANDLE + 1;
119 handle_index = index%SHORTCUTS_PER_HANDLE;
120 do {
121 h = core_get_data(current_handle);
122 current_handle = h->next_handle;
123 handle_count--;
124 } while (handle_count > 0 && current_handle > 0);
125 if (handle_count > 0 && handle_index == 0)
127 char buf[32];
128 snprintf(buf, sizeof buf, "shortcuts_%d", index/SHORTCUTS_PER_HANDLE);
129 h->next_handle = core_alloc(buf, sizeof(struct shortcut_handle));
130 if (h->next_handle <= 0)
131 return NULL;
132 h = core_get_data(h->next_handle);
133 h->next_handle = 0;
135 return &h->shortcuts[handle_index];
138 static void remove_shortcut(int index)
140 int this = index, next = index + 1;
141 struct shortcut *prev = get_shortcut(this);
143 while (next <= shortcut_count)
145 struct shortcut *sc = get_shortcut(next);
146 memcpy(prev, sc, sizeof(struct shortcut));
147 next++;
148 prev = sc;
150 shortcut_count--;
153 static bool verify_shortcut(struct shortcut* sc)
155 switch (sc->type)
157 case SHORTCUT_UNDEFINED:
158 return false;
159 case SHORTCUT_BROWSER:
160 case SHORTCUT_FILE:
161 case SHORTCUT_PLAYLISTMENU:
162 return sc->u.path[0] != '\0';
163 case SHORTCUT_SETTING:
164 return sc->u.setting != NULL;
165 case SHORTCUT_TIME:
166 return sc->name[0] != '\0';
167 case SHORTCUT_DEBUGITEM:
168 case SHORTCUT_SEPARATOR:
169 case SHORTCUT_SHUTDOWN:
170 default:
171 break;
173 return true;
176 static void init_shortcut(struct shortcut* sc)
178 sc->type = SHORTCUT_UNDEFINED;
179 sc->name[0] = '\0';
180 sc->u.path[0] = '\0';
181 sc->talk_clip[0] = '\0';
182 sc->icon = Icon_NOICON;
185 static int first_idx_to_writeback = -1;
186 static bool overwrite_shortcuts = false;
187 static void shortcuts_ata_idle_callback(void* data)
189 (void)data;
190 int fd;
191 char buf[MAX_PATH];
192 int current_idx = first_idx_to_writeback;
193 int append = overwrite_shortcuts ? O_TRUNC : O_APPEND;
195 if (first_idx_to_writeback < 0)
196 return;
197 fd = open(SHORTCUTS_FILENAME, append|O_RDWR|O_CREAT, 0644);
198 if (fd < 0)
199 return;
200 while (current_idx < shortcut_count)
202 struct shortcut* sc = get_shortcut(current_idx++);
203 const char *type;
204 int len;
205 if (!sc)
206 break;
207 type = type_strings[sc->type];
208 len = snprintf(buf, MAX_PATH, "[shortcut]\ntype: %s\ndata: ", type);
209 write(fd, buf, len);
210 if (sc->type == SHORTCUT_SETTING)
211 write(fd, sc->u.setting->cfg_name, strlen(sc->u.setting->cfg_name));
212 else
213 write(fd, sc->u.path, strlen(sc->u.path));
214 write(fd, "\n\n", 2);
216 close(fd);
217 if (first_idx_to_writeback == 0)
219 /* reload all shortcuts because we appended to the shortcuts file which
220 * has not been read yet.
222 reset_shortcuts();
223 shortcuts_init();
225 first_idx_to_writeback = -1;
228 void shortcuts_add(enum shortcut_type type, const char* value)
230 struct shortcut* sc = get_shortcut(shortcut_count++);
231 if (!sc)
232 return;
233 init_shortcut(sc);
234 sc->type = type;
235 if (type == SHORTCUT_SETTING)
236 sc->u.setting = (void*)value;
237 else
238 strlcpy(sc->u.path, value, MAX_PATH);
240 if (first_idx_to_writeback < 0)
241 first_idx_to_writeback = shortcut_count - 1;
242 overwrite_shortcuts = false;
243 register_storage_idle_func(shortcuts_ata_idle_callback);
246 static int readline_cb(int n, char *buf, void *parameters)
248 (void)n;
249 (void)parameters;
250 struct shortcut **param = (struct shortcut**)parameters;
251 struct shortcut* sc = *param;
252 char *name, *value;
254 if (!strcasecmp(skip_whitespace(buf), "[shortcut]"))
256 if (sc && verify_shortcut(sc))
257 shortcut_count++;
258 sc = get_shortcut(shortcut_count);
259 if (!sc)
260 return 1;
261 init_shortcut(sc);
262 *param = sc;
264 else if (sc && settings_parseline(buf, &name, &value))
266 if (!strcmp(name, "type"))
268 int t = 0;
269 for (t=0; t<SHORTCUT_TYPE_COUNT && sc->type == SHORTCUT_UNDEFINED; t++)
270 if (!strcmp(value, type_strings[t]))
271 sc->type = t;
273 else if (!strcmp(name, "name"))
275 strlcpy(sc->name, value, MAX_SHORTCUT_NAME);
277 else if (!strcmp(name, "data"))
279 switch (sc->type)
281 case SHORTCUT_UNDEFINED:
282 case SHORTCUT_TYPE_COUNT:
283 *param = NULL;
284 break;
285 case SHORTCUT_BROWSER:
286 case SHORTCUT_FILE:
287 case SHORTCUT_DEBUGITEM:
288 case SHORTCUT_PLAYLISTMENU:
289 strlcpy(sc->u.path, value, MAX_PATH);
290 break;
291 case SHORTCUT_SETTING:
292 sc->u.setting = find_setting_by_cfgname(value, NULL);
293 break;
294 case SHORTCUT_TIME:
295 #if CONFIG_RTC
296 sc->u.timedata.talktime = false;
297 if (!strcasecmp(value, "talk"))
298 sc->u.timedata.talktime = true;
299 else
300 #endif
301 if (!strncasecmp(value, "sleep ", strlen("sleep ")))
302 sc->u.timedata.sleep_timeout = atoi(&value[strlen("sleep ")]);
303 else
304 sc->type = SHORTCUT_UNDEFINED; /* error */
305 break;
306 case SHORTCUT_SEPARATOR:
307 case SHORTCUT_SHUTDOWN:
308 break;
311 else if (!strcmp(name, "icon"))
313 if (!strcmp(value, "filetype") && sc->type != SHORTCUT_SETTING && sc->u.path[0])
315 sc->icon = filetype_get_icon(filetype_get_attr(sc->u.path));
317 else
319 sc->icon = atoi(value);
322 else if (!strcmp(name, "talkclip"))
324 strlcpy(sc->talk_clip, value, MAX_PATH);
327 return 0;
330 void shortcuts_init(void)
332 int fd;
333 char buf[512];
334 struct shortcut *param = NULL;
335 struct shortcut_handle *h;
336 shortcut_count = 0;
337 fd = open_utf8(SHORTCUTS_FILENAME, O_RDONLY);
338 if (fd < 0)
339 return;
340 first_handle = core_alloc("shortcuts_head", sizeof(struct shortcut_handle));
341 if (first_handle <= 0)
342 return;
343 h = core_get_data(first_handle);
344 h->next_handle = 0;
345 fast_readline(fd, buf, sizeof buf, &param, readline_cb);
346 close(fd);
347 if (param && verify_shortcut(param))
348 shortcut_count++;
351 static const char * shortcut_menu_get_name(int selected_item, void * data,
352 char * buffer, size_t buffer_len)
354 (void)data;
355 (void)buffer;
356 (void)buffer_len;
357 struct shortcut *sc = get_shortcut(selected_item);
358 if (!sc)
359 return "";
360 if (sc->type == SHORTCUT_SETTING)
361 return sc->name[0] ? sc->name : P2STR(ID2P(sc->u.setting->lang_id));
362 else if (sc->type == SHORTCUT_SEPARATOR || sc->type == SHORTCUT_TIME)
363 return sc->name;
364 else if (sc->type == SHORTCUT_SHUTDOWN && sc->name[0] == '\0')
366 /* No translation support as only soft_shutdown has LANG_SHUTDOWN defined */
367 return type_strings[SHORTCUT_SHUTDOWN];
369 return sc->name[0] ? sc->name : sc->u.path;
372 static int shortcut_menu_get_action(int action, struct gui_synclist *lists)
374 (void)lists;
375 if (action == ACTION_STD_OK)
376 return ACTION_STD_CANCEL;
377 else if (action == ACTION_STD_CONTEXT)
379 int selection = gui_synclist_get_sel_pos(lists);
381 if (!yesno_pop(ID2P(LANG_REALLY_DELETE)))
382 return ACTION_REDRAW;
384 remove_shortcut(selection);
385 gui_synclist_set_nb_items(lists, shortcut_count);
386 if (selection >= shortcut_count)
387 gui_synclist_select_item(lists, shortcut_count - 1);
388 first_idx_to_writeback = 0;
389 overwrite_shortcuts = true;
390 shortcuts_ata_idle_callback(NULL);
391 if (shortcut_count == 0)
392 return ACTION_STD_CANCEL;
393 return ACTION_REDRAW;
395 return action;
398 static enum themable_icons shortcut_menu_get_icon(int selected_item, void * data)
400 (void)data;
401 struct shortcut *sc = get_shortcut(selected_item);
402 if (!sc)
403 return Icon_NOICON;
404 if (sc->icon == Icon_NOICON)
406 switch (sc->type)
408 case SHORTCUT_FILE:
409 return filetype_get_icon(filetype_get_attr(sc->u.path));
410 case SHORTCUT_BROWSER:
411 return Icon_Folder;
412 case SHORTCUT_SETTING:
413 return Icon_Menu_setting;
414 case SHORTCUT_DEBUGITEM:
415 return Icon_Menu_functioncall;
416 case SHORTCUT_PLAYLISTMENU:
417 return Icon_Playlist;
418 case SHORTCUT_SHUTDOWN:
419 return Icon_System_menu;
420 case SHORTCUT_TIME:
421 return Icon_Menu_functioncall;
422 default:
423 break;
426 return sc->icon;
429 static int shortcut_menu_speak_item(int selected_item, void * data)
431 (void)data;
432 struct shortcut *sc = get_shortcut(selected_item);
433 if (sc && sc->talk_clip[0])
434 talk_file(NULL, NULL, sc->talk_clip, NULL, NULL, false);
435 return 0;
438 void talk_timedate(void);
439 const char* sleep_timer_formatter(char* buffer, size_t buffer_size,
440 int value, const char* unit);
442 int do_shortcut_menu(void *ignored)
444 (void)ignored;
445 struct simplelist_info list;
446 struct shortcut *sc;
447 int done = GO_TO_PREVIOUS;
448 if (first_handle == 0)
449 shortcuts_init();
450 simplelist_info_init(&list, P2STR(ID2P(LANG_SHORTCUTS)), shortcut_count, NULL);
451 list.get_name = shortcut_menu_get_name;
452 list.action_callback = shortcut_menu_get_action;
453 if (global_settings.show_icons)
454 list.get_icon = shortcut_menu_get_icon;
455 list.title_icon = Icon_Bookmark;
456 if (global_settings.talk_menu)
457 list.get_talk = shortcut_menu_speak_item;
459 if (shortcut_count == 0)
461 splash(HZ, str(LANG_NO_FILES));
462 return GO_TO_PREVIOUS;
464 push_current_activity(ACTIVITY_SHORTCUTSMENU);
466 while (done == GO_TO_PREVIOUS)
468 if (simplelist_show_list(&list))
469 break; /* some error happened?! */
470 if (list.selection == -1)
471 break;
472 else
474 sc = get_shortcut(list.selection);
475 if (!sc)
476 continue;
477 switch (sc->type)
479 case SHORTCUT_PLAYLISTMENU:
480 if (!file_exists(sc->u.path))
482 splash(HZ, ID2P(LANG_NO_FILES));
483 break;
485 else
487 onplay_show_playlist_menu(sc->u.path);
489 break;
490 case SHORTCUT_FILE:
491 if (!file_exists(sc->u.path))
493 splash(HZ, ID2P(LANG_NO_FILES));
494 break;
496 /* else fall through */
497 case SHORTCUT_BROWSER:
499 struct browse_context browse;
500 browse_context_init(&browse, global_settings.dirfilter, 0,
501 NULL, NOICON, sc->u.path, NULL);
502 if (sc->type == SHORTCUT_FILE)
503 browse.flags |= BROWSE_RUNFILE;
504 done = rockbox_browse(&browse);
506 break;
507 case SHORTCUT_SETTING:
508 do_setting_screen(sc->u.setting,
509 sc->name[0] ? sc->name : P2STR(ID2P(sc->u.setting->lang_id)),NULL);
510 break;
511 case SHORTCUT_DEBUGITEM:
512 run_debug_screen(sc->u.path);
513 break;
514 case SHORTCUT_SHUTDOWN:
515 #if CONFIG_CHARGING
516 if (charger_inserted())
517 charging_splash();
518 else
519 #endif
520 sys_poweroff();
521 break;
522 case SHORTCUT_TIME:
523 #if CONFIG_RTC
524 if (sc->u.timedata.talktime) {
525 talk_timedate();
526 talk_force_enqueue_next();
527 } else
528 #endif
530 char timer_buf[10];
531 set_sleeptimer_duration(sc->u.timedata.sleep_timeout);
532 splashf(HZ, "%s (%s)", str(LANG_SLEEP_TIMER),
533 sleep_timer_formatter(timer_buf, sizeof(timer_buf),
534 sc->u.timedata.sleep_timeout, NULL));
536 break;
537 case SHORTCUT_UNDEFINED:
538 default:
539 break;
543 pop_current_activity();
544 return done;