wayland: Remove all references to destroyed outputs from windows
The removal of a wl_output may not be accompanied by leave events for the surfaces present on it. Ensure that no window continues to hold a reference to a removed output.main
parent
84aaf63bd3
commit
c259a20f96
|
@ -947,6 +947,13 @@ static void Wayland_free_display(SDL_VideoDisplay *display)
|
||||||
if (display) {
|
if (display) {
|
||||||
SDL_DisplayData *display_data = display->driverdata;
|
SDL_DisplayData *display_data = display->driverdata;
|
||||||
|
|
||||||
|
/* A preceding surface leave event is not guaranteed when an output is removed,
|
||||||
|
* so ensure that no window continues to hold a reference to a removed output.
|
||||||
|
*/
|
||||||
|
for (SDL_Window *window = SDL_GetVideoDevice()->windows; window; window = window->next) {
|
||||||
|
Wayland_RemoveOutputFromWindow(window->driverdata, display_data->output);
|
||||||
|
}
|
||||||
|
|
||||||
SDL_free(display_data->wl_output_name);
|
SDL_free(display_data->wl_output_name);
|
||||||
|
|
||||||
if (display_data->xdg_output) {
|
if (display_data->xdg_output) {
|
||||||
|
|
|
@ -1244,7 +1244,7 @@ static void Wayland_MaybeUpdateScaleFactor(SDL_WindowData *window)
|
||||||
factor = SDL_max(factor, driverdata->scale_factor);
|
factor = SDL_max(factor, driverdata->scale_factor);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* No monitor (somehow)? Just fall back. */
|
/* All outputs removed, just fall back. */
|
||||||
factor = window->windowed_scale_factor;
|
factor = window->windowed_scale_factor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1304,6 +1304,37 @@ static void Wayland_move_window(SDL_Window *window, SDL_DisplayData *driverdata)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Wayland_RemoveOutputFromWindow(SDL_WindowData *window, struct wl_output *output)
|
||||||
|
{
|
||||||
|
int i, send_move_event = 0;
|
||||||
|
SDL_DisplayData *driverdata = wl_output_get_user_data(output);
|
||||||
|
|
||||||
|
for (i = 0; i < window->num_outputs; i++) {
|
||||||
|
if (window->outputs[i] == driverdata) { /* remove this one */
|
||||||
|
if (i == (window->num_outputs - 1)) {
|
||||||
|
window->outputs[i] = NULL;
|
||||||
|
send_move_event = 1;
|
||||||
|
} else {
|
||||||
|
SDL_memmove(&window->outputs[i],
|
||||||
|
&window->outputs[i + 1],
|
||||||
|
sizeof(SDL_DisplayData *) * ((window->num_outputs - i) - 1));
|
||||||
|
}
|
||||||
|
window->num_outputs--;
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (window->num_outputs == 0) {
|
||||||
|
SDL_free(window->outputs);
|
||||||
|
window->outputs = NULL;
|
||||||
|
} else if (send_move_event) {
|
||||||
|
Wayland_move_window(window->sdlwindow,
|
||||||
|
window->outputs[window->num_outputs - 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
Wayland_MaybeUpdateScaleFactor(window);
|
||||||
|
}
|
||||||
|
|
||||||
static void handle_surface_enter(void *data, struct wl_surface *surface,
|
static void handle_surface_enter(void *data, struct wl_surface *surface,
|
||||||
struct wl_output *output)
|
struct wl_output *output)
|
||||||
{
|
{
|
||||||
|
@ -1332,37 +1363,12 @@ static void handle_surface_leave(void *data, struct wl_surface *surface,
|
||||||
struct wl_output *output)
|
struct wl_output *output)
|
||||||
{
|
{
|
||||||
SDL_WindowData *window = data;
|
SDL_WindowData *window = data;
|
||||||
int i, send_move_event = 0;
|
|
||||||
SDL_DisplayData *driverdata = wl_output_get_user_data(output);
|
|
||||||
|
|
||||||
if (!SDL_WAYLAND_own_output(output) || !SDL_WAYLAND_own_surface(surface)) {
|
if (!SDL_WAYLAND_own_output(output) || !SDL_WAYLAND_own_surface(surface)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < window->num_outputs; i++) {
|
Wayland_RemoveOutputFromWindow(window, output);
|
||||||
if (window->outputs[i] == driverdata) { /* remove this one */
|
|
||||||
if (i == (window->num_outputs - 1)) {
|
|
||||||
window->outputs[i] = NULL;
|
|
||||||
send_move_event = 1;
|
|
||||||
} else {
|
|
||||||
SDL_memmove(&window->outputs[i],
|
|
||||||
&window->outputs[i + 1],
|
|
||||||
sizeof(SDL_DisplayData *) * ((window->num_outputs - i) - 1));
|
|
||||||
}
|
|
||||||
window->num_outputs--;
|
|
||||||
i--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (window->num_outputs == 0) {
|
|
||||||
SDL_free(window->outputs);
|
|
||||||
window->outputs = NULL;
|
|
||||||
} else if (send_move_event) {
|
|
||||||
Wayland_move_window(window->sdlwindow,
|
|
||||||
window->outputs[window->num_outputs - 1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
Wayland_MaybeUpdateScaleFactor(window);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_preferred_buffer_scale(void *data, struct wl_surface *wl_surface, int32_t factor)
|
static void handle_preferred_buffer_scale(void *data, struct wl_surface *wl_surface, int32_t factor)
|
||||||
|
|
|
@ -206,4 +206,6 @@ extern int Wayland_SetWindowHitTest(SDL_Window *window, SDL_bool enabled);
|
||||||
extern int Wayland_FlashWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_FlashOperation operation);
|
extern int Wayland_FlashWindow(SDL_VideoDevice *_this, SDL_Window *window, SDL_FlashOperation operation);
|
||||||
extern int Wayland_SyncWindow(SDL_VideoDevice *_this, SDL_Window *window);
|
extern int Wayland_SyncWindow(SDL_VideoDevice *_this, SDL_Window *window);
|
||||||
|
|
||||||
|
extern void Wayland_RemoveOutputFromWindow(SDL_WindowData *window, struct wl_output *output);
|
||||||
|
|
||||||
#endif /* SDL_waylandwindow_h_ */
|
#endif /* SDL_waylandwindow_h_ */
|
||||||
|
|
Loading…
Reference in New Issue