Fix T103586: Crash removing monitor under Wayland & WLROOTS compositors

WLROOTS compositors don't run surface leave callbacks,
while this may be considered a bug in WLROOTS, neither GTK/SDL crash
so workaround the crash too.

This also fixes a minor glitch where the cursor scale wasn't updated
when changing monitor scale at run-time.
This commit is contained in:
Campbell Barton 2023-01-04 15:57:38 +11:00
parent 50dbedf0d8
commit cbd12e730a
Notes: blender-bot 2023-02-14 03:29:37 +01:00
Referenced by issue #103586, Segfault when disconnecting the monitor Blender is on, using Wayland
Referenced by issue #102967, 3.4: Potential candidates for corrective releases
2 changed files with 58 additions and 14 deletions

View File

@ -4535,18 +4535,7 @@ static void output_handle_scale(void *data, struct wl_output * /*wl_output*/, co
CLOG_INFO(LOG, 2, "scale");
GWL_Output *output = static_cast<GWL_Output *>(data);
output->scale = factor;
GHOST_WindowManager *window_manager = output->system->getWindowManager();
if (window_manager) {
for (GHOST_IWindow *iwin : window_manager->getWindows()) {
GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(iwin);
const std::vector<GWL_Output *> &outputs = win->outputs();
if (std::find(outputs.begin(), outputs.end(), output) == outputs.cend()) {
continue;
}
win->outputs_changed_update_scale();
}
}
output->system->output_scale_update_maybe_leave(output, false);
}
static const struct wl_output_listener output_listener = {
@ -4736,11 +4725,21 @@ static void gwl_registry_wl_output_update(GWL_Display *display,
}
static void gwl_registry_wl_output_remove(GWL_Display *display,
void *user_data,
const bool /*on_exit*/)
const bool on_exit)
{
/* While windows & cursors hold references to outputs, there is no need to manually remove
* these references as the compositor will remove references via #wl_surface_listener.leave. */
* these references as the compositor will remove references via #wl_surface_listener.leave.
*
* WARNING: this is not the case for WLROOTS based compositors which have a (bug?)
* where surface leave events don't run. So `system->output_leave(..)` is needed
* until the issue is resolved in WLROOTS. */
GWL_Output *output = static_cast<GWL_Output *>(user_data);
if (!on_exit) {
/* Needed for WLROOTS, does nothing if surface leave callbacks have already run. */
output->system->output_scale_update_maybe_leave(output, true);
}
if (output->xdg_output) {
zxdg_output_v1_destroy(output->xdg_output);
}
@ -6765,6 +6764,49 @@ void GHOST_SystemWayland::window_surface_unref(const wl_surface *wl_surface)
#undef SURFACE_CLEAR_PTR
}
void GHOST_SystemWayland::output_scale_update_maybe_leave(GWL_Output *output, bool leave)
{
/* Update scale, optionally leaving the outputs beforehand. */
GHOST_WindowManager *window_manager = output->system->getWindowManager();
if (window_manager) {
for (GHOST_IWindow *iwin : window_manager->getWindows()) {
GHOST_WindowWayland *win = static_cast<GHOST_WindowWayland *>(iwin);
const std::vector<GWL_Output *> &outputs = win->outputs();
bool found = leave ? win->outputs_leave(output) :
!(std::find(outputs.begin(), outputs.end(), output) == outputs.cend());
if (found) {
win->outputs_changed_update_scale();
}
}
}
for (GWL_Seat *seat : display_->seats) {
bool found;
found = leave ? seat->pointer.outputs.erase(output) : seat->pointer.outputs.count(output);
if (found) {
if (seat->cursor.wl_surface_cursor != nullptr) {
update_cursor_scale(
seat->cursor, seat->system->wl_shm(), &seat->pointer, seat->cursor.wl_surface_cursor);
}
}
found = leave ? seat->tablet.outputs.erase(output) : seat->tablet.outputs.count(output);
if (found) {
for (struct zwp_tablet_tool_v2 *zwp_tablet_tool_v2 : seat->tablet_tools) {
GWL_TabletTool *tablet_tool = static_cast<GWL_TabletTool *>(
zwp_tablet_tool_v2_get_user_data(zwp_tablet_tool_v2));
if (tablet_tool->wl_surface_cursor != nullptr) {
update_cursor_scale(seat->cursor,
seat->system->wl_shm(),
&seat->pointer,
tablet_tool->wl_surface_cursor);
}
}
}
}
}
bool GHOST_SystemWayland::window_cursor_grab_set(const GHOST_TGrabCursorMode mode,
const GHOST_TGrabCursorMode mode_current,
int32_t init_grab_xy[2],

View File

@ -194,6 +194,8 @@ class GHOST_SystemWayland : public GHOST_System {
/** Set this seat to be active. */
void seat_active_set(const struct GWL_Seat *seat);
void output_scale_update_maybe_leave(GWL_Output *output, bool leave);
/** Clear all references to this surface to prevent accessing NULL pointers. */
void window_surface_unref(const wl_surface *wl_surface);