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