monitor-manager: Reload monitor manager in idle callback

When a virtual stream is destroyed, its respective virtual monitor is
destroyed too. When the virtual monitor is destroyed, mutter reloads
the monitor manager.
However, at this point, the virtual stream is not completely destroyed
yet. The viewport of the virtual monitor still exists at this point and
when the monitor manager reloads, it will try to fetch the logical
monitor of the now destroyed virtual monitor, which will fail and thus
gnome-shell will run into a segfault.

Fix this situation by reloading the monitor manager in an idle callback.
When the monitor manager reloads, the virtual monitor is completely
gone, since the viewport of the virtual monitor is destroyed after the
virtual monitor itself.

Closes: https://gitlab.gnome.org/GNOME/mutter/-/issues/2864
Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/3307>
This commit is contained in:
Pascal Nowack 2023-09-29 14:31:41 +02:00
parent e70fa342a9
commit d2122a02a3
3 changed files with 24 additions and 3 deletions

View File

@ -118,6 +118,7 @@ typedef struct _MetaMonitorManagerPrivate
gboolean night_light_supported;
const char *experimental_hdr;
guint reload_monitor_manager_id;
guint switch_config_handle_id;
} MetaMonitorManagerPrivate;
@ -483,6 +484,8 @@ prepare_shutdown (MetaBackend *backend,
meta_monitor_manager_get_instance_private (manager);
priv->shutting_down = TRUE;
g_clear_handle_id (&priv->reload_monitor_manager_id, g_source_remove);
}
static void
@ -678,8 +681,12 @@ on_virtual_monitor_destroyed (MetaVirtualMonitor *virtual_monitor,
priv->virtual_monitors = g_list_remove (priv->virtual_monitors,
virtual_monitor);
if (!priv->shutting_down)
meta_monitor_manager_reload (manager);
if (!priv->shutting_down && !priv->reload_monitor_manager_id)
{
priv->reload_monitor_manager_id =
g_idle_add_once ((GSourceOnceFunc) meta_monitor_manager_reload,
manager);
}
}
MetaVirtualMonitor *
@ -1403,6 +1410,7 @@ meta_monitor_manager_dispose (GObject *object)
g_clear_handle_id (&manager->persistent_timeout_id, g_source_remove);
g_clear_handle_id (&manager->restore_config_id, g_source_remove);
g_clear_handle_id (&priv->switch_config_handle_id, g_source_remove);
g_clear_handle_id (&priv->reload_monitor_manager_id, g_source_remove);
G_OBJECT_CLASS (meta_monitor_manager_parent_class)->dispose (object);
}
@ -3807,6 +3815,11 @@ meta_monitor_manager_reconfigure (MetaMonitorManager *manager)
void
meta_monitor_manager_reload (MetaMonitorManager *manager)
{
MetaMonitorManagerPrivate *priv =
meta_monitor_manager_get_instance_private (manager);
g_clear_handle_id (&priv->reload_monitor_manager_id, g_source_remove);
meta_monitor_manager_read_current_state (manager);
meta_monitor_manager_reconfigure (manager);
}

View File

@ -146,6 +146,7 @@ meta_test_cursor_hotplug (void)
meta_wayland_test_client_finish (test_client);
g_clear_object (&virtual_monitor);
meta_wait_for_monitors_changed (test_context);
meta_wait_for_paint (test_context);
}
@ -207,6 +208,7 @@ meta_test_hotplug_multi_view_invalidation (void)
g_signal_handler_disconnect (cursor_sprite, texture_changed_handler_id);
g_clear_object (&virtual_monitor);
meta_wait_for_monitors_changed (test_context);
meta_wait_for_paint (test_context);
}

View File

@ -249,7 +249,7 @@ meta_test_switch_config (void)
ClutterActor *stage = meta_backend_get_stage (backend);
ClutterSeat *seat = meta_backend_get_default_seat (backend);
g_autoptr (ClutterVirtualInputDevice) virtual_keyboard = NULL;
g_autoptr (MetaVirtualMonitor) virtual_monitor = NULL;
MetaVirtualMonitor *virtual_monitor;
GList *logical_monitors;
MtkRectangle logical_monitor_layout;
gulong after_paint_handler_id;
@ -327,6 +327,12 @@ meta_test_switch_config (void)
g_signal_handler_disconnect (stage, after_paint_handler_id);
g_signal_handler_disconnect (stage, presented_handler_id);
monitors_changed = FALSE;
g_clear_object (&virtual_monitor);
while (!monitors_changed)
g_main_context_iteration (NULL, TRUE);
g_signal_handler_disconnect (monitor_manager, monitors_changed_handler_id);
}