From 2ff6b3bfa327f510412cd874409619eaece9a1ba Mon Sep 17 00:00:00 2001 From: Ilia Bozhinov Date: Wed, 24 Jul 2024 12:14:23 +0200 Subject: [PATCH] vswitch: move most of the implementation to the cpp file We don't need most of vswitch in the places where it is included. --- plugins/vswitch/vswitch.cpp | 310 ++++++++++++++++++++ plugins/vswitch/wayfire/plugins/vswitch.hpp | 304 ------------------- 2 files changed, 310 insertions(+), 304 deletions(-) diff --git a/plugins/vswitch/vswitch.cpp b/plugins/vswitch/vswitch.cpp index d6b35178c..adc4906ef 100644 --- a/plugins/vswitch/vswitch.cpp +++ b/plugins/vswitch/vswitch.cpp @@ -7,6 +7,316 @@ #include #include "plugins/ipc/ipc-method-repository.hpp" #include "wayfire/plugins/common/shared-core-data.hpp" +#include "wayfire/unstable/translation-node.hpp" +#include "wayfire/scene-operations.hpp" +#include "wayfire/render-manager.hpp" + +namespace wf +{ +namespace vswitch +{ +using namespace animation; +class workspace_animation_t : public duration_t +{ + public: + using duration_t::duration_t; + timed_transition_t dx{*this}; + timed_transition_t dy{*this}; +}; + +/** + * A simple scenegraph node which draws a view at a fixed position and as an overlay over the workspace wall. + */ +class vswitch_overlay_node_t : public wf::scene::node_t +{ + std::weak_ptr _view; + + public: + vswitch_overlay_node_t(wayfire_toplevel_view view) : node_t(true) + { + _view = view->weak_from_this(); + } + + // Since we do not grab focus via a grab node, route focus to the view being rendered as an overlay + wf::keyboard_focus_node_t keyboard_refocus(wf::output_t *output) + { + if (auto view = _view.lock()) + { + return view->get_transformed_node()->keyboard_refocus(output); + } + + return wf::keyboard_focus_node_t{}; + } + + virtual void gen_render_instances(std::vector& instances, + scene::damage_callback push_damage, wf::output_t *output = nullptr) + { + if (auto view = _view.lock()) + { + view->get_transformed_node()->gen_render_instances(instances, push_damage, output); + } + } + + virtual wf::geometry_t get_bounding_box() + { + if (auto view = _view.lock()) + { + return view->get_transformed_node()->get_bounding_box(); + } + + return {0, 0, 0, 0}; + } +}; + +/** + * Represents the action of switching workspaces with the vswitch algorithm. + * + * The workspace is actually switched at the end of the animation + */ +class workspace_switch_t +{ + public: + /** + * Initialize the workspace switch process. + * + * @param output The output the workspace switch happens on. + */ + workspace_switch_t(output_t *output) + { + this->output = output; + wall = std::make_unique(output); + animation = workspace_animation_t{ + wf::option_wrapper_t{"vswitch/duration"} + }; + } + + /** + * Initialize switching animation. + * At this point, the calling plugin needs to have the custom renderer + * ability set. + */ + virtual void start_switch() + { + /* Setup wall */ + wall->set_gap_size(gap); + wall->set_viewport(wall->get_workspace_rectangle( + output->wset()->get_current_workspace())); + wall->set_background_color(background_color); + wall->start_output_renderer(); + + if (overlay_view_node) + { + wf::scene::readd_front(wf::get_core().scene(), overlay_view_node); + } + + output->render->add_effect(&post_render, OUTPUT_EFFECT_POST); + + running = true; + + /* Setup animation */ + animation.dx.set(0, 0); + animation.dy.set(0, 0); + animation.start(); + } + + /** + * Start workspace switch animation towards the given workspace, + * and set that workspace as current. + * + * @param workspace The new target workspace. + */ + virtual void set_target_workspace(point_t workspace) + { + point_t cws = output->wset()->get_current_workspace(); + + animation.dx.set(animation.dx + cws.x - workspace.x, 0); + animation.dy.set(animation.dy + cws.y - workspace.y, 0); + animation.start(); + + std::vector fixed_views; + if (overlay_view) + { + fixed_views.push_back(overlay_view); + } + + output->wset()->set_workspace(workspace, fixed_views); + } + + /** + * Set the overlay view. It will be hidden from the normal workspace layers + * and shown on top of the workspace wall. The overlay view's position is + * not animated together with the workspace transition, but its alpha is. + * + * Note: if the view disappears, the caller is responsible for resetting the + * overlay view. + * + * @param view The desired overlay view, or NULL if the overlay view needs + * to be unset. + */ + virtual void set_overlay_view(wayfire_toplevel_view view) + { + if (this->overlay_view == view) + { + /* Nothing to do */ + return; + } + + /* Reset old view */ + if (this->overlay_view) + { + wf::scene::set_node_enabled(overlay_view->get_transformed_node(), true); + overlay_view->get_transformed_node()->rem_transformer( + vswitch_view_transformer_name); + + wf::scene::remove_child(overlay_view_node); + overlay_view_node.reset(); + } + + /* Set new view */ + this->overlay_view = view; + if (view) + { + view->get_transformed_node()->add_transformer( + std::make_shared(view), + wf::TRANSFORMER_2D, vswitch_view_transformer_name); + wf::scene::set_node_enabled(view->get_transformed_node(), false); + + // Render as an overlay, but make sure it is translated to the local output + auto vswitch_overlay = std::make_shared(view); + + overlay_view_node = std::make_shared(); + overlay_view_node->set_children_list({vswitch_overlay}); + overlay_view_node->set_offset(origin(output->get_layout_geometry())); + + wf::scene::add_front(wf::get_core().scene(), overlay_view_node); + } + } + + /** @return the current overlay view, might be NULL. */ + virtual wayfire_view get_overlay_view() + { + return this->overlay_view; + } + + /** + * Called automatically when the workspace switch animation is done. + * By default, this stops the animation. + * + * @param normal_exit Whether the operation has ended because of animation + * running out, in which case the workspace and the overlay view are + * adjusted, and otherwise not. + */ + virtual void stop_switch(bool normal_exit) + { + if (normal_exit) + { + auto old_ws = output->wset()->get_current_workspace(); + adjust_overlay_view_switch_done(old_ws); + } + + wall->stop_output_renderer(true); + output->render->rem_effect(&post_render); + running = false; + } + + virtual bool is_running() const + { + return running; + } + + virtual ~workspace_switch_t() + {} + + protected: + option_wrapper_t gap{"vswitch/gap"}; + option_wrapper_t background_color{"vswitch/background"}; + workspace_animation_t animation; + + output_t *output; + std::unique_ptr wall; + + const std::string vswitch_view_transformer_name = "vswitch-transformer"; + wayfire_toplevel_view overlay_view; + std::shared_ptr overlay_view_node; + + bool running = false; + void update_overlay_fb() + { + if (!overlay_view) + { + return; + } + + double progress = animation.progress(); + + auto tmanager = overlay_view->get_transformed_node(); + auto tr = tmanager->get_transformer( + vswitch_view_transformer_name); + + static constexpr double smoothing_in = 0.4; + static constexpr double smoothing_out = 0.2; + static constexpr double smoothing_amount = 0.5; + + tmanager->begin_transform_update(); + if (progress <= smoothing_in) + { + tr->alpha = 1.0 - (smoothing_amount / smoothing_in) * progress; + } else if (progress >= 1.0 - smoothing_out) + { + tr->alpha = 1.0 - (smoothing_amount / smoothing_out) * (1.0 - progress); + } else + { + tr->alpha = smoothing_amount; + } + + tmanager->end_transform_update(); + } + + wf::effect_hook_t post_render = [=] () + { + auto start = wall->get_workspace_rectangle( + output->wset()->get_current_workspace()); + auto size = output->get_screen_size(); + geometry_t viewport = { + (int)std::round(animation.dx * (size.width + gap) + start.x), + (int)std::round(animation.dy * (size.height + gap) + start.y), + start.width, + start.height, + }; + wall->set_viewport(viewport); + update_overlay_fb(); + + output->render->damage_whole(); + output->render->schedule_redraw(); + if (!animation.running()) + { + stop_switch(true); + } + }; + + /** + * Emit the view-change-workspace signal from the old workspace to the current + * workspace and unset the view. + */ + virtual void adjust_overlay_view_switch_done(wf::point_t old_workspace) + { + if (!overlay_view) + { + return; + } + + wf::view_change_workspace_signal data; + data.view = overlay_view; + data.from = old_workspace; + data.to = output->wset()->get_current_workspace(); + output->emit(&data); + + set_overlay_view(nullptr); + wf::get_core().seat->refocus(); + } +}; +} +} class vswitch : public wf::per_output_plugin_instance_t { diff --git a/plugins/vswitch/wayfire/plugins/vswitch.hpp b/plugins/vswitch/wayfire/plugins/vswitch.hpp index 306153f24..69a44ac9e 100644 --- a/plugins/vswitch/wayfire/plugins/vswitch.hpp +++ b/plugins/vswitch/wayfire/plugins/vswitch.hpp @@ -1,14 +1,11 @@ #pragma once #include "wayfire/scene-input.hpp" -#include "wayfire/scene-operations.hpp" #include "wayfire/seat.hpp" #include "wayfire/core.hpp" -#include "wayfire/render-manager.hpp" #include "wayfire/scene-render.hpp" #include "wayfire/scene.hpp" #include "wayfire/toplevel-view.hpp" -#include "wayfire/unstable/translation-node.hpp" #include "wayfire/view-helpers.hpp" #include #include @@ -25,307 +22,6 @@ namespace wf { namespace vswitch { -using namespace animation; -class workspace_animation_t : public duration_t -{ - public: - using duration_t::duration_t; - timed_transition_t dx{*this}; - timed_transition_t dy{*this}; -}; - -/** - * A simple scenegraph node which draws a view at a fixed position and as an overlay over the workspace wall. - */ -class vswitch_overlay_node_t : public wf::scene::node_t -{ - std::weak_ptr _view; - - public: - vswitch_overlay_node_t(wayfire_toplevel_view view) : node_t(true) - { - _view = view->weak_from_this(); - } - - // Since we do not grab focus via a grab node, route focus to the view being rendered as an overlay - wf::keyboard_focus_node_t keyboard_refocus(wf::output_t *output) - { - if (auto view = _view.lock()) - { - return view->get_transformed_node()->keyboard_refocus(output); - } - - return wf::keyboard_focus_node_t{}; - } - - virtual void gen_render_instances(std::vector& instances, - scene::damage_callback push_damage, wf::output_t *output = nullptr) - { - if (auto view = _view.lock()) - { - view->get_transformed_node()->gen_render_instances(instances, push_damage, output); - } - } - - virtual wf::geometry_t get_bounding_box() - { - if (auto view = _view.lock()) - { - return view->get_transformed_node()->get_bounding_box(); - } - - return {0, 0, 0, 0}; - } -}; - -/** - * Represents the action of switching workspaces with the vswitch algorithm. - * - * The workspace is actually switched at the end of the animation - */ -class workspace_switch_t -{ - public: - /** - * Initialize the workspace switch process. - * - * @param output The output the workspace switch happens on. - */ - workspace_switch_t(output_t *output) - { - this->output = output; - wall = std::make_unique(output); - animation = workspace_animation_t{ - wf::option_wrapper_t{"vswitch/duration"} - }; - } - - /** - * Initialize switching animation. - * At this point, the calling plugin needs to have the custom renderer - * ability set. - */ - virtual void start_switch() - { - /* Setup wall */ - wall->set_gap_size(gap); - wall->set_viewport(wall->get_workspace_rectangle( - output->wset()->get_current_workspace())); - wall->set_background_color(background_color); - wall->start_output_renderer(); - - if (overlay_view_node) - { - wf::scene::readd_front(wf::get_core().scene(), overlay_view_node); - } - - output->render->add_effect(&post_render, OUTPUT_EFFECT_POST); - - running = true; - - /* Setup animation */ - animation.dx.set(0, 0); - animation.dy.set(0, 0); - animation.start(); - } - - /** - * Start workspace switch animation towards the given workspace, - * and set that workspace as current. - * - * @param workspace The new target workspace. - */ - virtual void set_target_workspace(point_t workspace) - { - point_t cws = output->wset()->get_current_workspace(); - - animation.dx.set(animation.dx + cws.x - workspace.x, 0); - animation.dy.set(animation.dy + cws.y - workspace.y, 0); - animation.start(); - - std::vector fixed_views; - if (overlay_view) - { - fixed_views.push_back(overlay_view); - } - - output->wset()->set_workspace(workspace, fixed_views); - } - - /** - * Set the overlay view. It will be hidden from the normal workspace layers - * and shown on top of the workspace wall. The overlay view's position is - * not animated together with the workspace transition, but its alpha is. - * - * Note: if the view disappears, the caller is responsible for resetting the - * overlay view. - * - * @param view The desired overlay view, or NULL if the overlay view needs - * to be unset. - */ - virtual void set_overlay_view(wayfire_toplevel_view view) - { - if (this->overlay_view == view) - { - /* Nothing to do */ - return; - } - - /* Reset old view */ - if (this->overlay_view) - { - wf::scene::set_node_enabled(overlay_view->get_transformed_node(), true); - overlay_view->get_transformed_node()->rem_transformer( - vswitch_view_transformer_name); - - wf::scene::remove_child(overlay_view_node); - overlay_view_node.reset(); - } - - /* Set new view */ - this->overlay_view = view; - if (view) - { - view->get_transformed_node()->add_transformer( - std::make_shared(view), - wf::TRANSFORMER_2D, vswitch_view_transformer_name); - wf::scene::set_node_enabled(view->get_transformed_node(), false); - - // Render as an overlay, but make sure it is translated to the local output - auto vswitch_overlay = std::make_shared(view); - - overlay_view_node = std::make_shared(); - overlay_view_node->set_children_list({vswitch_overlay}); - overlay_view_node->set_offset(origin(output->get_layout_geometry())); - - wf::scene::add_front(wf::get_core().scene(), overlay_view_node); - } - } - - /** @return the current overlay view, might be NULL. */ - virtual wayfire_view get_overlay_view() - { - return this->overlay_view; - } - - /** - * Called automatically when the workspace switch animation is done. - * By default, this stops the animation. - * - * @param normal_exit Whether the operation has ended because of animation - * running out, in which case the workspace and the overlay view are - * adjusted, and otherwise not. - */ - virtual void stop_switch(bool normal_exit) - { - if (normal_exit) - { - auto old_ws = output->wset()->get_current_workspace(); - adjust_overlay_view_switch_done(old_ws); - } - - wall->stop_output_renderer(true); - output->render->rem_effect(&post_render); - running = false; - } - - virtual bool is_running() const - { - return running; - } - - virtual ~workspace_switch_t() - {} - - protected: - option_wrapper_t gap{"vswitch/gap"}; - option_wrapper_t background_color{"vswitch/background"}; - workspace_animation_t animation; - - output_t *output; - std::unique_ptr wall; - - const std::string vswitch_view_transformer_name = "vswitch-transformer"; - wayfire_toplevel_view overlay_view; - std::shared_ptr overlay_view_node; - - bool running = false; - void update_overlay_fb() - { - if (!overlay_view) - { - return; - } - - double progress = animation.progress(); - - auto tmanager = overlay_view->get_transformed_node(); - auto tr = tmanager->get_transformer( - vswitch_view_transformer_name); - - static constexpr double smoothing_in = 0.4; - static constexpr double smoothing_out = 0.2; - static constexpr double smoothing_amount = 0.5; - - tmanager->begin_transform_update(); - if (progress <= smoothing_in) - { - tr->alpha = 1.0 - (smoothing_amount / smoothing_in) * progress; - } else if (progress >= 1.0 - smoothing_out) - { - tr->alpha = 1.0 - (smoothing_amount / smoothing_out) * (1.0 - progress); - } else - { - tr->alpha = smoothing_amount; - } - - tmanager->end_transform_update(); - } - - wf::effect_hook_t post_render = [=] () - { - auto start = wall->get_workspace_rectangle( - output->wset()->get_current_workspace()); - auto size = output->get_screen_size(); - geometry_t viewport = { - (int)std::round(animation.dx * (size.width + gap) + start.x), - (int)std::round(animation.dy * (size.height + gap) + start.y), - start.width, - start.height, - }; - wall->set_viewport(viewport); - update_overlay_fb(); - - output->render->damage_whole(); - output->render->schedule_redraw(); - if (!animation.running()) - { - stop_switch(true); - } - }; - - /** - * Emit the view-change-workspace signal from the old workspace to the current - * workspace and unset the view. - */ - virtual void adjust_overlay_view_switch_done(wf::point_t old_workspace) - { - if (!overlay_view) - { - return; - } - - wf::view_change_workspace_signal data; - data.view = overlay_view; - data.from = old_workspace; - data.to = output->wset()->get_current_workspace(); - output->emit(&data); - - set_overlay_view(nullptr); - wf::get_core().seat->refocus(); - } -}; - /** * A simple class to register the vswitch bindings and get a custom callback called. */