diff --git a/apps/SOURCES b/apps/SOURCES index 5335258f70..ba36bc3ef6 100644 --- a/apps/SOURCES +++ b/apps/SOURCES @@ -38,6 +38,7 @@ menus/sound_menu.c menus/time_menu.c #endif misc.c +open_plugin.c onplay.c playlist.c playlist_catalog.c diff --git a/apps/filetree.c b/apps/filetree.c index d645b7225c..cfa14f86b5 100644 --- a/apps/filetree.c +++ b/apps/filetree.c @@ -357,7 +357,8 @@ int ft_load(struct tree_context* c, const char* tempdir) (*c->dirfilter == SHOW_LNG && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_LNG) || (*c->dirfilter == SHOW_MOD && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_MOD) || (*c->dirfilter == SHOW_PLUGINS && (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_ROCK && - (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_LUA) || + (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_LUA && + (dptr->attr & FILE_ATTR_MASK) != FILE_ATTR_OPX) || (callback_show_item && !callback_show_item(entry->d_name, dptr->attr, c))) { continue; @@ -625,6 +626,7 @@ int ft_enter(struct tree_context* c) /* plugin file */ case FILE_ATTR_ROCK: case FILE_ATTR_LUA: + case FILE_ATTR_OPX: { char *plugin = buf, *argument = NULL, lua_path[MAX_PATH]; int ret; @@ -634,6 +636,11 @@ int ft_enter(struct tree_context* c) plugin = lua_path; argument = buf; } + else if ((file_attr & FILE_ATTR_MASK) == FILE_ATTR_OPX) { + snprintf(lua_path, sizeof(lua_path)-1, "%s/open_plugins.rock", VIEWERS_DIR); /* Use a #define here ? */ + plugin = lua_path; + argument = buf; + } if (global_settings.party_mode && audio_status()) { splash(HZ, ID2P(LANG_PARTY_MODE)); @@ -645,6 +652,9 @@ int ft_enter(struct tree_context* c) case PLUGIN_GOTO_WPS: play = true; break; + case PLUGIN_GOTO_PLUGIN: + rc = GO_TO_PLUGIN; + break; case PLUGIN_USB_CONNECTED: if(*c->dirfilter > NUM_FILTER_MODES) /* leave sub-browsers after usb, doing @@ -690,6 +700,9 @@ int ft_enter(struct tree_context* c) case PLUGIN_USB_CONNECTED: rc = GO_TO_FILEBROWSER; break; + case PLUGIN_GOTO_PLUGIN: + rc = GO_TO_PLUGIN; + break; case PLUGIN_GOTO_WPS: rc = GO_TO_WPS; break; diff --git a/apps/filetypes.c b/apps/filetypes.c index 39fb2c5b32..391412b172 100644 --- a/apps/filetypes.c +++ b/apps/filetypes.c @@ -125,6 +125,7 @@ static const struct filetype inbuilt_filetypes[] = { { "lng", FILE_ATTR_LNG, Icon_Language, LANG_LANGUAGE }, { "rock",FILE_ATTR_ROCK,Icon_Plugin, VOICE_EXT_ROCK }, { "lua", FILE_ATTR_LUA, Icon_Plugin, VOICE_EXT_ROCK }, + { "opx", FILE_ATTR_OPX, Icon_Plugin, VOICE_EXT_ROCK }, { "fnt", FILE_ATTR_FONT,Icon_Font, VOICE_EXT_FONT }, { "kbd", FILE_ATTR_KBD, Icon_Keyboard, VOICE_EXT_KBD }, { "bmark",FILE_ATTR_BMARK, Icon_Bookmark, VOICE_EXT_BMARK }, diff --git a/apps/filetypes.h b/apps/filetypes.h index 8c9e9a5d93..23f259b3ca 100644 --- a/apps/filetypes.h +++ b/apps/filetypes.h @@ -47,6 +47,7 @@ #define FILE_ATTR_LUA 0x1100 /* Lua rockbox plugin */ #define FILE_ATTR_FMS 0x1200 /* FM screen skin file */ #define FILE_ATTR_RFMS 0x1300 /* FM screen skin file */ +#define FILE_ATTR_OPX 0x1400 /* open plugins shortcut */ #define FILE_ATTR_MASK 0xFF00 /* which bits tree.c uses for file types */ struct filetype { diff --git a/apps/gui/option_select.c b/apps/gui/option_select.c index ec8b474191..ff257a4925 100644 --- a/apps/gui/option_select.c +++ b/apps/gui/option_select.c @@ -467,6 +467,8 @@ bool option_screen(const struct settings_list *setting, int oldvalue, nb_items = 0, selected = 0, temp_var; int *variable; bool allow_wrap = setting->flags & F_NO_WRAP ? false : true; + bool cb_on_select_only = + ((setting->flags & F_CB_ON_SELECT_ONLY) == F_CB_ON_SELECT_ONLY); int var_type = setting->flags&F_T_MASK; void (*function)(int) = NULL; char *title; @@ -554,12 +556,15 @@ bool option_screen(const struct settings_list *setting, } settings_save(); done = true; + if (cb_on_select_only && function) + function(*variable); } else if(default_event_handler(action) == SYS_USB_CONNECTED) return true; /* callback */ - if ( function ) + if (function && !cb_on_select_only) function(*variable); + /* if the volume is changing we need to let the skins know */ if (function == sound_get_fn(SOUND_VOLUME)) global_status.last_volume_change = current_tick; diff --git a/apps/gui/wps.c b/apps/gui/wps.c index 8d0453385b..8a51d9b810 100644 --- a/apps/gui/wps.c +++ b/apps/gui/wps.c @@ -687,10 +687,8 @@ long gui_wps_show(void) return GO_TO_ROOT; else if (retval == ONPLAY_PLAYLIST) return GO_TO_PLAYLIST_VIEWER; -#ifdef HAVE_PICTUREFLOW_INTEGRATION - else if (retval == ONPLAY_PICTUREFLOW) - return GO_TO_PICTUREFLOW; -#endif + else if (retval == ONPLAY_PLUGIN) + return GO_TO_PLUGIN; restore = true; } break; diff --git a/apps/lang/english.lang b/apps/lang/english.lang index 5937df64c0..8af6e55c5e 100644 --- a/apps/lang/english.lang +++ b/apps/lang/english.lang @@ -16150,3 +16150,59 @@ hotkey: "Hold for settings" + + id: LANG_OPEN_PLUGIN + desc: onplay open plugin + user: core + + *: "Open Plugin" + + + *: "Open Plugin" + + + *: "Open Plugin" + + + + id: LANG_OPEN_PLUGIN_NOT_A_PLUGIN + desc: open plugin module + user: core + + *: "Not a plugin: %s" + + + *: "Not a plugin: %s" + + + *: "Not a plugin" + + + + id: LANG_OPEN_PLUGIN_SET_WPS_CONTEXT_PLUGIN + desc: open plugin module + user: core + + *: "Set Wps Context Plugin" + + + *: "Set Wps Context Plugin" + + + *: "Set Wps Context Plugin" + + + + id: LANG_PARAMETER + desc: + user: core + + *: "Parameter" + + + *: "Parameter" + + + *: "Parameter" + + diff --git a/apps/menus/settings_menu.c b/apps/menus/settings_menu.c index 431600bbe1..9275ff10d6 100644 --- a/apps/menus/settings_menu.c +++ b/apps/menus/settings_menu.c @@ -28,6 +28,7 @@ #include "action.h" #include "settings.h" #include "menu.h" +#include "open_plugin.h" #include "keyboard.h" #include "sound_menu.h" #include "exported_menus.h" @@ -711,6 +712,18 @@ MAKE_MENU(voice_settings_menu, ID2P(LANG_VOICE), 0, Icon_Voice, /* VOICE MENU */ /***********************************/ +/* WPS_CONTEXT_PLUGIN */ +/***********************************/ +static void wps_plugin_cb(void) +{ + open_plugin_browse(ID2P(LANG_OPEN_PLUGIN_SET_WPS_CONTEXT_PLUGIN)); +} +MENUITEM_FUNCTION(wps_set_context_plugin, 0, + ID2P(LANG_OPEN_PLUGIN_SET_WPS_CONTEXT_PLUGIN), + wps_plugin_cb, NULL, NULL, Icon_Plugin); + +/* WPS_CONTEXT_PLUGIN */ +/***********************************/ /***********************************/ /* HOTKEY MENU */ @@ -745,6 +758,7 @@ MAKE_MENU(settings_menu_item, ID2P(LANG_GENERAL_SETTINGS), 0, &autoresume_menu, #endif &browse_langs, &voice_settings_menu, + &wps_set_context_plugin, #ifdef HAVE_HOTKEY &hotkey_menu, #endif diff --git a/apps/onplay.c b/apps/onplay.c index fd956167d3..f2ebd47630 100644 --- a/apps/onplay.c +++ b/apps/onplay.c @@ -43,6 +43,7 @@ #include "talk.h" #include "onplay.h" #include "filetypes.h" +#include "open_plugin.h" #include "plugin.h" #include "bookmark.h" #include "action.h" @@ -1415,10 +1416,8 @@ MENUITEM_FUNCTION(rating_item, 0, ID2P(LANG_MENU_SET_RATING), set_rating_inline, NULL, ratingitem_callback, Icon_Questionmark); #endif -#ifdef HAVE_PICTUREFLOW_INTEGRATION -MENUITEM_RETURNVALUE(pictureflow_item, ID2P(LANG_ONPLAY_PICTUREFLOW), - GO_TO_PICTUREFLOW, NULL, Icon_NOICON); -#endif +MENUITEM_RETURNVALUE(plugin_item, ID2P(LANG_OPEN_PLUGIN), + GO_TO_PLUGIN, NULL, Icon_Plugin); static bool view_cue(void) { @@ -1650,9 +1649,7 @@ MAKE_ONPLAYMENU( wps_onplay_menu, ID2P(LANG_ONPLAY_MENU_TITLE), &rating_item, #endif &bookmark_menu, -#ifdef HAVE_PICTUREFLOW_INTEGRATION - &pictureflow_item, -#endif + &plugin_item, &browse_id3_item, &list_viewers_item, &delete_file_item, &view_cue_item, #ifdef HAVE_PITCHCONTROL @@ -1732,6 +1729,11 @@ static int playlist_insert_shuffled(void) return ONPLAY_RELOAD_DIR; } +static void hotkey_run_plugin(void) +{ + open_plugin_run(ID2P(LANG_HOTKEY_WPS)); +} + struct hotkey_assignment { int action; /* hotkey_action */ int lang_id; /* Language ID */ @@ -1768,11 +1770,9 @@ static struct hotkey_assignment hotkey_items[] = { { HOTKEY_INSERT_SHUFFLED, LANG_INSERT_SHUFFLED, HOTKEY_FUNC(playlist_insert_shuffled, NULL), ONPLAY_RELOAD_DIR }, -#ifdef HAVE_PICTUREFLOW_INTEGRATION - { HOTKEY_PICTUREFLOW, LANG_ONPLAY_PICTUREFLOW, - HOTKEY_FUNC(NULL, NULL), - ONPLAY_PICTUREFLOW }, -#endif + { HOTKEY_PLUGIN, LANG_OPEN_PLUGIN, + HOTKEY_FUNC(hotkey_run_plugin, NULL), + ONPLAY_OK }, { HOTKEY_BOOKMARK, LANG_BOOKMARK_MENU_CREATE, HOTKEY_FUNC(bookmark_create_menu, NULL), ONPLAY_OK }, @@ -1861,10 +1861,8 @@ int onplay(char* file, int attr, int from, bool hotkey) return ONPLAY_MAINMENU; case GO_TO_PLAYLIST_VIEWER: return ONPLAY_PLAYLIST; -#ifdef HAVE_PICTUREFLOW_INTEGRATION - case GO_TO_PICTUREFLOW: - return ONPLAY_PICTUREFLOW; -#endif + case GO_TO_PLUGIN: + return ONPLAY_PLUGIN; default: return onplay_result; } diff --git a/apps/onplay.h b/apps/onplay.h index 24637ac18c..27f0436403 100644 --- a/apps/onplay.h +++ b/apps/onplay.h @@ -29,7 +29,7 @@ enum { ONPLAY_RELOAD_DIR, ONPLAY_START_PLAY, ONPLAY_PLAYLIST, - ONPLAY_PICTUREFLOW, + ONPLAY_PLUGIN, }; #ifdef HAVE_HOTKEY @@ -44,7 +44,7 @@ enum hotkey_action { HOTKEY_DELETE, HOTKEY_INSERT, HOTKEY_INSERT_SHUFFLED, - HOTKEY_PICTUREFLOW, + HOTKEY_PLUGIN, HOTKEY_BOOKMARK, }; #endif diff --git a/apps/open_plugin.c b/apps/open_plugin.c new file mode 100644 index 0000000000..0fb20403bc --- /dev/null +++ b/apps/open_plugin.c @@ -0,0 +1,204 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2020 by William Wilgus + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#ifndef __PCTOOL__ + +#include "plugin.h" +#include "open_plugin.h" +#include "pathfuncs.h" +#include "keyboard.h" +#include "splash.h" +#include "lang.h" + +struct open_plugin_entry_t open_plugin_entry; + +static const int op_entry_sz = sizeof(struct open_plugin_entry_t); + +static void get_param(void) +{ + char tmp_buf[OPEN_PLUGIN_BUFSZ+1]; + strlcpy(tmp_buf, open_plugin_entry.param, OPEN_PLUGIN_BUFSZ); + if (kbd_input(tmp_buf, OPEN_PLUGIN_BUFSZ, NULL)) + strlcpy(open_plugin_entry.param, tmp_buf, OPEN_PLUGIN_BUFSZ); +} + +uint32_t open_plugin_add_path(const char *key, const char *plugin, const char *parameter) +{ + int len; + uint32_t hash; + char *pos; + int fd = 0; + + /*strlcpy(plug_entry.key, key, sizeof(plug_entry.key));*/ + open_plugin_entry.lang_id = P2ID((unsigned char*)key); + key = P2STR((unsigned char *)key); + + open_plugin_get_hash(key, &hash); + open_plugin_entry.hash = hash; + + if (plugin) + { + /* name */ + if (path_basename(plugin, (const char **)&pos) == 0) + pos = "\0"; + + len = strlcpy(open_plugin_entry.name, pos, OPEN_PLUGIN_NAMESZ); + + if(len > 5 && strcasecmp(&(pos[len-5]), ".rock") == 0) + { + fd = open(OPEN_PLUGIN_DAT ".tmp", O_WRONLY | O_CREAT | O_TRUNC, 0666); + if (!fd) + return 0; + + /* path */ + strlcpy(open_plugin_entry.path, plugin, OPEN_PLUGIN_BUFSZ); + + if(parameter) + { + if (parameter[0] == '\0' && + yesno_pop(ID2P(LANG_PARAMETER))) + { + get_param(); + } + else + strlcpy(open_plugin_entry.param, parameter, OPEN_PLUGIN_BUFSZ); + } + + write(fd, &open_plugin_entry, op_entry_sz); + } + else + { + if (open_plugin_entry.lang_id != LANG_SHORTCUTS) + splashf(HZ / 2, str(LANG_OPEN_PLUGIN_NOT_A_PLUGIN), pos); + return 0; + } + } + + int fd1 = open(OPEN_PLUGIN_DAT, O_RDONLY); + if (fd1) + { + while (read(fd1, &open_plugin_entry, op_entry_sz) == op_entry_sz) + { + if (open_plugin_entry.hash != hash) + write(fd, &open_plugin_entry, op_entry_sz); + } + close(fd1); + } + close(fd); + + if(fd1) + { + remove(OPEN_PLUGIN_DAT); + rename(OPEN_PLUGIN_DAT ".tmp", OPEN_PLUGIN_DAT); + } + else + hash = 0; + + return hash; +} + +void open_plugin_browse(const char *key) +{ + struct browse_context browse; + char tmp_buf[OPEN_PLUGIN_BUFSZ+1]; + open_plugin_get_entry(key, &open_plugin_entry); + + if (open_plugin_entry.path[0] == '\0') + strcpy(open_plugin_entry.path, PLUGIN_DIR"/"); + + browse_context_init(&browse, SHOW_ALL, BROWSE_SELECTONLY, "", + Icon_Plugin, open_plugin_entry.path, NULL); + + browse.buf = tmp_buf; + browse.bufsize = OPEN_PLUGIN_BUFSZ; + + if (rockbox_browse(&browse) == GO_TO_PREVIOUS) + { + open_plugin_add_path(key, tmp_buf, NULL); + } +} + +void open_plugin_remove(const char *key) +{ + (void)key; + open_plugin_add_path(key, NULL, NULL); +} + +static int open_plugin_hash_get_entry(uint32_t hash, struct open_plugin_entry_t *entry) +{ + int ret = -1, record = -1; + + if (entry) + { + int fd = open(OPEN_PLUGIN_DAT, O_RDONLY); + + if (fd) + { + while (read(fd, entry, op_entry_sz) == op_entry_sz) + { + record++; + if (entry->hash == hash) + { + ret = record; + break; + } + } + close(fd); + } + if (ret < 0) + { + memset(entry, 0, op_entry_sz); + entry->lang_id = -1; + } + } + + return ret; +} + +int open_plugin_get_entry(const char *key, struct open_plugin_entry_t *entry) +{ + uint32_t hash; + key = P2STR((unsigned char *)key); + + open_plugin_get_hash(key, &hash); + return open_plugin_hash_get_entry(hash, entry); +} + +int open_plugin_run(const char *key) +{ + int ret = 0; + const char *path; + const char *param; + + open_plugin_get_entry(key, &open_plugin_entry); + + path = open_plugin_entry.path; + param = open_plugin_entry.param; + if (param[0] == '\0') + param = NULL; + + if (path) + ret = plugin_load(path, param); + + return ret; +} + +#endif /* ndef __PCTOOL__ */ diff --git a/apps/open_plugin.h b/apps/open_plugin.h new file mode 100644 index 0000000000..2d8a527073 --- /dev/null +++ b/apps/open_plugin.h @@ -0,0 +1,66 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2020 by William Wilgus + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef OPEN_PLUGIN_H +#define OPEN_PLUGIN_H + +/* Open_plugin module + * OP stores and retrieves plugin path and parameters by key + * from a dictionary file + * + * plugins can load other plugins + * return rb->plugin_open(path, parameter); + */ + +#ifndef __PCTOOL__ +/* open_plugin path lookup */ +#define OPEN_PLUGIN_DAT PLUGIN_DIR "/plugin.dat" +#define OPEN_PLUGIN_BUFSZ MAX_PATH +#define OPEN_PLUGIN_NAMESZ 32 +struct open_plugin_entry_t +{ + uint32_t hash; + int32_t lang_id; + char name[OPEN_PLUGIN_NAMESZ+1]; + /*char key[OPEN_PLUGIN_BUFSZ+1];*/ + char path[OPEN_PLUGIN_BUFSZ+1]; + char param[OPEN_PLUGIN_BUFSZ+1]; +}; + +inline static void open_plugin_get_hash(const char *key, uint32_t *hash) +{ + /* Calculate modified FNV1a hash of string */ + const uint32_t p = 16777619; + *hash = 0x811C9DC5; //seed, 2166136261; + while(*key) + *hash = (*key++ ^ *hash) * p; +} + +#ifndef PLUGIN +extern struct open_plugin_entry_t open_plugin_entry; +uint32_t open_plugin_add_path(const char *key, const char *plugin, const char *parameter); +int open_plugin_get_entry(const char *key, struct open_plugin_entry_t *entry); +void open_plugin_browse(const char *key); +void open_plugin_remove(const char *key); +int open_plugin_run(const char *key); +#endif + +#endif /*ndef __PCTOOL__ */ +#endif /* OPEN_PLUGIN_H */ diff --git a/apps/plugin.c b/apps/plugin.c index 2066d3a108..749132cde8 100644 --- a/apps/plugin.c +++ b/apps/plugin.c @@ -21,6 +21,7 @@ #define DIRFUNCTIONS_DEFINED #define FILEFUNCTIONS_DEFINED #include "plugin.h" +#include "open_plugin.h" #include #include #include @@ -807,6 +808,7 @@ static const struct plugin_api rockbox_api = { #ifdef HAVE_TAGCACHE tagcache_get_stat, #endif + plugin_open, }; static int plugin_buffer_handle; @@ -1019,6 +1021,12 @@ static void plugin_tsr(bool (*exit_callback)(bool)) pfn_tsr_exit = exit_callback; /* remember the callback for later */ } +int plugin_open(char *plugin, char *parameter) +{ + open_plugin_add_path(ID2P(LANG_OPEN_PLUGIN), plugin, parameter); + return PLUGIN_GOTO_PLUGIN; +} + char *plugin_get_current_filename(void) { return current_plugin; diff --git a/apps/plugin.h b/apps/plugin.h index 2585d17205..fc3da61c57 100644 --- a/apps/plugin.h +++ b/apps/plugin.h @@ -49,6 +49,7 @@ char* strncpy(char *, const char *, size_t); void* plugin_get_buffer(size_t *buffer_size); +int plugin_open(char *plugin, char *parameter); #ifndef __PCTOOL__ #include "config.h" @@ -172,6 +173,7 @@ enum plugin_status { PLUGIN_USB_CONNECTED = INTERNAL_PLUGIN_RETVAL_START, PLUGIN_POWEROFF, PLUGIN_GOTO_WPS, + PLUGIN_GOTO_PLUGIN, PLUGIN_ERROR = -1, }; @@ -934,6 +936,7 @@ struct plugin_api { #ifdef HAVE_TAGCACHE struct tagcache_stat* (*tagcache_get_stat)(void); #endif + int (*plugin_open)(char *path, char *parameter); }; diff --git a/apps/plugins/pictureflow/pictureflow.c b/apps/plugins/pictureflow/pictureflow.c index d1da10ee09..91062f8f11 100644 --- a/apps/plugins/pictureflow/pictureflow.c +++ b/apps/plugins/pictureflow/pictureflow.c @@ -533,19 +533,28 @@ static void free_all_slide_prio(int prio); static bool check_database(bool prompt) { bool needwarn = true; + int spin = 5; + struct tagcache_stat *stat = rb->tagcache_get_stat(); + while ( !(stat->initialized && stat->ready) ) { - if (needwarn) + if (--spin > 0) + { + rb->sleep(HZ/5); + } + else if (needwarn) + { + needwarn = false; rb->splash(0, ID2P(LANG_TAGCACHE_BUSY)); - if (!prompt) + } + else if (!prompt) return false; else if (rb->action_userabort(HZ/5)) return false; - needwarn = false; - stat = rb->tagcache_get_stat(); rb->yield(); + stat = rb->tagcache_get_stat(); } return true; } @@ -3841,7 +3850,7 @@ enum plugin_status plugin_start(const void *parameter) void * buf; size_t buf_size; - bool prompt = (parameter && ((char *) parameter)[0] == ACTIVITY_MAINMENU); + bool prompt = (parameter && (((char *) parameter)[0] == ACTIVITY_MAINMENU)); if (!check_database(prompt)) { diff --git a/apps/plugins/shortcuts/shortcuts_view.c b/apps/plugins/shortcuts/shortcuts_view.c index cfc9d8d746..f4c4b58bc1 100644 --- a/apps/plugins/shortcuts/shortcuts_view.c +++ b/apps/plugins/shortcuts/shortcuts_view.c @@ -22,7 +22,7 @@ #include "shortcuts.h" - +#define LOOP_EXIT 1 enum sc_list_action_type { @@ -35,7 +35,6 @@ enum sc_list_action_type static char *link_filename; static bool user_file; -static bool usb_connected = false; enum sc_list_action_type draw_sc_list(struct gui_synclist *gui_sc); @@ -43,10 +42,10 @@ enum sc_list_action_type draw_sc_list(struct gui_synclist *gui_sc); static const char* build_sc_list(int selected_item, void *data, char *buffer, size_t buffer_len); -/* Returns true iff we should leave the main loop */ -bool list_sc(void); +/* Returns LOOP_EXIT iff we should leave the main loop */ +int list_sc(void); -bool goto_entry(char *file_or_dir); +int goto_entry(char *file_or_dir); bool ends_with(char *str, char *suffix); @@ -104,7 +103,7 @@ static const char* build_sc_list(int selected_item, void *data, } -bool list_sc(void) +int list_sc(void) { int selected_item = 0; enum sc_list_action_type action = SCLA_NONE; @@ -122,8 +121,7 @@ bool list_sc(void) /* Draw the prepared widget to the LCD now */ action = draw_sc_list(&gui_sc); if (action == SCLA_USB) { - usb_connected = true; - return true; + return PLUGIN_USB_CONNECTED; } /* which item do we action? */ @@ -132,7 +130,7 @@ bool list_sc(void) if (!is_valid_index(&sc_file, selected_item)) { /* This should never happen */ rb->splash(HZ*2, "Bad entry selected!"); - return true; + return PLUGIN_ERROR; } /* perform the following actions if the user "selected" @@ -145,13 +143,13 @@ bool list_sc(void) rb->splashf(HZ, "Deleting %s", sc_file.entries[selected_item].disp); remove_entry(&sc_file, selected_item); dump_sc_file(&sc_file, link_filename); - return (sc_file.entry_cnt == 0); + return (sc_file.entry_cnt == 0)? LOOP_EXIT : PLUGIN_OK; default: - return true; + return LOOP_EXIT; } } - +#if 0 bool goto_entry(char *file_or_dir) { DEBUGF("Trying to go to '%s'...\n", file_or_dir); @@ -181,7 +179,46 @@ bool goto_entry(char *file_or_dir) rb->set_current_file(file_or_dir); return true; } +#endif +int goto_entry(char *file_or_dir) +{ + DEBUGF("Trying to go to '%s'...\n", file_or_dir); + + bool is_dir = ends_with(file_or_dir, PATH_SEPARATOR); + bool exists; + char *what; + if (is_dir) { + what = "Directory"; + exists = rb->dir_exists(file_or_dir); + } else { + what = "File"; + exists = rb->file_exists(file_or_dir); + } + + if (!exists) { + rb->splashf(HZ*2, "%s %s no longer exists on disk", what, file_or_dir); + return PLUGIN_ERROR; + } + + int len = rb->strlen(file_or_dir); + if(!is_dir && len > 5 && rb->strcasecmp(&(file_or_dir[len-5]), ".rock") == 0) + { + return rb->plugin_open(file_or_dir, NULL); + } + else + { + /* Set the browsers dirfilter to the global setting + * This is required in case the plugin was launched + * from the plugins browser, in which case the + * dirfilter is set to only display .rock files */ + rb->set_dirfilter(rb->global_settings->dirfilter); + + /* Change directory to the entry selected by the user */ + rb->set_current_file(file_or_dir); + } + return PLUGIN_OK; +} bool ends_with(char *string, char *suffix) { @@ -195,7 +232,7 @@ bool ends_with(char *string, char *suffix) enum plugin_status plugin_start(const void* void_parameter) { - bool leave_loop; + int ret; /* This is a viewer, so a parameter must have been specified */ if (void_parameter == NULL) { @@ -219,8 +256,7 @@ enum plugin_status plugin_start(const void* void_parameter) /* if there's only one entry in the user .link file, * go straight to it without displaying the menu * thus allowing 'quick links' */ - goto_entry(sc_file.entries[0].path); - return PLUGIN_OK; + return goto_entry(sc_file.entries[0].path); } FOR_NB_SCREENS(i) @@ -228,11 +264,13 @@ enum plugin_status plugin_start(const void* void_parameter) do { /* Display a menu to choose between the entries */ - leave_loop = list_sc(); - } while (!leave_loop); + ret = list_sc(); + } while (ret == PLUGIN_OK); + if (ret == LOOP_EXIT) + ret = PLUGIN_OK; FOR_NB_SCREENS(i) rb->viewportmanager_theme_undo(i, false); - return usb_connected ? PLUGIN_USB_CONNECTED : PLUGIN_OK; + return ret; } diff --git a/apps/root_menu.c b/apps/root_menu.c index c59c39fe88..2a8662a170 100644 --- a/apps/root_menu.c +++ b/apps/root_menu.c @@ -32,6 +32,7 @@ #include "kernel.h" #include "debug.h" #include "misc.h" +#include "open_plugin.h" #include "rolo.h" #include "powermgmt.h" #include "power.h" @@ -347,6 +348,7 @@ static int miscscrn(void * param) int result = do_menu(menu, NULL, NULL, false); switch (result) { + case GO_TO_PLUGIN: case GO_TO_PLAYLIST_VIEWER: case GO_TO_WPS: return result; @@ -703,7 +705,6 @@ static int load_context_screen(int selection) return retval; } -#ifdef HAVE_PICTUREFLOW_INTEGRATION static int load_plugin_screen(char *plug_path, void* plug_param) { int ret_val; @@ -717,6 +718,9 @@ static int load_plugin_screen(char *plug_path, void* plug_param) case PLUGIN_GOTO_WPS: ret_val = GO_TO_WPS; break; + case PLUGIN_GOTO_PLUGIN: + ret_val = GO_TO_PLUGIN; + break; case PLUGIN_OK: ret_val = audio_status() ? GO_TO_PREVIOUS : GO_TO_ROOT; break; @@ -729,7 +733,6 @@ static int load_plugin_screen(char *plug_path, void* plug_param) last_screen = (old_previous == next_screen) ? GO_TO_ROOT : old_previous; return ret_val; } -#endif void root_menu(void) { @@ -807,21 +810,36 @@ void root_menu(void) case GO_TO_ROOTITEM_CONTEXT: next_screen = load_context_screen(selected); break; -#ifdef HAVE_PICTUREFLOW_INTEGRATION - case GO_TO_PICTUREFLOW: + case GO_TO_PLUGIN: { - char pf_path[MAX_PATH]; - char activity[6];/* big enough to display int */ - snprintf(activity, sizeof(activity), "%d", get_current_activity()); - snprintf(pf_path, sizeof(pf_path), - "%s/pictureflow.rock", - PLUGIN_DEMOS_DIR); - - next_screen = load_plugin_screen(pf_path, &activity); - previous_browser = (next_screen != GO_TO_WPS) ? GO_TO_FILEBROWSER : GO_TO_PICTUREFLOW; + char *key; + switch (last_screen) + { + case GO_TO_ROOT: + key = ID2P(LANG_START_SCREEN); + break; + case GO_TO_WPS: + key = ID2P(LANG_OPEN_PLUGIN_SET_WPS_CONTEXT_PLUGIN); + break; + case GO_TO_SHORTCUTMENU: + key = ID2P(LANG_SHORTCUTS); + break; + default: + key = ID2P(LANG_OPEN_PLUGIN); + break; + } + + open_plugin_get_entry(key, &open_plugin_entry); + char *path = open_plugin_entry.path; + char *param = open_plugin_entry.param; + if (param[0] == '\0') + param = NULL; + + next_screen = load_plugin_screen(path, param); + + previous_browser = (next_screen != GO_TO_WPS) ? GO_TO_FILEBROWSER : GO_TO_PLUGIN; break; } -#endif default: #ifdef HAVE_TAGCACHE /* With !HAVE_TAGCACHE previous_browser is always GO_TO_FILEBROWSER */ diff --git a/apps/root_menu.h b/apps/root_menu.h index 262b1d9a0c..55ea6c72d6 100644 --- a/apps/root_menu.h +++ b/apps/root_menu.h @@ -55,7 +55,7 @@ enum { GO_TO_FM, #endif GO_TO_RECENTBMARKS, - GO_TO_PICTUREFLOW, + GO_TO_PLUGIN, /* Do Not add any items above here unless you want it to be able to be the "start screen" after a boot up. The setting in settings_list.c will need editing if this is the case. */ diff --git a/apps/settings_list.c b/apps/settings_list.c index 1c33f3dc86..a38ebc639c 100644 --- a/apps/settings_list.c +++ b/apps/settings_list.c @@ -38,6 +38,7 @@ #include "power.h" #include "powermgmt.h" #include "kernel.h" +#include "open_plugin.h" #ifdef HAVE_REMOTE_LCD #include "lcd-remote.h" #endif @@ -680,6 +681,11 @@ static void tsc_set_default(void* setting, void* defaultval) } #endif #ifdef HAVE_HOTKEY +static void hotkey_callback(int var) +{ + if (get_hotkey_lang_id(var) == LANG_OPEN_PLUGIN) + open_plugin_browse(ID2P(LANG_HOTKEY_WPS)); +} static const char* hotkey_formatter(char* buffer, size_t buffer_size, int value, const char* unit) { @@ -695,6 +701,12 @@ static int32_t hotkey_getlang(int value, int unit) } #endif /* HAVE_HOTKEY */ +static void start_in_callback(int var) +{ + if (var - 2 == GO_TO_PLUGIN) + open_plugin_browse(ID2P(LANG_START_SCREEN)); +} + /* volume limiter */ static void volume_limit_load_from_cfg(void* var, char*value) { @@ -1872,7 +1884,7 @@ const struct settings_list settings[] = { UNIT_SEC, formatter_time_unit_0_is_skip_track, getlang_time_unit_0_is_skip_track, NULL, 25, timeout_sec_common), - CHOICE_SETTING(0, start_in_screen, LANG_START_SCREEN, 1, + CHOICE_SETTING(F_CB_ON_SELECT_ONLY, start_in_screen, LANG_START_SCREEN, 1, "start in screen", "previous,root,files," #ifdef HAVE_TAGCACHE #define START_DB_COUNT 1 @@ -1893,15 +1905,10 @@ const struct settings_list settings[] = { #else #define START_TUNER_COUNT 0 #endif - "bookmarks" -#ifdef HAVE_PICTUREFLOW_INTEGRATION -#define START_PF_COUNT 1 - ",pictureflow" -#else -#define START_PF_COUNT 0 -#endif - , NULL, - (6 + START_DB_COUNT + START_REC_COUNT + START_TUNER_COUNT + START_PF_COUNT), + "bookmarks," + "plugin" + , start_in_callback, + (7 + START_DB_COUNT + START_REC_COUNT + START_TUNER_COUNT), ID2P(LANG_PREVIOUS_SCREEN), ID2P(LANG_MAIN_MENU), ID2P(LANG_DIR_BROWSER), #ifdef HAVE_TAGCACHE @@ -1914,10 +1921,8 @@ const struct settings_list settings[] = { #if CONFIG_TUNER ID2P(LANG_FM_RADIO), #endif - ID2P(LANG_BOOKMARK_MENU_RECENT_BOOKMARKS) -#ifdef HAVE_PICTUREFLOW_INTEGRATION - ,ID2P(LANG_ONPLAY_PICTUREFLOW) -#endif + ID2P(LANG_BOOKMARK_MENU_RECENT_BOOKMARKS), + ID2P(LANG_OPEN_PLUGIN) ), SYSTEM_SETTING(NVRAM(1),last_screen,-1), #if defined(HAVE_RTC_ALARM) && \ @@ -2098,25 +2103,12 @@ const struct settings_list settings[] = { #endif #ifdef HAVE_HOTKEY - TABLE_SETTING(F_ALLOW_ARBITRARY_VALS, hotkey_wps, + TABLE_SETTING(F_ALLOW_ARBITRARY_VALS | F_CB_ON_SELECT_ONLY, hotkey_wps, LANG_HOTKEY_WPS, HOTKEY_VIEW_PLAYLIST, "hotkey wps", - "off,view playlist,show track info,pitchscreen,open with,delete,bookmark" -#ifdef HAVE_PICTUREFLOW_INTEGRATION - ",pictureflow" -#endif - ,UNIT_INT, hotkey_formatter, hotkey_getlang, NULL, -#ifdef HAVE_PICTUREFLOW_INTEGRATION - 8, -#else - 7, -#endif - HOTKEY_OFF, + "off,view playlist,show track info,pitchscreen,open with,delete,bookmark,plugin" + ,UNIT_INT, hotkey_formatter, hotkey_getlang, hotkey_callback,8, HOTKEY_OFF, HOTKEY_VIEW_PLAYLIST, HOTKEY_SHOW_TRACK_INFO, HOTKEY_PITCHSCREEN, - HOTKEY_OPEN_WITH, HOTKEY_DELETE, HOTKEY_BOOKMARK -#ifdef HAVE_PICTUREFLOW_INTEGRATION - , HOTKEY_PICTUREFLOW -#endif - ), + HOTKEY_OPEN_WITH, HOTKEY_DELETE, HOTKEY_BOOKMARK, HOTKEY_PLUGIN), TABLE_SETTING(F_ALLOW_ARBITRARY_VALS, hotkey_tree, LANG_HOTKEY_FILE_BROWSER, HOTKEY_OFF, "hotkey tree", "off,open with,delete,insert,insert shuffled", diff --git a/apps/settings_list.h b/apps/settings_list.h index 7f0ae6484f..36c4d8062f 100644 --- a/apps/settings_list.h +++ b/apps/settings_list.h @@ -100,6 +100,7 @@ struct table_setting { }; #define F_TABLE_SETTING 0x2000 #define F_ALLOW_ARBITRARY_VALS 0x4000 +#define F_CB_ON_SELECT_ONLY 0x20000 /* these use the _isfunc_type type for the function */ /* typedef int (*_isfunc_type)(void); */ #define F_MIN_ISFUNC 0x100000 /* min(above) is function pointer to above type */ diff --git a/apps/shortcuts.c b/apps/shortcuts.c index c7e5755c1a..aa9a32bbb2 100644 --- a/apps/shortcuts.c +++ b/apps/shortcuts.c @@ -36,6 +36,7 @@ #include "lang.h" #include "menu.h" #include "misc.h" +#include "open_plugin.h" #include "tree.h" #include "splash.h" #include "pathfuncs.h" @@ -608,6 +609,12 @@ int do_shortcut_menu(void *ignored) /* else fall through */ case SHORTCUT_BROWSER: { + + if(open_plugin_add_path(ID2P(LANG_SHORTCUTS), sc->u.path, NULL) != 0) + { + done = GO_TO_PLUGIN; + break; + } struct browse_context browse; browse_context_init(&browse, global_settings.dirfilter, 0, NULL, NOICON, sc->u.path, NULL); diff --git a/apps/tree.c b/apps/tree.c index 316139427d..48723c4f2e 100644 --- a/apps/tree.c +++ b/apps/tree.c @@ -676,6 +676,8 @@ static int dirbrowse(void) #endif { case GO_TO_FILEBROWSER: reload_dir = true; break; + case GO_TO_PLUGIN: + return GO_TO_PLUGIN; case GO_TO_WPS: return GO_TO_WPS; #if CONFIG_TUNER diff --git a/manual/advanced_topics/main.tex b/manual/advanced_topics/main.tex index 00b1688e11..997850a6fd 100755 --- a/manual/advanced_topics/main.tex +++ b/manual/advanced_topics/main.tex @@ -36,6 +36,12 @@ This configuration entry can only be created and edited with a text editor or the Main Menu Config Plugin (see \reference{ref:main_menu_config}). It is not possible to change this setting via the settings menu. +\subsection{\label{ref:OpenPlugins}Open Plugin Menu Items} + +Rockbox allows you to choose a plugin to run for select menu options. +Simply choose the option in the setting menu and choose the plugin +you would like to run. + \opt{lcd_bitmap}{ \subsection{\label{ref:GettingExtras}Getting Extras} diff --git a/manual/configure_rockbox/main.tex b/manual/configure_rockbox/main.tex index 0eeea4e256..83089b6d4e 100644 --- a/manual/configure_rockbox/main.tex +++ b/manual/configure_rockbox/main.tex @@ -21,6 +21,7 @@ }} \input{configure_rockbox/language.tex} \input{configure_rockbox/voice.tex} + \input{configure_rockbox/wps_context_plugin.tex} \input{configure_rockbox/hotkey_settings.tex} \chapter{Theme Settings} diff --git a/manual/configure_rockbox/wps_context_plugin.tex b/manual/configure_rockbox/wps_context_plugin.tex new file mode 100644 index 0000000000..8d193d47d6 --- /dev/null +++ b/manual/configure_rockbox/wps_context_plugin.tex @@ -0,0 +1,5 @@ +\section{\label{ref:SetWPSContextPlugin}Set WPS Context Plugin} + + \begin{description} + {This option will allow you to run a rockbox plugin from the WPS context menu} + \end{description}