1 /***************************************************************************
4 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
5 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
6 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
7 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
28 #include "ata_idle_notify.h"
29 #include "debug_menu.h"
30 #include "core_alloc.h"
33 #include "settings_list.h"
39 #include "filefuncs.h"
40 #include "filetypes.h"
41 #include "shortcuts.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",
59 enum shortcut_type type
;
60 char name
[MAX_SHORTCUT_NAME
];
64 const struct settings_list
*setting
;
67 #define SHORTCUTS_PER_HANDLE 32
68 struct shortcut_handle
{
69 struct shortcut shortcuts
[SHORTCUTS_PER_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)
82 h
= core_get_data(current_handle
);
83 next
= h
->next_handle
;
84 core_free(current_handle
);
85 current_handle
= next
;
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)
102 h
= core_get_data(first_handle
);
104 current_handle
= first_handle
;
107 handle_count
= index
/SHORTCUTS_PER_HANDLE
+ 1;
108 handle_index
= index
%SHORTCUTS_PER_HANDLE
;
110 h
= core_get_data(current_handle
);
111 current_handle
= h
->next_handle
;
113 } while (handle_count
> 0 && current_handle
> 0);
114 if (handle_count
> 0 && handle_index
== 0)
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)
121 h
= core_get_data(h
->next_handle
);
124 return &h
->shortcuts
[handle_index
];
127 bool verify_shortcut(struct shortcut
* sc
)
131 case SHORTCUT_UNDEFINED
:
133 case SHORTCUT_BROWSER
:
135 case SHORTCUT_PLAYLISTMENU
:
136 if (sc
->u
.path
[0] == '\0')
139 case SHORTCUT_SETTING
:
140 return sc
->u
.setting
!= NULL
;
141 case SHORTCUT_DEBUGITEM
:
142 case SHORTCUT_SEPARATOR
:
149 static void init_shortcut(struct shortcut
* sc
)
151 sc
->type
= SHORTCUT_UNDEFINED
;
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
)
162 int current_idx
= first_idx_to_writeback
;
163 if (first_idx_to_writeback
< 0)
165 fd
= open(SHORTCUTS_FILENAME
, O_APPEND
|O_RDWR
|O_CREAT
, 0644);
168 while (current_idx
< shortcut_count
)
170 struct shortcut
* sc
= get_shortcut(current_idx
++);
175 type
= type_strings
[sc
->type
];
176 len
= snprintf(buf
, MAX_PATH
, "[shortcut]\ntype: %s\ndata: ", type
);
178 if (sc
->type
== SHORTCUT_SETTING
)
179 write(fd
, sc
->u
.setting
->cfg_name
, strlen(sc
->u
.setting
->cfg_name
));
181 write(fd
, sc
->u
.path
, strlen(sc
->u
.path
));
182 write(fd
, "\n\n", 2);
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.
193 first_idx_to_writeback
= -1;
195 void shortcuts_add(enum shortcut_type type
, char* value
)
197 struct shortcut
* sc
= get_shortcut(shortcut_count
++);
202 if (type
== SHORTCUT_SETTING
)
203 sc
->u
.setting
= (void*)value
;
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
)
216 struct shortcut
**param
= (struct shortcut
**)parameters
;
217 struct shortcut
* sc
= *param
;
220 if (!strcasecmp(skip_whitespace(buf
), "[shortcut]"))
222 if (sc
&& verify_shortcut(sc
))
224 sc
= get_shortcut(shortcut_count
);
230 else if (sc
&& settings_parseline(buf
, &name
, &value
))
232 if (!strcmp(name
, "type"))
235 for (t
=0; t
<SHORTCUT_TYPE_COUNT
&& sc
->type
== SHORTCUT_UNDEFINED
; t
++)
236 if (!strcmp(value
, type_strings
[t
]))
239 else if (!strcmp(name
, "name"))
241 strlcpy(sc
->name
, value
, MAX_SHORTCUT_NAME
);
243 else if (!strcmp(name
, "data"))
247 case SHORTCUT_UNDEFINED
:
248 case SHORTCUT_TYPE_COUNT
:
251 case SHORTCUT_BROWSER
:
253 case SHORTCUT_DEBUGITEM
:
254 case SHORTCUT_PLAYLISTMENU
:
255 strlcpy(sc
->u
.path
, value
, MAX_PATH
);
257 case SHORTCUT_SETTING
:
258 sc
->u
.setting
= find_setting_by_cfgname(value
, NULL
);
260 case SHORTCUT_SEPARATOR
:
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
));
272 sc
->icon
= atoi(value
);
278 void shortcuts_init(void)
282 struct shortcut
*param
= NULL
;
283 struct shortcut_handle
*h
;
285 fd
= open_utf8(SHORTCUTS_FILENAME
, O_RDONLY
);
288 first_handle
= core_alloc("shortcuts_head", sizeof(struct shortcut_handle
));
289 if (first_handle
<= 0)
291 h
= core_get_data(first_handle
);
293 fast_readline(fd
, buf
, sizeof buf
, ¶m
, readline_cb
);
295 if (param
&& verify_shortcut(param
))
299 const char * shortcut_menu_get_name(int selected_item
, void * data
,
300 char * buffer
, size_t buffer_len
)
305 struct shortcut
*sc
= get_shortcut(selected_item
);
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
)
312 return sc
->name
[0] ? sc
->name
: sc
->u
.path
;
315 int shortcut_menu_get_action(int action
, struct gui_synclist
*lists
)
318 if (action
== ACTION_STD_OK
)
319 return ACTION_STD_CANCEL
;
322 enum themable_icons
shortcut_menu_get_icon(int selected_item
, void * data
)
325 struct shortcut
*sc
= get_shortcut(selected_item
);
328 if (sc
->icon
== Icon_NOICON
)
333 return filetype_get_icon(filetype_get_attr(sc
->u
.path
));
334 case SHORTCUT_BROWSER
:
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
;
349 int do_shortcut_menu(void *ignored
)
352 struct simplelist_info list
;
354 int done
= GO_TO_PREVIOUS
;
355 if (first_handle
== 0)
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)
374 sc
= get_shortcut(list
.selection
);
379 case SHORTCUT_PLAYLISTMENU
:
380 if (!file_exists(sc
->u
.path
))
382 splash(HZ
, ID2P(LANG_NO_FILES
));
387 onplay_show_playlist_menu(sc
->u
.path
);
391 if (!file_exists(sc
->u
.path
))
393 splash(HZ
, ID2P(LANG_NO_FILES
));
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
);
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
);
411 case SHORTCUT_DEBUGITEM
:
412 run_debug_screen(sc
->u
.path
);
414 case SHORTCUT_UNDEFINED
:
420 pop_current_activity();