diff --git a/src/app.c b/src/app.c index 6ac3aef..b355fdd 100644 --- a/src/app.c +++ b/src/app.c @@ -137,6 +137,21 @@ static void tune_relative(App *app, int delta) { player_tune(&app->player, next_index); } +static void toggle_fullscreen(App *app) { + Uint32 flags; + + if (!app || !app->window) { + return; + } + + flags = app->is_fullscreen ? 0 : SDL_WINDOW_FULLSCREEN_DESKTOP; + if (SDL_SetWindowFullscreen(app->window, flags) == 0) { + app->is_fullscreen = !app->is_fullscreen; + } else { + fprintf(stderr, "Fullscreen toggle failed: %s\n", SDL_GetError()); + } +} + static void handle_event(App *app, const SDL_Event *event) { if (event->type == SDL_QUIT) { app->running = 0; @@ -158,6 +173,9 @@ static void handle_event(App *app, const SDL_Event *event) { case SDLK_TAB: app->mode = app->mode == MODE_FULLSCREEN ? MODE_GUIDE : MODE_FULLSCREEN; break; + case SDLK_f: + toggle_fullscreen(app); + break; case SDLK_UP: tune_relative(app, -1); break; @@ -243,6 +261,8 @@ void app_run(App *app) { while (app->running) { int in_blackout; + int output_width = WINDOW_WIDTH; + int output_height = WINDOW_HEIGHT; Uint64 now_ticks; time_t now_wall; @@ -255,6 +275,11 @@ void app_run(App *app) { break; } + if (SDL_GetRendererOutputSize(app->renderer, &output_width, &output_height) != 0) { + output_width = WINDOW_WIDTH; + output_height = WINDOW_HEIGHT; + } + in_blackout = player_is_in_blackout(&app->player); now_ticks = SDL_GetTicks64(); now_wall = time(NULL); @@ -266,7 +291,7 @@ void app_run(App *app) { app->last_blackout_state = in_blackout; if (app->channels.count == 0) { - ui_render_no_media(app->renderer, &app->ui_cache); + ui_render_no_media(app->renderer, &app->ui_cache, output_width, output_height); } else if (app->mode == MODE_GUIDE) { if (!in_blackout) { player_resume_audio(&app->player); @@ -275,6 +300,8 @@ void app_run(App *app) { in_blackout ? NULL : app->video_texture, app->texture_width, app->texture_height, + output_width, + output_height, &app->fonts, &app->ui_cache, &app->channels, @@ -289,7 +316,9 @@ void app_run(App *app) { ui_render_fullscreen(app->renderer, in_blackout ? NULL : app->video_texture, app->texture_width, - app->texture_height); + app->texture_height, + output_width, + output_height); } SDL_RenderPresent(app->renderer); diff --git a/src/app.h b/src/app.h index 1a70c95..9f0e269 100644 --- a/src/app.h +++ b/src/app.h @@ -16,6 +16,7 @@ typedef struct App { int texture_height; AppMode mode; int running; + int is_fullscreen; int startup_handoff_active; int last_blackout_state; Uint32 startup_handoff_until; diff --git a/src/app.o b/src/app.o index b89b500..c3becbd 100644 Binary files a/src/app.o and b/src/app.o differ diff --git a/src/ui.c b/src/ui.c index d9d9bc3..ea9d2de 100644 --- a/src/ui.c +++ b/src/ui.c @@ -481,16 +481,21 @@ static void draw_scanline_overlay(SDL_Renderer *renderer, int width, int height) SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE); } -void ui_render_no_media(SDL_Renderer *renderer, const UiCache *cache) { - SDL_Rect full = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT}; +void ui_render_no_media(SDL_Renderer *renderer, const UiCache *cache, int window_width, int window_height) { + SDL_Rect full = {0, 0, window_width, window_height}; fill_rect(renderer, &full, COLOR_NAVY_DARK); draw_cached_text(renderer, &cache->no_media_title, 58, 80); draw_cached_text(renderer, &cache->no_media_body, 58, 136); draw_cached_text(renderer, &cache->no_media_hint, 58, 176); } -void ui_render_fullscreen(SDL_Renderer *renderer, SDL_Texture *video_texture, int texture_width, int texture_height) { - SDL_Rect window = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT}; +void ui_render_fullscreen(SDL_Renderer *renderer, + SDL_Texture *video_texture, + int texture_width, + int texture_height, + int window_width, + int window_height) { + SDL_Rect window = {0, 0, window_width, window_height}; fill_rect(renderer, &window, COLOR_BLACK); draw_video(renderer, video_texture, texture_width, texture_height, window); } @@ -499,6 +504,8 @@ void ui_render_guide(SDL_Renderer *renderer, SDL_Texture *video_texture, int texture_width, int texture_height, + int window_width, + int window_height, const UiFonts *fonts, UiCache *cache, const ChannelList *channels, @@ -506,14 +513,18 @@ void ui_render_guide(SDL_Renderer *renderer, Uint64 app_start_ticks, Uint64 now_ticks, time_t now_wall) { - SDL_Rect full = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT}; - SDL_Rect info_panel = {0, 0, GUIDE_INFO_WIDTH, GUIDE_INFO_HEIGHT}; - SDL_Rect preview = {WINDOW_WIDTH - GUIDE_PREVIEW_WIDTH, 0, GUIDE_PREVIEW_WIDTH, GUIDE_PREVIEW_HEIGHT}; - SDL_Rect status_bar = {GUIDE_INFO_WIDTH, 0, WINDOW_WIDTH - GUIDE_INFO_WIDTH, GUIDE_STATUS_HEIGHT}; - SDL_Rect header_row = {0, GUIDE_GRID_TOP - GUIDE_STATUS_HEIGHT, WINDOW_WIDTH, GUIDE_STATUS_HEIGHT}; - SDL_Rect grid = {0, GUIDE_GRID_TOP, WINDOW_WIDTH, WINDOW_HEIGHT - GUIDE_GRID_TOP - GUIDE_FOOTER_HEIGHT}; + double scale_x = (double) window_width / WINDOW_WIDTH; + double scale_y = (double) window_height / WINDOW_HEIGHT; + int guide_x_start = (int) (GUIDE_X_START * scale_x); + int sidebar_width = (int) (GUIDE_SIDEBAR_WIDTH * scale_x); + SDL_Rect full = {0, 0, window_width, window_height}; + SDL_Rect info_panel = {0, 0, (int) (GUIDE_INFO_WIDTH * scale_x), (int) (GUIDE_INFO_HEIGHT * scale_y)}; + SDL_Rect preview = {window_width - (int) (GUIDE_PREVIEW_WIDTH * scale_x), 0, (int) (GUIDE_PREVIEW_WIDTH * scale_x), (int) (GUIDE_PREVIEW_HEIGHT * scale_y)}; + SDL_Rect status_bar = {info_panel.w, 0, window_width - info_panel.w, (int) (GUIDE_STATUS_HEIGHT * scale_y)}; + SDL_Rect header_row = {0, (int) ((GUIDE_GRID_TOP - GUIDE_STATUS_HEIGHT) * scale_y), window_width, (int) (GUIDE_STATUS_HEIGHT * scale_y)}; + SDL_Rect grid = {0, (int) (GUIDE_GRID_TOP * scale_y), window_width, window_height - (int) (GUIDE_GRID_TOP * scale_y) - (int) (GUIDE_FOOTER_HEIGHT * scale_y)}; int row_height = grid.h / GUIDE_VISIBLE_ROWS; - int timeline_w = WINDOW_WIDTH - GUIDE_X_START - 20; + int timeline_w = window_width - guide_x_start - (int) (20 * scale_x); int start_index = active_channel - 2; const Channel *selected_channel = NULL; double pixels_per_minute = timeline_w / 90.0; @@ -554,9 +565,9 @@ void ui_render_guide(SDL_Renderer *renderer, for (int row = 0; row < GUIDE_VISIBLE_ROWS; ++row) { int channel_index = start_index + row; - SDL_Rect row_rect = {0, grid.y + row * row_height, WINDOW_WIDTH, row_height}; - SDL_Rect sidebar = {0, row_rect.y, GUIDE_SIDEBAR_WIDTH, row_height}; - SDL_Rect timeline_rect = {GUIDE_X_START, row_rect.y + 6, timeline_w, row_height - 12}; + SDL_Rect row_rect = {0, grid.y + row * row_height, window_width, row_height}; + SDL_Rect sidebar = {0, row_rect.y, sidebar_width, row_height}; + SDL_Rect timeline_rect = {guide_x_start, row_rect.y + (int) (6 * scale_y), timeline_w, row_height - (int) (12 * scale_y)}; SDL_Rect clip = timeline_rect; int is_selected = channel_index == active_channel; SDL_Rect inset = {row_rect.x + 4, row_rect.y + 3, row_rect.w - 8, row_rect.h - 6}; @@ -588,9 +599,9 @@ void ui_render_guide(SDL_Renderer *renderer, const ProgramEntry *program = channel_resolve_program(channel, app_start_ticks, now_ticks, &program_seek, NULL); time_t guide_view_start_time = now_wall - (30 * 60); time_t program_start_time = now_wall - (time_t) live_position; - int block_x = GUIDE_X_START; + int block_x = guide_x_start; int block_w = 48; - SDL_Rect block = {GUIDE_X_START, timeline_rect.y + 4, 48, timeline_rect.h - 8}; + SDL_Rect block = {guide_x_start, timeline_rect.y + 4, 48, timeline_rect.h - 8}; SDL_Rect title_rect = {block.x + 8, block.y + 8, block.w - 16, block.h - 16}; char title[128]; @@ -599,7 +610,7 @@ void ui_render_guide(SDL_Renderer *renderer, } live_position = channel_live_position_precise(channel, app_start_ticks, now_ticks); program_start_time = now_wall - (time_t) program_seek; - block_x = GUIDE_X_START + (int) (((double) (program_start_time - guide_view_start_time)) / 60.0 * pixels_per_minute); + block_x = guide_x_start + (int) (((double) (program_start_time - guide_view_start_time)) / 60.0 * pixels_per_minute); block_w = (int) ((program->duration_seconds / 60.0) * pixels_per_minute); block = (SDL_Rect){block_x, timeline_rect.y + 4, SDL_max(block_w, 48), timeline_rect.h - 8}; title_rect = (SDL_Rect){block.x + 8, block.y + 8, block.w - 16, block.h - 16}; @@ -642,13 +653,13 @@ void ui_render_guide(SDL_Renderer *renderer, } if (selected_channel && active_channel >= 0 && start_index <= active_channel && active_channel < start_index + GUIDE_VISIBLE_ROWS) { - SDL_Rect highlight = {0, grid.y + (active_channel - start_index) * row_height, WINDOW_WIDTH, row_height}; + SDL_Rect highlight = {0, grid.y + (active_channel - start_index) * row_height, window_width, row_height}; draw_selection_glow(renderer, &highlight); - draw_selection_glow(renderer, &(SDL_Rect){GUIDE_X_START, highlight.y + 6, timeline_w, row_height - 12}); + draw_selection_glow(renderer, &(SDL_Rect){guide_x_start, highlight.y + (int) (6 * scale_y), timeline_w, row_height - (int) (12 * scale_y)}); } - draw_footer_legend(renderer, cache, WINDOW_WIDTH, WINDOW_HEIGHT); - draw_scanline_overlay(renderer, WINDOW_WIDTH, WINDOW_HEIGHT); + draw_footer_legend(renderer, cache, window_width, window_height); + draw_scanline_overlay(renderer, window_width, window_height); } int ui_cache_init(UiCache *cache, SDL_Renderer *renderer, const UiFonts *fonts, const ChannelList *channels) { diff --git a/src/ui.h b/src/ui.h index 3b3208b..02fc9ac 100644 --- a/src/ui.h +++ b/src/ui.h @@ -46,11 +46,18 @@ typedef struct UiCache { int channel_count; } UiCache; -void ui_render_fullscreen(SDL_Renderer *renderer, SDL_Texture *video_texture, int texture_width, int texture_height); +void ui_render_fullscreen(SDL_Renderer *renderer, + SDL_Texture *video_texture, + int texture_width, + int texture_height, + int window_width, + int window_height); void ui_render_guide(SDL_Renderer *renderer, SDL_Texture *video_texture, int texture_width, int texture_height, + int window_width, + int window_height, const UiFonts *fonts, UiCache *cache, const ChannelList *channels, @@ -58,7 +65,7 @@ void ui_render_guide(SDL_Renderer *renderer, Uint64 app_start_ticks, Uint64 now_ticks, time_t now_wall); -void ui_render_no_media(SDL_Renderer *renderer, const UiCache *cache); +void ui_render_no_media(SDL_Renderer *renderer, const UiCache *cache, int window_width, int window_height); int ui_load_fonts(UiFonts *fonts); void ui_destroy_fonts(UiFonts *fonts); int ui_cache_init(UiCache *cache, SDL_Renderer *renderer, const UiFonts *fonts, const ChannelList *channels); diff --git a/src/ui.o b/src/ui.o index b930071..a98777d 100644 Binary files a/src/ui.o and b/src/ui.o differ