summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Soffke <christian.soffke@gmail.com>2023-08-27 01:17:34 +0200
committerChristian Soffke <christian.soffke@gmail.com>2024-12-25 08:34:40 -0500
commit60f3283f48d07926d64f001602f8c2aeb57a871d (patch)
treef5e5ca9beba1b630e5d3a3b12c63d6d7741ef2d6
parent79191bf9bb62df95ff27e5ab2a54639e1ad0c8f7 (diff)
downloadrockbox-60f3283f48.tar.gz
rockbox-60f3283f48.zip
sdl: make window resizable, enable high DPI
Tested on Linux, MacOS, and Windows. On MacOS and Windows, we constrain the window's aspect ratio by adjusting the size when responding to resize events. On Linux, I've not found a way to do so, that doesn't result in fairly stuttery behavior and weird jumpy behavior of the resize handle, possibly depending on your window manager. So, black bars are displayed around the content. Maybe someone, at some point, finds a way. (SDL3 seems to have SDL_SetWindowAspectRatio) When the window is in fullscreen, black bars are display necessarily, of course, on all systems, unless the player GUI has exactly the same aspect ratio as the screen... Change-Id: I535e6617497611ea57a4c19e08e552f990859cfe
-rw-r--r--firmware/drivers/button_queue.c6
-rw-r--r--firmware/target/hosted/sdl/button-sdl.c12
-rw-r--r--firmware/target/hosted/sdl/lcd-sdl.c101
-rw-r--r--firmware/target/hosted/sdl/lcd-sdl.h5
-rw-r--r--firmware/target/hosted/sdl/system-sdl.c33
5 files changed, 127 insertions, 30 deletions
diff --git a/firmware/drivers/button_queue.c b/firmware/drivers/button_queue.c
index 1679fc224e..f539b88b75 100644
--- a/firmware/drivers/button_queue.c
+++ b/firmware/drivers/button_queue.c
@@ -24,6 +24,7 @@
#include "button.h"
#ifdef HAVE_SDL
#include "button-sdl.h"
+#include "lcd-sdl.h"
#endif
static struct event_queue button_queue SHAREDBSS_ATTR;
@@ -100,7 +101,7 @@ static inline void button_queue_wait(struct queue_event *evp, int timeout)
unsigned long curr_tick, remaining;
while(true)
{
- handle_sdl_events();
+ handle_sdl_events(); /* Includes window updates after resize events */
queue_wait_w_tmo(&button_queue, evp, TIMEOUT_NOBLOCK);
if (evp->id != SYS_TIMEOUT || timeout == TIMEOUT_NOBLOCK)
return;
@@ -117,6 +118,9 @@ static inline void button_queue_wait(struct queue_event *evp, int timeout)
}
#else
queue_wait_w_tmo(&button_queue, evp, timeout);
+#ifdef HAVE_SDL
+ sdl_update_window(); /* Window may have been resized */
+#endif
#endif
}
#endif /* HAVE_ADJUSTABLE_CPU_FREQ */
diff --git a/firmware/target/hosted/sdl/button-sdl.c b/firmware/target/hosted/sdl/button-sdl.c
index 621b63f930..0ba54d064a 100644
--- a/firmware/target/hosted/sdl/button-sdl.c
+++ b/firmware/target/hosted/sdl/button-sdl.c
@@ -31,6 +31,7 @@
#include "backlight.h"
#include "system.h"
#include "button-sdl.h"
+#include "lcd-sdl.h"
#include "sim_tasks.h"
#include "buttonmap.h"
#include "debug.h"
@@ -240,6 +241,17 @@ static bool event_handler(SDL_Event *event)
sdl_app_has_input_focus = 1;
else if (event->window.event == SDL_WINDOWEVENT_FOCUS_LOST)
sdl_app_has_input_focus = 0;
+ else if(event->window.event == SDL_WINDOWEVENT_RESIZED)
+ {
+ sdl_window_needs_update();
+#if !defined (__APPLE__) && !defined(__WIN32)
+ static unsigned long last_tick;
+ if (TIME_AFTER(current_tick, last_tick + HZ/20) && !button_queue_full())
+ button_queue_post(SDLK_UNKNOWN, 0); /* update window on main thread */
+ else
+ last_tick = current_tick;
+#endif
+ }
break;
case SDL_KEYDOWN:
case SDL_KEYUP:
diff --git a/firmware/target/hosted/sdl/lcd-sdl.c b/firmware/target/hosted/sdl/lcd-sdl.c
index 1e9daeffd3..2e4caa7edc 100644
--- a/firmware/target/hosted/sdl/lcd-sdl.c
+++ b/firmware/target/hosted/sdl/lcd-sdl.c
@@ -23,9 +23,99 @@
#include "lcd-sdl.h"
#include "sim-ui-defines.h"
#include "system.h" /* for MIN() and MAX() */
+#include "misc.h"
double display_zoom = 1;
+static bool window_needs_update;
+
+void sdl_get_window_dimensions(int *w, int *h)
+{
+ if (background)
+ {
+ *w = UI_WIDTH;
+ *h = UI_HEIGHT;
+ }
+ else
+ {
+#ifdef HAVE_REMOTE_LCD
+ if (showremote)
+ {
+ *w = SIM_LCD_WIDTH > SIM_REMOTE_WIDTH ? SIM_LCD_WIDTH : SIM_REMOTE_WIDTH;
+ *h = SIM_LCD_HEIGHT + SIM_REMOTE_HEIGHT;
+ }
+ else
+#endif
+ {
+ *w = SIM_LCD_WIDTH;
+ *h = SIM_LCD_HEIGHT;
+ }
+ }
+}
+
+static inline void sdl_render(void)
+{
+ SDL_Texture *sdlTexture = SDL_CreateTextureFromSurface(sdlRenderer, gui_surface);
+ SDL_RenderClear(sdlRenderer);
+ SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL);
+ SDL_RenderPresent(sdlRenderer);
+ SDL_DestroyTexture(sdlTexture);
+}
+
+
+#define SNAP_MARGIN 50
+int sdl_update_window(void)
+{
+ if (!window_needs_update)
+ return false;
+ window_needs_update = false;
+
+#if defined (__APPLE__) || defined(__WIN32) /* Constrain aspect ratio */
+ if (!(SDL_GetWindowFlags(window) & (SDL_WINDOW_MAXIMIZED | SDL_WINDOW_FULLSCREEN)))
+ {
+ float aspect_ratio;
+ int w, h;
+
+ sdl_get_window_dimensions(&w, &h);
+ aspect_ratio = (float) h / w;
+
+ int original_height = h;
+ int original_width = w;
+
+ SDL_GetWindowSize(window, &w, &h);
+ if (w != original_width || h != original_height)
+ {
+ if (abs(original_width - w) < SNAP_MARGIN)
+ {
+ w = original_width;
+ h = original_height;
+ }
+ else
+ h = w * aspect_ratio;
+
+ SDL_SetWindowSize(window, w, h);
+ }
+ }
+#endif
+ sdl_render();
+ return true;
+}
+
+void sdl_window_needs_update(void)
+{
+ window_needs_update = true;
+
+ /* For MacOS and Windows, we're on a main or
+ display thread already, and can immediately
+ update the window.
+ On Linux, we have to defer the update, until
+ it is handled by the main thread later. */
+#if defined (__APPLE__) || defined(__WIN32)
+ sdl_update_window();
+#endif
+}
+
+
void sdl_update_rect(SDL_Surface *surface, int x_start, int y_start, int width,
int height, int max_x, int max_y,
unsigned long (*getpixel)(int, int))
@@ -117,15 +207,12 @@ void sdl_gui_update(SDL_Surface *surface, int x_start, int y_start, int width,
uint8_t alpha;
if (SDL_GetSurfaceAlphaMod(surface,&alpha) == 0 && alpha < 255)
- SDL_FillRect(gui_surface, &dest, 0);
+ SDL_FillRect(gui_surface, &dest, 0); /* alpha needs a black background */
- SDL_BlitSurface(surface, &src, gui_surface, &dest); /* alpha needs a black background */
+ SDL_BlitSurface(surface, &src, gui_surface, &dest);
- SDL_Texture *sdlTexture = SDL_CreateTextureFromSurface(sdlRenderer, gui_surface);
- SDL_RenderClear(sdlRenderer);
- SDL_RenderCopy(sdlRenderer, sdlTexture, NULL, NULL);
- SDL_RenderPresent(sdlRenderer);
- SDL_DestroyTexture(sdlTexture);
+ if (!sdl_update_window()) /* already calls sdl_render itself */
+ sdl_render();
}
/* set a range of bitmap indices to a gradient from startcolour to endcolour */
diff --git a/firmware/target/hosted/sdl/lcd-sdl.h b/firmware/target/hosted/sdl/lcd-sdl.h
index 3f1334e4a2..17fa6e192e 100644
--- a/firmware/target/hosted/sdl/lcd-sdl.h
+++ b/firmware/target/hosted/sdl/lcd-sdl.h
@@ -28,6 +28,11 @@
/* Default display zoom level */
extern SDL_Surface *gui_surface;
extern SDL_Renderer *sdlRenderer;
+extern SDL_Window *window;
+
+void sdl_get_window_dimensions(int *w, int *h);
+int sdl_update_window(void);
+void sdl_window_needs_update(void);
void sdl_update_rect(SDL_Surface *surface, int x_start, int y_start, int width,
int height, int max_x, int max_y,
diff --git a/firmware/target/hosted/sdl/system-sdl.c b/firmware/target/hosted/sdl/system-sdl.c
index e1c00a3915..e18bbd779c 100644
--- a/firmware/target/hosted/sdl/system-sdl.c
+++ b/firmware/target/hosted/sdl/system-sdl.c
@@ -91,28 +91,7 @@ static void sdl_window_setup(void)
}
}
- /* Set things up */
- if (background)
- {
- width = UI_WIDTH;
- height = UI_HEIGHT;
- }
- else
- {
-#ifdef HAVE_REMOTE_LCD
- if (showremote)
- {
- width = SIM_LCD_WIDTH > SIM_REMOTE_WIDTH ? SIM_LCD_WIDTH : SIM_REMOTE_WIDTH;
- height = SIM_LCD_HEIGHT + SIM_REMOTE_HEIGHT;
- }
- else
-#endif
- {
- width = SIM_LCD_WIDTH;
- height = SIM_LCD_HEIGHT;
- }
- }
-
+ sdl_get_window_dimensions(&width, &height);
depth = LCD_DEPTH;
if (depth < 8)
depth = 16;
@@ -122,11 +101,20 @@ static void sdl_window_setup(void)
flags |= SDL_WINDOW_FULLSCREEN;
#endif
+ if (display_zoom == 1)
+ flags |= SDL_WINDOW_RESIZABLE;
+
+ flags |= SDL_WINDOW_ALLOW_HIGHDPI;
+
if ((window = SDL_CreateWindow(UI_TITLE, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
width * display_zoom, height * display_zoom , flags)) == NULL)
panicf("%s", SDL_GetError());
if ((sdlRenderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_PRESENTVSYNC)) == NULL)
panicf("%s", SDL_GetError());
+
+ SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear");
+ SDL_RenderSetLogicalSize(sdlRenderer, width * display_zoom, height * display_zoom);
+
if ((gui_surface = SDL_CreateRGBSurface(0, width * display_zoom, height * display_zoom, depth,
0, 0, 0, 0)) == NULL)
panicf("%s", SDL_GetError());
@@ -152,6 +140,7 @@ static void sdl_window_setup(void)
static int sdl_event_thread(void * param)
{
#ifdef __WIN32 /* Fails on Linux and MacOS */
+ SDL_SetHint(SDL_HINT_WINDOWS_DPI_SCALING, "1");
SDL_InitSubSystem(SDL_INIT_VIDEO);
sdl_window_setup();
#endif