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:
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
|
@ -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],
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue