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 ****************************************************************************/
27 #include "powermgmt.h"
30 #include "ata_idle_notify.h"
31 #include "debug_menu.h"
32 #include "core_alloc.h"
35 #include "settings_list.h"
41 #include "filefuncs.h"
42 #include "filetypes.h"
43 #include "shortcuts.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",
63 enum shortcut_type type
;
64 char name
[MAX_SHORTCUT_NAME
];
65 char talk_clip
[MAX_PATH
];
69 const struct settings_list
*setting
;
78 #define SHORTCUTS_PER_HANDLE 32
79 struct shortcut_handle
{
80 struct shortcut shortcuts
[SHORTCUTS_PER_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)
93 h
= core_get_data(current_handle
);
94 next
= h
->next_handle
;
95 core_free(current_handle
);
96 current_handle
= next
;
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)
113 h
= core_get_data(first_handle
);
115 current_handle
= first_handle
;
118 handle_count
= index
/SHORTCUTS_PER_HANDLE
+ 1;
119 handle_index
= index
%SHORTCUTS_PER_HANDLE
;
121 h
= core_get_data(current_handle
);
122 current_handle
= h
->next_handle
;
124 } while (handle_count
> 0 && current_handle
> 0);
125 if (handle_count
> 0 && handle_index
== 0)
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)
132 h
= core_get_data(h
->next_handle
);
135 return &h
->shortcuts
[handle_index
];
138 static bool verify_shortcut(struct shortcut
* sc
)
142 case SHORTCUT_UNDEFINED
:
144 case SHORTCUT_BROWSER
:
146 case SHORTCUT_PLAYLISTMENU
:
147 return sc
->u
.path
[0] != '\0';
148 case SHORTCUT_SETTING
:
149 return sc
->u
.setting
!= NULL
;
151 return sc
->name
[0] != '\0';
152 case SHORTCUT_DEBUGITEM
:
153 case SHORTCUT_SEPARATOR
:
154 case SHORTCUT_SHUTDOWN
:
161 static void init_shortcut(struct shortcut
* sc
)
163 sc
->type
= SHORTCUT_UNDEFINED
;
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
)
176 int current_idx
= first_idx_to_writeback
;
177 if (first_idx_to_writeback
< 0)
179 fd
= open(SHORTCUTS_FILENAME
, O_APPEND
|O_RDWR
|O_CREAT
, 0644);
182 while (current_idx
< shortcut_count
)
184 struct shortcut
* sc
= get_shortcut(current_idx
++);
189 type
= type_strings
[sc
->type
];
190 len
= snprintf(buf
, MAX_PATH
, "[shortcut]\ntype: %s\ndata: ", type
);
192 if (sc
->type
== SHORTCUT_SETTING
)
193 write(fd
, sc
->u
.setting
->cfg_name
, strlen(sc
->u
.setting
->cfg_name
));
195 write(fd
, sc
->u
.path
, strlen(sc
->u
.path
));
196 write(fd
, "\n\n", 2);
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.
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
++);
217 if (type
== SHORTCUT_SETTING
)
218 sc
->u
.setting
= (void*)value
;
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
)
230 struct shortcut
**param
= (struct shortcut
**)parameters
;
231 struct shortcut
* sc
= *param
;
234 if (!strcasecmp(skip_whitespace(buf
), "[shortcut]"))
236 if (sc
&& verify_shortcut(sc
))
238 sc
= get_shortcut(shortcut_count
);
244 else if (sc
&& settings_parseline(buf
, &name
, &value
))
246 if (!strcmp(name
, "type"))
249 for (t
=0; t
<SHORTCUT_TYPE_COUNT
&& sc
->type
== SHORTCUT_UNDEFINED
; t
++)
250 if (!strcmp(value
, type_strings
[t
]))
253 else if (!strcmp(name
, "name"))
255 strlcpy(sc
->name
, value
, MAX_SHORTCUT_NAME
);
257 else if (!strcmp(name
, "data"))
261 case SHORTCUT_UNDEFINED
:
262 case SHORTCUT_TYPE_COUNT
:
265 case SHORTCUT_BROWSER
:
267 case SHORTCUT_DEBUGITEM
:
268 case SHORTCUT_PLAYLISTMENU
:
269 strlcpy(sc
->u
.path
, value
, MAX_PATH
);
271 case SHORTCUT_SETTING
:
272 sc
->u
.setting
= find_setting_by_cfgname(value
, NULL
);
276 sc
->u
.timedata
.talktime
= false;
277 if (!strcasecmp(value
, "talk"))
278 sc
->u
.timedata
.talktime
= true;
281 if (!strncasecmp(value
, "sleep ", strlen("sleep ")))
282 sc
->u
.timedata
.sleep_timeout
= atoi(&value
[strlen("sleep ")]);
284 sc
->type
= SHORTCUT_UNDEFINED
; /* error */
286 case SHORTCUT_SEPARATOR
:
287 case SHORTCUT_SHUTDOWN
:
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
));
299 sc
->icon
= atoi(value
);
302 else if (!strcmp(name
, "talkclip"))
304 strlcpy(sc
->talk_clip
, value
, MAX_PATH
);
310 void shortcuts_init(void)
314 struct shortcut
*param
= NULL
;
315 struct shortcut_handle
*h
;
317 fd
= open_utf8(SHORTCUTS_FILENAME
, O_RDONLY
);
320 first_handle
= core_alloc("shortcuts_head", sizeof(struct shortcut_handle
));
321 if (first_handle
<= 0)
323 h
= core_get_data(first_handle
);
325 fast_readline(fd
, buf
, sizeof buf
, ¶m
, readline_cb
);
327 if (param
&& verify_shortcut(param
))
331 static const char * shortcut_menu_get_name(int selected_item
, void * data
,
332 char * buffer
, size_t buffer_len
)
337 struct shortcut
*sc
= get_shortcut(selected_item
);
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
)
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
)
355 if (action
== ACTION_STD_OK
)
356 return ACTION_STD_CANCEL
;
360 static enum themable_icons
shortcut_menu_get_icon(int selected_item
, void * data
)
363 struct shortcut
*sc
= get_shortcut(selected_item
);
366 if (sc
->icon
== Icon_NOICON
)
371 return filetype_get_icon(filetype_get_attr(sc
->u
.path
));
372 case SHORTCUT_BROWSER
:
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
;
383 return Icon_Menu_functioncall
;
391 static int shortcut_menu_speak_item(int selected_item
, 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);
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
)
407 struct simplelist_info list
;
409 int done
= GO_TO_PREVIOUS
;
410 if (first_handle
== 0)
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)
436 sc
= get_shortcut(list
.selection
);
441 case SHORTCUT_PLAYLISTMENU
:
442 if (!file_exists(sc
->u
.path
))
444 splash(HZ
, ID2P(LANG_NO_FILES
));
449 onplay_show_playlist_menu(sc
->u
.path
);
453 if (!file_exists(sc
->u
.path
))
455 splash(HZ
, ID2P(LANG_NO_FILES
));
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
);
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
);
473 case SHORTCUT_DEBUGITEM
:
474 run_debug_screen(sc
->u
.path
);
476 case SHORTCUT_SHUTDOWN
:
478 if (charger_inserted())
486 if (sc
->u
.timedata
.talktime
) {
488 talk_force_enqueue_next();
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
));
499 case SHORTCUT_UNDEFINED
:
505 pop_current_activity();