--- a/src/api/wayfire/workspace-stream.hpp +++ b/src/api/wayfire/workspace-stream.hpp @@ -8,6 +8,27 @@ namespace wf { +/** An output-local wallpaper which can render a specific workspace. + * + * Attach directly to an output's BOTTOM layer, behind its other children. + * Normal scene rendering selects the active workspace. Workspace streams call + * gen_workspace_instances with their own coordinates, without translating the + * wallpaper like a window or duplicating its normal render instance. + */ +class workspace_background_node_t : public scene::node_t +{ + public: + workspace_background_node_t() : scene::node_t(false) + {} + virtual void gen_workspace_instances(wf::point_t workspace, + std::vector& instances, + scene::damage_callback push_damage, wf::output_t *output) = 0; +}; + +// Additive API capability; referencing this symbol prevents plugins using the +// new stream contract from silently loading on a compositor without it. +uint32_t workspace_background_api_version(); + /** * A workspace stream is a special node which displays a workspace of an output. */ --- a/src/output/workspace-stream.cpp +++ b/src/output/workspace-stream.cpp @@ -12,14 +12,19 @@ namespace wf { +uint32_t workspace_background_api_version() +{ + return 1; +} + class workspace_stream_node_t::workspace_stream_instance_t : public scene:: render_instance_t { workspace_stream_node_t *self; std::vector instances; - // True for each instance generated from a desktop environment view. - std::vector is_desktop_environment; + // True for output-local instances (desktop surfaces and workspace wallpaper). + std::vector output_local_instances; wf::pointf_t get_offset() { @@ -62,6 +67,20 @@ { if (ch->is_enabled()) { + if (auto wallpaper = dynamic_cast(ch.get())) + { + if (self->include_workspace_views) + { + size_t count = this->instances.size(); + wallpaper->gen_workspace_instances(self->ws, this->instances, + push_damage, self->output); + output_local_instances.insert(output_local_instances.end(), + this->instances.size() - count, true); + } + + continue; + } + auto view = node_to_view(ch); const bool is_de = (view && (view->role == wf::VIEW_ROLE_DESKTOP_ENVIRONMENT)); static wf::option_wrapper_t rotate_layer_shell{ @@ -99,18 +118,18 @@ ch->gen_render_instances(this->instances, is_de ? push_damage : translate_and_push_damage, self->output); - // Mark whether the instances were generated from a desktop environment view + // Mark whether instances use output-local rather than workspace coordinates num_generated = this->instances.size() - num_generated; for (size_t i = 0; i < num_generated; i++) { // Inclusion in a rotating texture does not make a panel // workspace-local: keep it visible and damaged on every face. - is_desktop_environment.push_back(is_de); + output_local_instances.push_back(is_de); } } } - wf::dassert(instances.size() == is_desktop_environment.size(), "Setting de flag is wrong!"); + wf::dassert(instances.size() == output_local_instances.size(), "Setting de flag is wrong!"); } } @@ -128,7 +147,7 @@ our_damage += offset; for (size_t i = 0; i < instances.size(); i++) { - if (is_desktop_environment[i]) + if (output_local_instances[i]) { // Special handling: move everything to 'current workspace' so that panels and backgrounds // render at the correct position. --- a/plugins/cube/cube.cpp +++ b/plugins/cube/cube.cpp @@ -1132,7 +1132,10 @@ * that are on the back, and then we render those at the front, so we * don't have to use depth testing and we also can support alpha cube. */ GL_CALL(glEnable(GL_BLEND)); - GL_CALL(glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); + // Workspace buffers are composed by wlroots with premultiplied + // alpha. Multiplying their RGB by alpha again darkens transparent + // wallpapers and windows when the face is blended onto the desktop. + GL_CALL(glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA)); GL_CALL(glEnable(GL_CULL_FACE)); wf::gles::for_each_scissor_rect(data.target, data.damage, [&] {