Jelajahi Sumber

LibGUI+WindowServer: Separate window manager IPC from regular IPC

With this patch the window manager related functionality is split out
onto a new endpoint pair named WindowManagerServer/Client.  This allows
window manager functionality to be potentially privilege separated in
the future.  To this end, a new client named WMConnectionClient
is used to maintain a window manager connection.  When a process
connects to the endpoint and greets the WindowServer as a window manager
(via Window::make_window_manager(int)), they're subscribed to the events
they requested via the WM event mask.

This patch also removes the hardcoding of the Taskbar WindowType to
receive WM events automatically.  However, being a window manager still
requires having an active window, at the moment.
sin-ack 4 tahun lalu
induk
melakukan
aa56f9a1e0

+ 1 - 1
Base/etc/SystemServer.ini

@@ -63,7 +63,7 @@ User=anon
 BootModes=text,graphical
 
 [WindowServer]
-Socket=/tmp/portal/window
+Socket=/tmp/portal/window,/tmp/portal/wm
 SocketPermissions=660
 Priority=high
 KeepAlive=1

+ 1 - 0
Userland/Libraries/LibGUI/CMakeLists.txt

@@ -96,6 +96,7 @@ set(SOURCES
     Widget.cpp
     Window.cpp
     WindowServerConnection.cpp
+    WindowManagerServerConnection.cpp
     Wizards/WizardDialog.cpp
     Wizards/AbstractWizardPage.cpp
     Wizards/CoverWizardPage.cpp

+ 9 - 0
Userland/Libraries/LibGUI/Window.cpp

@@ -39,6 +39,7 @@
 #include <LibGUI/Painter.h>
 #include <LibGUI/Widget.h>
 #include <LibGUI/Window.h>
+#include <LibGUI/WindowManagerServerConnection.h>
 #include <LibGUI/WindowServerConnection.h>
 #include <LibGfx/Bitmap.h>
 #include <fcntl.h>
@@ -315,6 +316,14 @@ void Window::set_window_type(WindowType window_type)
     }
 }
 
+void Window::make_window_manager(unsigned event_mask)
+{
+    GUI::WindowManagerServerConnection::the()
+        .post_message(Messages::WindowManagerServer::SetEventMask(event_mask));
+    GUI::WindowManagerServerConnection::the()
+        .post_message(Messages::WindowManagerServer::SetManagerWindow(m_window_id));
+}
+
 void Window::set_cursor(Gfx::StandardCursor cursor)
 {
     if (m_cursor == cursor)

+ 2 - 0
Userland/Libraries/LibGUI/Window.h

@@ -80,6 +80,8 @@ public:
 
     int window_id() const { return m_window_id; }
 
+    void make_window_manager(unsigned event_mask);
+
     String title() const;
     void set_title(String);
 

+ 77 - 0
Userland/Libraries/LibGUI/WindowManagerServerConnection.cpp

@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2021, the SerenityOS developers.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <LibGUI/Event.h>
+#include <LibGUI/Window.h>
+#include <LibGUI/WindowManagerServerConnection.h>
+#include <WindowServer/Window.h>
+
+namespace GUI {
+
+WindowManagerServerConnection& WindowManagerServerConnection::the()
+{
+    static WindowManagerServerConnection* s_connection = nullptr;
+    if (!s_connection)
+        s_connection = new WindowManagerServerConnection;
+    return *s_connection;
+}
+
+void WindowManagerServerConnection::handshake()
+{
+    // :^)
+}
+
+void WindowManagerServerConnection::handle(const Messages::WindowManagerClient::WindowStateChanged& message)
+{
+    if (auto* window = Window::from_window_id(message.wm_id()))
+        Core::EventLoop::current().post_event(*window, make<WMWindowStateChangedEvent>(message.client_id(), message.window_id(), message.parent_client_id(), message.parent_window_id(), message.title(), message.rect(), message.is_active(), message.is_modal(), static_cast<WindowType>(message.window_type()), message.is_minimized(), message.is_frameless(), message.progress()));
+}
+
+void WindowManagerServerConnection::handle(const Messages::WindowManagerClient::AppletAreaSizeChanged& message)
+{
+    if (auto* window = Window::from_window_id(message.wm_id()))
+        Core::EventLoop::current().post_event(*window, make<WMAppletAreaSizeChangedEvent>(message.size()));
+}
+
+void WindowManagerServerConnection::handle(const Messages::WindowManagerClient::WindowRectChanged& message)
+{
+    if (auto* window = Window::from_window_id(message.wm_id()))
+        Core::EventLoop::current().post_event(*window, make<WMWindowRectChangedEvent>(message.client_id(), message.window_id(), message.rect()));
+}
+
+void WindowManagerServerConnection::handle(const Messages::WindowManagerClient::WindowIconBitmapChanged& message)
+{
+    if (auto* window = Window::from_window_id(message.wm_id())) {
+        Core::EventLoop::current().post_event(*window, make<WMWindowIconBitmapChangedEvent>(message.client_id(), message.window_id(), message.bitmap().bitmap()));
+    }
+}
+
+void WindowManagerServerConnection::handle(const Messages::WindowManagerClient::WindowRemoved& message)
+{
+    if (auto* window = Window::from_window_id(message.wm_id()))
+        Core::EventLoop::current().post_event(*window, make<WMWindowRemovedEvent>(message.client_id(), message.window_id()));
+}
+}

+ 57 - 0
Userland/Libraries/LibGUI/WindowManagerServerConnection.h

@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2021, the SerenityOS developers.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include <LibIPC/ServerConnection.h>
+#include <WindowServer/WindowManagerClientEndpoint.h>
+#include <WindowServer/WindowManagerServerEndpoint.h>
+
+namespace GUI {
+
+class WindowManagerServerConnection
+    : public IPC::ServerConnection<WindowManagerClientEndpoint, WindowManagerServerEndpoint>
+    , public WindowManagerClientEndpoint {
+    C_OBJECT(WindowManagerServerConnection)
+public:
+    WindowManagerServerConnection()
+        : IPC::ServerConnection<WindowManagerClientEndpoint, WindowManagerServerEndpoint>(*this, "/tmp/portal/wm")
+    {
+        handshake();
+    }
+
+    virtual void handshake() override;
+    static WindowManagerServerConnection& the();
+
+private:
+    virtual void handle(const Messages::WindowManagerClient::WindowRemoved&) override;
+    virtual void handle(const Messages::WindowManagerClient::WindowStateChanged&) override;
+    virtual void handle(const Messages::WindowManagerClient::WindowIconBitmapChanged&) override;
+    virtual void handle(const Messages::WindowManagerClient::WindowRectChanged&) override;
+    virtual void handle(const Messages::WindowManagerClient::AppletAreaSizeChanged&) override;
+};
+
+}

+ 0 - 31
Userland/Libraries/LibGUI/WindowServerConnection.cpp

@@ -273,37 +273,6 @@ void WindowServerConnection::handle(const Messages::WindowClient::MenuItemActiva
         action->activate(menu);
 }
 
-void WindowServerConnection::handle(const Messages::WindowClient::WM_WindowStateChanged& message)
-{
-    if (auto* window = Window::from_window_id(message.wm_id()))
-        Core::EventLoop::current().post_event(*window, make<WMWindowStateChangedEvent>(message.client_id(), message.window_id(), message.parent_client_id(), message.parent_window_id(), message.title(), message.rect(), message.is_active(), message.is_modal(), static_cast<WindowType>(message.window_type()), message.is_minimized(), message.is_frameless(), message.progress()));
-}
-
-void WindowServerConnection::handle(const Messages::WindowClient::WM_AppletAreaSizeChanged& message)
-{
-    if (auto* window = Window::from_window_id(message.wm_id()))
-        Core::EventLoop::current().post_event(*window, make<WMAppletAreaSizeChangedEvent>(message.size()));
-}
-
-void WindowServerConnection::handle(const Messages::WindowClient::WM_WindowRectChanged& message)
-{
-    if (auto* window = Window::from_window_id(message.wm_id()))
-        Core::EventLoop::current().post_event(*window, make<WMWindowRectChangedEvent>(message.client_id(), message.window_id(), message.rect()));
-}
-
-void WindowServerConnection::handle(const Messages::WindowClient::WM_WindowIconBitmapChanged& message)
-{
-    if (auto* window = Window::from_window_id(message.wm_id())) {
-        Core::EventLoop::current().post_event(*window, make<WMWindowIconBitmapChangedEvent>(message.client_id(), message.window_id(), message.bitmap().bitmap()));
-    }
-}
-
-void WindowServerConnection::handle(const Messages::WindowClient::WM_WindowRemoved& message)
-{
-    if (auto* window = Window::from_window_id(message.wm_id()))
-        Core::EventLoop::current().post_event(*window, make<WMWindowRemovedEvent>(message.client_id(), message.window_id()));
-}
-
 void WindowServerConnection::handle(const Messages::WindowClient::ScreenRectChanged& message)
 {
     Desktop::the().did_receive_screen_rect({}, message.rect());

+ 0 - 5
Userland/Libraries/LibGUI/WindowServerConnection.h

@@ -66,11 +66,6 @@ private:
     virtual void handle(const Messages::WindowClient::MenuItemActivated&) override;
     virtual void handle(const Messages::WindowClient::MenuVisibilityDidChange&) override;
     virtual void handle(const Messages::WindowClient::ScreenRectChanged&) override;
-    virtual void handle(const Messages::WindowClient::WM_WindowRemoved&) override;
-    virtual void handle(const Messages::WindowClient::WM_WindowStateChanged&) override;
-    virtual void handle(const Messages::WindowClient::WM_WindowIconBitmapChanged&) override;
-    virtual void handle(const Messages::WindowClient::WM_WindowRectChanged&) override;
-    virtual void handle(const Messages::WindowClient::WM_AppletAreaSizeChanged&) override;
     virtual void handle(const Messages::WindowClient::AsyncSetWallpaperFinished&) override;
     virtual void handle(const Messages::WindowClient::DragDropped&) override;
     virtual void handle(const Messages::WindowClient::DragAccepted&) override;

+ 1 - 1
Userland/Services/WindowServer/AppletManager.cpp

@@ -155,7 +155,7 @@ void AppletManager::relayout()
 
     repaint();
 
-    WindowManager::the().tell_wm_listeners_applet_area_size_changed(rect.size());
+    WindowManager::the().tell_wms_applet_area_size_changed(rect.size());
 }
 
 void AppletManager::repaint()

+ 5 - 0
Userland/Services/WindowServer/CMakeLists.txt

@@ -1,5 +1,7 @@
 compile_ipc(WindowServer.ipc WindowServerEndpoint.h)
 compile_ipc(WindowClient.ipc WindowClientEndpoint.h)
+compile_ipc(WindowManagerServer.ipc WindowManagerServerEndpoint.h)
+compile_ipc(WindowManagerClient.ipc WindowManagerClientEndpoint.h)
 
 set(SOURCES
     AppletManager.cpp
@@ -20,6 +22,9 @@ set(SOURCES
     WindowSwitcher.cpp
     WindowServerEndpoint.h
     WindowClientEndpoint.h
+    WindowManagerServerEndpoint.h
+    WindowManagerClientEndpoint.h
+    WMClientConnection.cpp
 )
 
 serenity_bin(WindowServer)

+ 2 - 97
Userland/Services/WindowServer/ClientConnection.cpp

@@ -302,7 +302,7 @@ OwnPtr<Messages::WindowServer::SetFramelessResponse> ClientConnection::handle(co
         return {};
     }
     it->value->set_frameless(message.frameless());
-    WindowManager::the().tell_wm_listeners_window_state_changed(*it->value);
+    WindowManager::the().tell_wms_window_state_changed(*it->value);
     return make<Messages::WindowServer::SetFramelessResponse>();
 }
 
@@ -393,7 +393,7 @@ OwnPtr<Messages::WindowServer::SetWindowIconBitmapResponse> ClientConnection::ha
     }
 
     window.frame().invalidate_title_bar();
-    WindowManager::the().tell_wm_listeners_window_icon_changed(window);
+    WindowManager::the().tell_wms_window_icon_changed(window);
     return make<Messages::WindowServer::SetWindowIconBitmapResponse>();
 }
 
@@ -722,49 +722,6 @@ OwnPtr<Messages::WindowServer::SetWindowAlphaHitThresholdResponse> ClientConnect
     return make<Messages::WindowServer::SetWindowAlphaHitThresholdResponse>();
 }
 
-OwnPtr<Messages::WindowServer::WM_SetAppletAreaPositionResponse> ClientConnection::handle(const Messages::WindowServer::WM_SetAppletAreaPosition& message)
-{
-    AppletManager::the().set_position(message.position());
-    return make<Messages::WindowServer::WM_SetAppletAreaPositionResponse>();
-}
-
-void ClientConnection::handle(const Messages::WindowServer::WM_SetActiveWindow& message)
-{
-    auto* client = ClientConnection::from_client_id(message.client_id());
-    if (!client) {
-        did_misbehave("WM_SetActiveWindow: Bad client ID");
-        return;
-    }
-    auto it = client->m_windows.find(message.window_id());
-    if (it == client->m_windows.end()) {
-        did_misbehave("WM_SetActiveWindow: Bad window ID");
-        return;
-    }
-    auto& window = *(*it).value;
-    WindowManager::the().minimize_windows(window, false);
-    WindowManager::the().move_to_front_and_make_active(window);
-}
-
-void ClientConnection::handle(const Messages::WindowServer::WM_PopupWindowMenu& message)
-{
-    auto* client = ClientConnection::from_client_id(message.client_id());
-    if (!client) {
-        did_misbehave("WM_PopupWindowMenu: Bad client ID");
-        return;
-    }
-    auto it = client->m_windows.find(message.window_id());
-    if (it == client->m_windows.end()) {
-        did_misbehave("WM_PopupWindowMenu: Bad window ID");
-        return;
-    }
-    auto& window = *(*it).value;
-    if (auto* modal_window = window.blocking_modal_window()) {
-        modal_window->popup_window_menu(message.screen_position(), WindowMenuDefaultAction::BasedOnWindowState);
-    } else {
-        window.popup_window_menu(message.screen_position(), WindowMenuDefaultAction::BasedOnWindowState);
-    }
-}
-
 void ClientConnection::handle(const Messages::WindowServer::StartWindowResize& request)
 {
     auto it = m_windows.find(request.window_id());
@@ -778,63 +735,11 @@ void ClientConnection::handle(const Messages::WindowServer::StartWindowResize& r
     WindowManager::the().start_window_resize(window, Screen::the().cursor_location(), MouseButton::Left);
 }
 
-void ClientConnection::handle(const Messages::WindowServer::WM_StartWindowResize& request)
-{
-    auto* client = ClientConnection::from_client_id(request.client_id());
-    if (!client) {
-        did_misbehave("WM_StartWindowResize: Bad client ID");
-        return;
-    }
-    auto it = client->m_windows.find(request.window_id());
-    if (it == client->m_windows.end()) {
-        did_misbehave("WM_StartWindowResize: Bad window ID");
-        return;
-    }
-    auto& window = *(*it).value;
-    // FIXME: We are cheating a bit here by using the current cursor location and hard-coding the left button.
-    //        Maybe the client should be allowed to specify what initiated this request?
-    WindowManager::the().start_window_resize(window, Screen::the().cursor_location(), MouseButton::Left);
-}
-
-void ClientConnection::handle(const Messages::WindowServer::WM_SetWindowMinimized& message)
-{
-    auto* client = ClientConnection::from_client_id(message.client_id());
-    if (!client) {
-        did_misbehave("WM_SetWindowMinimized: Bad client ID");
-        return;
-    }
-    auto it = client->m_windows.find(message.window_id());
-    if (it == client->m_windows.end()) {
-        did_misbehave("WM_SetWindowMinimized: Bad window ID");
-        return;
-    }
-    auto& window = *(*it).value;
-    WindowManager::the().minimize_windows(window, message.minimized());
-}
-
 OwnPtr<Messages::WindowServer::GreetResponse> ClientConnection::handle(const Messages::WindowServer::Greet&)
 {
     return make<Messages::WindowServer::GreetResponse>(Screen::the().rect(), Gfx::current_system_theme_buffer());
 }
 
-void ClientConnection::handle(const Messages::WindowServer::WM_SetWindowTaskbarRect& message)
-{
-    // Because the Taskbar (which should be the only user of this API) does not own the
-    // window or the client id, there is a possibility that it may send this message for
-    // a window or client that may have been destroyed already. This is not an error,
-    // and we should not call did_misbehave() for either.
-    auto* client = ClientConnection::from_client_id(message.client_id());
-    if (!client)
-        return;
-
-    auto it = client->m_windows.find(message.window_id());
-    if (it == client->m_windows.end())
-        return;
-
-    auto& window = *(*it).value;
-    window.set_taskbar_rect(message.rect());
-}
-
 OwnPtr<Messages::WindowServer::StartDragResponse> ClientConnection::handle(const Messages::WindowServer::StartDrag& message)
 {
     auto& wm = WindowManager::the();

+ 4 - 6
Userland/Services/WindowServer/ClientConnection.h

@@ -45,6 +45,7 @@ class Compositor;
 class Window;
 class Menu;
 class Menubar;
+class WMClientConnection;
 
 class ClientConnection final
     : public IPC::ClientConnection<WindowClientEndpoint, WindowServerEndpoint>
@@ -132,11 +133,6 @@ private:
     virtual OwnPtr<Messages::WindowServer::SetGlobalCursorTrackingResponse> handle(const Messages::WindowServer::SetGlobalCursorTracking&) override;
     virtual OwnPtr<Messages::WindowServer::SetWindowOpacityResponse> handle(const Messages::WindowServer::SetWindowOpacity&) override;
     virtual OwnPtr<Messages::WindowServer::SetWindowBackingStoreResponse> handle(const Messages::WindowServer::SetWindowBackingStore&) override;
-    virtual void handle(const Messages::WindowServer::WM_SetActiveWindow&) override;
-    virtual void handle(const Messages::WindowServer::WM_SetWindowMinimized&) override;
-    virtual void handle(const Messages::WindowServer::WM_StartWindowResize&) override;
-    virtual void handle(const Messages::WindowServer::WM_PopupWindowMenu&) override;
-    virtual OwnPtr<Messages::WindowServer::WM_SetAppletAreaPositionResponse> handle(const Messages::WindowServer::WM_SetAppletAreaPosition&) override;
     virtual OwnPtr<Messages::WindowServer::SetWindowHasAlphaChannelResponse> handle(const Messages::WindowServer::SetWindowHasAlphaChannel&) override;
     virtual OwnPtr<Messages::WindowServer::SetWindowAlphaHitThresholdResponse> handle(const Messages::WindowServer::SetWindowAlphaHitThreshold&) override;
     virtual OwnPtr<Messages::WindowServer::MoveWindowToFrontResponse> handle(const Messages::WindowServer::MoveWindowToFront&) override;
@@ -152,7 +148,6 @@ private:
     virtual OwnPtr<Messages::WindowServer::PopupMenuResponse> handle(const Messages::WindowServer::PopupMenu&) override;
     virtual OwnPtr<Messages::WindowServer::DismissMenuResponse> handle(const Messages::WindowServer::DismissMenu&) override;
     virtual OwnPtr<Messages::WindowServer::SetWindowIconBitmapResponse> handle(const Messages::WindowServer::SetWindowIconBitmap&) override;
-    virtual void handle(const Messages::WindowServer::WM_SetWindowTaskbarRect&) override;
     virtual OwnPtr<Messages::WindowServer::StartDragResponse> handle(const Messages::WindowServer::StartDrag&) override;
     virtual OwnPtr<Messages::WindowServer::SetSystemThemeResponse> handle(const Messages::WindowServer::SetSystemTheme&) override;
     virtual OwnPtr<Messages::WindowServer::GetSystemThemeResponse> handle(const Messages::WindowServer::GetSystemTheme&) override;
@@ -186,6 +181,9 @@ private:
 
     bool m_has_display_link { false };
     bool m_unresponsive { false };
+
+    // Need this to get private client connection stuff
+    friend WMClientConnection;
 };
 
 }

+ 19 - 4
Userland/Services/WindowServer/EventLoop.cpp

@@ -33,6 +33,7 @@
 #include <WindowServer/Event.h>
 #include <WindowServer/EventLoop.h>
 #include <WindowServer/Screen.h>
+#include <WindowServer/WMClientConnection.h>
 #include <WindowServer/WindowManager.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -46,16 +47,19 @@
 namespace WindowServer {
 
 EventLoop::EventLoop()
-    : m_server(Core::LocalServer::construct())
+    : m_window_server(Core::LocalServer::construct())
+    , m_wm_server(Core::LocalServer::construct())
 {
     m_keyboard_fd = open("/dev/keyboard", O_RDONLY | O_NONBLOCK | O_CLOEXEC);
     m_mouse_fd = open("/dev/mouse", O_RDONLY | O_NONBLOCK | O_CLOEXEC);
 
-    bool ok = m_server->take_over_from_system_server();
+    bool ok = m_window_server->take_over_from_system_server("/tmp/portal/window");
+    VERIFY(ok);
+    ok = m_wm_server->take_over_from_system_server("/tmp/portal/wm");
     VERIFY(ok);
 
-    m_server->on_ready_to_accept = [this] {
-        auto client_socket = m_server->accept();
+    m_window_server->on_ready_to_accept = [this] {
+        auto client_socket = m_window_server->accept();
         if (!client_socket) {
             dbgln("WindowServer: accept failed.");
             return;
@@ -65,6 +69,17 @@ EventLoop::EventLoop()
         IPC::new_client_connection<ClientConnection>(client_socket.release_nonnull(), client_id);
     };
 
+    m_wm_server->on_ready_to_accept = [this] {
+        auto client_socket = m_wm_server->accept();
+        if (!client_socket) {
+            dbgln("WindowServer: WM accept failed.");
+            return;
+        }
+        static int s_next_wm_id = 0;
+        int wm_id = ++s_next_wm_id;
+        IPC::new_client_connection<WMClientConnection>(client_socket.release_nonnull(), wm_id);
+    };
+
     if (m_keyboard_fd >= 0) {
         m_keyboard_notifier = Core::Notifier::construct(m_keyboard_fd, Core::Notifier::Read);
         m_keyboard_notifier->on_ready_to_read = [this] { drain_keyboard(); };

+ 2 - 1
Userland/Services/WindowServer/EventLoop.h

@@ -51,7 +51,8 @@ private:
     RefPtr<Core::Notifier> m_keyboard_notifier;
     int m_mouse_fd { -1 };
     RefPtr<Core::Notifier> m_mouse_notifier;
-    RefPtr<Core::LocalServer> m_server;
+    RefPtr<Core::LocalServer> m_window_server;
+    RefPtr<Core::LocalServer> m_wm_server;
 };
 
 }

+ 174 - 0
Userland/Services/WindowServer/WMClientConnection.cpp

@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2021, the SerenityOS developers.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <WindowServer/AppletManager.h>
+#include <WindowServer/ClientConnection.h>
+#include <WindowServer/Screen.h>
+#include <WindowServer/WMClientConnection.h>
+
+namespace WindowServer {
+
+HashMap<int, NonnullRefPtr<WMClientConnection>> WMClientConnection::s_connections {};
+
+WMClientConnection::WMClientConnection(NonnullRefPtr<Core::LocalSocket> client_socket, int client_id)
+    : IPC::ClientConnection<WindowManagerClientEndpoint, WindowManagerServerEndpoint>(*this, move(client_socket), client_id)
+{
+    s_connections.set(client_id, *this);
+}
+
+WMClientConnection::~WMClientConnection()
+{
+    // The WM has gone away, so take away the applet manager (cause there's nowhere
+    // to draw it in).
+    AppletManager::the().set_position({});
+}
+
+void WMClientConnection::die()
+{
+    deferred_invoke([this](auto&) {
+        s_connections.remove(client_id());
+    });
+}
+
+OwnPtr<Messages::WindowManagerServer::SetAppletAreaPositionResponse> WMClientConnection::handle(const Messages::WindowManagerServer::SetAppletAreaPosition& message)
+{
+    if (m_window_id < 0) {
+        did_misbehave("SetAppletAreaPosition: WM didn't assign window as manager yet");
+        // FIXME: return ok boolean?
+        return make<Messages::WindowManagerServer::SetAppletAreaPositionResponse>();
+    }
+
+    AppletManager::the().set_position(message.position());
+    return make<Messages::WindowManagerServer::SetAppletAreaPositionResponse>();
+}
+
+void WMClientConnection::handle(const Messages::WindowManagerServer::SetActiveWindow& message)
+{
+    auto* client = WindowServer::ClientConnection::from_client_id(message.client_id());
+    if (!client) {
+        did_misbehave("SetActiveWindow: Bad client ID");
+        return;
+    }
+    auto it = client->m_windows.find(message.window_id());
+    if (it == client->m_windows.end()) {
+        did_misbehave("SetActiveWindow: Bad window ID");
+        return;
+    }
+    auto& window = *(*it).value;
+    WindowManager::the().minimize_windows(window, false);
+    WindowManager::the().move_to_front_and_make_active(window);
+}
+
+void WMClientConnection::handle(const Messages::WindowManagerServer::PopupWindowMenu& message)
+{
+    auto* client = WindowServer::ClientConnection::from_client_id(message.client_id());
+    if (!client) {
+        did_misbehave("PopupWindowMenu: Bad client ID");
+        return;
+    }
+    auto it = client->m_windows.find(message.window_id());
+    if (it == client->m_windows.end()) {
+        did_misbehave("PopupWindowMenu: Bad window ID");
+        return;
+    }
+    auto& window = *(*it).value;
+    if (auto* modal_window = window.blocking_modal_window()) {
+        modal_window->popup_window_menu(message.screen_position(), WindowMenuDefaultAction::BasedOnWindowState);
+    } else {
+        window.popup_window_menu(message.screen_position(), WindowMenuDefaultAction::BasedOnWindowState);
+    }
+}
+
+void WMClientConnection::handle(const Messages::WindowManagerServer::StartWindowResize& request)
+{
+    auto* client = WindowServer::ClientConnection::from_client_id(request.client_id());
+    if (!client) {
+        did_misbehave("WM_StartWindowResize: Bad client ID");
+        return;
+    }
+    auto it = client->m_windows.find(request.window_id());
+    if (it == client->m_windows.end()) {
+        did_misbehave("WM_StartWindowResize: Bad window ID");
+        return;
+    }
+    auto& window = *(*it).value;
+    // FIXME: We are cheating a bit here by using the current cursor location and hard-coding the left button.
+    //        Maybe the client should be allowed to specify what initiated this request?
+    WindowManager::the().start_window_resize(window, Screen::the().cursor_location(), MouseButton::Left);
+}
+
+void WMClientConnection::handle(const Messages::WindowManagerServer::SetWindowMinimized& message)
+{
+    auto* client = WindowServer::ClientConnection::from_client_id(message.client_id());
+    if (!client) {
+        did_misbehave("WM_SetWindowMinimized: Bad client ID");
+        return;
+    }
+    auto it = client->m_windows.find(message.window_id());
+    if (it == client->m_windows.end()) {
+        did_misbehave("WM_SetWindowMinimized: Bad window ID");
+        return;
+    }
+    auto& window = *(*it).value;
+    WindowManager::the().minimize_windows(window, message.minimized());
+}
+
+OwnPtr<Messages::WindowManagerServer::SetEventMaskResponse> WMClientConnection::handle(const Messages::WindowManagerServer::SetEventMask& message)
+{
+    m_event_mask = message.event_mask();
+    return make<Messages::WindowManagerServer::SetEventMaskResponse>();
+}
+
+OwnPtr<Messages::WindowManagerServer::SetManagerWindowResponse> WMClientConnection::handle(const Messages::WindowManagerServer::SetManagerWindow& message)
+{
+    m_window_id = message.window_id();
+
+    // Let the window manager know that we obtained a manager window, and should
+    // receive information about other windows.
+    WindowManager::the().greet_window_manager(*this);
+
+    return make<Messages::WindowManagerServer::SetManagerWindowResponse>();
+}
+
+void WMClientConnection::handle(const Messages::WindowManagerServer::SetWindowTaskbarRect& message)
+{
+    // Because the Taskbar (which should be the only user of this API) does not own the
+    // window or the client id, there is a possibility that it may send this message for
+    // a window or client that may have been destroyed already. This is not an error,
+    // and we should not call did_misbehave() for either.
+    auto* client = WindowServer::ClientConnection::from_client_id(message.client_id());
+    if (!client)
+        return;
+
+    auto it = client->m_windows.find(message.window_id());
+    if (it == client->m_windows.end())
+        return;
+
+    auto& window = *(*it).value;
+    window.set_taskbar_rect(message.rect());
+}
+
+}

+ 73 - 0
Userland/Services/WindowServer/WMClientConnection.h

@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2021, the SerenityOS developers.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this
+ *    list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "AK/NonnullRefPtr.h"
+#include <AK/HashMap.h>
+#include <LibIPC/ClientConnection.h>
+#include <WindowServer/WindowManagerClientEndpoint.h>
+#include <WindowServer/WindowManagerServerEndpoint.h>
+
+namespace WindowServer {
+
+class WMClientConnection final
+    : public IPC::ClientConnection<WindowManagerClientEndpoint, WindowManagerServerEndpoint>
+    , public WindowManagerServerEndpoint {
+    C_OBJECT(WMClientConnection)
+
+public:
+    ~WMClientConnection() override;
+
+    virtual void handle(const Messages::WindowManagerServer::SetActiveWindow&) override;
+    virtual void handle(const Messages::WindowManagerServer::SetWindowMinimized&) override;
+    virtual void handle(const Messages::WindowManagerServer::StartWindowResize&) override;
+    virtual void handle(const Messages::WindowManagerServer::PopupWindowMenu&) override;
+    virtual void handle(const Messages::WindowManagerServer::SetWindowTaskbarRect&) override;
+    virtual OwnPtr<Messages::WindowManagerServer::SetAppletAreaPositionResponse> handle(const Messages::WindowManagerServer::SetAppletAreaPosition&) override;
+    virtual OwnPtr<Messages::WindowManagerServer::SetEventMaskResponse> handle(const Messages::WindowManagerServer::SetEventMask&) override;
+    virtual OwnPtr<Messages::WindowManagerServer::SetManagerWindowResponse> handle(const Messages::WindowManagerServer::SetManagerWindow&) override;
+
+    unsigned event_mask() const { return m_event_mask; }
+    int window_id() const { return m_window_id; }
+
+private:
+    explicit WMClientConnection(NonnullRefPtr<Core::LocalSocket> client_socket, int client_id);
+
+    // ^ClientConnection
+    virtual void die() override;
+
+    // RefPtr<Core::Timer> m_ping_timer;
+    static HashMap<int, NonnullRefPtr<WMClientConnection>> s_connections;
+    unsigned m_event_mask { 0 };
+    int m_window_id { -1 };
+
+    // WindowManager needs to access the window manager clients to notify
+    // about events.
+    friend class WindowManager;
+};
+
+};

+ 0 - 6
Userland/Services/WindowServer/Window.cpp

@@ -113,12 +113,6 @@ Window::Window(ClientConnection& client, WindowType window_type, int window_id,
     , m_icon(default_window_icon())
     , m_frame(*this)
 {
-    // FIXME: This should not be hard-coded here.
-    if (m_type == WindowType::Taskbar) {
-        m_wm_event_mask = WMEventMask::WindowStateChanges | WMEventMask::WindowRemovals | WMEventMask::WindowIconChanges;
-        m_listens_to_wm_events = true;
-    }
-
     // Set default minimum size for Normal windows
     if (m_type == WindowType::Normal)
         m_minimum_size = s_default_normal_minimum_size;

+ 0 - 7
Userland/Services/WindowServer/Window.h

@@ -100,9 +100,6 @@ public:
     void window_menu_activate_default();
     void request_close();
 
-    unsigned wm_event_mask() const { return m_wm_event_mask; }
-    void set_wm_event_mask(unsigned mask) { m_wm_event_mask = mask; }
-
     bool is_minimized() const { return m_minimized; }
     void set_minimized(bool);
 
@@ -137,8 +134,6 @@ public:
 
     Window* blocking_modal_window();
 
-    bool listens_to_wm_events() const { return m_listens_to_wm_events; }
-
     ClientConnection* client() { return m_client; }
     const ClientConnection* client() const { return m_client; }
 
@@ -381,7 +376,6 @@ private:
     bool m_frameless { false };
     bool m_resizable { false };
     Optional<Gfx::IntSize> m_resize_aspect_ratio {};
-    bool m_listens_to_wm_events { false };
     bool m_minimized { false };
     bool m_maximized { false };
     bool m_fullscreen { false };
@@ -411,7 +405,6 @@ private:
     RefPtr<Cursor> m_cursor;
     RefPtr<Cursor> m_cursor_override;
     WindowFrame m_frame;
-    unsigned m_wm_event_mask { 0 };
     Gfx::DisjointRectSet m_pending_paint_rects;
     Gfx::IntRect m_unmaximized_rect;
     Gfx::IntRect m_rect_in_applet_area;

+ 0 - 6
Userland/Services/WindowServer/WindowClient.ipc

@@ -23,12 +23,6 @@ endpoint WindowClient = 4
 
     ScreenRectChanged(Gfx::IntRect rect) =|
 
-    WM_WindowRemoved(i32 wm_id, i32 client_id, i32 window_id) =|
-    WM_WindowStateChanged(i32 wm_id, i32 client_id, i32 window_id, i32 parent_client_id, i32 parent_window_id, bool is_active, bool is_minimized, bool is_modal, bool is_frameless, i32 window_type, [UTF8] String title, Gfx::IntRect rect, i32 progress) =|
-    WM_WindowIconBitmapChanged(i32 wm_id, i32 client_id, i32 window_id, Gfx::ShareableBitmap bitmap) =|
-    WM_WindowRectChanged(i32 wm_id, i32 client_id, i32 window_id, Gfx::IntRect rect) =|
-    WM_AppletAreaSizeChanged(i32 wm_id, Gfx::IntSize size) =|
-
     AsyncSetWallpaperFinished(bool success) =|
 
     DragAccepted() =|

+ 57 - 44
Userland/Services/WindowServer/WindowManager.cpp

@@ -209,21 +209,9 @@ void WindowManager::add_window(Window& window)
 
     Compositor::the().invalidate_occlusions();
 
-    if (window.listens_to_wm_events()) {
-        for_each_window([&](Window& other_window) {
-            if (&window != &other_window) {
-                tell_wm_listener_about_window(window, other_window);
-                tell_wm_listener_about_window_icon(window, other_window);
-            }
-            return IterationDecision::Continue;
-        });
-        if (auto* applet_area_window = AppletManager::the().window())
-            tell_wm_listeners_applet_area_size_changed(applet_area_window->size());
-    }
-
     window.invalidate(true, true);
 
-    tell_wm_listeners_window_state_changed(window);
+    tell_wms_window_state_changed(window);
 }
 
 void WindowManager::move_to_front_and_make_active(Window& window)
@@ -295,71 +283,96 @@ void WindowManager::remove_window(Window& window)
 
     Compositor::the().invalidate_occlusions();
 
-    for_each_window_listening_to_wm_events([&window](Window& listener) {
-        if (!(listener.wm_event_mask() & WMEventMask::WindowRemovals))
+    for_each_window_manager([&window](WMClientConnection& conn) {
+        if (conn.window_id() < 0 || !(conn.event_mask() & WMEventMask::WindowRemovals))
             return IterationDecision::Continue;
         if (!window.is_internal() && !window.is_modal())
-            listener.client()->post_message(Messages::WindowClient::WM_WindowRemoved(listener.window_id(), window.client_id(), window.window_id()));
+            conn.post_message(Messages::WindowManagerClient::WindowRemoved(conn.window_id(), window.client_id(), window.window_id()));
         return IterationDecision::Continue;
     });
 }
 
-void WindowManager::tell_wm_listener_about_window(Window& listener, Window& window)
+void WindowManager::greet_window_manager(WMClientConnection& conn)
 {
-    if (!(listener.wm_event_mask() & WMEventMask::WindowStateChanges))
+    if (conn.window_id() < 0)
+        return;
+
+    for_each_window([&](Window& other_window) {
+        //if (conn.window_id() != other_window.window_id()) {
+        tell_wm_about_window(conn, other_window);
+        tell_wm_about_window_icon(conn, other_window);
+        //}
+        return IterationDecision::Continue;
+    });
+    if (auto* applet_area_window = AppletManager::the().window())
+        tell_wms_applet_area_size_changed(applet_area_window->size());
+}
+
+void WindowManager::tell_wm_about_window(WMClientConnection& conn, Window& window)
+{
+    if (conn.window_id() < 0)
+        return;
+    if (!(conn.event_mask() & WMEventMask::WindowStateChanges))
         return;
     if (window.is_internal())
         return;
     auto* parent = window.parent_window();
-    listener.client()->post_message(Messages::WindowClient::WM_WindowStateChanged(listener.window_id(), window.client_id(), window.window_id(), parent ? parent->client_id() : -1, parent ? parent->window_id() : -1, window.is_active(), window.is_minimized(), window.is_modal_dont_unparent(), window.is_frameless(), (i32)window.type(), window.title(), window.rect(), window.progress()));
+    conn.post_message(Messages::WindowManagerClient::WindowStateChanged(conn.window_id(), window.client_id(), window.window_id(), parent ? parent->client_id() : -1, parent ? parent->window_id() : -1, window.is_active(), window.is_minimized(), window.is_modal_dont_unparent(), window.is_frameless(), (i32)window.type(), window.title(), window.rect(), window.progress()));
 }
 
-void WindowManager::tell_wm_listener_about_window_rect(Window& listener, Window& window)
+void WindowManager::tell_wm_about_window_rect(WMClientConnection& conn, Window& window)
 {
-    if (!(listener.wm_event_mask() & WMEventMask::WindowRectChanges))
+    if (conn.window_id() < 0)
+        return;
+    if (!(conn.event_mask() & WMEventMask::WindowRectChanges))
         return;
     if (window.is_internal())
         return;
-    listener.client()->post_message(Messages::WindowClient::WM_WindowRectChanged(listener.window_id(), window.client_id(), window.window_id(), window.rect()));
+    conn.post_message(Messages::WindowManagerClient::WindowRectChanged(conn.window_id(), window.client_id(), window.window_id(), window.rect()));
 }
 
-void WindowManager::tell_wm_listener_about_window_icon(Window& listener, Window& window)
+void WindowManager::tell_wm_about_window_icon(WMClientConnection& conn, Window& window)
 {
-    if (!(listener.wm_event_mask() & WMEventMask::WindowIconChanges))
+    if (conn.window_id() < 0)
+        return;
+    if (!(conn.event_mask() & WMEventMask::WindowIconChanges))
         return;
     if (window.is_internal())
         return;
-    listener.client()->post_message(Messages::WindowClient::WM_WindowIconBitmapChanged(listener.window_id(), window.client_id(), window.window_id(), window.icon().to_shareable_bitmap()));
+    conn.post_message(Messages::WindowManagerClient::WindowIconBitmapChanged(conn.window_id(), window.client_id(), window.window_id(), window.icon().to_shareable_bitmap()));
 }
 
-void WindowManager::tell_wm_listeners_window_state_changed(Window& window)
+void WindowManager::tell_wms_window_state_changed(Window& window)
 {
-    for_each_window_listening_to_wm_events([&](Window& listener) {
-        tell_wm_listener_about_window(listener, window);
+    for_each_window_manager([&](WMClientConnection& conn) {
+        tell_wm_about_window(conn, window);
         return IterationDecision::Continue;
     });
 }
 
-void WindowManager::tell_wm_listeners_window_icon_changed(Window& window)
+void WindowManager::tell_wms_window_icon_changed(Window& window)
 {
-    for_each_window_listening_to_wm_events([&](Window& listener) {
-        tell_wm_listener_about_window_icon(listener, window);
+    for_each_window_manager([&](WMClientConnection& conn) {
+        tell_wm_about_window_icon(conn, window);
         return IterationDecision::Continue;
     });
 }
 
-void WindowManager::tell_wm_listeners_window_rect_changed(Window& window)
+void WindowManager::tell_wms_window_rect_changed(Window& window)
 {
-    for_each_window_listening_to_wm_events([&](Window& listener) {
-        tell_wm_listener_about_window_rect(listener, window);
+    for_each_window_manager([&](WMClientConnection& conn) {
+        tell_wm_about_window_rect(conn, window);
         return IterationDecision::Continue;
     });
 }
 
-void WindowManager::tell_wm_listeners_applet_area_size_changed(const Gfx::IntSize& size)
+void WindowManager::tell_wms_applet_area_size_changed(const Gfx::IntSize& size)
 {
-    for_each_window_listening_to_wm_events([&](Window& listener) {
-        listener.client()->post_message(Messages::WindowClient::WM_AppletAreaSizeChanged(listener.window_id(), size));
+    for_each_window_manager([&](WMClientConnection& conn) {
+        if (conn.window_id() < 0)
+            return IterationDecision::Continue;
+
+        conn.post_message(Messages::WindowManagerClient::AppletAreaSizeChanged(conn.window_id(), size));
         return IterationDecision::Continue;
     });
 }
@@ -379,7 +392,7 @@ void WindowManager::notify_title_changed(Window& window)
     if (m_switcher.is_visible())
         m_switcher.refresh();
 
-    tell_wm_listeners_window_state_changed(window);
+    tell_wms_window_state_changed(window);
 }
 
 void WindowManager::notify_modal_unparented(Window& window)
@@ -392,7 +405,7 @@ void WindowManager::notify_modal_unparented(Window& window)
     if (m_switcher.is_visible())
         m_switcher.refresh();
 
-    tell_wm_listeners_window_state_changed(window);
+    tell_wms_window_state_changed(window);
 }
 
 void WindowManager::notify_rect_changed(Window& window, const Gfx::IntRect& old_rect, const Gfx::IntRect& new_rect)
@@ -402,7 +415,7 @@ void WindowManager::notify_rect_changed(Window& window, const Gfx::IntRect& old_
     if (m_switcher.is_visible() && window.type() != WindowType::WindowSwitcher)
         m_switcher.refresh();
 
-    tell_wm_listeners_window_rect_changed(window);
+    tell_wms_window_rect_changed(window);
 
     if (window.type() == WindowType::Applet)
         AppletManager::the().relayout();
@@ -417,7 +430,7 @@ void WindowManager::notify_opacity_changed(Window&)
 
 void WindowManager::notify_minimization_state_changed(Window& window)
 {
-    tell_wm_listeners_window_state_changed(window);
+    tell_wms_window_state_changed(window);
 
     if (window.client())
         window.client()->post_message(Messages::WindowClient::WindowStateChanged(window.window_id(), window.is_minimized(), window.is_occluded()));
@@ -434,7 +447,7 @@ void WindowManager::notify_occlusion_state_changed(Window& window)
 
 void WindowManager::notify_progress_changed(Window& window)
 {
-    tell_wm_listeners_window_state_changed(window);
+    tell_wms_window_state_changed(window);
 }
 
 bool WindowManager::pick_new_active_window(Window* previous_active)
@@ -1360,14 +1373,14 @@ void WindowManager::set_active_window(Window* window, bool make_input)
         previously_active_window->invalidate(true, true);
         m_active_window = nullptr;
         m_active_input_tracking_window = nullptr;
-        tell_wm_listeners_window_state_changed(*previously_active_window);
+        tell_wms_window_state_changed(*previously_active_window);
     }
 
     if (window) {
         m_active_window = *window;
         Core::EventLoop::current().post_event(*m_active_window, make<Event>(Event::WindowActivated));
         m_active_window->invalidate(true, true);
-        tell_wm_listeners_window_state_changed(*m_active_window);
+        tell_wms_window_state_changed(*m_active_window);
     }
 
     // Window shapes may have changed (e.g. shadows for inactive/active windows)

+ 18 - 14
Userland/Services/WindowServer/WindowManager.h

@@ -41,6 +41,7 @@
 #include <WindowServer/Event.h>
 #include <WindowServer/MenuManager.h>
 #include <WindowServer/Menubar.h>
+#include <WindowServer/WMClientConnection.h>
 #include <WindowServer/Window.h>
 #include <WindowServer/WindowSwitcher.h>
 #include <WindowServer/WindowType.h>
@@ -169,10 +170,11 @@ public:
     void clear_resize_candidate();
     ResizeDirection resize_direction_of_window(const Window&);
 
-    void tell_wm_listeners_window_state_changed(Window&);
-    void tell_wm_listeners_window_icon_changed(Window&);
-    void tell_wm_listeners_window_rect_changed(Window&);
-    void tell_wm_listeners_applet_area_size_changed(const Gfx::IntSize&);
+    void greet_window_manager(WMClientConnection&);
+    void tell_wms_window_state_changed(Window&);
+    void tell_wms_window_icon_changed(Window&);
+    void tell_wms_window_rect_changed(Window&);
+    void tell_wms_applet_area_size_changed(const Gfx::IntSize&);
 
     bool is_active_window_or_accessory(Window&) const;
 
@@ -263,17 +265,18 @@ private:
     template<typename Callback>
     IterationDecision for_each_visible_window_from_back_to_front(Callback);
     template<typename Callback>
-    void for_each_window_listening_to_wm_events(Callback);
-    template<typename Callback>
     void for_each_window(Callback);
     template<typename Callback>
     IterationDecision for_each_window_of_type_from_front_to_back(WindowType, Callback, bool ignore_highlight = false);
 
+    template<typename Callback>
+    void for_each_window_manager(Callback);
+
     virtual void event(Core::Event&) override;
     void paint_window_frame(const Window&);
-    void tell_wm_listener_about_window(Window& listener, Window&);
-    void tell_wm_listener_about_window_icon(Window& listener, Window&);
-    void tell_wm_listener_about_window_rect(Window& listener, Window&);
+    void tell_wm_about_window(WMClientConnection& conn, Window&);
+    void tell_wm_about_window_icon(WMClientConnection& conn, Window&);
+    void tell_wm_about_window_rect(WMClientConnection& conn, Window&);
     bool pick_new_active_window(Window*);
 
     void do_move_to_front(Window&, bool, bool);
@@ -460,12 +463,13 @@ IterationDecision WindowManager::for_each_visible_window_from_front_to_back(Call
 }
 
 template<typename Callback>
-void WindowManager::for_each_window_listening_to_wm_events(Callback callback)
+void WindowManager::for_each_window_manager(Callback callback)
 {
-    for (auto* window = m_windows_in_order.tail(); window; window = window->prev()) {
-        if (!window->listens_to_wm_events())
-            continue;
-        if (callback(*window) == IterationDecision::Break)
+    auto& connections = WMClientConnection::s_connections;
+
+    // FIXME: this isn't really ordered... does it need to be?
+    for (auto it = connections.begin(); it != connections.end(); ++it) {
+        if (callback(*it->value) == IterationDecision::Break)
             return;
     }
 }

+ 8 - 0
Userland/Services/WindowServer/WindowManagerClient.ipc

@@ -0,0 +1,8 @@
+endpoint WindowManagerClient = 1872
+{
+    WindowRemoved(i32 wm_id, i32 client_id, i32 window_id) =|
+    WindowStateChanged(i32 wm_id, i32 client_id, i32 window_id, i32 parent_client_id, i32 parent_window_id, bool is_active, bool is_minimized, bool is_modal, bool is_frameless, i32 window_type, [UTF8] String title, Gfx::IntRect rect, i32 progress) =|
+    WindowIconBitmapChanged(i32 wm_id, i32 client_id, i32 window_id, Gfx::ShareableBitmap bitmap) =|
+    WindowRectChanged(i32 wm_id, i32 client_id, i32 window_id, Gfx::IntRect rect) =|
+    AppletAreaSizeChanged(i32 wm_id, Gfx::IntSize size) =|
+}

+ 12 - 0
Userland/Services/WindowServer/WindowManagerServer.ipc

@@ -0,0 +1,12 @@
+endpoint WindowManagerServer = 1871
+{
+    SetEventMask(u32 event_mask) => ()
+    SetManagerWindow(i32 window_id) => ()
+
+    SetActiveWindow(i32 client_id, i32 window_id) =|
+    SetWindowMinimized(i32 client_id, i32 window_id, bool minimized) =|
+    StartWindowResize(i32 client_id, i32 window_id) =|
+    PopupWindowMenu(i32 client_id, i32 window_id, Gfx::IntPoint screen_position) =|
+    SetWindowTaskbarRect(i32 client_id, i32 window_id, Gfx::IntRect rect) =|
+    SetAppletAreaPosition(Gfx::IntPoint position) => ()
+}

+ 0 - 7
Userland/Services/WindowServer/WindowServer.ipc

@@ -78,13 +78,6 @@ endpoint WindowServer = 2
 
     SetWindowBackingStore(i32 window_id, i32 bpp, i32 pitch, IPC::File anon_file, i32 serial, bool has_alpha_channel, Gfx::IntSize size, bool flush_immediately) => ()
 
-    WM_SetActiveWindow(i32 client_id, i32 window_id) =|
-    WM_SetWindowMinimized(i32 client_id, i32 window_id, bool minimized) =|
-    WM_StartWindowResize(i32 client_id, i32 window_id) =|
-    WM_PopupWindowMenu(i32 client_id, i32 window_id, Gfx::IntPoint screen_position) =|
-    WM_SetWindowTaskbarRect(i32 client_id, i32 window_id, Gfx::IntRect rect) =|
-    WM_SetAppletAreaPosition(Gfx::IntPoint position) => ()
-
     SetWindowHasAlphaChannel(i32 window_id, bool has_alpha_channel) => ()
     MoveWindowToFront(i32 window_id) => ()
     SetFullscreen(i32 window_id, bool fullscreen) => ()