1 /***************************************************************************
4 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
5 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
6 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
7 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
26 #include "powermgmt.h"
29 #include "ata_idle_notify.h"
30 #include "debug_menu.h"
31 #include "core_alloc.h"
34 #include "settings_list.h"
40 #include "filefuncs.h"
41 #include "filetypes.h"
42 #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 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
));
153 static bool verify_shortcut(struct shortcut
* sc
)
157 case SHORTCUT_UNDEFINED
:
159 case SHORTCUT_BROWSER
:
161 case SHORTCUT_PLAYLISTMENU
:
162 return sc
->u
.path
[0] != '\0';
163 case SHORTCUT_SETTING
:
164 return sc
->u
.setting
!= NULL
;
166 return sc
->name
[0] != '\0';
167 case SHORTCUT_DEBUGITEM
:
168 case SHORTCUT_SEPARATOR
:
169 case SHORTCUT_SHUTDOWN
:
176 static void init_shortcut(struct shortcut
* sc
)
178 sc
->type
= SHORTCUT_UNDEFINED
;
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
)
192 int current_idx
= first_idx_to_writeback
;
193 int append
= overwrite_shortcuts
? O_TRUNC
: O_APPEND
;
195 if (first_idx_to_writeback
< 0)
197 fd
= open(SHORTCUTS_FILENAME
, append
|O_RDWR
|O_CREAT
, 0644);
200 while (current_idx
< shortcut_count
)
202 struct shortcut
* sc
= get_shortcut(current_idx
++);
207 type
= type_strings
[sc
->type
];
208 len
= snprintf(buf
, MAX_PATH
, "[shortcut]\ntype: %s\ndata: ", type
);
210 if (sc
->type
== SHORTCUT_SETTING
)
211 write(fd
, sc
->u
.setting
->cfg_name
, strlen(sc
->u
.setting
->cfg_name
));
213 write(fd
, sc
->u
.path
, strlen(sc
->u
.path
));
214 write(fd
, "\n\n", 2);
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.
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
++);
235 if (type
== SHORTCUT_SETTING
)
236 sc
->u
.setting
= (void*)value
;
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
)
250 struct shortcut
**param
= (struct shortcut
**)parameters
;
251 struct shortcut
* sc
= *param
;
254 if (!strcasecmp(skip_whitespace(buf
), "[shortcut]"))
256 if (sc
&& verify_shortcut(sc
))
258 sc
= get_shortcut(shortcut_count
);
264 else if (sc
&& settings_parseline(buf
, &name
, &value
))
266 if (!strcmp(name
, "type"))
269 for (t
=0; t
<SHORTCUT_TYPE_COUNT
&& sc
->type
== SHORTCUT_UNDEFINED
; t
++)
270 if (!strcmp(value
, type_strings
[t
]))
273 else if (!strcmp(name
, "name"))
275 strlcpy(sc
->name
, value
, MAX_SHORTCUT_NAME
);
277 else if (!strcmp(name
, "data"))
281 case SHORTCUT_UNDEFINED
:
282 case SHORTCUT_TYPE_COUNT
:
285 case SHORTCUT_BROWSER
:
287 case SHORTCUT_DEBUGITEM
:
288 case SHORTCUT_PLAYLISTMENU
:
289 strlcpy(sc
->u
.path
, value
, MAX_PATH
);
291 case SHORTCUT_SETTING
:
292 sc
->u
.setting
= find_setting_by_cfgname(value
, NULL
);
296 sc
->u
.timedata
.talktime
= false;
297 if (!strcasecmp(value
, "talk"))
298 sc
->u
.timedata
.talktime
= true;
301 if (!strncasecmp(value
, "sleep ", strlen("sleep ")))
302 sc
->u
.timedata
.sleep_timeout
= atoi(&value
[strlen("sleep ")]);
304 sc
->type
= SHORTCUT_UNDEFINED
; /* error */
306 case SHORTCUT_SEPARATOR
:
307 case SHORTCUT_SHUTDOWN
:
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
));
319 sc
->icon
= atoi(value
);
322 else if (!strcmp(name
, "talkclip"))
324 strlcpy(sc
->talk_clip
, value
, MAX_PATH
);
330 void shortcuts_init(void)
334 struct shortcut
*param
= NULL
;
335 struct shortcut_handle
*h
;
337 fd
= open_utf8(SHORTCUTS_FILENAME
, O_RDONLY
);
340 first_handle
= core_alloc("shortcuts_head", sizeof(struct shortcut_handle
));
341 if (first_handle
<= 0)
343 h
= core_get_data(first_handle
);
345 fast_readline(fd
, buf
, sizeof buf
, ¶m
, readline_cb
);
347 if (param
&& verify_shortcut(param
))
351 static const char * shortcut_menu_get_name(int selected_item
, void * data
,
352 char * buffer
, size_t buffer_len
)
357 struct shortcut
*sc
= get_shortcut(selected_item
);
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
)
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
)
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
;
398 static enum themable_icons
shortcut_menu_get_icon(int selected_item
, void * data
)
401 struct shortcut
*sc
= get_shortcut(selected_item
);
404 if (sc
->icon
== Icon_NOICON
)
409 return filetype_get_icon(filetype_get_attr(sc
->u
.path
));
410 case SHORTCUT_BROWSER
:
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
;
421 return Icon_Menu_functioncall
;
429 static int shortcut_menu_speak_item(int selected_item
, 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);
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
)
445 struct simplelist_info list
;
447 int done
= GO_TO_PREVIOUS
;
448 if (first_handle
== 0)
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)
474 sc
= get_shortcut(list
.selection
);
479 case SHORTCUT_PLAYLISTMENU
:
480 if (!file_exists(sc
->u
.path
))
482 splash(HZ
, ID2P(LANG_NO_FILES
));
487 onplay_show_playlist_menu(sc
->u
.path
);
491 if (!file_exists(sc
->u
.path
))
493 splash(HZ
, ID2P(LANG_NO_FILES
));
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
);
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
);
511 case SHORTCUT_DEBUGITEM
:
512 run_debug_screen(sc
->u
.path
);
514 case SHORTCUT_SHUTDOWN
:
516 if (charger_inserted())
524 if (sc
->u
.timedata
.talktime
) {
526 talk_force_enqueue_next();
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
));
537 case SHORTCUT_UNDEFINED
:
543 pop_current_activity();