From d7afd99d63f3514d8f5e449db0a5a72a354cdb42 Mon Sep 17 00:00:00 2001 From: gprot42 Date: Thu, 9 Jul 2026 16:26:21 +0100 Subject: [PATCH 1/2] webOS: fix file browser hang on filesystem root Under jailer, readdir/stat on / can stall the UI via /proc and /sys. Do not offer "/" as a drive, redirect root back to the safe drive list, and skip virtual FS nodes if root is enumerated. --- frontend/drivers/platform_unix.c | 71 ++++++++++++++++++++++++-------- libretro-common/lists/dir_list.c | 11 +++++ menu/menu_displaylist.c | 14 +++++++ 3 files changed, 79 insertions(+), 17 deletions(-) diff --git a/frontend/drivers/platform_unix.c b/frontend/drivers/platform_unix.c index 53deda53eab6..08ed3fed1b2b 100644 --- a/frontend/drivers/platform_unix.c +++ b/frontend/drivers/platform_unix.c @@ -2360,23 +2360,58 @@ static int frontend_unix_parse_drive_list(void *data, bool load_content) } #elif defined(WEBOS) - if (path_is_directory("/media/developer/temp")) - menu_entries_append(list, "/media/developer/temp", - msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR), - enum_idx, - FILE_TYPE_DIRECTORY, 0, 0, NULL); - - if (path_is_directory("/media/internal")) - menu_entries_append(list, "/media/internal", - msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR), - enum_idx, - FILE_TYPE_DIRECTORY, 0, 0, NULL); + /* Prefer real storage paths. Do not list jail root "/" — readdir on + * /proc and /sys under jailer can stall the UI for a long time. */ + { + char app_dir[PATH_MAX_LENGTH]; + char app_config[PATH_MAX_LENGTH]; + size_t wi; + static const char *const webos_storage[] = { + "/media/developer/temp", + "/media/developer", + "/media/internal/downloads", + "/media/internal", + "/tmp/usb", + "/tmp", + NULL + }; + + /* Application package, config tree, and downloads (common content). */ + app_dir[0] = '\0'; + fill_pathname_application_dir(app_dir, sizeof(app_dir)); + if (!string_is_empty(app_dir) && path_is_directory(app_dir)) + { + menu_entries_append(list, app_dir, + msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR), + enum_idx, + FILE_TYPE_DIRECTORY, 0, 0, NULL); - if (path_is_directory("/tmp/usb")) - menu_entries_append(list, "/tmp/usb", - msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR), - enum_idx, - FILE_TYPE_DIRECTORY, 0, 0, NULL); + fill_pathname_join_special(app_config, app_dir, ".config/retroarch", + sizeof(app_config)); + if (path_is_directory(app_config)) + menu_entries_append(list, app_config, + msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR), + enum_idx, + FILE_TYPE_DIRECTORY, 0, 0, NULL); + + fill_pathname_join_special(app_config, app_dir, + ".config/retroarch/downloads", sizeof(app_config)); + if (path_is_directory(app_config)) + menu_entries_append(list, app_config, + msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR), + enum_idx, + FILE_TYPE_DIRECTORY, 0, 0, NULL); + } + + for (wi = 0; webos_storage[wi]; wi++) + { + if (path_is_directory(webos_storage[wi])) + menu_entries_append(list, webos_storage[wi], + msg_hash_to_str(MENU_ENUM_LABEL_FILE_DETECT_CORE_LIST_PUSH_DIR), + enum_idx, + FILE_TYPE_DIRECTORY, 0, 0, NULL); + } + } #else char base_path[PATH_MAX] = {0}; char udisks_media_path[PATH_MAX] = {0}; @@ -2446,7 +2481,8 @@ static int frontend_unix_parse_drive_list(void *data, bool load_content) } #endif -#ifdef ANDROID +#if !defined(WEBOS) +#if defined(ANDROID) if (!g_android->is_play_store_build) #else if (1) @@ -2457,6 +2493,7 @@ static int frontend_unix_parse_drive_list(void *data, bool load_content) enum_idx, FILE_TYPE_DIRECTORY, 0, 0, NULL); } +#endif #if defined(ANDROID) && defined(HAVE_SAF) if (g_android->have_saf) diff --git a/libretro-common/lists/dir_list.c b/libretro-common/lists/dir_list.c index 49f4e846f43f..c6ca9b5fa15d 100644 --- a/libretro-common/lists/dir_list.c +++ b/libretro-common/lists/dir_list.c @@ -187,6 +187,17 @@ static int dir_list_read(const char *dir, fill_pathname_join_special(file_path, dir, name, sizeof(file_path)); +#if defined(WEBOS) + /* Skip virtual / dangerous FS nodes under jail root — readdir+stat + * on /proc or /sys can stall the main thread for a long time. */ + if ( (string_is_equal(dir, "/") || string_is_equal(dir, "//")) + && ( string_is_equal(name, "proc") + || string_is_equal(name, "sys") + || string_is_equal(name, "dev") + || string_is_equal(name, "run"))) + continue; +#endif + if (retro_dirent_is_dir(entry, NULL)) { /* Exclude this frequent hidden dir on platforms which can not handle hidden attribute */ diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index f976a496dcd8..ff48bee16450 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -260,6 +260,20 @@ static int filebrowser_parse( || string_is_equal(label, "cursor_manager_list")) allow_parent_directory = false; +#if defined(WEBOS) + /* Parent-directory navigation can still reach "/". Re-show the + * platform drive list instead of readdir() on jail root, which + * freezes the UI when /proc or /sys is scanned. */ + if (string_is_equal(full_path, "/") || string_is_equal(full_path, "//")) + { + frontend_driver_parse_drive_list(info_list, true); + allow_parent_directory = false; + count = 1; /* info_list already has drives; avoid "No items" */ + ret = true; + goto end; + } +#endif + if (filebrowser_type == FILEBROWSER_SELECT_FILE_SUBSYSTEM) { runloop_state_t *runloop_st = runloop_state_get_ptr(); From 1c8c2ef920b18d0726758a32930608cad1eb4dda Mon Sep 17 00:00:00 2001 From: gprot42 Date: Thu, 9 Jul 2026 16:26:21 +0100 Subject: [PATCH 2/2] webOS: fix Load Content not listing user files Jail HOME/XDG paths often miss the app package; extension filtering hides files when no matching core is selected. Point defaults at package .config/retroarch and internal storage, disable extension filter by default, and list app config/downloads in the drive list. --- config.def.h | 9 +++++++++ configuration.c | 2 +- frontend/drivers/platform_unix.c | 25 +++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) diff --git a/config.def.h b/config.def.h index a2f36dab486c..c17c664642a2 100644 --- a/config.def.h +++ b/config.def.h @@ -1906,4 +1906,13 @@ #define DEFAULT_FILTER_BY_CURRENT_CORE false +/* Filter file browser to core-supported extensions only. + * On webOS TVs this often hides content when no core is loaded or the + * wrong core is selected — default off so Load Content lists files. */ +#if defined(WEBOS) +#define DEFAULT_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE false +#else +#define DEFAULT_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE true +#endif + #endif diff --git a/configuration.c b/configuration.c index 0ec2ee4c680b..53d3c9304b81 100644 --- a/configuration.c +++ b/configuration.c @@ -2078,7 +2078,7 @@ static struct config_bool_setting *populate_settings_bool( SETTING_BOOL("filter_by_current_core", &settings->bools.filter_by_current_core, true, DEFAULT_FILTER_BY_CURRENT_CORE, false); SETTING_BOOL("menu_use_preferred_system_color_theme", &settings->bools.menu_use_preferred_system_color_theme, true, DEFAULT_MENU_USE_PREFERRED_SYSTEM_COLOR_THEME, false); SETTING_BOOL("menu_navigation_wraparound_enable", &settings->bools.menu_navigation_wraparound_enable, true, true, false); - SETTING_BOOL("menu_navigation_browser_filter_supported_extensions_enable", &settings->bools.menu_navigation_browser_filter_supported_extensions_enable, true, true, false); + SETTING_BOOL("menu_navigation_browser_filter_supported_extensions_enable", &settings->bools.menu_navigation_browser_filter_supported_extensions_enable, true, DEFAULT_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE, false); SETTING_BOOL("menu_show_advanced_settings", &settings->bools.menu_show_advanced_settings, true, DEFAULT_SHOW_ADVANCED_SETTINGS, false); SETTING_BOOL("menu_thumbnail_background_enable", &settings->bools.menu_thumbnail_background_enable, true, DEFAULT_MENU_THUMBNAIL_BACKGROUND_ENABLE, false); #ifdef HAVE_MATERIALUI diff --git a/frontend/drivers/platform_unix.c b/frontend/drivers/platform_unix.c index 08ed3fed1b2b..7f987cc6ed7e 100644 --- a/frontend/drivers/platform_unix.c +++ b/frontend/drivers/platform_unix.c @@ -1784,6 +1784,31 @@ static void frontend_unix_get_env(int *argc, getcwd(base_path, sizeof(base_path)); #elif defined(DINGUX) dingux_get_base_path(base_path, sizeof(base_path)); +#elif defined(WEBOS) + /* Jailer: HOME/XDG often do not point at the package. Prefer + * /.config/retroarch so cores, system, and content defaults match + * where the app actually stores data. */ + { + char app_dir[PATH_MAX_LENGTH]; + + app_dir[0] = '\0'; + fill_pathname_application_dir(app_dir, sizeof(app_dir)); + if (!string_is_empty(app_dir)) + fill_pathname_join(base_path, app_dir, ".config/retroarch", + sizeof(base_path)); + else + strlcpy(base_path, "/media/developer/temp", sizeof(base_path)); + + /* Start file browser on shared storage when available (user content). */ + if (path_is_directory("/media/internal")) + strlcpy(g_defaults.dirs[DEFAULT_DIR_MENU_CONTENT], + "/media/internal", + sizeof(g_defaults.dirs[DEFAULT_DIR_MENU_CONTENT])); + else + strlcpy(g_defaults.dirs[DEFAULT_DIR_MENU_CONTENT], + base_path, + sizeof(g_defaults.dirs[DEFAULT_DIR_MENU_CONTENT])); + } #else const char *xdg = getenv("XDG_CONFIG_HOME"); const char *home = getenv("HOME");