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"
+
+
+
+ id: LANG_OPEN_PLUGIN_NOT_A_PLUGIN
+ desc: open plugin module
+ user: core
+
+
+ *: "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"
+
+
+
+ id: LANG_PARAMETER
+ desc:
+ user: core
+
+
+ *: "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}