Browse Source

WindowServer: Fix traversing modal stack

When walking the modal window stack upwards, we need to check if
the top modal window is still a descendant of the window that
the parent is blocked by. Fixes not all windows being brought to
the front when trying to active a parent in the middle of the
modal window stack.
Tom 5 years ago
parent
commit
603c17262c

+ 13 - 0
Services/WindowServer/Window.cpp

@@ -634,4 +634,17 @@ void Window::set_progress(int progress)
     WindowManager::the().notify_progress_changed(*this);
     WindowManager::the().notify_progress_changed(*this);
 }
 }
 
 
+bool Window::is_descendant_of(Window& window) const
+{
+    for (auto* parent = parent_window(); parent; parent = parent->parent_window()) {
+        if (parent == &window)
+            return true;
+        for (auto& accessory : parent->accessory_windows()) {
+            if (accessory == &window)
+                return true;
+        }
+    }
+    return false;
+}
+
 }
 }

+ 2 - 0
Services/WindowServer/Window.h

@@ -244,6 +244,8 @@ public:
     Vector<WeakPtr<Window>>& accessory_windows() { return m_accessory_windows; }
     Vector<WeakPtr<Window>>& accessory_windows() { return m_accessory_windows; }
     const Vector<WeakPtr<Window>>& accessory_windows() const { return m_accessory_windows; }
     const Vector<WeakPtr<Window>>& accessory_windows() const { return m_accessory_windows; }
 
 
+    bool is_descendant_of(Window&) const;
+
     void set_accessory(bool accessory) { m_accessory = accessory; }
     void set_accessory(bool accessory) { m_accessory = accessory; }
     bool is_accessory() const;
     bool is_accessory() const;
     bool is_accessory_of(Window&) const;
     bool is_accessory_of(Window&) const;

+ 2 - 1
Services/WindowServer/WindowManager.h

@@ -193,7 +193,8 @@ public:
             Vector<Window*> modal_stack;
             Vector<Window*> modal_stack;
             auto* modal_stack_top = blocking_modal_window ? blocking_modal_window : &window;
             auto* modal_stack_top = blocking_modal_window ? blocking_modal_window : &window;
             for (auto* parent = modal_stack_top->parent_window(); parent; parent = parent->parent_window()) {
             for (auto* parent = modal_stack_top->parent_window(); parent; parent = parent->parent_window()) {
-                if (parent->is_blocked_by_modal_window() != modal_stack_top)
+                auto* blocked_by = parent->is_blocked_by_modal_window();
+                if (!blocked_by || (blocked_by != modal_stack_top && !modal_stack_top->is_descendant_of(*blocked_by)))
                     break;
                     break;
                 modal_stack.append(parent);
                 modal_stack.append(parent);
                 if (!parent->is_modal())
                 if (!parent->is_modal())