rockbox/apps/root_menu.c

843 lines
26 KiB
C
Raw Normal View History

/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2007 Jonathan Gordon
*
* 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.
*
****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include "string-extra.h"
#include "config.h"
#include "appevents.h"
#include "menu.h"
#include "root_menu.h"
#include "lang.h"
#include "settings.h"
#include "screens.h"
#include "kernel.h"
#include "debug.h"
#include "misc.h"
#include "rolo.h"
#include "powermgmt.h"
#include "power.h"
#include "talk.h"
#include "audio.h"
#include "shortcuts.h"
#ifdef HAVE_HOTSWAP
#include "storage.h"
#include "dir.h"
#endif
/* gui api */
#include "list.h"
#include "splash.h"
#include "action.h"
#include "yesno.h"
#include "viewport.h"
#include "tree.h"
#if CONFIG_TUNER
#include "radio.h"
#endif
#ifdef HAVE_RECORDING
#include "recording.h"
#endif
#include "wps.h"
#include "bookmark.h"
#include "playlist.h"
#include "playlist_viewer.h"
#include "playlist_catalog.h"
#include "menus/exported_menus.h"
#ifdef HAVE_RTC_ALARM
#include "rtc.h"
#endif
#ifdef HAVE_TAGCACHE
#include "tagcache.h"
#endif
#include "language.h"
#include "plugin.h"
#include "disk.h"
struct root_items {
int (*function)(void* param);
void* param;
const struct menu_item_ex *context_menu;
};
static int next_screen = GO_TO_ROOT; /* holding info about the upcoming screen
* which is the current screen for the
* rest of the code after load_screen
* is called */
static int last_screen = GO_TO_ROOT; /* unfortunatly needed so we can resume
or goto current track based on previous
screen */
static char current_track_path[MAX_PATH];
static void rootmenu_track_changed_callback(void* param)
{
struct mp3entry *id3 = ((struct track_event *)param)->id3;
strlcpy(current_track_path, id3->path, MAX_PATH);
}
static int browser(void* param)
{
int ret_val;
#ifdef HAVE_TAGCACHE
struct tree_context* tc = tree_get_context();
#endif
struct browse_context browse;
int filter = SHOW_SUPPORTED;
char folder[MAX_PATH] = "/";
/* stuff needed to remember position in file browser */
static char last_folder[MAX_PATH] = "/";
/* and stuff for the database browser */
#ifdef HAVE_TAGCACHE
static int last_db_dirlevel = 0, last_db_selection = 0;
#endif
switch ((intptr_t)param)
{
case GO_TO_FILEBROWSER:
filter = global_settings.dirfilter;
if (global_settings.browse_current &&
last_screen == GO_TO_WPS &&
current_track_path[0])
{
strcpy(folder, current_track_path);
}
else if (!strcmp(last_folder, "/"))
{
strcpy(folder, global_settings.start_directory);
}
else
{
#ifdef HAVE_HOTSWAP
bool in_hotswap = false;
/* handle entering an ejected drive */
int i;
for (i = 0; i < NUM_VOLUMES; i++)
{
char vol_string[VOL_ENUM_POS + 8];
if (!volume_removable(i))
continue;
/* VOL_NAMES contains a %d */
snprintf(vol_string, sizeof(vol_string), "/"VOL_NAMES, i);
/* test whether we would browse the external card */
if (!volume_present(i) &&
(strstr(last_folder, vol_string)
#ifdef HAVE_HOTSWAP_STORAGE_AS_MAIN
|| (i == 0)
#endif
))
{ /* leave folder as "/" to avoid crash when trying
* to access an ejected drive */
strcpy(folder, "/");
in_hotswap = true;
break;
}
}
if (!in_hotswap)
#endif
strcpy(folder, last_folder);
}
push_current_activity(ACTIVITY_FILEBROWSER);
break;
#ifdef HAVE_TAGCACHE
case GO_TO_DBBROWSER:
if (!tagcache_is_usable())
{
bool reinit_attempted = false;
/* Now display progress until it's ready or the user exits */
while(!tagcache_is_usable())
{
struct tagcache_stat *stat = tagcache_get_stat();
/* Allow user to exit */
if (action_userabort(HZ/2))
break;
/* Maybe just needs to reboot due to delayed commit */
if (stat->commit_delayed)
{
splash(HZ*2, ID2P(LANG_PLEASE_REBOOT));
break;
}
/* Check if ready status is known */
if (!stat->readyvalid)
{
splash(0, str(LANG_TAGCACHE_BUSY));
continue;
}
/* Re-init if required */
if (!reinit_attempted && !stat->ready &&
stat->processed_entries == 0 && stat->commit_step == 0)
{
/* Prompt the user */
reinit_attempted = true;
static const char *lines[]={
ID2P(LANG_TAGCACHE_BUSY), ID2P(LANG_TAGCACHE_FORCE_UPDATE)};
static const struct text_message message={lines, 2};
if(gui_syncyesno_run(&message, NULL, NULL) == YESNO_NO)
break;
FOR_NB_SCREENS(i)
screens[i].clear_display();
/* Start initialisation */
tagcache_rebuild();
}
/* Display building progress */
static long talked_tick = 0;
if(global_settings.talk_menu &&
(talked_tick == 0
|| TIME_AFTER(current_tick, talked_tick+7*HZ)))
{
talked_tick = current_tick;
if (stat->commit_step > 0)
{
talk_id(LANG_TAGCACHE_INIT, false);
talk_number(stat->commit_step, true);
talk_id(VOICE_OF, true);
talk_number(tagcache_get_max_commit_step(), true);
} else if(stat->processed_entries)
{
talk_number(stat->processed_entries, false);
talk_id(LANG_BUILDING_DATABASE, true);
}
}
if (stat->commit_step > 0)
{
if (lang_is_rtl())
{
splashf(0, "[%d/%d] %s", stat->commit_step,
tagcache_get_max_commit_step(),
str(LANG_TAGCACHE_INIT));
}
else
{
splashf(0, "%s [%d/%d]", str(LANG_TAGCACHE_INIT),
stat->commit_step,
tagcache_get_max_commit_step());
}
}
else
{
splashf(0, str(LANG_BUILDING_DATABASE),
stat->processed_entries);
}
}
}
if (!tagcache_is_usable())
return GO_TO_PREVIOUS;
filter = SHOW_ID3DB;
tc->dirlevel = last_db_dirlevel;
tc->selected_item = last_db_selection;
push_current_activity(ACTIVITY_DATABASEBROWSER);
break;
#endif
}
browse_context_init(&browse, filter, 0, NULL, NOICON, folder, NULL);
ret_val = rockbox_browse(&browse);
pop_current_activity();
switch ((intptr_t)param)
{
case GO_TO_FILEBROWSER:
if (!get_current_file(last_folder, MAX_PATH) ||
(!strchr(&last_folder[1], '/') &&
global_settings.start_directory[1] != '\0'))
{
last_folder[0] = '/';
last_folder[1] = '\0';
}
break;
#ifdef HAVE_TAGCACHE
case GO_TO_DBBROWSER:
last_db_dirlevel = tc->dirlevel;
last_db_selection = tc->selected_item;
break;
#endif
}
return ret_val;
}
#ifdef HAVE_RECORDING
static int recscrn(void* param)
{
(void)param;
recording_screen(false);
return GO_TO_ROOT;
}
#endif
static int wpsscrn(void* param)
{
int ret_val = GO_TO_PREVIOUS;
(void)param;
push_current_activity(ACTIVITY_WPS);
if (audio_status())
{
talk_shutup();
ret_val = gui_wps_show();
}
else if ( global_status.resume_index != -1 )
{
DEBUGF("Resume index %X crc32 %lX offset %lX\n",
global_status.resume_index,
(unsigned long)global_status.resume_crc32,
(unsigned long)global_status.resume_offset);
if (playlist_resume() != -1)
{
playlist_resume_track(global_status.resume_index,
global_status.resume_crc32,
global_status.resume_offset);
ret_val = gui_wps_show();
}
}
else
{
splash(HZ*2, ID2P(LANG_NOTHING_TO_RESUME));
}
pop_current_activity();
return ret_val;
}
#if CONFIG_TUNER
static int radio(void* param)
{
(void)param;
radio_screen();
return GO_TO_ROOT;
}
#endif
static int miscscrn(void * param)
{
const struct menu_item_ex *menu = (const struct menu_item_ex*)param;
int result = do_menu(menu, NULL, NULL, false);
switch (result)
{
case GO_TO_PLAYLIST_VIEWER:
case GO_TO_WPS:
return result;
default:
return GO_TO_ROOT;
}
}
static int playlist_view_catalog(void * param)
{
/* kludge untill catalog_view_playlists() returns something useful */
int old_playstatus = audio_status();
(void)param;
push_current_activity(ACTIVITY_PLAYLISTBROWSER);
catalog_view_playlists();
pop_current_activity();
if (!old_playstatus && audio_status())
return GO_TO_WPS;
return GO_TO_PREVIOUS;
}
static int playlist_view(void * param)
{
(void)param;
int val;
push_current_activity(ACTIVITY_PLAYLISTVIEWER);
val = playlist_viewer();
pop_current_activity();
switch (val)
{
case PLAYLIST_VIEWER_MAINMENU:
case PLAYLIST_VIEWER_USB:
return GO_TO_ROOT;
case PLAYLIST_VIEWER_OK:
return GO_TO_PREVIOUS;
}
return GO_TO_PREVIOUS;
}
static int load_bmarks(void* param)
{
(void)param;
if(bookmark_mrb_load())
return GO_TO_WPS;
return GO_TO_PREVIOUS;
}
/* These are all static const'd from apps/menus/ *.c
so little hack so we can use them */
extern struct menu_item_ex
file_menu,
#ifdef HAVE_TAGCACHE
tagcache_menu,
#endif
main_menu_,
manage_settings,
plugin_menu,
playlist_options,
info_menu,
system_menu;
static const struct root_items items[] = {
[GO_TO_FILEBROWSER] = { browser, (void*)GO_TO_FILEBROWSER, &file_menu},
#ifdef HAVE_TAGCACHE
[GO_TO_DBBROWSER] = { browser, (void*)GO_TO_DBBROWSER, &tagcache_menu },
#endif
[GO_TO_WPS] = { wpsscrn, NULL, &playback_settings },
[GO_TO_MAINMENU] = { miscscrn, (struct menu_item_ex*)&main_menu_,
&manage_settings },
#ifdef HAVE_RECORDING
[GO_TO_RECSCREEN] = { recscrn, NULL, &recording_settings_menu },
#endif
#if CONFIG_TUNER
[GO_TO_FM] = { radio, NULL, &radio_settings_menu },
#endif
[GO_TO_RECENTBMARKS] = { load_bmarks, NULL, &bookmark_settings_menu },
[GO_TO_BROWSEPLUGINS] = { miscscrn, &plugin_menu, NULL },
[GO_TO_PLAYLISTS_SCREEN] = { playlist_view_catalog, NULL,
&playlist_options },
[GO_TO_PLAYLIST_VIEWER] = { playlist_view, NULL, &playlist_options },
[GO_TO_SYSTEM_SCREEN] = { miscscrn, &info_menu, &system_menu },
[GO_TO_SHORTCUTMENU] = { do_shortcut_menu, NULL, NULL },
};
static const int nb_items = sizeof(items)/sizeof(*items);
static int item_callback(int action, const struct menu_item_ex *this_item) ;
MENUITEM_RETURNVALUE(shortcut_menu, ID2P(LANG_SHORTCUTS), GO_TO_SHORTCUTMENU,
NULL, Icon_Bookmark);
MENUITEM_RETURNVALUE(file_browser, ID2P(LANG_DIR_BROWSER), GO_TO_FILEBROWSER,
NULL, Icon_file_view_menu);
#ifdef HAVE_TAGCACHE
MENUITEM_RETURNVALUE(db_browser, ID2P(LANG_TAGCACHE), GO_TO_DBBROWSER,
NULL, Icon_Audio);
#endif
MENUITEM_RETURNVALUE(rocks_browser, ID2P(LANG_PLUGINS), GO_TO_BROWSEPLUGINS,
NULL, Icon_Plugin);
MENUITEM_RETURNVALUE(playlist_browser, ID2P(LANG_CATALOG), GO_TO_PLAYLIST_VIEWER,
NULL, Icon_Playlist);
static char *get_wps_item_name(int selected_item, void * data, char *buffer)
{
(void)selected_item; (void)data; (void)buffer;
if (audio_status())
return ID2P(LANG_NOW_PLAYING);
return ID2P(LANG_RESUME_PLAYBACK);
}
MENUITEM_RETURNVALUE_DYNTEXT(wps_item, GO_TO_WPS, NULL, get_wps_item_name,
NULL, NULL, Icon_Playback_menu);
#ifdef HAVE_RECORDING
MENUITEM_RETURNVALUE(rec, ID2P(LANG_RECORDING), GO_TO_RECSCREEN,
NULL, Icon_Recording);
#endif
#if CONFIG_TUNER
MENUITEM_RETURNVALUE(fm, ID2P(LANG_FM_RADIO), GO_TO_FM,
item_callback, Icon_Radio_screen);
#endif
MENUITEM_RETURNVALUE(menu_, ID2P(LANG_SETTINGS), GO_TO_MAINMENU,
NULL, Icon_Submenu_Entered);
MENUITEM_RETURNVALUE(bookmarks, ID2P(LANG_BOOKMARK_MENU_RECENT_BOOKMARKS),
GO_TO_RECENTBMARKS, item_callback,
Icon_Bookmark);
MENUITEM_RETURNVALUE(playlists, ID2P(LANG_CATALOG), GO_TO_PLAYLISTS_SCREEN,
NULL, Icon_Playlist);
MENUITEM_RETURNVALUE(system_menu_, ID2P(LANG_SYSTEM), GO_TO_SYSTEM_SCREEN,
NULL, Icon_System_menu);
#if CONFIG_KEYPAD == PLAYER_PAD
static int do_shutdown(void)
{
#if CONFIG_CHARGING
if (charger_inserted())
charging_splash();
else
#endif
sys_poweroff();
return 0;
}
MENUITEM_FUNCTION(do_shutdown_item, 0, ID2P(LANG_SHUTDOWN),
do_shutdown, NULL, NULL, Icon_NOICON);
#endif
struct menu_item_ex root_menu_;
static struct menu_callback_with_desc root_menu_desc = {
item_callback, ID2P(LANG_ROCKBOX_TITLE), Icon_Rockbox };
struct menu_table {
char *string;
const struct menu_item_ex *item;
};
static struct menu_table menu_table[] = {
/* Order here represents the default ordering */
{ "bookmarks", &bookmarks },
{ "files", &file_browser },
#ifdef HAVE_TAGCACHE
{ "database", &db_browser },
#endif
{ "wps", &wps_item },
{ "settings", &menu_ },
#ifdef HAVE_RECORDING
{ "recording", &rec },
#endif
#if CONFIG_TUNER
{ "radio", &fm },
#endif
{ "playlists", &playlists },
{ "plugins", &rocks_browser },
{ "system_menu", &system_menu_ },
#if CONFIG_KEYPAD == PLAYER_PAD
{ "shutdown", &do_shutdown_item },
#endif
{ "shortcuts", &shortcut_menu },
};
#define MAX_MENU_ITEMS (sizeof(menu_table) / sizeof(struct menu_table))
static struct menu_item_ex *root_menu__[MAX_MENU_ITEMS];
void root_menu_load_from_cfg(void* setting, char *value)
{
char *next = value, *start, *end;
unsigned int menu_item_count = 0, i;
bool main_menu_added = false;
if (*value == '-')
{
root_menu_set_default(setting, NULL);
return;
}
root_menu_.flags = MENU_HAS_DESC | MT_MENU;
root_menu_.submenus = (const struct menu_item_ex **)&root_menu__;
root_menu_.callback_and_desc = &root_menu_desc;
while (next && menu_item_count < MAX_MENU_ITEMS)
{
start = next;
next = strchr(next, ',');
if (next)
{
*next = '\0';
next++;
}
start = skip_whitespace(start);
if ((end = strchr(start, ' ')))
*end = '\0';
for (i=0; i<MAX_MENU_ITEMS; i++)
{
if (*start && !strcmp(start, menu_table[i].string))
{
root_menu__[menu_item_count++] = (struct menu_item_ex *)menu_table[i].item;
if (menu_table[i].item == &menu_)
main_menu_added = true;
break;
}
}
}
if (!main_menu_added)
root_menu__[menu_item_count++] = (struct menu_item_ex *)&menu_;
root_menu_.flags |= MENU_ITEM_COUNT(menu_item_count);
*(bool*)setting = true;
}
char* root_menu_write_to_cfg(void* setting, char*buf, int buf_len)
{
(void)setting;
unsigned i, written, j;
for (i = 0; i < MENU_GET_COUNT(root_menu_.flags); i++)
{
for (j=0; j<MAX_MENU_ITEMS; j++)
{
if (menu_table[j].item == root_menu__[i])
{
written = snprintf(buf, buf_len, "%s, ", menu_table[j].string);
buf_len -= written;
buf += written;
break;
}
}
}
return buf;
}
void root_menu_set_default(void* setting, void* defaultval)
{
unsigned i;
(void)defaultval;
root_menu_.flags = MENU_HAS_DESC | MT_MENU;
root_menu_.submenus = (const struct menu_item_ex **)&root_menu__;
root_menu_.callback_and_desc = &root_menu_desc;
for (i=0; i<MAX_MENU_ITEMS; i++)
{
root_menu__[i] = (struct menu_item_ex *)menu_table[i].item;
}
root_menu_.flags |= MENU_ITEM_COUNT(MAX_MENU_ITEMS);
*(bool*)setting = false;
}
bool root_menu_is_changed(void* setting, void* defaultval)
{
(void)defaultval;
return *(bool*)setting;
}
static int item_callback(int action, const struct menu_item_ex *this_item)
{
switch (action)
{
case ACTION_TREE_STOP:
return ACTION_REDRAW;
case ACTION_REQUEST_MENUITEM:
#if CONFIG_TUNER
if (this_item == &fm)
{
if (radio_hardware_present() == 0)
return ACTION_EXIT_MENUITEM;
}
else
#endif
if (this_item == &bookmarks)
{
if (global_settings.usemrb == 0)
return ACTION_EXIT_MENUITEM;
}
break;
}
return action;
}
static int get_selection(int last_screen)
{
int i;
int len = ARRAYLEN(root_menu__);
for(i=0; i < len; i++)
{
if (((root_menu__[i]->flags&MENU_TYPE_MASK) == MT_RETURN_VALUE) &&
(root_menu__[i]->value == last_screen))
{
return i;
}
}
return 0;
}
static inline int load_screen(int screen)
{
/* set the global_status.last_screen before entering,
if we dont we will always return to the wrong screen on boot */
int old_previous = last_screen;
int ret_val;
enum current_activity activity = ACTIVITY_UNKNOWN;
if (screen <= GO_TO_ROOT)
return screen;
if (screen == old_previous)
old_previous = GO_TO_ROOT;
global_status.last_screen = (char)screen;
status_save();
if (screen == GO_TO_BROWSEPLUGINS)
activity = ACTIVITY_PLUGINBROWSER;
else if (screen == GO_TO_MAINMENU)
activity = ACTIVITY_SETTINGS;
else if (screen == GO_TO_SYSTEM_SCREEN)
activity = ACTIVITY_SYSTEMSCREEN;
if (activity != ACTIVITY_UNKNOWN)
push_current_activity(activity);
ret_val = items[screen].function(items[screen].param);
if (activity != ACTIVITY_UNKNOWN)
pop_current_activity();
last_screen = screen;
if (ret_val == GO_TO_PREVIOUS)
last_screen = old_previous;
return ret_val;
}
static int load_context_screen(int selection)
{
const struct menu_item_ex *context_menu = NULL;
int retval = GO_TO_PREVIOUS;
push_current_activity(ACTIVITY_CONTEXTMENU);
if ((root_menu__[selection]->flags&MENU_TYPE_MASK) == MT_RETURN_VALUE)
{
int item = root_menu__[selection]->value;
context_menu = items[item].context_menu;
}
/* special cases */
else if (root_menu__[selection] == &info_menu)
{
context_menu = &system_menu;
}
if (context_menu)
retval = do_menu(context_menu, NULL, NULL, false);
pop_current_activity();
return retval;
}
#ifdef HAVE_PICTUREFLOW_INTEGRATION
static int load_plugin_screen(char *plug_path)
{
int ret_val;
int old_previous = last_screen;
last_screen = next_screen;
global_status.last_screen = (char)next_screen;
status_save();
switch (plugin_load(plug_path, NULL))
{
case PLUGIN_GOTO_WPS:
ret_val = GO_TO_WPS;
break;
case PLUGIN_OK:
ret_val = audio_status() ? GO_TO_PREVIOUS : GO_TO_ROOT;
break;
default:
ret_val = GO_TO_PREVIOUS;
break;
}
if (ret_val == GO_TO_PREVIOUS)
last_screen = (old_previous == next_screen) ? GO_TO_ROOT : old_previous;
return ret_val;
}
#endif
static int previous_music = GO_TO_WPS;
void previous_music_is_wps(void)
{
previous_music = GO_TO_WPS;
}
void root_menu(void)
{
int previous_browser = GO_TO_FILEBROWSER;
int selected = 0;
push_current_activity(ACTIVITY_MAINMENU);
if (global_settings.start_in_screen == 0)
next_screen = (int)global_status.last_screen;
else next_screen = global_settings.start_in_screen - 2;
add_event(PLAYBACK_EVENT_TRACK_CHANGE, false, rootmenu_track_changed_callback);
#ifdef HAVE_RTC_ALARM
if ( rtc_check_alarm_started(true) )
{
rtc_enable_alarm(false);
next_screen = GO_TO_WPS;
#if CONFIG_TUNER
if (global_settings.alarm_wake_up_screen == ALARM_START_FM)
next_screen = GO_TO_FM;
#endif
#ifdef HAVE_RECORDING
if (global_settings.alarm_wake_up_screen == ALARM_START_REC)
{
recording_start_automatic = true;
next_screen = GO_TO_RECSCREEN;
}
#endif
}
#endif /* HAVE_RTC_ALARM */
#ifdef HAVE_HEADPHONE_DETECTION
if (next_screen == GO_TO_WPS &&
(global_settings.unplug_autoresume && !headphones_inserted() ))
next_screen = GO_TO_ROOT;
#endif
while (true)
{
switch (next_screen)
{
case MENU_ATTACHED_USB:
case MENU_SELECTED_EXIT:
/* fall through */
case GO_TO_ROOT:
if (last_screen != GO_TO_ROOT)
selected = get_selection(last_screen);
#if (CONFIG_PLATFORM&PLATFORM_ANDROID)
/* When we are in the main menu we want the hardware BACK
* button to be handled by Android instead of rockbox */
android_ignore_back_button(true);
#endif
next_screen = do_menu(&root_menu_, &selected, NULL, false);
#if (CONFIG_PLATFORM&PLATFORM_ANDROID)
android_ignore_back_button(false);
#endif
if (next_screen != GO_TO_PREVIOUS)
last_screen = GO_TO_ROOT;
break;
case GO_TO_PREVIOUS:
next_screen = last_screen;
break;
case GO_TO_PREVIOUS_BROWSER:
next_screen = previous_browser;
break;
case GO_TO_PREVIOUS_MUSIC:
next_screen = previous_music;
break;
case GO_TO_ROOTITEM_CONTEXT:
next_screen = load_context_screen(selected);
break;
#ifdef HAVE_PICTUREFLOW_INTEGRATION
case GO_TO_PICTUREFLOW:
while ( !tagcache_is_usable() )
{
splash(0, str(LANG_TAGCACHE_BUSY));
if ( action_userabort(HZ/5) )
break;
}
{
char pf_path[MAX_PATH];
snprintf(pf_path, sizeof(pf_path),
"%s/pictureflow.rock",
PLUGIN_DEMOS_DIR);
next_screen = load_plugin_screen(pf_path);
}
previous_browser = GO_TO_PICTUREFLOW;
break;
#endif
default:
if (next_screen == GO_TO_FILEBROWSER
#ifdef HAVE_TAGCACHE
|| next_screen == GO_TO_DBBROWSER
#endif
)
previous_browser = next_screen;
if (next_screen == GO_TO_WPS
#if CONFIG_TUNER
|| next_screen == GO_TO_FM
#endif
)
previous_music = next_screen;
next_screen = load_screen(next_screen);
break;
} /* switch() */
}
}