1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-27 08:27:46 +00:00

WindowServer: Replace modal stacks with modal chains

And apply modal effects on move_to_front_and_make_active()

Instead of building a vector of windows every time we want to
loop over a group of related modals, simply recurse through
their ancestory. This lineage is now called a modal chain. Modal
chains begin at the first modeless parent, and a new chain
starts at every modeless child. This lets apps spawn child windows
independent of the main window's modal effects, restore state,
and workspace, yet still remain descendants.

Looping through a modal chain is recursive and includes the
modeless window which begins it.
This commit is contained in:
thankyouverycool 2022-08-22 14:29:33 -04:00 committed by Andreas Kling
parent 4c7f95e2f8
commit 788b16cbf8
3 changed files with 55 additions and 72 deletions

View file

@ -238,35 +238,31 @@ public:
void maximize_windows(Window&, bool);
void set_always_on_top(Window&, bool);
template<typename Function>
IterationDecision for_each_window_in_modal_stack(Window& window, Function f)
template<typename Callback>
Window* for_each_window_in_modal_chain(Window& window, Callback callback)
{
auto* blocking_modal_window = window.blocking_modal_window();
if (blocking_modal_window || window.is_modal()) {
Vector<Window&> modal_stack;
auto* modal_stack_top = blocking_modal_window ? blocking_modal_window : &window;
for (auto* parent = modal_stack_top->parent_window(); parent; parent = parent->parent_window()) {
auto* blocked_by = parent->blocking_modal_window();
if (!blocked_by || (blocked_by != modal_stack_top && !modal_stack_top->is_descendant_of(*blocked_by)))
break;
modal_stack.append(*parent);
if (!parent->is_modal())
break;
Window* maybe_break = nullptr;
Function<Window*(Window&)> recurse = [&](Window& w) -> Window* {
if (!w.is_modal()) {
auto decision = callback(w);
if (decision == IterationDecision::Break)
return maybe_break = &w;
}
if (!modal_stack.is_empty()) {
for (size_t i = modal_stack.size(); i > 0; i--) {
IterationDecision decision = f(modal_stack[i - 1], false);
if (decision != IterationDecision::Continue)
return decision;
}
for (auto& child : w.child_windows()) {
if (!child || child->is_destroyed() || !child->is_modal())
continue;
auto decision = callback(*child);
if (decision == IterationDecision::Break)
return maybe_break = child;
recurse(*child);
}
return f(*modal_stack_top, true);
} else {
// Not a modal window stack, just "iterate" over this window
return f(window, true);
}
return maybe_break;
};
if (auto* modeless = window.modeless_ancestor(); modeless)
return recurse(*modeless);
return nullptr;
}
bool is_window_in_modal_stack(Window& window_in_modal_stack, Window& other_window);
bool is_window_in_modal_chain(Window& chain_window, Window& other_window);
Gfx::IntPoint get_recommended_window_position(Gfx::IntPoint const& desired);
@ -376,8 +372,6 @@ private:
void tell_wm_about_current_window_stack(WMConnectionFromClient&);
bool pick_new_active_window(Window*);
void do_move_to_front(Window&, bool, bool);
bool sync_config_to_disk();
[[nodiscard]] static WindowStack& get_rendering_window_stacks(WindowStack*&);