wayland: Don't leave un-acked configurations when throttling resize events
Compositors that send multiple resize events per frame could result in the most recent configuration requests being left un-acked when the resize ends. Ack the most recent resized state on frame callbacks, so as to always ack the most recent configuration within a reasonable timeframe.
This commit is contained in:
@@ -301,7 +301,7 @@ static void SetSurfaceOpaqueRegion(SDL_WindowData *wind, bool is_opaque)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool ConfigureWindowGeometry(SDL_Window *window)
|
static void ConfigureWindowGeometry(SDL_Window *window)
|
||||||
{
|
{
|
||||||
SDL_WindowData *data = window->internal;
|
SDL_WindowData *data = window->internal;
|
||||||
const double scale_factor = GetWindowScale(window);
|
const double scale_factor = GetWindowScale(window);
|
||||||
@@ -310,17 +310,6 @@ static bool ConfigureWindowGeometry(SDL_Window *window)
|
|||||||
int window_width, window_height;
|
int window_width, window_height;
|
||||||
bool window_size_changed;
|
bool window_size_changed;
|
||||||
|
|
||||||
// Throttle interactive resize events to once per refresh cycle to prevent lag.
|
|
||||||
if (data->resizing) {
|
|
||||||
data->resizing = false;
|
|
||||||
|
|
||||||
if (data->drop_interactive_resizes) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
data->drop_interactive_resizes = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the drawable backbuffer size.
|
// Set the drawable backbuffer size.
|
||||||
GetBufferSize(window, &data->current.pixel_width, &data->current.pixel_height);
|
GetBufferSize(window, &data->current.pixel_width, &data->current.pixel_height);
|
||||||
const bool buffer_size_changed = data->current.pixel_width != old_pixel_width ||
|
const bool buffer_size_changed = data->current.pixel_width != old_pixel_width ||
|
||||||
@@ -469,8 +458,6 @@ static bool ConfigureWindowGeometry(SDL_Window *window)
|
|||||||
SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_OCCLUDED, 0, 0);
|
SDL_SendWindowEvent(window, SDL_EVENT_WINDOW_OCCLUDED, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void CommitLibdecorFrame(SDL_Window *window)
|
static void CommitLibdecorFrame(SDL_Window *window)
|
||||||
@@ -690,7 +677,15 @@ static void surface_frame_done(void *data, struct wl_callback *cb, uint32_t time
|
|||||||
wl_surface_damage(wind->surface, 0, 0, SDL_MAX_SINT32, SDL_MAX_SINT32);
|
wl_surface_damage(wind->surface, 0, 0, SDL_MAX_SINT32, SDL_MAX_SINT32);
|
||||||
}
|
}
|
||||||
|
|
||||||
wind->drop_interactive_resizes = false;
|
if (wind->shell_surface_type == WAYLAND_SHELL_SURFACE_TYPE_XDG_TOPLEVEL) {
|
||||||
|
if (wind->pending_config_ack) {
|
||||||
|
wind->pending_config_ack = false;
|
||||||
|
ConfigureWindowGeometry(wind->sdlwindow);
|
||||||
|
xdg_surface_ack_configure(wind->shell_surface.xdg.surface, wind->shell_surface.xdg.serial);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
wind->resizing = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (wind->shell_surface_status == WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_FRAME) {
|
if (wind->shell_surface_status == WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_FRAME) {
|
||||||
wind->shell_surface_status = WAYLAND_SHELL_SURFACE_STATUS_SHOWN;
|
wind->shell_surface_status = WAYLAND_SHELL_SURFACE_STATUS_SHOWN;
|
||||||
@@ -746,8 +741,17 @@ static void handle_xdg_surface_configure(void *data, struct xdg_surface *xdg, ui
|
|||||||
SDL_WindowData *wind = (SDL_WindowData *)data;
|
SDL_WindowData *wind = (SDL_WindowData *)data;
|
||||||
SDL_Window *window = wind->sdlwindow;
|
SDL_Window *window = wind->sdlwindow;
|
||||||
|
|
||||||
if (ConfigureWindowGeometry(window)) {
|
/* Interactive resizes are throttled by acking and committing only the most recent configuration at
|
||||||
|
* the next frame callback, or certain combinations of clients and compositors can exhibit severe lag
|
||||||
|
* when resizing.
|
||||||
|
*/
|
||||||
|
wind->shell_surface.xdg.serial = serial;
|
||||||
|
if (!wind->resizing) {
|
||||||
|
wind->pending_config_ack = false;
|
||||||
|
ConfigureWindowGeometry(window);
|
||||||
xdg_surface_ack_configure(xdg, serial);
|
xdg_surface_ack_configure(xdg, serial);
|
||||||
|
} else {
|
||||||
|
wind->pending_config_ack = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wind->shell_surface_status == WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_CONFIGURE) {
|
if (wind->shell_surface_status == WAYLAND_SHELL_SURFACE_STATUS_WAITING_FOR_CONFIGURE) {
|
||||||
@@ -1404,6 +1408,7 @@ static void decoration_frame_configure(struct libdecor_frame *frame,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Store the new state.
|
// Store the new state.
|
||||||
|
const bool started_resize = !wind->resizing && resizing;
|
||||||
wind->last_configure.width = width;
|
wind->last_configure.width = width;
|
||||||
wind->last_configure.height = height;
|
wind->last_configure.height = height;
|
||||||
wind->floating = floating;
|
wind->floating = floating;
|
||||||
@@ -1430,9 +1435,15 @@ static void decoration_frame_configure(struct libdecor_frame *frame,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Calculate the new window geometry
|
if (!wind->resizing || started_resize) {
|
||||||
if (ConfigureWindowGeometry(window)) {
|
/* Calculate the new window geometry and commit the changes on the libdecor side.
|
||||||
// ... then commit the changes on the libdecor side.
|
*
|
||||||
|
* XXX: This will potentially leave un-acked configurations, but libdecor invalidates the
|
||||||
|
* configuration upon returning from the frame event, so there is nothing that can be
|
||||||
|
* done, unless libdecor adds the ability to copy or refcount the configuration state
|
||||||
|
* to apply later.
|
||||||
|
*/
|
||||||
|
ConfigureWindowGeometry(window);
|
||||||
struct libdecor_state *state = libdecor_state_new(wind->current.logical_width, wind->current.logical_height);
|
struct libdecor_state *state = libdecor_state_new(wind->current.logical_width, wind->current.logical_height);
|
||||||
libdecor_frame_commit(frame, state, configuration);
|
libdecor_frame_commit(frame, state, configuration);
|
||||||
libdecor_state_free(state);
|
libdecor_state_free(state);
|
||||||
|
|||||||
@@ -63,6 +63,8 @@ struct SDL_WindowData
|
|||||||
struct xdg_positioner *xdg_positioner;
|
struct xdg_positioner *xdg_positioner;
|
||||||
} popup;
|
} popup;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Uint32 serial;
|
||||||
} xdg;
|
} xdg;
|
||||||
} shell_surface;
|
} shell_surface;
|
||||||
enum
|
enum
|
||||||
@@ -203,7 +205,7 @@ struct SDL_WindowData
|
|||||||
bool suspended;
|
bool suspended;
|
||||||
bool resizing;
|
bool resizing;
|
||||||
bool active;
|
bool active;
|
||||||
bool drop_interactive_resizes;
|
bool pending_config_ack;
|
||||||
bool is_fullscreen;
|
bool is_fullscreen;
|
||||||
bool fullscreen_exclusive;
|
bool fullscreen_exclusive;
|
||||||
bool drop_fullscreen_requests;
|
bool drop_fullscreen_requests;
|
||||||
|
|||||||
Reference in New Issue
Block a user