The threading model should be set from configure, not config.h.
[maemo-rb.git] / apps / shortcuts.c
blobd7868461a74fe15dd9732e0c80ab11ca7068bc82
1 /***************************************************************************
3 * __________ __ ___.
4 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
5 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
6 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
7 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
8 * \/ \/ \/ \/ \/
9 * $Id$
11 * Copyright (C) 2011 Jonathan Gordon
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ****************************************************************************/
23 #include <stdbool.h>
24 #include <stdlib.h>
25 #include "config.h"
26 #include "system.h"
27 #include "powermgmt.h"
28 #include "power.h"
29 #include "action.h"
30 #include "ata_idle_notify.h"
31 #include "debug_menu.h"
32 #include "core_alloc.h"
33 #include "list.h"
34 #include "settings.h"
35 #include "settings_list.h"
36 #include "lang.h"
37 #include "menu.h"
38 #include "misc.h"
39 #include "tree.h"
40 #include "splash.h"
41 #include "filefuncs.h"
42 #include "filetypes.h"
43 #include "shortcuts.h"
44 #include "onplay.h"
45 #include "screens.h"
46 #include "talk.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 bool verify_shortcut(struct shortcut* sc)
140 switch (sc->type)
142 case SHORTCUT_UNDEFINED:
143 return false;
144 case SHORTCUT_BROWSER:
145 case SHORTCUT_FILE:
146 case SHORTCUT_PLAYLISTMENU:
147 return sc->u.path[0] != '\0';
148 case SHORTCUT_SETTING:
149 return sc->u.setting != NULL;
150 case SHORTCUT_TIME:
151 return sc->name[0] != '\0';
152 case SHORTCUT_DEBUGITEM:
153 case SHORTCUT_SEPARATOR:
154 case SHORTCUT_SHUTDOWN:
155 default:
156 break;
158 return true;
161 static void init_shortcut(struct shortcut* sc)
163 sc->type = SHORTCUT_UNDEFINED;
164 sc->name[0] = '\0';
165 sc->u.path[0] = '\0';
166 sc->talk_clip[0] = '\0';
167 sc->icon = Icon_NOICON;
170 static int first_idx_to_writeback = -1;
171 static void shortcuts_ata_idle_callback(void* data)
173 (void)data;
174 int fd;
175 char buf[MAX_PATH];
176 int current_idx = first_idx_to_writeback;
177 if (first_idx_to_writeback < 0)
178 return;
179 fd = open(SHORTCUTS_FILENAME, O_APPEND|O_RDWR|O_CREAT, 0644);
180 if (fd < 0)
181 return;
182 while (current_idx < shortcut_count)
184 struct shortcut* sc = get_shortcut(current_idx++);
185 const char *type;
186 int len;
187 if (!sc)
188 break;
189 type = type_strings[sc->type];
190 len = snprintf(buf, MAX_PATH, "[shortcut]\ntype: %s\ndata: ", type);
191 write(fd, buf, len);
192 if (sc->type == SHORTCUT_SETTING)
193 write(fd, sc->u.setting->cfg_name, strlen(sc->u.setting->cfg_name));
194 else
195 write(fd, sc->u.path, strlen(sc->u.path));
196 write(fd, "\n\n", 2);
198 close(fd);
199 if (first_idx_to_writeback == 0)
201 /* reload all shortcuts because we appended to the shortcuts file which
202 * has not been read yet.
204 reset_shortcuts();
205 shortcuts_init();
207 first_idx_to_writeback = -1;
210 void shortcuts_add(enum shortcut_type type, const char* value)
212 struct shortcut* sc = get_shortcut(shortcut_count++);
213 if (!sc)
214 return;
215 init_shortcut(sc);
216 sc->type = type;
217 if (type == SHORTCUT_SETTING)
218 sc->u.setting = (void*)value;
219 else
220 strlcpy(sc->u.path, value, MAX_PATH);
221 if (first_idx_to_writeback < 0)
222 first_idx_to_writeback = shortcut_count - 1;
223 register_storage_idle_func(shortcuts_ata_idle_callback);
226 static int readline_cb(int n, char *buf, void *parameters)
228 (void)n;
229 (void)parameters;
230 struct shortcut **param = (struct shortcut**)parameters;
231 struct shortcut* sc = *param;
232 char *name, *value;
234 if (!strcasecmp(skip_whitespace(buf), "[shortcut]"))
236 if (sc && verify_shortcut(sc))
237 shortcut_count++;
238 sc = get_shortcut(shortcut_count);
239 if (!sc)
240 return 1;
241 init_shortcut(sc);
242 *param = sc;
244 else if (sc && settings_parseline(buf, &name, &value))
246 if (!strcmp(name, "type"))
248 int t = 0;
249 for (t=0; t<SHORTCUT_TYPE_COUNT && sc->type == SHORTCUT_UNDEFINED; t++)
250 if (!strcmp(value, type_strings[t]))
251 sc->type = t;
253 else if (!strcmp(name, "name"))
255 strlcpy(sc->name, value, MAX_SHORTCUT_NAME);
257 else if (!strcmp(name, "data"))
259 switch (sc->type)
261 case SHORTCUT_UNDEFINED:
262 case SHORTCUT_TYPE_COUNT:
263 *param = NULL;
264 break;
265 case SHORTCUT_BROWSER:
266 case SHORTCUT_FILE:
267 case SHORTCUT_DEBUGITEM:
268 case SHORTCUT_PLAYLISTMENU:
269 strlcpy(sc->u.path, value, MAX_PATH);
270 break;
271 case SHORTCUT_SETTING:
272 sc->u.setting = find_setting_by_cfgname(value, NULL);
273 break;
274 case SHORTCUT_TIME:
275 #if CONFIG_RTC
276 sc->u.timedata.talktime = false;
277 if (!strcasecmp(value, "talk"))
278 sc->u.timedata.talktime = true;
279 else
280 #endif
281 if (!strncasecmp(value, "sleep ", strlen("sleep ")))
282 sc->u.timedata.sleep_timeout = atoi(&value[strlen("sleep ")]);
283 else
284 sc->type = SHORTCUT_UNDEFINED; /* error */
285 break;
286 case SHORTCUT_SEPARATOR:
287 case SHORTCUT_SHUTDOWN:
288 break;
291 else if (!strcmp(name, "icon"))
293 if (!strcmp(value, "filetype") && sc->type != SHORTCUT_SETTING && sc->u.path[0])
295 sc->icon = filetype_get_icon(filetype_get_attr(sc->u.path));
297 else
299 sc->icon = atoi(value);
302 else if (!strcmp(name, "talkclip"))
304 strlcpy(sc->talk_clip, value, MAX_PATH);
307 return 0;
310 void shortcuts_init(void)
312 int fd;
313 char buf[512];
314 struct shortcut *param = NULL;
315 struct shortcut_handle *h;
316 shortcut_count = 0;
317 fd = open_utf8(SHORTCUTS_FILENAME, O_RDONLY);
318 if (fd < 0)
319 return;
320 first_handle = core_alloc("shortcuts_head", sizeof(struct shortcut_handle));
321 if (first_handle <= 0)
322 return;
323 h = core_get_data(first_handle);
324 h->next_handle = 0;
325 fast_readline(fd, buf, sizeof buf, &param, readline_cb);
326 close(fd);
327 if (param && verify_shortcut(param))
328 shortcut_count++;
331 static const char * shortcut_menu_get_name(int selected_item, void * data,
332 char * buffer, size_t buffer_len)
334 (void)data;
335 (void)buffer;
336 (void)buffer_len;
337 struct shortcut *sc = get_shortcut(selected_item);
338 if (!sc)
339 return "";
340 if (sc->type == SHORTCUT_SETTING)
341 return sc->name[0] ? sc->name : P2STR(ID2P(sc->u.setting->lang_id));
342 else if (sc->type == SHORTCUT_SEPARATOR || sc->type == SHORTCUT_TIME)
343 return sc->name;
344 else if (sc->type == SHORTCUT_SHUTDOWN && sc->name[0] == '\0')
346 /* No translation support as only soft_shutdown has LANG_SHUTDOWN defined */
347 return type_strings[SHORTCUT_SHUTDOWN];
349 return sc->name[0] ? sc->name : sc->u.path;
352 static int shortcut_menu_get_action(int action, struct gui_synclist *lists)
354 (void)lists;
355 if (action == ACTION_STD_OK)
356 return ACTION_STD_CANCEL;
357 return action;
360 static enum themable_icons shortcut_menu_get_icon(int selected_item, void * data)
362 (void)data;
363 struct shortcut *sc = get_shortcut(selected_item);
364 if (!sc)
365 return Icon_NOICON;
366 if (sc->icon == Icon_NOICON)
368 switch (sc->type)
370 case SHORTCUT_FILE:
371 return filetype_get_icon(filetype_get_attr(sc->u.path));
372 case SHORTCUT_BROWSER:
373 return Icon_Folder;
374 case SHORTCUT_SETTING:
375 return Icon_Menu_setting;
376 case SHORTCUT_DEBUGITEM:
377 return Icon_Menu_functioncall;
378 case SHORTCUT_PLAYLISTMENU:
379 return Icon_Playlist;
380 case SHORTCUT_SHUTDOWN:
381 return Icon_System_menu;
382 case SHORTCUT_TIME:
383 return Icon_Menu_functioncall;
384 default:
385 break;
388 return sc->icon;
391 static int shortcut_menu_speak_item(int selected_item, void * data)
393 (void)data;
394 struct shortcut *sc = get_shortcut(selected_item);
395 if (sc && sc->talk_clip[0])
396 talk_file(NULL, NULL, sc->talk_clip, NULL, NULL, false);
397 return 0;
400 void talk_timedate(void);
401 const char* sleep_timer_formatter(char* buffer, size_t buffer_size,
402 int value, const char* unit);
404 int do_shortcut_menu(void *ignored)
406 (void)ignored;
407 struct simplelist_info list;
408 struct shortcut *sc;
409 int done = GO_TO_PREVIOUS;
410 if (first_handle == 0)
411 shortcuts_init();
412 simplelist_info_init(&list, P2STR(ID2P(LANG_SHORTCUTS)), shortcut_count, NULL);
413 list.get_name = shortcut_menu_get_name;
414 list.action_callback = shortcut_menu_get_action;
415 if (global_settings.show_icons)
416 list.get_icon = shortcut_menu_get_icon;
417 list.title_icon = Icon_Bookmark;
418 if (global_settings.talk_menu)
419 list.get_talk = shortcut_menu_speak_item;
421 if (shortcut_count == 0)
423 splash(HZ, str(LANG_NO_FILES));
424 return GO_TO_PREVIOUS;
426 push_current_activity(ACTIVITY_SHORTCUTSMENU);
428 while (done == GO_TO_PREVIOUS)
430 if (simplelist_show_list(&list))
431 break; /* some error happened?! */
432 if (list.selection == -1)
433 break;
434 else
436 sc = get_shortcut(list.selection);
437 if (!sc)
438 continue;
439 switch (sc->type)
441 case SHORTCUT_PLAYLISTMENU:
442 if (!file_exists(sc->u.path))
444 splash(HZ, ID2P(LANG_NO_FILES));
445 break;
447 else
449 onplay_show_playlist_menu(sc->u.path);
451 break;
452 case SHORTCUT_FILE:
453 if (!file_exists(sc->u.path))
455 splash(HZ, ID2P(LANG_NO_FILES));
456 break;
458 /* else fall through */
459 case SHORTCUT_BROWSER:
461 struct browse_context browse;
462 browse_context_init(&browse, global_settings.dirfilter, 0,
463 NULL, NOICON, sc->u.path, NULL);
464 if (sc->type == SHORTCUT_FILE)
465 browse.flags |= BROWSE_RUNFILE;
466 done = rockbox_browse(&browse);
468 break;
469 case SHORTCUT_SETTING:
470 do_setting_screen(sc->u.setting,
471 sc->name[0] ? sc->name : P2STR(ID2P(sc->u.setting->lang_id)),NULL);
472 break;
473 case SHORTCUT_DEBUGITEM:
474 run_debug_screen(sc->u.path);
475 break;
476 case SHORTCUT_SHUTDOWN:
477 #if CONFIG_CHARGING
478 if (charger_inserted())
479 charging_splash();
480 else
481 #endif
482 sys_poweroff();
483 break;
484 case SHORTCUT_TIME:
485 #if CONFIG_RTC
486 if (sc->u.timedata.talktime) {
487 talk_timedate();
488 talk_force_enqueue_next();
489 } else
490 #endif
492 char timer_buf[10];
493 set_sleep_timer(sc->u.timedata.sleep_timeout * 60);
494 splashf(HZ, "%s (%s)", str(LANG_SLEEP_TIMER),
495 sleep_timer_formatter(timer_buf, sizeof(timer_buf),
496 sc->u.timedata.sleep_timeout, NULL));
498 break;
499 case SHORTCUT_UNDEFINED:
500 default:
501 break;
505 pop_current_activity();
506 return done;