@@ -58,6 +58,10 @@ typedef struct {
5858 gulong name_owner_changed_id ;
5959 gulong proxy_signals_id ;
6060 gulong fallback_size_changed_id ;
61+ gulong monitor_added_id ;
62+ gulong monitor_removed_id ;
63+
64+ gboolean has_wayland_app_hold ;
6165} NemoDesktopManagerPrivate ;
6266
6367struct _NemoDesktopManager
@@ -572,6 +576,37 @@ on_failsafe_timeout (NemoDesktopManager *manager)
572576 return G_SOURCE_REMOVE ;
573577}
574578
579+ static void
580+ on_monitor_removed_wayland (GdkDisplay * display ,
581+ GdkMonitor * monitor ,
582+ NemoDesktopManager * manager )
583+ {
584+ FETCH_PRIV (manager );
585+
586+ if (priv -> current_run_state < RUN_STATE_RUNNING ) {
587+ return ;
588+ }
589+
590+ /* The compositor sent zwlr_layer_surface_v1.closed for the layer surface
591+ * associated with the removed output. gtk-layer-shell will destroy the
592+ * backing wl_surface in response. We must destroy our GtkWindow first,
593+ * before that happens, or a pending frame clock event will call
594+ * gdk_window_begin_draw_frame() on the dead wl_surface and crash. */
595+ DEBUG ("Wayland output removed - closing desktop windows immediately" );
596+
597+ close_all_windows (manager );
598+ queue_update_layout (manager );
599+ }
600+
601+ static void
602+ on_monitor_added_wayland (GdkDisplay * display ,
603+ GdkMonitor * monitor ,
604+ NemoDesktopManager * manager )
605+ {
606+ DEBUG ("Wayland output added - queuing layout update" );
607+ queue_update_layout (manager );
608+ }
609+
575610static void
576611connect_fallback_signals (NemoDesktopManager * manager )
577612{
@@ -583,6 +618,20 @@ connect_fallback_signals (NemoDesktopManager *manager)
583618 "size_changed" ,
584619 G_CALLBACK (queue_update_layout ),
585620 manager );
621+
622+ if (eel_check_is_wayland ()) {
623+ GdkDisplay * display = gdk_display_get_default ();
624+
625+ priv -> monitor_removed_id = g_signal_connect (display ,
626+ "monitor-removed" ,
627+ G_CALLBACK (on_monitor_removed_wayland ),
628+ manager );
629+
630+ priv -> monitor_added_id = g_signal_connect (display ,
631+ "monitor-added" ,
632+ G_CALLBACK (on_monitor_added_wayland ),
633+ manager );
634+ }
586635}
587636
588637static void
@@ -671,6 +720,25 @@ nemo_desktop_manager_dispose (GObject *object)
671720 priv -> fallback_size_changed_id = 0 ;
672721 }
673722
723+ if (priv -> monitor_removed_id > 0 || priv -> monitor_added_id > 0 ) {
724+ GdkDisplay * display = gdk_display_get_default ();
725+
726+ if (priv -> monitor_removed_id > 0 ) {
727+ g_signal_handler_disconnect (display , priv -> monitor_removed_id );
728+ priv -> monitor_removed_id = 0 ;
729+ }
730+
731+ if (priv -> monitor_added_id > 0 ) {
732+ g_signal_handler_disconnect (display , priv -> monitor_added_id );
733+ priv -> monitor_added_id = 0 ;
734+ }
735+ }
736+
737+ if (priv -> has_wayland_app_hold ) {
738+ g_application_release (G_APPLICATION (nemo_application_get_singleton ()));
739+ priv -> has_wayland_app_hold = FALSE;
740+ }
741+
674742 G_OBJECT_CLASS (nemo_desktop_manager_parent_class )-> dispose (object );
675743}
676744
@@ -764,6 +832,18 @@ nemo_desktop_manager_init (NemoDesktopManager *manager)
764832 }
765833
766834 connect_fallback_signals (manager );
835+
836+ if (eel_check_is_wayland ()) {
837+ /* Hold the application alive independently of any windows so that
838+ * nemo-desktop survives monitor removal (e.g. KVM switch). Without
839+ * this, gtk-layer-shell destroys our windows when the compositor
840+ * removes an output and GtkApplication exits immediately with no
841+ * windows left. The hold is released in nemo_desktop_manager_dispose
842+ * when the application is genuinely quitting. */
843+ g_application_hold (G_APPLICATION (nemo_application_get_singleton ()));
844+ priv -> has_wayland_app_hold = TRUE;
845+ }
846+
767847 g_timeout_add (250 , (GSourceFunc ) fallback_startup_idle_cb , manager );
768848}
769849
0 commit comments