From 90529c62b2c73412cba454ce4a96f1746fdadd80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Kelemen=20=28vudiq=29?= Date: Sat, 17 Apr 2021 23:54:45 +0200 Subject: [PATCH] Lakka: add menu for time zone setting This adds new entry under Settings -> Services (where all Lakka related services are currently available, such as switches for services like SSH, Samba, etc.). By adding this the users do not have to use the command line / access the file system directly to change their local time zone to adjust the date/time displayed in RetroArch. --- configuration.c | 42 +++++++++++++++++++++++++++++++++++ configuration.h | 12 ++++++++++ intl/msg_hash_lbl.h | 4 ++++ intl/msg_hash_us.c | 9 ++++++++ intl/msg_hash_us.h | 8 +++++++ lakka.h | 4 ++++ list_special.h | 3 +++ menu/cbs/menu_cbs_get_value.c | 3 +++ menu/cbs/menu_cbs_sublabel.c | 4 ++++ menu/menu_displaylist.c | 1 + menu/menu_setting.c | 35 +++++++++++++++++++++++++++++ msg_hash.h | 1 + retroarch.c | 38 +++++++++++++++++++++++++++++++ 13 files changed, 164 insertions(+) diff --git a/configuration.c b/configuration.c index f27376525b..2edb598279 100644 --- a/configuration.c +++ b/configuration.c @@ -1185,6 +1185,47 @@ const char *config_get_midi_driver_options(void) return char_list_new_special(STRING_LIST_MIDI_DRIVERS, NULL); } +#ifdef HAVE_LAKKA +void config_set_timezone(char *timezone) +{ + setenv("TZ", timezone, 1); + tzset(); +} + +const char *config_get_all_timezones(void) +{ + return char_list_new_special(STRING_LIST_TIMEZONES, NULL); +} + +static void load_timezone(char *setting) +{ + char haystack[TIMEZONE_LENGTH+32]; + static char *needle = "TIMEZONE="; + size_t needle_len = strlen(needle); + + RFILE *tzfp = filestream_open(LAKKA_TIMEZONE_PATH, + RETRO_VFS_FILE_ACCESS_READ, + RETRO_VFS_FILE_ACCESS_HINT_NONE); + + if (tzfp != NULL) + { + filestream_gets(tzfp, haystack, sizeof(haystack)-1); + filestream_close(tzfp); + + char *start = strstr(haystack, needle); + + if (start != NULL) + snprintf(setting, TIMEZONE_LENGTH, "%s", start + needle_len); + else + snprintf(setting, TIMEZONE_LENGTH, "%s", DEFAULT_TIMEZONE); + } + else + snprintf(setting, TIMEZONE_LENGTH, "%s", DEFAULT_TIMEZONE); + + config_set_timezone(setting); +} +#endif + bool config_overlay_enable_default(void) { if (g_defaults.overlay_set) @@ -2347,6 +2388,7 @@ void config_set_defaults(void *data) configuration_set_bool(settings, settings->bools.bluetooth_enable, filestream_exists(LAKKA_BLUETOOTH_PATH)); configuration_set_bool(settings, settings->bools.localap_enable, false); + load_timezone(settings->arrays.timezone); #endif #ifdef HAVE_MENU diff --git a/configuration.h b/configuration.h index e03455679b..0d728a5be8 100644 --- a/configuration.h +++ b/configuration.h @@ -29,6 +29,10 @@ #include "input/input_defines.h" #include "led/led_defines.h" +#ifdef HAVE_LAKKA +#include "lakka.h" +#endif + #define configuration_set_float(settings, var, newvar) \ { \ settings->modified = true; \ @@ -381,6 +385,9 @@ typedef struct settings char ai_service_url[PATH_MAX_LENGTH]; char crt_switch_timings[255]; +#ifdef HAVE_LAKKA + char timezone[TIMEZONE_LENGTH]; +#endif } arrays; struct @@ -1011,6 +1018,11 @@ void config_save_file_salamander(void); settings_t *config_get_ptr(void); +#ifdef HAVE_LAKKA +const char *config_get_all_timezones(void); +void config_set_timezone(char *timezone); +#endif + RETRO_END_DECLS #endif diff --git a/intl/msg_hash_lbl.h b/intl/msg_hash_lbl.h index dca4d8c9ce..c2b03d1b7f 100644 --- a/intl/msg_hash_lbl.h +++ b/intl/msg_hash_lbl.h @@ -195,6 +195,10 @@ MSG_HASH( MENU_ENUM_LABEL_BLUETOOTH_ENABLE, "bluetooth_enable" ) +MSG_HASH( + MENU_ENUM_LABEL_TIMEZONE, + "timezone" + ) #endif MSG_HASH( MENU_ENUM_LABEL_BUILDBOT_ASSETS_URL, diff --git a/intl/msg_hash_us.c b/intl/msg_hash_us.c index 514aed48ae..39418993bf 100644 --- a/intl/msg_hash_us.c +++ b/intl/msg_hash_us.c @@ -2289,6 +2289,15 @@ int msg_hash_get_help_us_enum(enum msg_hash_enums msg, char *s, size_t len) snprintf(s, len, "MIDI driver to use."); break; +#ifdef HAVE_LAKKA + case MENU_ENUM_LABEL_TIMEZONE: + snprintf(s, len, + "Displays a list of available timezones. After\n" + "selecting a time zone, time and date is adjusted\n" + "to the selected time zone. It assumes, that system/\n" + "hardware clock is set to UTC."); + break; +#endif case MENU_ENUM_LABEL_MIDI_INPUT: snprintf(s, len, "Sets the input device (driver specific).\n" diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 4c354ac29c..0959680230 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -12218,6 +12218,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_LOCALAP_ENABLE, "Enable or disable Wi-Fi Access Point." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_TIMEZONE, + "Time zone" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_TIMEZONE, + "Select your time zone to adjust the date and time to your location." + ) MSG_HASH( MSG_LOCALAP_SWITCHING_OFF, "Switching off Wi-Fi Access Point." diff --git a/lakka.h b/lakka.h index f098a1080c..3f369ff05c 100644 --- a/lakka.h +++ b/lakka.h @@ -24,6 +24,10 @@ #define LAKKA_UPDATE_DIR "/storage/.update/" #define LAKKA_CONNMAN_DIR "/storage/.cache/connman/" #define LAKKA_LOCALAP_PATH "/storage/.cache/services/localap.conf" +#define LAKKA_TIMEZONE_PATH "/storage/.cache/timezone" + +#define DEFAULT_TIMEZONE "UTC" +#define TIMEZONE_LENGTH 255 #include "switch_performance_profiles.h" diff --git a/list_special.h b/list_special.h index cbdbf0b877..ae245be6e3 100644 --- a/list_special.h +++ b/list_special.h @@ -56,6 +56,9 @@ enum string_list_type STRING_LIST_RECORD_DRIVERS, STRING_LIST_MIDI_DRIVERS, STRING_LIST_SUPPORTED_CORES_PATHS, +#ifdef HAVE_LAKKA + STRING_LIST_TIMEZONES, +#endif STRING_LIST_SUPPORTED_CORES_NAMES }; diff --git a/menu/cbs/menu_cbs_get_value.c b/menu/cbs/menu_cbs_get_value.c index 2b0d01e794..c734f81efe 100644 --- a/menu/cbs/menu_cbs_get_value.c +++ b/menu/cbs/menu_cbs_get_value.c @@ -1572,6 +1572,9 @@ static int menu_cbs_init_bind_get_string_representation_compare_label( case MENU_ENUM_LABEL_BLUETOOTH_DRIVER: case MENU_ENUM_LABEL_WIFI_DRIVER: case MENU_ENUM_LABEL_MENU_DRIVER: +#ifdef HAVE_LAKKA + case MENU_ENUM_LABEL_TIMEZONE: +#endif BIND_ACTION_GET_VALUE(cbs, menu_action_setting_disp_set_label); break; case MENU_ENUM_LABEL_CONNECT_BLUETOOTH: diff --git a/menu/cbs/menu_cbs_sublabel.c b/menu/cbs/menu_cbs_sublabel.c index 4193cfe8d3..6a6da555e9 100644 --- a/menu/cbs/menu_cbs_sublabel.c +++ b/menu/cbs/menu_cbs_sublabel.c @@ -227,6 +227,7 @@ DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_ssh_enable, MENU_ DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_samba_enable, MENU_ENUM_SUBLABEL_SAMBA_ENABLE ) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_bluetooth_enable, MENU_ENUM_SUBLABEL_BLUETOOTH_ENABLE ) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_localap_enable, MENU_ENUM_SUBLABEL_LOCALAP_ENABLE ) +DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_timezone, MENU_ENUM_SUBLABEL_TIMEZONE) #endif DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_user_language, MENU_ENUM_SUBLABEL_USER_LANGUAGE) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_max_swapchain_images, MENU_ENUM_SUBLABEL_VIDEO_MAX_SWAPCHAIN_IMAGES ) @@ -3907,6 +3908,9 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_LOCALAP_ENABLE: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_localap_enable); break; + case MENU_ENUM_LABEL_TIMEZONE: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_timezone); + break; #endif case MENU_ENUM_LABEL_USER_LANGUAGE: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_user_language); diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index 2ef6228b7f..15bab6631c 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -7704,6 +7704,7 @@ unsigned menu_displaylist_build_list( {MENU_ENUM_LABEL_SAMBA_ENABLE, PARSE_ONLY_BOOL}, {MENU_ENUM_LABEL_BLUETOOTH_ENABLE, PARSE_ONLY_BOOL}, {MENU_ENUM_LABEL_LOCALAP_ENABLE, PARSE_ONLY_BOOL}, + {MENU_ENUM_LABEL_TIMEZONE, PARSE_ONLY_STRING_OPTIONS}, }; for (i = 0; i < ARRAY_SIZE(build_list); i++) diff --git a/menu/menu_setting.c b/menu/menu_setting.c index 18bf8eff50..97164655a3 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -7991,6 +7991,24 @@ static void localap_enable_toggle_change_handler(rarch_setting_t *setting) driver_wifi_tether_start_stop(*setting->value.target.boolean, LAKKA_LOCALAP_PATH); } + +static void timezone_change_handler(rarch_setting_t *setting) +{ + if (!setting) + return; + + config_set_timezone(setting->value.target.string); + + RFILE *tzfp = filestream_open(LAKKA_TIMEZONE_PATH, + RETRO_VFS_FILE_ACCESS_WRITE, + RETRO_VFS_FILE_ACCESS_HINT_NONE); + + if (tzfp != NULL) + { + filestream_printf(tzfp, "TIMEZONE=%s", setting->value.target.string); + filestream_close(tzfp); + } +} #endif static bool setting_append_list_input_player_options( @@ -18539,6 +18557,23 @@ static bool setting_append_list( SD_FLAG_NONE); (*list)[list_info->index - 1].change_handler = localap_enable_toggle_change_handler; + CONFIG_STRING_OPTIONS( + list, list_info, + settings->arrays.timezone, + sizeof(settings->arrays.timezone), + MENU_ENUM_LABEL_TIMEZONE, + MENU_ENUM_LABEL_VALUE_TIMEZONE, + DEFAULT_TIMEZONE, + config_get_all_timezones(), + &group_info, + &subgroup_info, + parent_group, + general_read_handler, + general_write_handler); + SETTINGS_DATA_LIST_CURRENT_ADD_FLAGS(list, list_info, SD_FLAG_IS_DRIVER); + (*list)[list_info->index - 1].action_ok = setting_action_ok_mapped_string; + (*list)[list_info->index - 1].change_handler = timezone_change_handler; + END_SUB_GROUP(list, list_info, parent_group); END_GROUP(list, list_info, parent_group); #endif diff --git a/msg_hash.h b/msg_hash.h index 819411ec91..a7a987dd4b 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -1826,6 +1826,7 @@ enum msg_hash_enums MENU_LABEL(SAMBA_ENABLE), MENU_LABEL(BLUETOOTH_ENABLE), MENU_LABEL(LOCALAP_ENABLE), + MENU_LABEL(TIMEZONE), #endif MENU_LABEL(NETPLAY_DELAY_FRAMES), MENU_LABEL(NETPLAY_PUBLIC_ANNOUNCE), diff --git a/retroarch.c b/retroarch.c index 0d4db54a19..82babc5b79 100644 --- a/retroarch.c +++ b/retroarch.c @@ -277,6 +277,10 @@ /* Forward declarations */ #include "retroarch_fwd_decls.h" +#ifdef HAVE_LAKKA +#include "lakka.h" +#endif + /* GLOBAL POINTER GETTERS */ #ifdef HAVE_NETWORKING @@ -8722,6 +8726,40 @@ struct string_list *string_list_new_special(enum string_list_type type, string_list_append(s, opt, attr); } break; +#ifdef HAVE_LAKKA + case STRING_LIST_TIMEZONES: + { + const char *opt = DEFAULT_TIMEZONE; + *len += strlen(opt) + 1; + string_list_append(s, opt, attr); + + FILE *zones_file = popen("grep -v ^# /usr/share/zoneinfo/zone.tab | " + "cut -f3 | " + "sort", "r"); + + if (zones_file != NULL) + { + char zone_desc[TIMEZONE_LENGTH]; + while (fgets(zone_desc, TIMEZONE_LENGTH, zones_file)) + { + size_t zone_desc_len = strlen(zone_desc); + + if (zone_desc_len > 0) + if (zone_desc[--zone_desc_len] == '\n') + zone_desc[zone_desc_len] = '\0'; + + if (strlen(zone_desc) > 0) + { + const char *opt = zone_desc; + *len += strlen(opt) + 1; + string_list_append(s, opt, attr); + } + } + pclose(zones_file); + } + } + break; +#endif case STRING_LIST_SUPPORTED_CORES_PATHS: core_info_get_list(&core_info_list);