--- a/plugins/cube/cube.cpp +++ b/plugins/cube/cube.cpp @@ -31,6 +31,7 @@ #include "simple-background.hpp" #include "skydome.hpp" #include "cubemap.hpp" +#include "warp-background.hpp" #include "cube-control-signal.hpp" #include "wayfire/region.hpp" #include "wayfire/scene-render.hpp" @@ -443,8 +444,49 @@ std::string last_background_mode; std::unique_ptr background; + std::unique_ptr warp_background; + wf::wl_timer warp_timer; wf::option_wrapper_t background_mode{"cube/background_mode"}; + + bool warp_visible() const + { + return render_node && !resting_renderer && !cube_render_paused && !shutting_down && + std::string(background_mode) == "warp"; + } + + void sync_warp_animation() + { + if (!warp_background) return; + warp_background->set_active(warp_visible()); + if (!warp_background->animated()) + { + warp_timer.disconnect(); + } else if (!warp_timer.is_connected()) + { + warp_timer.set_timeout(warp_background->frame_interval(), [this] + { + if (!warp_visible() || !warp_background->animated()) return false; + wf::scene::damage_node(render_node, render_node->get_bounding_box()); + output->render->schedule_redraw(); + return true; + }); + } + } + + template void ensure_warp_option(const std::string& name, const T& value) + { + // A running compositor may have loaded its metadata before this + // plugin upgrade. Promote only missing/untyped new options in place. + auto section = wf::get_core().config->get_section("cube"); + auto existing = section->get_option_or(name); + if (!std::dynamic_pointer_cast>(existing)) + { + auto option = std::make_shared>(name, value); + if (existing) option->set_value_str(existing->get_value_str()); + section->register_new_option(option); + } + } void reload_background() { @@ -464,6 +506,9 @@ } else if (last_background_mode == "cubemap") { background = std::make_unique(); + } else if (last_background_mode == "warp") + { + background.reset(); } else { LOGE("cube: Unrecognized background mode %s. Using default \"simple\"", @@ -592,6 +637,28 @@ } mouse_overview.load_option("cube/mouse_overview"); render_at_rest.load_option("cube/render_at_rest"); + ensure_warp_option("warp_speed", 0.8); + ensure_warp_option("warp_density", 1.0); + ensure_warp_option("warp_streak_length", 0.6); + ensure_warp_option("warp_glow", 0.7); + ensure_warp_option("warp_brightness", 0.85); + ensure_warp_option("warp_twist", 0.10); + ensure_warp_option("warp_ring_strength", 0.15); + ensure_warp_option("warp_color", wf::color_t{0.45, 0.62, 0.90, 1.0}); + ensure_warp_option("warp_quality", 1); + ensure_warp_option("warp_fps", 30); + warp_background = std::make_unique([this] + { + warp_timer.disconnect(); + sync_warp_animation(); + output->render->damage_whole(); + }); + background_mode.set_callback([this] + { + reload_background(); + sync_warp_animation(); + output->render->damage_whole(); + }); input_grab = std::make_unique("cube", output, nullptr, this, nullptr); input_grab->set_wants_raw_input(true); @@ -904,6 +971,7 @@ if (render_node) wf::scene::remove_child(render_node); render_node = nullptr; resting_renderer = false; + sync_warp_animation(); output->render->set_require_depth_buffer(false); clear_unused_fixed_top_node(); output->render->damage_whole(); @@ -924,6 +992,7 @@ refresh_cube_geometry(); resting_renderer = true; + sync_warp_animation(); return_to_rest = false; animation.in_exit = false; animation.cube_animation.rotation.set(0, 0); @@ -958,6 +1027,7 @@ output->render->damage_whole(); } cube_render_paused = true; + sync_warp_animation(); return; } @@ -1119,6 +1189,7 @@ output->render->set_require_depth_buffer(true); reload_background(); + sync_warp_animation(); animation.cube_animation.offset_z.set(identity_z_offset + front_face_distance(), identity_z_offset + front_face_distance()); return true; @@ -1144,6 +1215,7 @@ render_node = nullptr; output->render->rem_effect(&pre_hook); + sync_warp_animation(); output->render->set_require_depth_buffer(false); // Vswitch already committed its destination before starting this @@ -1520,6 +1592,8 @@ } /* The fixed output background is scheduled behind the cube. */ + if (warp_visible()) warp_background->render(data.target, data.damage, + wf::dimensions(output->get_relative_geometry())); program.use(wf::TEXTURE_TYPE_RGBA); GL_CALL(glEnable(GL_DEPTH_TEST)); @@ -1591,6 +1665,7 @@ } update_view_matrix(); + sync_warp_animation(); const bool running = animation.cube_animation.running(); if (render_node && (running || animation_was_running)) { @@ -1771,6 +1846,7 @@ void fini() override { shutting_down = true; + warp_timer.disconnect(); clear_post_move_window_dim(); if (output->is_plugin_active(grab_interface.name)) { @@ -1782,6 +1858,7 @@ { program.free_resources(); }); + warp_background.reset(); } }; --- a/plugins/cube/meson.build +++ b/plugins/cube/meson.build @@ -1,5 +1,5 @@ animiate = shared_module('cube', - ['cube.cpp', 'cubemap.cpp', 'skydome.cpp', 'simple-background.cpp'], + ['cube.cpp', 'cubemap.cpp', 'skydome.cpp', 'simple-background.cpp', 'warp-background.cpp'], include_directories: [wayfire_api_inc, wayfire_conf_inc, plugins_common_inc, ipc_include_dirs], dependencies: [wlroots, pixman, wfconfig, json, plugin_pch_dep], install: true, --- a/metadata/cube.xml +++ b/metadata/cube.xml @@ -167,12 +167,98 @@ cubemap <_name>Cubemap + + warp + <_name>Warp tunnel + + + <_short>Warp tunnel + <_long>Choose Warp tunnel in Background mode to fly through a starfield behind Cube. The viewpoint spans joined monitors. It animates during mouse and keyboard Cube movement and returns to the normal desktop background at rest. + + + + + + + + + + +