--- a/src/output/workspace-stream.cpp +++ b/src/output/workspace-stream.cpp @@ -9,6 +9,7 @@ #include #include #include +#include "fullscreen-regions.hpp" namespace wf { @@ -25,6 +26,7 @@ std::vector instances; // True for output-local instances (desktop surfaces and workspace wallpaper). std::vector output_local_instances; + std::vector is_top_layer; wf::pointf_t get_offset() { @@ -74,8 +76,10 @@ 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); + count = this->instances.size() - count; + output_local_instances.insert(output_local_instances.end(), count, true); + is_top_layer.insert(is_top_layer.end(), count, + output_node == self->output->node_for_layer(scene::layer::TOP)); } continue; @@ -125,11 +129,13 @@ // Inclusion in a rotating texture does not make a panel // workspace-local: keep it visible and damaged on every face. output_local_instances.push_back(is_de); + is_top_layer.push_back(output_node == self->output->node_for_layer(scene::layer::TOP)); } } } wf::dassert(instances.size() == output_local_instances.size(), "Setting de flag is wrong!"); + wf::dassert(instances.size() == is_top_layer.size(), "Setting TOP flag is wrong!"); } } @@ -145,6 +151,7 @@ wf::render_target_t subtarget = target.translated(offset); our_damage += offset; + auto fullscreen = workspace_fullscreen_regions(self->output, self->ws); for (size_t i = 0; i < instances.size(); i++) { if (output_local_instances[i]) @@ -152,7 +159,10 @@ // Special handling: move everything to 'current workspace' so that panels and backgrounds // render at the correct position. our_damage -= offset; + auto excluded = is_top_layer[i] ? our_damage & fullscreen : wf::regionf_t{}; + our_damage ^= excluded; instances[i]->schedule_instructions(instructions, target, our_damage); + our_damage |= excluded; our_damage += offset; } else { @@ -193,8 +203,17 @@ void compute_visibility(wf::output_t *output, wf::regionf_t& visible) override { - scene::compute_visibility_from_list(instances, output, visible, - -get_offset()); + auto offset = get_offset(); + auto fullscreen = workspace_fullscreen_regions(self->output, self->ws); + for (size_t i = 0; i < instances.size(); ++i) + { + if (!output_local_instances[i]) visible += offset; + auto excluded = is_top_layer[i] ? visible & fullscreen : wf::regionf_t{}; + visible ^= excluded; + instances[i]->compute_visibility(output, visible); + visible |= excluded; + if (!output_local_instances[i]) visible -= offset; + } } }; --- /dev/null +++ b/src/output/fullscreen-regions.hpp @@ -0,0 +1,39 @@ +#pragma once +#include +#include +#include + +namespace wf +{ +// Workspace subpasses generate children directly, bypassing the TOP output +// node's render mask. Compute their mask in the sampled workspace's coordinates, +// not from the current viewport (which would hide bars on the wrong cube face). +inline regionf_t workspace_fullscreen_regions(output_t *output, point_t workspace) +{ + auto size = output->get_relative_geometry(); + auto delta = workspace - output->wset()->get_current_workspace(); + pointf_t offset{delta.x * size.width, delta.y * size.height}; + auto top_in_region = [&] (auto&& visit, const scene::node_ptr& node, + const geometry_t& region) -> wayfire_toplevel_view + { + if (auto top = toplevel_cast(node_to_view(node)); top && top->is_mapped() && !top->minimized && + output->wset()->view_visible_on(top, workspace)) + { + auto overlap = geometry_intersection(top->get_geometry(), region); + if (overlap.width > 0 && overlap.height > 0) return top; + } + for (const auto& child : node->get_children()) + if (child->is_enabled()) + if (auto top = visit(visit, child, region)) return top; + return nullptr; + }; + std::vector zones{{output->to_string(), size}}; + if (auto stitch = output->get_data()) zones = stitch->zones; + regionf_t hidden; + for (const auto& zone : zones) + if (auto top = top_in_region(top_in_region, output->wset()->get_node(), zone.geometry + offset); + top && top->toplevel()->current().fullscreen) + hidden |= geometry_intersection(top->get_geometry() - offset, zone.geometry); + return hidden; +} +}