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) {
|
||||
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);
|
||||
|
||||
if (display_data->xdg_output) {
|
||||
|
|
|
@ -1244,7 +1244,7 @@ static void Wayland_MaybeUpdateScaleFactor(SDL_WindowData *window)
|
|||
factor = SDL_max(factor, driverdata->scale_factor);
|
||||
}
|
||||
} else {
|
||||
/* No monitor (somehow)? Just fall back. */
|
||||
/* All outputs removed, just fall back. */
|
||||
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,
|
||||
struct wl_output *output)
|
||||
{
|
||||
|
@ -1332,37 +1363,12 @@ static void handle_surface_leave(void *data, struct wl_surface *surface,
|
|||
struct wl_output *output)
|
||||
{
|
||||
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)) {
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
Wayland_RemoveOutputFromWindow(window, output);
|
||||
}
|
||||
|
||||
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_SyncWindow(SDL_VideoDevice *_this, SDL_Window *window);
|
||||
|
||||
extern void Wayland_RemoveOutputFromWindow(SDL_WindowData *window, struct wl_output *output);
|
||||
|
||||
#endif /* SDL_waylandwindow_h_ */
|
||||
|
|
Loading…
Reference in New Issue