From 2aed4dc278f7cdd51e5628df70bc88ab14c1ffc9 Mon Sep 17 00:00:00 2001 From: tGecko Date: Fri, 15 Mar 2024 23:20:30 +0100 Subject: [PATCH 1/4] add clock overlay in MainUI --- Makefile | 1 + src/libmainuihooks/Makefile | 9 ++ src/libmainuihooks/mainuihooks.c | 146 ++++++++++++++++++++ static/build/.tmp_update/runtime.sh | 4 +- static/build/.tmp_update/script/get_time.sh | 3 + 5 files changed, 161 insertions(+), 2 deletions(-) create mode 100644 src/libmainuihooks/Makefile create mode 100644 src/libmainuihooks/mainuihooks.c create mode 100644 static/build/.tmp_update/script/get_time.sh diff --git a/Makefile b/Makefile index f125f61b2..9ef761a17 100644 --- a/Makefile +++ b/Makefile @@ -138,6 +138,7 @@ core: $(CACHE)/.setup @cd $(SRC_DIR)/pngScale && BUILD_DIR=$(BIN_DIR) make @cd $(SRC_DIR)/libgamename && BUILD_DIR=$(BIN_DIR) make @cd $(SRC_DIR)/gameNameList && BUILD_DIR=$(BIN_DIR) make + @cd $(SRC_DIR)/libmainuihooks && BUILD_DIR=$(LIB_DIR) make # Build dependencies for installer @mkdir -p $(INSTALLER_DIR)/bin @cd $(SRC_DIR)/installUI && BUILD_DIR=$(INSTALLER_DIR)/bin/ VERSION=$(VERSION) make diff --git a/src/libmainuihooks/Makefile b/src/libmainuihooks/Makefile new file mode 100644 index 000000000..70a97670d --- /dev/null +++ b/src/libmainuihooks/Makefile @@ -0,0 +1,9 @@ +INCLUDE_UTILS = 0 +include ../common/config.mk + +TARGET = libmainuihooks.so +CFLAGS := $(CFLAGS) -fpic +LDFLAGS := $(LDFLAGS) -shared -ldl -lSDL -lSDL_ttf + +include ../common/commands.mk +include ../common/recipes.mk diff --git a/src/libmainuihooks/mainuihooks.c b/src/libmainuihooks/mainuihooks.c new file mode 100644 index 000000000..3f8dbf67f --- /dev/null +++ b/src/libmainuihooks/mainuihooks.c @@ -0,0 +1,146 @@ +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include + +#define LOGGING_FILE "/mnt/SDCARD/.tmp_update/config/.logging" +#define GET_TIME_SCRIPT "/mnt/SDCARD/.tmp_update/script/get_time.sh" +#define TIME_FONT_FILE "/customer/app/Exo-2-Bold-Italic.ttf" +#define DEFAULT_PRELOAD "/mnt/SDCARD/miyoo/lib/libpadsp.so" + +typedef int (*SDL_Flip_ptr)(SDL_Surface *screen); +SDL_Flip_ptr original_SDL_Flip = NULL; +typedef int (*printf_ptr)(const char *format, ...); +printf_ptr original_printf = NULL; + +SDL_Surface *clock_surface = NULL; +TTF_Font *font = NULL; +SDL_Color white = {255, 255, 255}; + +bool mainUI_initialized = false; +bool logging = false; + +char *getTime() +{ + //TODO: 12/24h? + FILE *fp; + char output[6]; + + fp = popen(GET_TIME_SCRIPT, "r"); + if (fp == NULL) { + fprintf(stderr, "Failed to run get_time.sh\n"); + return NULL; + } + + if (fgets(output, sizeof(output), fp) == NULL) { + fprintf(stderr, "Failed to read get_time.sh output\n"); + pclose(fp); + return NULL; + } + + pclose(fp); + + char *newline = strchr(output, '\n'); + if (newline != NULL) + *newline = '\0'; + + return strdup(output); +} + +// +// rotate a 32bpp surface's pixels by 180 degrees without allocating new memory +// only works correctly for surfaces of even height +// +void RotateSurface(SDL_Surface *surface) +{ + if (!surface || surface->format->BytesPerPixel != 4) + return; + + int width = surface->w; + int height = surface->h; + uint32_t *pixels = (uint32_t *)surface->pixels; + + for (int y = 0; y < height / 2; y++) { + for (int x = 0; x < width; x++) { + uint32_t topPixel = pixels[y * width + x]; + uint32_t bottomPixel = pixels[(height - y - 1) * width + (width - x - 1)]; + pixels[y * width + x] = bottomPixel; + pixels[(height - y - 1) * width + (width - x - 1)] = topPixel; + } + } +} + +int printf(const char *format, ...) +{ + + if (!mainUI_initialized && strcmp(format, "%d run windows\n") == 0) + mainUI_initialized = true; + + if (!logging) + return 0; // don't waste time printing stuff no one will see + + va_list args; + va_start(args, format); + int res = vprintf(format, args); + va_end(args); + + return res; +} + +int SDL_Flip(SDL_Surface *screen) +{ + if (!original_SDL_Flip) // we fucked up + return -1; + else if (!mainUI_initialized || !font) + return original_SDL_Flip(screen); + + char *time_string = getTime(); + clock_surface = TTF_RenderUTF8_Blended(font, time_string, white); + free(time_string); + RotateSurface(clock_surface); + + // TODO: coords from theme config? + SDL_Rect dest = {160, 467 - (clock_surface->h), 0, 0}; + + SDL_BlitSurface(clock_surface, NULL, screen, &dest); + return original_SDL_Flip(screen); +} + +void __attribute__((constructor)) load(void) +{ + puts(":: Hi from mainuihooks"); + + // remove this .so from preload for child processes + setenv("LD_PRELOAD", DEFAULT_PRELOAD, 1); + + // get pointers to original functions + original_printf = dlsym(RTLD_NEXT, "printf"); + original_SDL_Flip = dlsym(RTLD_NEXT, "SDL_Flip"); + + // check if logging is enabled + if (access(LOGGING_FILE, F_OK) == 0) + logging = true; + + // load font + TTF_Init(); + + // TODO: font size from theme config? + font = TTF_OpenFont(TIME_FONT_FILE, 24); + if (!font) + printf("TTF_OpenFont: %s\n", TTF_GetError()); +} + +void __attribute__((destructor)) unload(void) +{ + if (font) + TTF_CloseFont(font); + if (clock_surface) + SDL_FreeSurface(clock_surface); + TTF_Quit(); + + puts(":: Bye from mainuihooks"); +} \ No newline at end of file diff --git a/static/build/.tmp_update/runtime.sh b/static/build/.tmp_update/runtime.sh index a2a9691a1..0dfd988cf 100644 --- a/static/build/.tmp_update/runtime.sh +++ b/static/build/.tmp_update/runtime.sh @@ -215,8 +215,8 @@ launch_main_ui() { cd $miyoodir/app PATH="$miyoodir/app:$PATH" \ LD_LIBRARY_PATH="$miyoodir/lib:/config/lib:/lib" \ - LD_PRELOAD="$miyoodir/lib/libpadsp.so" \ - ./MainUI 2>&1 > /dev/null + LD_PRELOAD="$sysdir/lib/libmainuihooks.so:$miyoodir/lib/libpadsp.so" \ + ./MainUI # Merge the last game launched into the recent list check_hide_recents diff --git a/static/build/.tmp_update/script/get_time.sh b/static/build/.tmp_update/script/get_time.sh new file mode 100644 index 000000000..8232ea57c --- /dev/null +++ b/static/build/.tmp_update/script/get_time.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +TZ="$(cat "/mnt/SDCARD/.tmp_update/config/.tz")" date +"%H:%M" \ No newline at end of file From 85a4bb1f231c4689a48532e9c98c41e615eaf59c Mon Sep 17 00:00:00 2001 From: tGecko Date: Tue, 19 Mar 2024 19:42:11 +0100 Subject: [PATCH 2/4] time overlay theme settings 12/24 hour format odd height surface rotation --- .gitignore | 1 + Makefile | 3 + src/common/theme/config.h | 28 +++++++ src/common/utils/file.c | 8 ++ src/common/utils/file.h | 2 + src/libmainuihooks/Makefile | 2 +- src/libmainuihooks/mainuihooks.c | 84 +++++++++++++-------- static/build/.tmp_update/runtime.sh | 24 ++++++ static/build/.tmp_update/script/get_time.sh | 4 +- 9 files changed, 123 insertions(+), 33 deletions(-) diff --git a/.gitignore b/.gitignore index c4ff22b3d..885183182 100644 --- a/.gitignore +++ b/.gitignore @@ -60,3 +60,4 @@ src/**/axp !axp/ src/**/batteryMonitorUI !batteryMonitorUI/ +src/**/libmainuihooks.so \ No newline at end of file diff --git a/Makefile b/Makefile index 9ef761a17..2d68369e5 100644 --- a/Makefile +++ b/Makefile @@ -138,6 +138,9 @@ core: $(CACHE)/.setup @cd $(SRC_DIR)/pngScale && BUILD_DIR=$(BIN_DIR) make @cd $(SRC_DIR)/libgamename && BUILD_DIR=$(BIN_DIR) make @cd $(SRC_DIR)/gameNameList && BUILD_DIR=$(BIN_DIR) make +# these need to be rebuilt with -fPIC + @rm -f $(ROOT_DIR)/include/cjson/cJSON.o + @rm -f $(SRC_DIR)/common/utils/*.o @cd $(SRC_DIR)/libmainuihooks && BUILD_DIR=$(LIB_DIR) make # Build dependencies for installer @mkdir -p $(INSTALLER_DIR)/bin diff --git a/src/common/theme/config.h b/src/common/theme/config.h index 5db9c8560..9309fe662 100644 --- a/src/common/theme/config.h +++ b/src/common/theme/config.h @@ -19,6 +19,15 @@ typedef enum TextAlign { RIGHT } Theme_TextAlign; +typedef struct Theme_Time { + int size; + SDL_Color color; + int X; + int Y; + bool hidelogo; + char font[STR_MAX]; +} Time_s; + typedef struct Theme_BatteryPercentage { bool visible; char font[STR_MAX]; @@ -61,6 +70,7 @@ typedef struct Theme { char description[STR_MAX]; HideLabels_s hideLabels; BatteryPercentage_s batteryPercentage; + Time_s time; Frame_s frame; FontStyle_s title; FontStyle_s hint; @@ -104,6 +114,7 @@ bool theme_applyConfig(Theme_s *config, const char *config_path, cJSON *json_root = cJSON_Parse(json_str); cJSON *json_batteryPercentage = cJSON_GetObjectItem(json_root, "batteryPercentage"); + cJSON *json_time = cJSON_GetObjectItem(json_root, "time"); cJSON *json_hideLabels = cJSON_GetObjectItem(json_root, "hideLabels"); cJSON *json_frame = cJSON_GetObjectItem(json_root, "frame"); cJSON *json_title = cJSON_GetObjectItem(json_root, "title"); @@ -172,6 +183,23 @@ bool theme_applyConfig(Theme_s *config, const char *config_path, json_getBool(json_batteryPercentage, "fixed", &config->batteryPercentage.fixed); + // Time overlay theme settings + + json_getBool(json_time, "hidelogo", &config->time.hidelogo); + + if (!json_getString(json_time, "font", config->time.font) && use_fallbacks) + strcpy(config->time.font, config->hint.font); + + json_getInt(json_time, "size", &config->time.size); + + if (!json_color(json_time, "color", &config->time.color) && use_fallbacks) + config->time.color = config->hint.color; + + json_getInt(json_time, "X", &config->time.X); + json_getInt(json_time, "Y", &config->time.Y); + + // Time overlay theme settings end + json_getInt(json_frame, "border-left", &config->frame.border_left); json_getInt(json_frame, "border-right", &config->frame.border_right); diff --git a/src/common/utils/file.c b/src/common/utils/file.c index a68ebf331..a83ccb26e 100644 --- a/src/common/utils/file.c +++ b/src/common/utils/file.c @@ -474,3 +474,11 @@ void file_add_line_to_beginning(const char *filename, const char *lineToAdd) } print_debug("Line added to the beginning of the file successfully.\n"); } + +long file_get_size(char *filename) +{ + struct stat file_status; + if (stat(filename, &file_status) < 0) + return -1; + return file_status.st_size; +} \ No newline at end of file diff --git a/src/common/utils/file.h b/src/common/utils/file.h index 5e00bcde4..0c924a56a 100644 --- a/src/common/utils/file.h +++ b/src/common/utils/file.h @@ -110,4 +110,6 @@ void file_delete_line(const char *fileName, int n); void file_add_line_to_beginning(const char *filename, const char *lineToAdd); +long file_get_size(char *filename); + #endif // UTILS_FILE_H__ diff --git a/src/libmainuihooks/Makefile b/src/libmainuihooks/Makefile index 70a97670d..718c3d6c2 100644 --- a/src/libmainuihooks/Makefile +++ b/src/libmainuihooks/Makefile @@ -1,4 +1,4 @@ -INCLUDE_UTILS = 0 +INCLUDE_CJSON=1 include ../common/config.mk TARGET = libmainuihooks.so diff --git a/src/libmainuihooks/mainuihooks.c b/src/libmainuihooks/mainuihooks.c index 3f8dbf67f..fabdac984 100644 --- a/src/libmainuihooks/mainuihooks.c +++ b/src/libmainuihooks/mainuihooks.c @@ -7,30 +7,42 @@ #include #include +#include "theme/config.h" +#include "theme/theme.h" +#include "utils/config.h" + #define LOGGING_FILE "/mnt/SDCARD/.tmp_update/config/.logging" #define GET_TIME_SCRIPT "/mnt/SDCARD/.tmp_update/script/get_time.sh" -#define TIME_FONT_FILE "/customer/app/Exo-2-Bold-Italic.ttf" #define DEFAULT_PRELOAD "/mnt/SDCARD/miyoo/lib/libpadsp.so" +bool mainUI_initialized = false; +bool logging = false; +char theme_path[STR_MAX]; +Theme_s *theme(void); + +typedef struct { + bool is_enabled; + bool is_12h; + SDL_Rect *position; + TTF_Font *font; + Time_s theme; +} TimeSettings; + +TimeSettings time_settings = {false, false, NULL, NULL}; +SDL_Surface *clock_surface = NULL; + typedef int (*SDL_Flip_ptr)(SDL_Surface *screen); SDL_Flip_ptr original_SDL_Flip = NULL; typedef int (*printf_ptr)(const char *format, ...); printf_ptr original_printf = NULL; -SDL_Surface *clock_surface = NULL; -TTF_Font *font = NULL; -SDL_Color white = {255, 255, 255}; - -bool mainUI_initialized = false; -bool logging = false; - char *getTime() { - //TODO: 12/24h? FILE *fp; - char output[6]; - - fp = popen(GET_TIME_SCRIPT, "r"); + char output[10]; + char command[strlen(GET_TIME_SCRIPT) + 10]; + snprintf(command, sizeof(command), time_settings.is_12h ? "%s --12h" : "%s", GET_TIME_SCRIPT); + fp = popen(command, "r"); if (fp == NULL) { fprintf(stderr, "Failed to run get_time.sh\n"); return NULL; @@ -53,7 +65,6 @@ char *getTime() // // rotate a 32bpp surface's pixels by 180 degrees without allocating new memory -// only works correctly for surfaces of even height // void RotateSurface(SDL_Surface *surface) { @@ -72,6 +83,17 @@ void RotateSurface(SDL_Surface *surface) pixels[(height - y - 1) * width + (width - x - 1)] = topPixel; } } + + // If the height is odd, handle the middle row separately + if (height % 2 != 0) { + int midY = height / 2; + for (int x = 0; x < width / 2; x++) { + uint32_t leftPixel = pixels[midY * width + x]; + uint32_t rightPixel = pixels[midY * width + (width - x - 1)]; + pixels[midY * width + x] = rightPixel; + pixels[midY * width + (width - x - 1)] = leftPixel; + } + } } int printf(const char *format, ...) @@ -95,18 +117,14 @@ int SDL_Flip(SDL_Surface *screen) { if (!original_SDL_Flip) // we fucked up return -1; - else if (!mainUI_initialized || !font) + else if (!time_settings.is_enabled || !mainUI_initialized || !time_settings.font) return original_SDL_Flip(screen); char *time_string = getTime(); - clock_surface = TTF_RenderUTF8_Blended(font, time_string, white); + clock_surface = TTF_RenderUTF8_Blended(time_settings.font, time_string, time_settings.theme.color); free(time_string); RotateSurface(clock_surface); - - // TODO: coords from theme config? - SDL_Rect dest = {160, 467 - (clock_surface->h), 0, 0}; - - SDL_BlitSurface(clock_surface, NULL, screen, &dest); + SDL_BlitSurface(clock_surface, NULL, screen, time_settings.position); return original_SDL_Flip(screen); } @@ -121,26 +139,30 @@ void __attribute__((constructor)) load(void) original_printf = dlsym(RTLD_NEXT, "printf"); original_SDL_Flip = dlsym(RTLD_NEXT, "SDL_Flip"); - // check if logging is enabled - if (access(LOGGING_FILE, F_OK) == 0) - logging = true; + time_settings.is_12h = config_flag_get(".mainuiTime12h"); + time_settings.is_enabled = config_flag_get(".mainuiTimeEnabled"); - // load font - TTF_Init(); + logging = config_flag_get(".logging"); - // TODO: font size from theme config? - font = TTF_OpenFont(TIME_FONT_FILE, 24); - if (!font) - printf("TTF_OpenFont: %s\n", TTF_GetError()); + // load time overlay theme settings + theme_getPath(theme_path); + TTF_Init(); + time_settings.theme = theme()->time; + SDL_Rect *position = calloc(1, sizeof(SDL_Rect)); + position->x = time_settings.theme.X; + position->y = time_settings.theme.Y; + time_settings.position = position; + time_settings.font = theme_loadFont(theme_path, time_settings.theme.font, time_settings.theme.size); } void __attribute__((destructor)) unload(void) { - if (font) - TTF_CloseFont(font); if (clock_surface) SDL_FreeSurface(clock_surface); + if (time_settings.position) + free(time_settings.position); TTF_Quit(); + // restore the logo puts(":: Bye from mainuihooks"); } \ No newline at end of file diff --git a/static/build/.tmp_update/runtime.sh b/static/build/.tmp_update/runtime.sh index 0dfd988cf..31f172b83 100644 --- a/static/build/.tmp_update/runtime.sh +++ b/static/build/.tmp_update/runtime.sh @@ -190,10 +190,34 @@ check_main_ui() { fi } +toggle_topbar() { + theme_path="$(/customer/app/jsonval theme)" + config_path="${theme_path%/}/config.json" + regular_path="${theme_path%/}/skin/miyoo-topbar.png" + hidden_path="${theme_path%/}/skin/miyoo-topbar-hidden.png" + invis_path=/mnt/SDCARD/.tmp_update/res/miyoo-topbar-invis.png + hide_logo=$(sed -n 's/.*"hidelogo": \([^,}]*\).*/\1/p' "$config_path") + + if [ $hide_logo == "true" ]; then + if [ ! $(xcrc "$regular_path") == $(xcrc "$invis_path") ]; then + cp -f "$regular_path" "$hidden_path" + cp -f "$invis_path" "$regular_path" + fi + else + if [ -f "$hidden_path" ] && [ $(xcrc "$regular_path") == $(xcrc "$invis_path") ]; then + cp -f "$hidden_path" "$regular_path" + fi + fi + sync +} + launch_main_ui() { log "\n:: Launch MainUI" cd $sysdir + + # hide or unhide miyoo-topbar + toggle_topbar # Generate battery percentage image mainUiBatPerc diff --git a/static/build/.tmp_update/script/get_time.sh b/static/build/.tmp_update/script/get_time.sh index 8232ea57c..eee36d97b 100644 --- a/static/build/.tmp_update/script/get_time.sh +++ b/static/build/.tmp_update/script/get_time.sh @@ -1,3 +1,5 @@ #!/bin/sh -TZ="$(cat "/mnt/SDCARD/.tmp_update/config/.tz")" date +"%H:%M" \ No newline at end of file +[ "$1" = "--12h" ] && FORMAT="+%I:%M %P" || FORMAT="+%H:%M" + +TZ="$(cat "/mnt/SDCARD/.tmp_update/config/.tz")" date "$FORMAT" \ No newline at end of file From ec87639c8163c50aa28c5fef0fabbc83bfaf06aa Mon Sep 17 00:00:00 2001 From: tGecko Date: Tue, 19 Mar 2024 18:47:11 +0000 Subject: [PATCH 3/4] =?UTF-8?q?=F0=9F=8E=A8=20apply=20clang-format=20chang?= =?UTF-8?q?es?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/theme/config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/theme/config.h b/src/common/theme/config.h index 9309fe662..bf7d1bea9 100644 --- a/src/common/theme/config.h +++ b/src/common/theme/config.h @@ -186,7 +186,7 @@ bool theme_applyConfig(Theme_s *config, const char *config_path, // Time overlay theme settings json_getBool(json_time, "hidelogo", &config->time.hidelogo); - + if (!json_getString(json_time, "font", config->time.font) && use_fallbacks) strcpy(config->time.font, config->hint.font); From 25d5a10fd26423cedea6aa5bae1ef869dbcfb0a1 Mon Sep 17 00:00:00 2001 From: tGecko Date: Tue, 19 Mar 2024 19:53:52 +0100 Subject: [PATCH 4/4] check for theme without config for time overlay --- .gitignore | 2 +- src/libmainuihooks/mainuihooks.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitignore b/.gitignore index 885183182..cd3421138 100644 --- a/.gitignore +++ b/.gitignore @@ -60,4 +60,4 @@ src/**/axp !axp/ src/**/batteryMonitorUI !batteryMonitorUI/ -src/**/libmainuihooks.so \ No newline at end of file +src/**/libmainuihooks.so diff --git a/src/libmainuihooks/mainuihooks.c b/src/libmainuihooks/mainuihooks.c index fabdac984..348316b43 100644 --- a/src/libmainuihooks/mainuihooks.c +++ b/src/libmainuihooks/mainuihooks.c @@ -117,7 +117,7 @@ int SDL_Flip(SDL_Surface *screen) { if (!original_SDL_Flip) // we fucked up return -1; - else if (!time_settings.is_enabled || !mainUI_initialized || !time_settings.font) + else if (!time_settings.is_enabled || time_settings.theme.size == 0 || !mainUI_initialized || !time_settings.font) return original_SDL_Flip(screen); char *time_string = getTime();