--- a/plugins/cube/cube.cpp +++ b/plugins/cube/cube.cpp @@ -220,7 +220,7 @@ auto push_background_damage = [=] (const wf::regionf_t& damage) { // An opaque effect or hidden image owns these pixels. - if (double(self->cube->backdrop_image_opacity) > 0 && !self->cube->warp_visible()) + if (self->cube->show_backdrop_image()) push_damage(self->get_bounding_box()); }; output_background->gen_render_instances(output_background_instances, @@ -272,7 +272,7 @@ wf::regionf_t background_damage = our_damage; auto background_target = target.translated(-wf::origin(self->get_bounding_box())); - if (double(self->cube->backdrop_image_opacity) > 0 && !self->cube->warp_visible()) + if (self->cube->show_backdrop_image()) { for (auto& instance : output_background_instances) { @@ -454,6 +454,7 @@ wf::option_wrapper_t background_mode{"cube/background_mode"}; wf::option_wrapper_t backdrop_image_opacity; + wf::option_wrapper_t warp_animate_at_rest; wf::option_wrapper_t backdrop_color{"cube/background"}; bool warp_visible() const @@ -462,10 +463,23 @@ std::string(background_mode) == "warp"; } + bool show_backdrop_image() const + { + return std::string(background_mode) != "none" && + double(backdrop_image_opacity) > 0 && !warp_visible(); + } + + bool warp_should_animate() const + { + return render_node && !cube_render_paused && !shutting_down && + std::string(background_mode) == "warp" && + (!resting_renderer || (bool(warp_animate_at_rest) && double(backdrop_image_opacity) < 1)); + } + void sync_warp_animation() { if (!warp_background) return; - warp_background->set_active(warp_visible()); + warp_background->set_active(warp_should_animate()); if (!warp_background->animated()) { warp_timer.disconnect(); @@ -473,7 +487,7 @@ { warp_timer.set_timeout(warp_background->frame_interval(), [this] { - if (!warp_visible() || !warp_background->animated()) return false; + if (!warp_should_animate() || !warp_background->animated()) return false; wf::scene::damage_node(render_node, render_node->get_bounding_box()); output->render->schedule_redraw(); return true; @@ -513,7 +527,7 @@ } else if (last_background_mode == "cubemap") { background = std::make_unique(); - } else if (last_background_mode == "warp") + } else if (last_background_mode == "warp" || last_background_mode == "none") { background.reset(); } else @@ -646,8 +660,19 @@ render_at_rest.load_option("cube/render_at_rest"); ensure_warp_option("backdrop_image_opacity", 1.0); backdrop_image_opacity.load_option("cube/backdrop_image_opacity"); - backdrop_image_opacity.set_callback([this] { output->render->damage_whole(); }); + backdrop_image_opacity.set_callback([this] + { + sync_warp_animation(); + output->render->damage_whole(); + }); backdrop_color.set_callback([this] { output->render->damage_whole(); }); + ensure_warp_option("warp_animate_at_rest", true); + warp_animate_at_rest.load_option("cube/warp_animate_at_rest"); + warp_animate_at_rest.set_callback([this] + { + sync_warp_animation(); + output->render->damage_whole(); + }); ensure_warp_option("warp_speed", 0.8); ensure_warp_option("warp_density", 1.0); ensure_warp_option("warp_streak_length", 0.6); @@ -1003,7 +1028,6 @@ refresh_cube_geometry(); resting_renderer = true; - sync_warp_animation(); return_to_rest = false; animation.in_exit = false; animation.cube_animation.rotation.set(0, 0); @@ -1016,6 +1040,7 @@ update_view_matrix(); render_node = std::make_shared(this); add_cube_render_node(); + sync_warp_animation(); output->render->add_effect(&pre_hook, wf::OUTPUT_EFFECT_PRE); output->render->set_require_depth_buffer(true); output->render->damage_whole(); @@ -1604,7 +1629,8 @@ // Fill the pixels withheld from the wallpaper pass before drawing // the faces. Never fade windows or foreground desktop surfaces. - const float opacity = warp_visible() ? 1.0f : + const bool no_background = std::string(background_mode) == "none"; + const float opacity = (no_background || warp_visible()) ? 1.0f : 1.0f - std::clamp(double(backdrop_image_opacity), 0.0, 1.0); if (opacity > 0 && std::string(background_mode) == "warp") { @@ -1612,7 +1638,9 @@ wf::dimensions(output->get_relative_geometry()), opacity); } else if (opacity > 0) { - auto color = wf::color_t(backdrop_color); + // None clears the owned pixels even when the image opacity + // is 100%, preventing wallpaper or stale tunnel frames. + auto color = no_background ? wf::color_t{0, 0, 0, 1} : wf::color_t(backdrop_color); color.a = opacity; color.r *= opacity; color.g *= opacity; color.b *= opacity; GL_CALL(glDisable(GL_DEPTH_TEST)); --- a/metadata/cube.xml +++ b/metadata/cube.xml @@ -153,7 +153,7 @@ <_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. Backdrop image opacity controls whether the resting Cube shows the desktop image, a still tunnel, or a blend of both. + <_long>Choose Warp tunnel in Background mode to fly through a starfield behind Cube. The viewpoint spans joined monitors. Backdrop image opacity controls whether the resting Cube shows the desktop image, the tunnel, or a blend of both. +