Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add configurable clock overlay for MainUI #1515

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,4 @@ src/**/axp
!axp/
src/**/batteryMonitorUI
!batteryMonitorUI/
src/**/libmainuihooks.so
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,10 @@ 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
@cd $(SRC_DIR)/installUI && BUILD_DIR=$(INSTALLER_DIR)/bin/ VERSION=$(VERSION) make
Expand Down
28 changes: 28 additions & 0 deletions src/common/theme/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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");
Expand Down Expand Up @@ -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);

Expand Down
8 changes: 8 additions & 0 deletions src/common/utils/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
2 changes: 2 additions & 0 deletions src/common/utils/file.h
Original file line number Diff line number Diff line change
Expand Up @@ -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__
9 changes: 9 additions & 0 deletions src/libmainuihooks/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
INCLUDE_CJSON=1
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
168 changes: 168 additions & 0 deletions src/libmainuihooks/mainuihooks.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
#define _GNU_SOURCE
#include <SDL/SDL.h>
#include <SDL/SDL_rotozoom.h>
#include <SDL/SDL_ttf.h>
#include <dlfcn.h>
#include <stdbool.h>
#include <time.h>
#include <unistd.h>

#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 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;

char *getTime()
{
FILE *fp;
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;
}

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
//
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;
}
}

// 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, ...)
{

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 (!time_settings.is_enabled || time_settings.theme.size == 0 || !mainUI_initialized || !time_settings.font)
return original_SDL_Flip(screen);

char *time_string = getTime();
clock_surface = TTF_RenderUTF8_Blended(time_settings.font, time_string, time_settings.theme.color);
free(time_string);
RotateSurface(clock_surface);
SDL_BlitSurface(clock_surface, NULL, screen, time_settings.position);
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");

time_settings.is_12h = config_flag_get(".mainuiTime12h");
time_settings.is_enabled = config_flag_get(".mainuiTimeEnabled");

logging = config_flag_get(".logging");

// 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 (clock_surface)
SDL_FreeSurface(clock_surface);
if (time_settings.position)
free(time_settings.position);
TTF_Quit();

// restore the logo
puts(":: Bye from mainuihooks");
}
28 changes: 26 additions & 2 deletions static/build/.tmp_update/runtime.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -215,8 +239,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
Expand Down
5 changes: 5 additions & 0 deletions static/build/.tmp_update/script/get_time.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/sh

[ "$1" = "--12h" ] && FORMAT="+%I:%M %P" || FORMAT="+%H:%M"

TZ="$(cat "/mnt/SDCARD/.tmp_update/config/.tz")" date "$FORMAT"
Loading