Skip to content

Commit

Permalink
Simplify size changes in fullscreen or maximized
Browse files Browse the repository at this point in the history
If the content size changes (due to rotation for example) while the
window is maximized or fullscreen, the resize must be applied once
fullscreen and maximized are disabled.

The previous strategy consisted in storing the windowed size, computing
the target size on rotation, and applying it on window restoration. But
tracking the windowed size (while ignoring the non-windowed size) was
tricky, due to unspecified order of SDL events (e.g. size changes can be
notified before "maximized" events), race conditions when reading window
flags, different behaviors on different platforms...

To simplify the whole resize management, store the old content size (the
frame size, possibly rotated) when it changes while the window is
maximized or fullscreen, so that the new optimal size can be computed on
window restoration.
  • Loading branch information
rom1v committed May 12, 2020
1 parent f038518 commit 6dc113e
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 67 deletions.
97 changes: 40 additions & 57 deletions app/src/screen.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,42 +30,23 @@ get_rotated_size(struct size size, int rotation) {

// get the window size in a struct size
static struct size
get_window_size(SDL_Window *window) {
get_window_size(const struct screen *screen) {
int width;
int height;
SDL_GetWindowSize(window, &width, &height);
SDL_GetWindowSize(screen->window, &width, &height);

struct size size;
size.width = width;
size.height = height;
return size;
}

// get the windowed window size
static struct size
get_windowed_window_size(const struct screen *screen) {
if (screen->fullscreen || screen->maximized) {
return screen->windowed_window_size;
}
return get_window_size(screen->window);
}

// apply the windowed window size if fullscreen and maximized are disabled
static void
apply_windowed_size(struct screen *screen) {
if (!screen->fullscreen && !screen->maximized) {
SDL_SetWindowSize(screen->window, screen->windowed_window_size.width,
screen->windowed_window_size.height);
}
}

// set the window size to be applied when fullscreen is disabled
static void
set_window_size(struct screen *screen, struct size new_size) {
// setting the window size during fullscreen is implementation defined,
// so apply the resize only after fullscreen is disabled
screen->windowed_window_size = new_size;
apply_windowed_size(screen);
assert(!screen->fullscreen);
assert(!screen->maximized);
SDL_SetWindowSize(screen->window, new_size.width, new_size.height);
}

// get the preferred display bounds (i.e. the screen bounds with some margins)
Expand Down Expand Up @@ -138,8 +119,8 @@ get_optimal_size(struct size current_size, struct size content_size) {
// same as get_optimal_size(), but read the current size from the window
static inline struct size
get_optimal_window_size(const struct screen *screen, struct size content_size) {
struct size windowed_size = get_windowed_window_size(screen);
return get_optimal_size(windowed_size, content_size);
struct size window_size = get_window_size(screen);
return get_optimal_size(window_size, content_size);
}

// initially, there is no current size, so use the frame size as current size
Expand Down Expand Up @@ -308,8 +289,6 @@ screen_init_rendering(struct screen *screen, const char *window_title,
return false;
}

screen->windowed_window_size = window_size;

return true;
}

Expand All @@ -332,20 +311,44 @@ screen_destroy(struct screen *screen) {
}

static void
set_content_size(struct screen *screen, struct size new_content_size) {
struct size old_content_size = screen->content_size;
struct size windowed_size = get_windowed_window_size(screen);
resize_for_content(struct screen *screen, struct size old_content_size,
struct size new_content_size) {
struct size window_size = get_window_size(screen);
struct size target_size = {
.width = (uint32_t) windowed_size.width * new_content_size.width
.width = (uint32_t) window_size.width * new_content_size.width
/ old_content_size.width,
.height = (uint32_t) windowed_size.height * new_content_size.height
.height = (uint32_t) window_size.height * new_content_size.height
/ old_content_size.height,
};
target_size = get_optimal_size(target_size, new_content_size);
set_window_size(screen, target_size);
}

static void
set_content_size(struct screen *screen, struct size new_content_size) {
if (!screen->fullscreen && !screen->maximized) {
resize_for_content(screen, screen->content_size, new_content_size);
} else if (!screen->resize_pending) {
// Store the windowed size to be able to compute the optimal size once
// fullscreen and maximized are disabled
screen->windowed_content_size = screen->content_size;
screen->resize_pending = true;
}

screen->content_size = new_content_size;
}

static void
apply_pending_resize(struct screen *screen) {
assert(!screen->fullscreen);
assert(!screen->maximized);
if (screen->resize_pending) {
resize_for_content(screen, screen->windowed_content_size,
screen->content_size);
screen->resize_pending = false;
}
}

void
screen_set_rotation(struct screen *screen, unsigned rotation) {
assert(rotation < 4);
Expand Down Expand Up @@ -471,7 +474,9 @@ screen_switch_fullscreen(struct screen *screen) {
}

screen->fullscreen = !screen->fullscreen;
apply_windowed_size(screen);
if (!screen->fullscreen && !screen->maximized) {
apply_pending_resize(screen);
}

LOGD("Switched to %s mode", screen->fullscreen ? "fullscreen" : "windowed");
screen_render(screen);
Expand Down Expand Up @@ -520,36 +525,14 @@ screen_handle_window_event(struct screen *screen,
screen_render(screen);
break;
case SDL_WINDOWEVENT_SIZE_CHANGED:
if (!screen->fullscreen && !screen->maximized) {
// Backup the previous size: if we receive the MAXIMIZED event,
// then the new size must be ignored (it's the maximized size).
// We could not rely on the window flags due to race conditions
// (they could be updated asynchronously, at least on X11).
screen->windowed_window_size_backup =
screen->windowed_window_size;

// Save the windowed size, so that it is available once the
// window is maximized or fullscreen is enabled.
screen->windowed_window_size = get_window_size(screen->window);
}
screen_render(screen);
break;
case SDL_WINDOWEVENT_MAXIMIZED:
// The backup size must be non-nul.
assert(screen->windowed_window_size_backup.width);
assert(screen->windowed_window_size_backup.height);
// Revert the last size, it was updated while screen was maximized.
screen->windowed_window_size = screen->windowed_window_size_backup;
#ifdef DEBUG
// Reset the backup to invalid values to detect unexpected usage
screen->windowed_window_size_backup.width = 0;
screen->windowed_window_size_backup.height = 0;
#endif
screen->maximized = true;
break;
case SDL_WINDOWEVENT_RESTORED:
screen->maximized = false;
apply_windowed_size(screen);
apply_pending_resize(screen);
break;
}
}
Expand Down
18 changes: 8 additions & 10 deletions app/src/screen.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,12 @@ struct screen {
struct sc_opengl gl;
struct size frame_size;
struct size content_size; // rotated frame_size
// The window size the last time it was not maximized or fullscreen.
struct size windowed_window_size;
// Since we receive the event SIZE_CHANGED before MAXIMIZED, we must be
// able to revert the size to its non-maximized value.
struct size windowed_window_size_backup;

bool resize_pending; // resize requested while fullscreen or maximized
// The content size the last time the window was not maximized or
// fullscreen (meaningful only when resize_pending is true)
struct size windowed_content_size;

// client rotation: 0, 1, 2 or 3 (x90 degrees counterclockwise)
unsigned rotation;
bool has_frame;
Expand All @@ -49,11 +50,8 @@ struct screen {
.width = 0, \
.height = 0, \
}, \
.windowed_window_size = { \
.width = 0, \
.height = 0, \
}, \
.windowed_window_size_backup = { \
.resize_pending = false, \
.windowed_content_size = { \
.width = 0, \
.height = 0, \
}, \
Expand Down

0 comments on commit 6dc113e

Please sign in to comment.