diff --git a/plugins/protocols/wayfire-shell.cpp b/plugins/protocols/wayfire-shell.cpp index 2c8b994bf..ff9df252c 100644 --- a/plugins/protocols/wayfire-shell.cpp +++ b/plugins/protocols/wayfire-shell.cpp @@ -312,6 +312,18 @@ class wfs_output void create_hotspot(uint32_t hotspot, uint32_t threshold, uint32_t timeout, uint32_t id) { + if (!this->output) + { + // It can happen that the client requests a hotspot immediately after an output is destroyed - + // this is an inherent race condition because the compositor and client are not in sync. + // + // In this case, we create a dummy hotspot resource to avoid Wayland protocol errors. + auto resource = wl_resource_create( + wl_resource_get_client(this->resource), &zwf_hotspot_v2_interface, 1, id); + wl_resource_set_implementation(resource, NULL, NULL, NULL); + return; + } + // will be auto-deleted when the resource is destroyed by the client new wfs_hotspot(this->output, hotspot, threshold, timeout, wl_resource_get_client(this->resource), id); diff --git a/src/api/wayfire/unstable/wlr-text-input-v3-popup.hpp b/src/api/wayfire/unstable/wlr-text-input-v3-popup.hpp index a0dd15e94..95eba2554 100644 --- a/src/api/wayfire/unstable/wlr-text-input-v3-popup.hpp +++ b/src/api/wayfire/unstable/wlr-text-input-v3-popup.hpp @@ -38,7 +38,6 @@ class text_input_v3_popup : public wf::view_interface_t wf::geometry_t geometry{0, 0, 0, 0}; std::shared_ptr main_surface; std::shared_ptr surface_root_node; - bool _is_mapped = false; virtual wlr_surface *get_keyboard_focus_surface() override { diff --git a/src/core/core.cpp b/src/core/core.cpp index 0af5a90de..53cccb63d 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -244,14 +244,19 @@ void wf::compositor_core_impl_t::post_init() void wf::compositor_core_impl_t::shutdown() { - this->state = compositor_state_t::SHUTDOWN; - core_shutdown_signal ev; - this->emit(&ev); - wl_display_terminate(wf::get_core().display); + // We might get multiple signals in some scenarios. Shutdown only on the first instance. + if (this->state != compositor_state_t::SHUTDOWN) + { + wl_display_terminate(wf::get_core().display); + } } void wf::compositor_core_impl_t::fini() { + this->state = compositor_state_t::SHUTDOWN; + core_shutdown_signal ev; + this->emit(&ev); + LOGI("Unloading plugins..."); plugin_mgr.reset(); LOGI("Stopping clients..."); @@ -494,10 +499,8 @@ void wf::move_view_to_output(wayfire_toplevel_view v, wf::output_t *new_output, new_output_g = new_output->get_relative_geometry(); auto ratio_x = (double)new_output_g.width / old_output_g.width; auto ratio_y = (double)new_output_g.height / old_output_g.height; - view_g.x *= ratio_x; - view_g.y *= ratio_y; - view_g.width *= ratio_x; - view_g.height *= ratio_y; + view_g.x *= ratio_x; + view_g.y *= ratio_y; } assert(new_output); diff --git a/src/core/output-layout.cpp b/src/core/output-layout.cpp index 46b66dbb1..054b57789 100644 --- a/src/core/output-layout.cpp +++ b/src/core/output-layout.cpp @@ -1005,6 +1005,7 @@ class output_layout_t::impl { // Destroy outputs first this->outputs.clear(); + noop_output.reset(); // Disconnect all signals on_new_output.disconnect(); diff --git a/src/core/seat/input-method-popup.cpp b/src/core/seat/input-method-popup.cpp index 074b93e8f..5d680514d 100644 --- a/src/core/seat/input-method-popup.cpp +++ b/src/core/seat/input-method-popup.cpp @@ -58,7 +58,6 @@ void wf::text_input_v3_popup::map() priv->set_mapped_surface_contents(main_surface); priv->set_mapped(true); - _is_mapped = true; on_commit.connect(&surface->events.commit); update_geometry(); @@ -80,7 +79,6 @@ void wf::text_input_v3_popup::unmap() emit_view_unmap(); priv->set_mapped(false); - _is_mapped = false; on_commit.disconnect(); } @@ -163,7 +161,7 @@ void wf::text_input_v3_popup::update_geometry() bool wf::text_input_v3_popup::is_mapped() const { - return priv->wsurface != nullptr && _is_mapped; + return priv->is_mapped; } wf::geometry_t wf::text_input_v3_popup::get_geometry() diff --git a/src/core/seat/tablet.cpp b/src/core/seat/tablet.cpp index f269beec4..0b9685955 100644 --- a/src/core/seat/tablet.cpp +++ b/src/core/seat/tablet.cpp @@ -460,7 +460,7 @@ wf::tablet_pad_t::tablet_pad_t(wlr_input_device *pad) : void wf::tablet_pad_t::update_focus() { auto focus_view = wf::get_core().seat->get_active_view(); - auto focus_surface = focus_view ? focus_view->priv->wsurface : nullptr; + auto focus_surface = focus_view ? focus_view->get_wlr_surface() : nullptr; update_focus(focus_surface); } diff --git a/src/view/layer-shell/layer-shell.cpp b/src/view/layer-shell/layer-shell.cpp index 1a24f29b5..1bf549eb9 100644 --- a/src/view/layer-shell/layer-shell.cpp +++ b/src/view/layer-shell/layer-shell.cpp @@ -83,7 +83,7 @@ class wayfire_layer_shell_view : public wf::view_interface_t /* Just pass to the default wlr surface implementation */ bool is_mapped() const override { - return priv->wsurface != nullptr; + return priv->is_mapped; } std::string get_app_id() override final diff --git a/src/view/view-impl.cpp b/src/view/view-impl.cpp index 4e86a3b93..3f555b663 100644 --- a/src/view/view-impl.cpp +++ b/src/view/view-impl.cpp @@ -217,7 +217,8 @@ void wf::view_interface_t::view_priv_impl::set_mapped_surface_contents( return; } - wsurface = content->get_surface(); + wsurface = content->get_surface(); + is_mapped = true; // Locate the proper place to add the surface contents. // This is not trivial because we may have added content node before (if we currently are remapping). @@ -233,7 +234,9 @@ void wf::view_interface_t::view_priv_impl::set_mapped_surface_contents( void wf::view_interface_t::view_priv_impl::unset_mapped_surface_contents() { - wsurface = nullptr; + wsurface = nullptr; + is_mapped = false; + replace_node_or_add_front(surface_root_node, current_content, dummy_node); if (auto wcont = dynamic_cast(current_content.get())) diff --git a/src/view/view-impl.hpp b/src/view/view-impl.hpp index fa6574042..6ac7b830a 100644 --- a/src/view/view-impl.hpp +++ b/src/view/view-impl.hpp @@ -30,6 +30,7 @@ namespace wf class view_interface_t::view_priv_impl { public: + bool is_mapped = false; wlr_surface *wsurface = nullptr; size_t last_view_cnt = 0; uint32_t allowed_actions = VIEW_ALLOW_ALL; diff --git a/src/view/xdg-shell.cpp b/src/view/xdg-shell.cpp index 8340e932c..3acfabd96 100644 --- a/src/view/xdg-shell.cpp +++ b/src/view/xdg-shell.cpp @@ -261,7 +261,7 @@ void wayfire_xdg_popup::update_size() bool wayfire_xdg_popup::is_mapped() const { - return priv->wsurface != nullptr; + return priv->is_mapped; } void wayfire_xdg_popup::handle_app_id_changed(std::string new_app_id) diff --git a/src/view/xdg-shell/xdg-toplevel-view.cpp b/src/view/xdg-shell/xdg-toplevel-view.cpp index 75ad0ef1a..980f58d82 100644 --- a/src/view/xdg-shell/xdg-toplevel-view.cpp +++ b/src/view/xdg-shell/xdg-toplevel-view.cpp @@ -151,7 +151,7 @@ std::string wf::xdg_toplevel_view_base_t::get_title() bool wf::xdg_toplevel_view_base_t::is_mapped() const { - return priv->wsurface; + return priv->is_mapped; } // ------------------------------------------ xdg-toplevel impl ---------------------------------------------- @@ -284,7 +284,7 @@ bool wf::xdg_toplevel_view_t::should_be_decorated() bool wf::xdg_toplevel_view_t::is_mapped() const { - return wtoplevel->current().mapped && priv->wsurface; + return wtoplevel->current().mapped && priv->is_mapped; } void wf::xdg_toplevel_view_t::map() diff --git a/src/view/xwayland.cpp b/src/view/xwayland.cpp index 8cd116f2e..1e214bb16 100644 --- a/src/view/xwayland.cpp +++ b/src/view/xwayland.cpp @@ -90,6 +90,7 @@ class xwayland_view_controller_t }); on_dissociate.set_callback([&] (void*) { + view->priv->wsurface = nullptr; on_map.disconnect(); on_unmap.disconnect(); }); diff --git a/src/view/xwayland/xwayland-view-base.cpp b/src/view/xwayland/xwayland-view-base.cpp index 4e436d8ee..0dc91ced8 100644 --- a/src/view/xwayland/xwayland-view-base.cpp +++ b/src/view/xwayland/xwayland-view-base.cpp @@ -120,7 +120,7 @@ void wf::xwayland_view_base_t::close() bool wf::xwayland_view_base_t::is_mapped() const { - return priv->wsurface != nullptr; + return priv->is_mapped; } wlr_surface*wf::xwayland_view_base_t::get_keyboard_focus_surface()