--- a/plugins/animate/animate.cpp +++ b/plugins/animate/animate.cpp @@ -7,6 +7,7 @@ #include #include #include "animate.hpp" +#include "animate-alias.hpp" #include "plugins/common/wayfire/plugins/common/shared-core-data.hpp" #include "system_fade.hpp" #include "basic_animations.hpp" @@ -29,7 +30,7 @@ public: std::shared_ptr view; wf::animate::animation_type type; - std::string name; + std::string name, effect_name; wf::output_t *current_output = nullptr; std::unique_ptr animation; std::shared_ptr unmapped_contents; @@ -85,11 +86,12 @@ std::unique_ptr _animation, wf::animation_description_t duration, wf::animate::animation_type type, - std::string name) + std::string name, std::string effect_name) { this->type = type; this->view = view->shared_from_this(); this->name = name; + this->effect_name = std::move(effect_name); this->animation = std::move(_animation); this->animation->init(view, duration, type); @@ -203,6 +205,10 @@ wf::view_matcher_t fire_enabled_for{"animate/fire_enabled_for"}; wf::shared_data::ref_ptr_t effects_registry; + wf::shared_data::ref_ptr_t hook_aliases; + // Retain the identities actually used, including none and aliases removed + // while a hook is alive. Cleanup must not depend on current registrations. + std::set used_hook_names; /** * Single-shot inhibit timer to uninhibit output rendering in case a @@ -223,6 +229,7 @@ void init() override { init_output_tracking(); + wf::get_core().connect(&effect_cleanup); register_effect("fade", default_duration); register_effect("zoom", default_duration); @@ -263,6 +270,7 @@ void fini() override { + effect_cleanup.disconnect(); cleanup_views_on_output(nullptr); effects_registry->unregister_effect("fade"); @@ -289,18 +297,11 @@ continue; } - for (auto& anim : effects_registry->effects) - { - auto map_name = get_map_animation_cdata_name(anim.first); - if (view->has_data(map_name)) + for (const auto& name : used_hook_names) + { + if (view->has_data(name)) { - view->get_data(map_name)->stop_hook(false); - } - - auto minimize_name = get_minimize_animation_cdata_name(anim.first); - if (view->has_data(minimize_name)) - { - view->get_data(minimize_name)->stop_hook(false); + view->get_data(name)->stop_hook(false); } } } @@ -390,6 +391,16 @@ std::string get_map_animation_cdata_name(std::string animation_name) { + auto identity = hook_aliases->resolve(animation_name, *effects_registry.get()); + if (identity) + { + animation_name = *identity; + } else + { + LOGE("Invalid MAP/UNMAP animation alias for ", animation_name, + "; retaining its own hook identity"); + } + return "animation-hook-" + animation_name; } @@ -418,9 +429,21 @@ } auto hook = std::make_unique(view, effect.generator(), - duration, type, cdata_name); + duration, type, cdata_name, animation_name); + used_hook_names.insert(cdata_name); view->store_data(std::move(hook), cdata_name); } + + wf::signal::connection_t effect_cleanup = + [this] (auto *ev) + { + std::vector> views; + for (auto view : wf::get_core().get_all_views()) views.push_back(view->shared_from_this()); + for (auto& view : views) + for (const auto& name : used_hook_names) + if (auto hook = view->get_data(name); hook && hook->effect_name == ev->effect) + hook->stop_hook(false); + }; /* TODO: enhance - add more animations */ wf::signal::connection_t on_view_mapped = [=] (wf::view_mapped_signal *ev) --- /dev/null +++ b/plugins/animate/animate-alias.hpp @@ -0,0 +1,46 @@ +// SPDX-License-Identifier: MIT +#pragma once +#include "animate.hpp" +#include + +namespace wf::animate +{ +// Synchronously stop a provider's active hooks before removing its callbacks. +// Emit on core during provider fini; existing effect registry layouts stay intact. +struct animate_effect_cleanup_signal { std::string effect; }; + +/** + * Optional MAP/UNMAP identities, held in separate shared core data so existing + * effect_description_t and animate_effects_registry_t layouts stay unchanged. + * Providers must remove their callbacks after stopping their active hooks and + * before unloading their code. Minimize/restore never consult this registry. + */ +class animate_hook_alias_registry_t +{ + public: + std::map> aliases; + + std::optional resolve(const std::string& effect, + const animate_effects_registry_t& registry) const + { + std::set visited; + auto name = effect; + while (true) + { + if (!visited.insert(name).second || + ((name != "none") && !registry.effects.count(name))) + { + return std::nullopt; + } + + auto alias = aliases.find(name); + if (alias == aliases.end()) + { + return name; + } + + name = alias->second(); + } + } +}; +} --- a/plugins/animate/meson.build +++ b/plugins/animate/meson.build @@ -16,4 +16,4 @@ install: true, install_dir: join_paths(get_option('libdir'), 'wayfire')) -install_headers(['animate.hpp'], subdir: 'wayfire/plugins/animate') +install_headers(['animate.hpp', 'animate-alias.hpp'], subdir: 'wayfire/plugins/animate')