Переглянути джерело

LibGUI+WindowServer: Inform WindowServer about parent/child windows

If a window has another window in its Core::Object ancestor chain,
we now communicate that relationship to WindowServer so that it can
act with awareness of parent/child windows.
Andreas Kling 5 роки тому
батько
коміт
6228f72b87

+ 14 - 1
Libraries/LibGUI/Window.cpp

@@ -89,6 +89,9 @@ void Window::show()
 {
     if (is_visible())
         return;
+
+    auto* parent_window = find_parent_window();
+
     m_override_cursor = StandardCursor::None;
     auto response = WindowServerConnection::the().send_sync<Messages::WindowServer::CreateWindow>(
         m_rect_when_windowless,
@@ -102,7 +105,8 @@ void Window::show()
         m_base_size,
         m_size_increment,
         (i32)m_window_type,
-        m_title_when_windowless);
+        m_title_when_windowless,
+        parent_window ? parent_window->window_id() : 0);
     m_window_id = response->window_id();
     m_visible = true;
 
@@ -113,6 +117,15 @@ void Window::show()
     update();
 }
 
+Window* Window::find_parent_window()
+{
+    for (auto* ancestor = parent(); ancestor; ancestor = ancestor->parent()) {
+        if (ancestor->is_window())
+            return static_cast<Window*>(ancestor);
+    }
+    return nullptr;
+}
+
 void Window::hide()
 {
     if (!is_visible())

+ 2 - 0
Libraries/LibGUI/Window.h

@@ -182,6 +182,8 @@ public:
 
     void did_remove_widget(Badge<Widget>, const Widget&);
 
+    Window* find_parent_window();
+
 protected:
     Window(Core::Object* parent = nullptr);
     virtual void wm_event(WMEvent&);

+ 20 - 0
Servers/WindowServer/ClientConnection.cpp

@@ -451,10 +451,30 @@ OwnPtr<Messages::WindowServer::GetClipboardContentsResponse> ClientConnection::h
     return make<Messages::WindowServer::GetClipboardContentsResponse>(shbuf_id, clipboard.size(), clipboard.data_type());
 }
 
+Window* ClientConnection::window_from_id(i32 window_id)
+{
+    auto it = m_windows.find(window_id);
+    if (it == m_windows.end())
+        return nullptr;
+    return it->value.ptr();
+}
+
 OwnPtr<Messages::WindowServer::CreateWindowResponse> ClientConnection::handle(const Messages::WindowServer::CreateWindow& message)
 {
     int window_id = m_next_window_id++;
     auto window = Window::construct(*this, (WindowType)message.type(), window_id, message.modal(), message.minimizable(), message.resizable(), message.fullscreen());
+
+    dbg() << "Constructing window with parent_window_id=" << message.parent_window_id();
+
+    if (message.parent_window_id()) {
+        auto* parent_window = window_from_id(message.parent_window_id());
+        if (!parent_window) {
+            did_misbehave("CreateWindow with bad parent_window_id");
+            return nullptr;
+        }
+        window->set_parent_window(*parent_window);
+    }
+
     window->set_has_alpha_channel(message.has_alpha_channel());
     window->set_title(message.title());
     if (!message.fullscreen()) {

+ 2 - 0
Servers/WindowServer/ClientConnection.h

@@ -127,6 +127,8 @@ private:
     virtual void handle(const Messages::WindowServer::EnableDisplayLink&) override;
     virtual void handle(const Messages::WindowServer::DisableDisplayLink&) override;
 
+    Window* window_from_id(i32 window_id);
+
     HashMap<int, NonnullRefPtr<Window>> m_windows;
     HashMap<int, NonnullOwnPtr<MenuBar>> m_menubars;
     HashMap<int, NonnullRefPtr<Menu>> m_menus;

+ 12 - 0
Servers/WindowServer/Window.cpp

@@ -482,4 +482,16 @@ void Window::recalculate_rect()
     Core::EventLoop::current().post_event(*this, make<ResizeEvent>(old_rect, m_rect));
 }
 
+void Window::add_child_window(Window& child_window)
+{
+    m_child_windows.append(child_window.make_weak_ptr());
+}
+
+void Window::set_parent_window(Window& parent_window)
+{
+    ASSERT(!m_parent_window);
+    m_parent_window = parent_window.make_weak_ptr();
+    parent_window.add_child_window(*this);
+}
+
 }

+ 11 - 0
Servers/WindowServer/Window.h

@@ -28,6 +28,7 @@
 
 #include <AK/InlineLinkedList.h>
 #include <AK/String.h>
+#include <AK/WeakPtr.h>
 #include <LibCore/Object.h>
 #include <LibGfx/Bitmap.h>
 #include <LibGfx/DisjointRectSet.h>
@@ -229,12 +230,22 @@ public:
 
     void detach_client(Badge<ClientConnection>);
 
+    Window* parent_window() { return m_parent_window; }
+    const Window* parent_window() const { return m_parent_window; }
+
+    void set_parent_window(Window&);
+
 private:
     void handle_mouse_event(const MouseEvent&);
     void update_menu_item_text(PopupMenuItem item);
     void update_menu_item_enabled(PopupMenuItem item);
+    void add_child_window(Window&);
 
     ClientConnection* m_client { nullptr };
+
+    WeakPtr<Window> m_parent_window;
+    Vector<WeakPtr<Window>> m_child_windows;
+
     String m_title;
     Gfx::Rect m_rect;
     Gfx::Rect m_saved_nonfullscreen_rect;

+ 2 - 1
Servers/WindowServer/WindowServer.ipc

@@ -41,7 +41,8 @@ endpoint WindowServer = 2
         Gfx::Size base_size,
         Gfx::Size size_increment,
         i32 type,
-        String title) => (i32 window_id)
+        String title,
+        i32 parent_window_id) => (i32 window_id)
 
     DestroyWindow(i32 window_id) => ()