Don't load the icons unless show_icons is actually enabled. And respect that setting...
[maemo-rb.git] / apps / shortcuts.c
blob8ded75c1f2f872d37283feec593378d0a0ba1ea8
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 "action.h"
28 #include "ata_idle_notify.h"
29 #include "debug_menu.h"
30 #include "core_alloc.h"
31 #include "list.h"
32 #include "settings.h"
33 #include "settings_list.h"
34 #include "lang.h"
35 #include "menu.h"
36 #include "misc.h"
37 #include "tree.h"
38 #include "splash.h"
39 #include "filefuncs.h"
40 #include "filetypes.h"
41 #include "shortcuts.h"
42 #include "onplay.h"
46 #define MAX_SHORTCUT_NAME 32
47 #define SHORTCUTS_FILENAME ROCKBOX_DIR "/shortcuts.txt"
48 char *type_strings[SHORTCUT_TYPE_COUNT] = {
49 [SHORTCUT_SETTING] = "setting",
50 [SHORTCUT_FILE] = "file",
51 [SHORTCUT_DEBUGITEM] = "debug",
52 [SHORTCUT_BROWSER] = "browse",
53 [SHORTCUT_PLAYLISTMENU] = "playlist menu",
54 [SHORTCUT_SEPARATOR] = "separator",
58 struct shortcut {
59 enum shortcut_type type;
60 char name[MAX_SHORTCUT_NAME];
61 int icon;
62 union {
63 char path[MAX_PATH];
64 const struct settings_list *setting;
65 } u;
67 #define SHORTCUTS_PER_HANDLE 32
68 struct shortcut_handle {
69 struct shortcut shortcuts[SHORTCUTS_PER_HANDLE];
70 int next_handle;
72 static int first_handle = 0;
73 static int shortcut_count = 0;
75 static void reset_shortcuts(void)
77 int current_handle = first_handle;
78 struct shortcut_handle *h = NULL;
79 while (current_handle > 0)
81 int next;
82 h = core_get_data(current_handle);
83 next = h->next_handle;
84 core_free(current_handle);
85 current_handle = next;
87 first_handle = 0;
88 shortcut_count = 0;
91 static struct shortcut* get_shortcut(int index)
93 int handle_count, handle_index;
94 int current_handle = first_handle;
95 struct shortcut_handle *h = NULL;
97 if (first_handle == 0)
99 first_handle = core_alloc("shortcuts_head", sizeof(struct shortcut_handle));
100 if (first_handle <= 0)
101 return NULL;
102 h = core_get_data(first_handle);
103 h->next_handle = 0;
104 current_handle = first_handle;
107 handle_count = index/SHORTCUTS_PER_HANDLE + 1;
108 handle_index = index%SHORTCUTS_PER_HANDLE;
109 do {
110 h = core_get_data(current_handle);
111 current_handle = h->next_handle;
112 handle_count--;
113 } while (handle_count > 0 && current_handle > 0);
114 if (handle_count > 0 && handle_index == 0)
116 char buf[32];
117 snprintf(buf, sizeof buf, "shortcuts_%d", index/SHORTCUTS_PER_HANDLE);
118 h->next_handle = core_alloc(buf, sizeof(struct shortcut_handle));
119 if (h->next_handle <= 0)
120 return NULL;
121 h = core_get_data(h->next_handle);
122 h->next_handle = 0;
124 return &h->shortcuts[handle_index];
127 bool verify_shortcut(struct shortcut* sc)
129 switch (sc->type)
131 case SHORTCUT_UNDEFINED:
132 return false;
133 case SHORTCUT_BROWSER:
134 case SHORTCUT_FILE:
135 case SHORTCUT_PLAYLISTMENU:
136 if (sc->u.path[0] == '\0')
137 return false;
138 break;
139 case SHORTCUT_SETTING:
140 return sc->u.setting != NULL;
141 case SHORTCUT_DEBUGITEM:
142 case SHORTCUT_SEPARATOR:
143 default:
144 break;
146 return true;
149 static void init_shortcut(struct shortcut* sc)
151 sc->type = SHORTCUT_UNDEFINED;
152 sc->name[0] = '\0';
153 sc->u.path[0] = '\0';
154 sc->icon = Icon_NOICON;
156 static int first_idx_to_writeback = -1;
157 void shortcuts_ata_idle_callback(void* data)
159 (void)data;
160 int fd;
161 char buf[MAX_PATH];
162 int current_idx = first_idx_to_writeback;
163 if (first_idx_to_writeback < 0)
164 return;
165 fd = open(SHORTCUTS_FILENAME, O_APPEND|O_RDWR|O_CREAT, 0644);
166 if (fd < 0)
167 return;
168 while (current_idx < shortcut_count)
170 struct shortcut* sc = get_shortcut(current_idx++);
171 char *type;
172 int len;
173 if (!sc)
174 break;
175 type = type_strings[sc->type];
176 len = snprintf(buf, MAX_PATH, "[shortcut]\ntype: %s\ndata: ", type);
177 write(fd, buf, len);
178 if (sc->type == SHORTCUT_SETTING)
179 write(fd, sc->u.setting->cfg_name, strlen(sc->u.setting->cfg_name));
180 else
181 write(fd, sc->u.path, strlen(sc->u.path));
182 write(fd, "\n\n", 2);
184 close(fd);
185 if (first_idx_to_writeback == 0)
187 /* reload all shortcuts because we appended to the shortcuts file which
188 * has not been read yet.
190 reset_shortcuts();
191 shortcuts_init();
193 first_idx_to_writeback = -1;
195 void shortcuts_add(enum shortcut_type type, char* value)
197 struct shortcut* sc = get_shortcut(shortcut_count++);
198 if (!sc)
199 return;
200 init_shortcut(sc);
201 sc->type = type;
202 if (type == SHORTCUT_SETTING)
203 sc->u.setting = (void*)value;
204 else
205 strlcpy(sc->u.path, value, MAX_PATH);
206 if (first_idx_to_writeback < 0)
207 first_idx_to_writeback = shortcut_count - 1;
208 register_storage_idle_func(shortcuts_ata_idle_callback);
212 int readline_cb(int n, char *buf, void *parameters)
214 (void)n;
215 (void)parameters;
216 struct shortcut **param = (struct shortcut**)parameters;
217 struct shortcut* sc = *param;
218 char *name, *value;
220 if (!strcasecmp(skip_whitespace(buf), "[shortcut]"))
222 if (sc && verify_shortcut(sc))
223 shortcut_count++;
224 sc = get_shortcut(shortcut_count);
225 if (!sc)
226 return 1;
227 init_shortcut(sc);
228 *param = sc;
230 else if (sc && settings_parseline(buf, &name, &value))
232 if (!strcmp(name, "type"))
234 int t = 0;
235 for (t=0; t<SHORTCUT_TYPE_COUNT && sc->type == SHORTCUT_UNDEFINED; t++)
236 if (!strcmp(value, type_strings[t]))
237 sc->type = t;
239 else if (!strcmp(name, "name"))
241 strlcpy(sc->name, value, MAX_SHORTCUT_NAME);
243 else if (!strcmp(name, "data"))
245 switch (sc->type)
247 case SHORTCUT_UNDEFINED:
248 case SHORTCUT_TYPE_COUNT:
249 *param = NULL;
250 break;
251 case SHORTCUT_BROWSER:
252 case SHORTCUT_FILE:
253 case SHORTCUT_DEBUGITEM:
254 case SHORTCUT_PLAYLISTMENU:
255 strlcpy(sc->u.path, value, MAX_PATH);
256 break;
257 case SHORTCUT_SETTING:
258 sc->u.setting = find_setting_by_cfgname(value, NULL);
259 break;
260 case SHORTCUT_SEPARATOR:
261 break;
264 else if (!strcmp(name, "icon"))
266 if (!strcmp(value, "filetype") && sc->type != SHORTCUT_SETTING && sc->u.path[0])
268 sc->icon = filetype_get_icon(filetype_get_attr(sc->u.path));
270 else
272 sc->icon = atoi(value);
276 return 0;
278 void shortcuts_init(void)
280 int fd;
281 char buf[512];
282 struct shortcut *param = NULL;
283 struct shortcut_handle *h;
284 shortcut_count = 0;
285 fd = open_utf8(SHORTCUTS_FILENAME, O_RDONLY);
286 if (fd < 0)
287 return;
288 first_handle = core_alloc("shortcuts_head", sizeof(struct shortcut_handle));
289 if (first_handle <= 0)
290 return;
291 h = core_get_data(first_handle);
292 h->next_handle = 0;
293 fast_readline(fd, buf, sizeof buf, &param, readline_cb);
294 close(fd);
295 if (param && verify_shortcut(param))
296 shortcut_count++;
299 const char * shortcut_menu_get_name(int selected_item, void * data,
300 char * buffer, size_t buffer_len)
302 (void)data;
303 (void)buffer;
304 (void)buffer_len;
305 struct shortcut *sc = get_shortcut(selected_item);
306 if (!sc)
307 return "";
308 if (sc->type == SHORTCUT_SETTING)
309 return sc->name[0] ? sc->name : P2STR(ID2P(sc->u.setting->lang_id));
310 else if (sc->type == SHORTCUT_SEPARATOR)
311 return sc->name;
312 return sc->name[0] ? sc->name : sc->u.path;
315 int shortcut_menu_get_action(int action, struct gui_synclist *lists)
317 (void)lists;
318 if (action == ACTION_STD_OK)
319 return ACTION_STD_CANCEL;
320 return action;
322 enum themable_icons shortcut_menu_get_icon(int selected_item, void * data)
324 (void)data;
325 struct shortcut *sc = get_shortcut(selected_item);
326 if (!sc)
327 return Icon_NOICON;
328 if (sc->icon == Icon_NOICON)
330 switch (sc->type)
332 case SHORTCUT_FILE:
333 return filetype_get_icon(filetype_get_attr(sc->u.path));
334 case SHORTCUT_BROWSER:
335 return Icon_Folder;
336 case SHORTCUT_SETTING:
337 return Icon_Menu_setting;
338 case SHORTCUT_DEBUGITEM:
339 return Icon_Menu_functioncall;
340 case SHORTCUT_PLAYLISTMENU:
341 return Icon_Playlist;
342 default:
343 break;
346 return sc->icon;
349 int do_shortcut_menu(void *ignored)
351 (void)ignored;
352 struct simplelist_info list;
353 struct shortcut *sc;
354 int done = GO_TO_PREVIOUS;
355 if (first_handle == 0)
356 shortcuts_init();
357 simplelist_info_init(&list, P2STR(ID2P(LANG_SHORTCUTS)), shortcut_count, NULL);
358 list.get_name = shortcut_menu_get_name;
359 list.action_callback = shortcut_menu_get_action;
360 if (global_settings.show_icons)
361 list.get_icon = shortcut_menu_get_icon;
362 list.title_icon = Icon_Bookmark;
364 push_current_activity(ACTIVITY_SHORTCUTSMENU);
366 while (done == GO_TO_PREVIOUS)
368 if (simplelist_show_list(&list))
369 break; /* some error happened?! */
370 if (list.selection == -1)
371 break;
372 else
374 sc = get_shortcut(list.selection);
375 if (!sc)
376 continue;
377 switch (sc->type)
379 case SHORTCUT_PLAYLISTMENU:
380 if (!file_exists(sc->u.path))
382 splash(HZ, ID2P(LANG_NO_FILES));
383 break;
385 else
387 onplay_show_playlist_menu(sc->u.path);
389 break;
390 case SHORTCUT_FILE:
391 if (!file_exists(sc->u.path))
393 splash(HZ, ID2P(LANG_NO_FILES));
394 break;
396 /* else fall through */
397 case SHORTCUT_BROWSER:
399 struct browse_context browse;
400 browse_context_init(&browse, global_settings.dirfilter, 0,
401 NULL, NOICON, sc->u.path, NULL);
402 if (sc->type == SHORTCUT_FILE)
403 browse.flags |= BROWSE_RUNFILE;
404 done = rockbox_browse(&browse);
406 break;
407 case SHORTCUT_SETTING:
408 do_setting_screen(sc->u.setting,
409 sc->name[0] ? sc->name : P2STR(ID2P(sc->u.setting->lang_id)),NULL);
410 break;
411 case SHORTCUT_DEBUGITEM:
412 run_debug_screen(sc->u.path);
413 break;
414 case SHORTCUT_UNDEFINED:
415 default:
416 break;
420 pop_current_activity();
421 return done;