From 35502834423049b319fde41ff305b48de67d2d51 Mon Sep 17 00:00:00 2001 From: William Wilgus Date: Fri, 31 Jul 2020 22:45:10 -0400 Subject: [PATCH] Add open_plugin to core open_plugin allows arbitrary plugins to be called in hotkey and start screen replaces PictureFlow Integration shortcuts menu plays plugins now too rather than store paths and parameters in the settings that reside in memory instead entries in a file are searched by hash. after all, the plugin has to be loaded from disk anyways ---------------------------------------------------------------------------- shortcut_viewer.rock-- can now call plugins rather than taking you to them in the browser ----------------------------------------------------------------------------- Added a new option to menus: F_CB_ON_SELECT_ONLY instead of option callback every time a item is accessed F_CB_ON_SELECT_ONLY fires callback only when item is selected ----------------------------------------------------------------------------- Added manual entries ----------------------------------------------------------------------------- Change-Id: I078b57b1d2b4dd633c89212c1082fcbc1b516e6a --- apps/SOURCES | 1 + apps/filetree.c | 15 +- apps/filetypes.c | 1 + apps/filetypes.h | 1 + apps/gui/option_select.c | 7 +- apps/gui/wps.c | 6 +- apps/lang/english.lang | 56 +++++ apps/menus/settings_menu.c | 14 ++ apps/onplay.c | 30 ++- apps/onplay.h | 4 +- apps/open_plugin.c | 204 ++++++++++++++++++ apps/open_plugin.h | 66 ++++++ apps/plugin.c | 8 + apps/plugin.h | 3 + apps/plugins/pictureflow/pictureflow.c | 19 +- apps/plugins/shortcuts/shortcuts_view.c | 74 +++++-- apps/root_menu.c | 46 ++-- apps/root_menu.h | 2 +- apps/settings_list.c | 54 ++--- apps/settings_list.h | 1 + apps/shortcuts.c | 7 + apps/tree.c | 2 + manual/advanced_topics/main.tex | 6 + manual/configure_rockbox/main.tex | 1 + .../configure_rockbox/wps_context_plugin.tex | 5 + 25 files changed, 540 insertions(+), 93 deletions(-) create mode 100644 apps/open_plugin.c create mode 100644 apps/open_plugin.h create mode 100644 manual/configure_rockbox/wps_context_plugin.tex 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}