Browse Source

WindowServer: Fix picking new active window after destroy

We need to mark windows as destroyed and not consider them
when picking a new active window. Fixes lost focus after
closing some windows.
Tom 5 năm trước cách đây
mục cha
commit
f591157eb8

+ 8 - 1
Services/WindowServer/ClientConnection.cpp

@@ -475,12 +475,19 @@ void ClientConnection::destroy_window(Window& window, Vector<i32>& destroyed_win
         destroy_window(*child_window, destroyed_window_ids);
     }
 
+    for (auto& accessory_window : window.accessory_windows()) {
+        if (!accessory_window)
+            continue;
+        ASSERT(accessory_window->window_id() != window.window_id());
+        destroy_window(*accessory_window, destroyed_window_ids);
+    }
+
     destroyed_window_ids.append(window.window_id());
 
     if (window.type() == WindowType::MenuApplet)
         AppletManager::the().remove_applet(window);
 
-    window.invalidate();
+    window.destroy();
     remove_child(window);
     m_windows.remove(window.window_id());
 }

+ 7 - 1
Services/WindowServer/Window.cpp

@@ -126,6 +126,12 @@ Window::~Window()
     WindowManager::the().remove_window(*this);
 }
 
+void Window::destroy()
+{
+    m_destroyed = true;
+    invalidate();
+}
+
 void Window::set_title(const String& title)
 {
     if (m_title == title)
@@ -389,7 +395,7 @@ Window* Window::is_blocked_by_modal_window()
     // A window is blocked if any immediate child, or any child further
     // down the chain is modal
     for (auto& window: m_child_windows) {
-        if (window) {
+        if (window && !window->is_destroyed()) {
             if (window->is_modal())
                 return window;
             

+ 4 - 0
Services/WindowServer/Window.h

@@ -256,6 +256,9 @@ public:
     int progress() const { return m_progress; }
     void set_progress(int);
 
+    bool is_destroyed() const { return m_destroyed; }
+    void destroy();
+
 private:
     void handle_mouse_event(const MouseEvent&);
     void update_menu_item_text(PopupMenuItem item);
@@ -289,6 +292,7 @@ private:
     bool m_maximized { false };
     bool m_fullscreen { false };
     bool m_accessory { false };
+    bool m_destroyed { false };
     WindowTileType m_tiled { WindowTileType::None };
     Gfx::IntRect m_untiled_rect;
     bool m_occluded { false };

+ 10 - 5
Services/WindowServer/WindowManager.cpp

@@ -260,7 +260,9 @@ void WindowManager::remove_window(Window& window)
 {
     window.invalidate();
     m_windows_in_order.remove(&window);
-    if (window.is_active())
+    auto* active = active_window();
+    auto* active_input = active_input_window();
+    if (active == &window || active_input == &window || (active && window.is_descendant_of(*active)) || (active_input && active_input != active && window.is_descendant_of(*active_input)))
         pick_new_active_window(&window);
     if (m_switcher.is_visible() && window.type() != WindowType::WindowSwitcher)
         m_switcher.refresh();
@@ -412,7 +414,10 @@ bool WindowManager::pick_new_active_window(Window* previous_active)
     bool new_window_picked = false;
     Window* first_candidate = nullptr;
     for_each_visible_window_of_type_from_front_to_back(WindowType::Normal, [&](Window& candidate) {
-        first_candidate = &candidate;
+        if (candidate.is_destroyed())
+            return IterationDecision::Continue;
+        if (previous_active != first_candidate)
+            first_candidate = &candidate;
         if ((!previous_active && !candidate.is_accessory()) || (previous_active && !candidate.is_accessory_of(*previous_active))) {
             set_active_window(&candidate);
             new_window_picked = true;
@@ -1167,10 +1172,10 @@ void WindowManager::set_active_window(Window* window, bool make_input)
             window = modal_window;
             make_input = true;
         }
-    }
 
-    if (window && !window_type_can_become_active(window->type()))
-        return;
+        if (!window_type_can_become_active(window->type()))
+            return;
+    }
 
     auto* new_active_input_window = window;
     if (window && window->is_accessory()) {