summaryrefslogtreecommitdiff
path: root/Servers/WindowServer
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2020-05-08 21:57:44 +0200
committerAndreas Kling <kling@serenityos.org>2020-05-08 21:57:44 +0200
commitcf3b58fbe8f836c13e44d6152d78960aff6089ef (patch)
treedcc7664f0004ee9c495f9d948cfb16d12f8a70bf /Servers/WindowServer
parent042b1f68145ad3754fd98429b405c5c1a173d3fc (diff)
downloadserenity-cf3b58fbe8f836c13e44d6152d78960aff6089ef.zip
Services: Renamed from Servers
It didn't feel right to have a "DHCPClient" in a "Servers" directory. Rename this to Services to better reflect the type of programs we'll be putting in there.
Diffstat (limited to 'Servers/WindowServer')
-rw-r--r--Servers/WindowServer/AppletManager.cpp135
-rw-r--r--Servers/WindowServer/AppletManager.h56
-rw-r--r--Servers/WindowServer/Button.cpp115
-rw-r--r--Servers/WindowServer/Button.h70
-rw-r--r--Servers/WindowServer/ClientConnection.cpp833
-rw-r--r--Servers/WindowServer/ClientConnection.h148
-rw-r--r--Servers/WindowServer/Clipboard.cpp78
-rw-r--r--Servers/WindowServer/Clipboard.h62
-rw-r--r--Servers/WindowServer/Compositor.cpp507
-rw-r--r--Servers/WindowServer/Compositor.h108
-rw-r--r--Servers/WindowServer/Cursor.cpp77
-rw-r--r--Servers/WindowServer/Cursor.h65
-rw-r--r--Servers/WindowServer/Event.h157
-rw-r--r--Servers/WindowServer/EventLoop.cpp157
-rw-r--r--Servers/WindowServer/EventLoop.h57
-rw-r--r--Servers/WindowServer/Makefile38
-rw-r--r--Servers/WindowServer/Menu.cpp570
-rw-r--r--Servers/WindowServer/Menu.h158
-rw-r--r--Servers/WindowServer/MenuBar.cpp55
-rw-r--r--Servers/WindowServer/MenuBar.h61
-rw-r--r--Servers/WindowServer/MenuItem.cpp96
-rw-r--r--Servers/WindowServer/MenuItem.h99
-rw-r--r--Servers/WindowServer/MenuManager.cpp404
-rw-r--r--Servers/WindowServer/MenuManager.h123
-rw-r--r--Servers/WindowServer/Screen.cpp171
-rw-r--r--Servers/WindowServer/Screen.h86
-rw-r--r--Servers/WindowServer/Window.cpp524
-rw-r--r--Servers/WindowServer/Window.h286
-rw-r--r--Servers/WindowServer/WindowClient.ipc40
-rw-r--r--Servers/WindowServer/WindowFrame.cpp414
-rw-r--r--Servers/WindowServer/WindowFrame.h74
-rw-r--r--Servers/WindowServer/WindowManager.cpp1317
-rw-r--r--Servers/WindowServer/WindowManager.h416
-rw-r--r--Servers/WindowServer/WindowServer.ipc97
-rw-r--r--Servers/WindowServer/WindowSwitcher.cpp256
-rw-r--r--Servers/WindowServer/WindowSwitcher.h84
-rw-r--r--Servers/WindowServer/WindowType.h41
-rw-r--r--Servers/WindowServer/main.cpp117
38 files changed, 0 insertions, 8152 deletions
diff --git a/Servers/WindowServer/AppletManager.cpp b/Servers/WindowServer/AppletManager.cpp
deleted file mode 100644
index 855ff3bcd3..0000000000
--- a/Servers/WindowServer/AppletManager.cpp
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright (c) 2020-2020, Hüseyin Aslıtürk <asliturk@hotmail.com>
- * 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 "AppletManager.h"
-#include <AK/QuickSort.h>
-#include <LibGfx/Painter.h>
-#include <WindowServer/MenuManager.h>
-
-namespace WindowServer {
-
-static AppletManager* s_the;
-Vector<String> order_vector;
-
-AppletManager::AppletManager()
-{
- s_the = this;
-
- auto wm_config = Core::ConfigFile::open("/etc/WindowServer/WindowServer.ini");
- auto order = wm_config->read_entry("Applet", "Order");
- order_vector = order.split(',');
-}
-
-AppletManager::~AppletManager()
-{
-}
-
-AppletManager& AppletManager::the()
-{
- ASSERT(s_the);
- return *s_the;
-}
-
-void AppletManager::event(Core::Event& event)
-{
- auto& mouse_event = static_cast<MouseEvent&>(event);
-
- for (auto& applet : m_applets) {
- if (!applet)
- continue;
- if (!applet->rect_in_menubar().contains(mouse_event.position()))
- continue;
- auto local_event = mouse_event.translated(-applet->rect_in_menubar().location());
- applet->event(local_event);
- }
-}
-
-void AppletManager::add_applet(Window& applet)
-{
- m_applets.append(applet.make_weak_ptr());
-
- // Prune any dead weak pointers from the applet list.
- m_applets.remove_all_matching([](auto& entry) {
- return entry.is_null();
- });
-
- quick_sort(m_applets, [](auto& a, auto& b) {
- auto index_a = order_vector.find_first_index(a->title());
- auto index_b = order_vector.find_first_index(b->title());
- return index_a.value_or(0) > index_b.value_or(0);
- });
-
- calculate_applet_rects(MenuManager::the().window());
-}
-
-void AppletManager::calculate_applet_rects(Window& window)
-{
- auto menubar_rect = window.rect();
- int right_edge_x = menubar_rect.width() - 4;
- for (auto& existing_applet : m_applets) {
-
- Gfx::Rect new_applet_rect(right_edge_x - existing_applet->size().width(), 0, existing_applet->size().width(), existing_applet->size().height());
- Gfx::Rect dummy_menubar_rect(0, 0, 0, 18);
- new_applet_rect.center_vertically_within(dummy_menubar_rect);
-
- existing_applet->set_rect_in_menubar(new_applet_rect);
- right_edge_x = existing_applet->rect_in_menubar().x() - 4;
- }
-}
-
-void AppletManager::remove_applet(Window& applet)
-{
- m_applets.remove_first_matching([&](auto& entry) {
- return &applet == entry.ptr();
- });
-}
-
-void AppletManager::draw()
-{
- for (auto& applet : m_applets) {
- if (!applet)
- continue;
- draw_applet(*applet);
- }
-}
-
-void AppletManager::draw_applet(const Window& applet)
-{
- if (!applet.backing_store())
- return;
-
- Gfx::Painter painter(*MenuManager::the().window().backing_store());
- painter.fill_rect(applet.rect_in_menubar(), WindowManager::the().palette().window());
- painter.blit(applet.rect_in_menubar().location(), *applet.backing_store(), applet.backing_store()->rect());
-}
-
-void AppletManager::invalidate_applet(const Window& applet, const Gfx::Rect& rect)
-{
- draw_applet(applet);
- MenuManager::the().window().invalidate(rect.translated(applet.rect_in_menubar().location()));
-}
-
-}
diff --git a/Servers/WindowServer/AppletManager.h b/Servers/WindowServer/AppletManager.h
deleted file mode 100644
index 4619fd0030..0000000000
--- a/Servers/WindowServer/AppletManager.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (c) 2020-2020, Hüseyin Aslıtürk <asliturk@hotmail.com>
- * 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 <WindowServer/Window.h>
-#include <WindowServer/WindowManager.h>
-
-namespace WindowServer {
-
-class AppletManager : public Core::Object {
- C_OBJECT(AppletManager)
-public:
- AppletManager();
- ~AppletManager();
-
- static AppletManager& the();
-
- virtual void event(Core::Event&) override;
-
- void add_applet(Window& applet);
- void remove_applet(Window& applet);
- void draw();
- void invalidate_applet(const Window& applet, const Gfx::Rect& rect);
- void calculate_applet_rects(Window& window);
-
-private:
- void draw_applet(const Window& applet);
-
- Vector<WeakPtr<Window>> m_applets;
-};
-
-}
diff --git a/Servers/WindowServer/Button.cpp b/Servers/WindowServer/Button.cpp
deleted file mode 100644
index 95037d4bc8..0000000000
--- a/Servers/WindowServer/Button.cpp
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * 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 <LibGfx/CharacterBitmap.h>
-#include <LibGfx/Painter.h>
-#include <LibGfx/StylePainter.h>
-#include <WindowServer/Button.h>
-#include <WindowServer/Event.h>
-#include <WindowServer/WindowManager.h>
-
-namespace WindowServer {
-
-Button::Button(WindowFrame& frame, NonnullRefPtr<Gfx::CharacterBitmap>&& bitmap, Function<void(Button&)>&& on_click_handler)
- : on_click(move(on_click_handler))
- , m_frame(frame)
- , m_bitmap(move(bitmap))
-{
-}
-
-Button::~Button()
-{
-}
-
-void Button::paint(Gfx::Painter& painter)
-{
- auto palette = WindowManager::the().palette();
- Gfx::PainterStateSaver saver(painter);
- painter.translate(relative_rect().location());
- Gfx::StylePainter::paint_button(painter, rect(), palette, Gfx::ButtonStyle::Normal, m_pressed, m_hovered);
- auto x_location = rect().center();
- x_location.move_by(-(m_bitmap->width() / 2), -(m_bitmap->height() / 2));
- if (m_pressed)
- x_location.move_by(1, 1);
- painter.draw_bitmap(x_location, *m_bitmap, palette.button_text());
-}
-
-void Button::on_mouse_event(const MouseEvent& event)
-{
- auto& wm = WindowManager::the();
-
- if (event.type() == Event::MouseDown && event.button() == MouseButton::Left) {
- m_pressed = true;
- wm.set_cursor_tracking_button(this);
- wm.invalidate(screen_rect());
- return;
- }
-
- if (event.type() == Event::MouseUp && event.button() == MouseButton::Left) {
- if (wm.cursor_tracking_button() != this)
- return;
- wm.set_cursor_tracking_button(nullptr);
- bool old_pressed = m_pressed;
- m_pressed = false;
- if (rect().contains(event.position())) {
- if (on_click)
- on_click(*this);
- }
- if (old_pressed != m_pressed) {
- // Would like to compute:
- // m_hovered = rect_after_action().contains(event.position());
- // However, we don't know that rect yet. We can make an educated
- // guess which also looks okay even when wrong:
- m_hovered = false;
- wm.invalidate(screen_rect());
- }
- return;
- }
-
- if (event.type() == Event::MouseMove) {
- bool old_hovered = m_hovered;
- m_hovered = rect().contains(event.position());
- wm.set_hovered_button(m_hovered ? this : nullptr);
- if (old_hovered != m_hovered)
- wm.invalidate(screen_rect());
- }
-
- if (event.type() == Event::MouseMove && event.buttons() & (unsigned)MouseButton::Left) {
- if (wm.cursor_tracking_button() != this)
- return;
- bool old_pressed = m_pressed;
- m_pressed = m_hovered;
- if (old_pressed != m_pressed)
- wm.invalidate(screen_rect());
- }
-}
-
-Gfx::Rect Button::screen_rect() const
-{
- return m_relative_rect.translated(m_frame.rect().location());
-}
-
-}
diff --git a/Servers/WindowServer/Button.h b/Servers/WindowServer/Button.h
deleted file mode 100644
index 555a5d6f9e..0000000000
--- a/Servers/WindowServer/Button.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * 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/Function.h>
-#include <AK/NonnullRefPtr.h>
-#include <AK/Weakable.h>
-#include <LibGfx/Rect.h>
-#include <LibGfx/Forward.h>
-
-namespace WindowServer {
-
-class MouseEvent;
-class WindowFrame;
-
-class Button : public Weakable<Button> {
-public:
- Button(WindowFrame&, NonnullRefPtr<Gfx::CharacterBitmap>&&, Function<void(Button&)>&& on_click_handler);
- ~Button();
-
- Gfx::Rect relative_rect() const { return m_relative_rect; }
- void set_relative_rect(const Gfx::Rect& rect) { m_relative_rect = rect; }
-
- Gfx::Rect rect() const { return { {}, m_relative_rect.size() }; }
- Gfx::Rect screen_rect() const;
-
- void paint(Gfx::Painter&);
-
- void on_mouse_event(const MouseEvent&);
-
- Function<void(Button&)> on_click;
-
- bool is_visible() const { return m_visible; }
-
- void set_bitmap(const Gfx::CharacterBitmap& bitmap) { m_bitmap = bitmap; }
-
-private:
- WindowFrame& m_frame;
- Gfx::Rect m_relative_rect;
- NonnullRefPtr<Gfx::CharacterBitmap> m_bitmap;
- bool m_pressed { false };
- bool m_visible { true };
- bool m_hovered { false };
-};
-
-}
diff --git a/Servers/WindowServer/ClientConnection.cpp b/Servers/WindowServer/ClientConnection.cpp
deleted file mode 100644
index 7f128689fb..0000000000
--- a/Servers/WindowServer/ClientConnection.cpp
+++ /dev/null
@@ -1,833 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * 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 <AK/Badge.h>
-#include <AK/SharedBuffer.h>
-#include <LibGfx/Bitmap.h>
-#include <LibGfx/SystemTheme.h>
-#include <WindowServer/AppletManager.h>
-#include <WindowServer/ClientConnection.h>
-#include <WindowServer/Clipboard.h>
-#include <WindowServer/Compositor.h>
-#include <WindowServer/EventLoop.h>
-#include <WindowServer/Menu.h>
-#include <WindowServer/MenuBar.h>
-#include <WindowServer/MenuItem.h>
-#include <WindowServer/Screen.h>
-#include <WindowServer/Window.h>
-#include <WindowServer/WindowClientEndpoint.h>
-#include <WindowServer/WindowManager.h>
-#include <WindowServer/WindowSwitcher.h>
-#include <errno.h>
-#include <serenity.h>
-#include <stdio.h>
-#include <unistd.h>
-
-namespace WindowServer {
-
-HashMap<int, NonnullRefPtr<ClientConnection>>* s_connections;
-
-static Gfx::Rect normalize_window_rect(Gfx::Rect rect, WindowType window_type)
-{
- auto min_size = 1;
- if (window_type == WindowType::Normal)
- min_size = 50;
- Gfx::Rect normalized_rect = { rect.x(), rect.y(), max(rect.width(), min_size), max(rect.height(), min_size) };
- return normalized_rect;
-}
-
-void ClientConnection::for_each_client(Function<void(ClientConnection&)> callback)
-{
- if (!s_connections)
- return;
- for (auto& it : *s_connections) {
- callback(*it.value);
- }
-}
-
-ClientConnection* ClientConnection::from_client_id(int client_id)
-{
- if (!s_connections)
- return nullptr;
- auto it = s_connections->find(client_id);
- if (it == s_connections->end())
- return nullptr;
- return (*it).value.ptr();
-}
-
-ClientConnection::ClientConnection(Core::LocalSocket& client_socket, int client_id)
- : IPC::ClientConnection<WindowServerEndpoint>(*this, client_socket, client_id)
-{
- if (!s_connections)
- s_connections = new HashMap<int, NonnullRefPtr<ClientConnection>>;
- s_connections->set(client_id, *this);
-}
-
-ClientConnection::~ClientConnection()
-{
- if (m_has_display_link)
- Compositor::the().decrement_display_link_count({});
-
- MenuManager::the().close_all_menus_from_client({}, *this);
- auto windows = move(m_windows);
- for (auto& window : windows) {
- window.value->detach_client({});
- if (window.value->type() == WindowType::MenuApplet)
- AppletManager::the().remove_applet(window.value);
- }
-}
-
-void ClientConnection::die()
-{
- deferred_invoke([this](auto&) {
- s_connections->remove(client_id());
- });
-}
-
-void ClientConnection::notify_about_new_screen_rect(const Gfx::Rect& rect)
-{
- post_message(Messages::WindowClient::ScreenRectChanged(rect));
-}
-
-void ClientConnection::notify_about_clipboard_contents_changed()
-{
- post_message(Messages::WindowClient::ClipboardContentsChanged(Clipboard::the().data_type()));
-}
-
-OwnPtr<Messages::WindowServer::CreateMenubarResponse> ClientConnection::handle(const Messages::WindowServer::CreateMenubar&)
-{
- int menubar_id = m_next_menubar_id++;
- auto menubar = make<MenuBar>(*this, menubar_id);
- m_menubars.set(menubar_id, move(menubar));
- return make<Messages::WindowServer::CreateMenubarResponse>(menubar_id);
-}
-
-OwnPtr<Messages::WindowServer::DestroyMenubarResponse> ClientConnection::handle(const Messages::WindowServer::DestroyMenubar& message)
-{
- int menubar_id = message.menubar_id();
- auto it = m_menubars.find(menubar_id);
- if (it == m_menubars.end()) {
- did_misbehave("DestroyMenubar: Bad menubar ID");
- return nullptr;
- }
- auto& menubar = *(*it).value;
- MenuManager::the().close_menubar(menubar);
- m_menubars.remove(it);
- return make<Messages::WindowServer::DestroyMenubarResponse>();
-}
-
-OwnPtr<Messages::WindowServer::CreateMenuResponse> ClientConnection::handle(const Messages::WindowServer::CreateMenu& message)
-{
- int menu_id = m_next_menu_id++;
- auto menu = Menu::construct(this, menu_id, message.menu_title());
- m_menus.set(menu_id, move(menu));
- return make<Messages::WindowServer::CreateMenuResponse>(menu_id);
-}
-
-OwnPtr<Messages::WindowServer::DestroyMenuResponse> ClientConnection::handle(const Messages::WindowServer::DestroyMenu& message)
-{
- int menu_id = message.menu_id();
- auto it = m_menus.find(menu_id);
- if (it == m_menus.end()) {
- did_misbehave("DestroyMenu: Bad menu ID");
- return nullptr;
- }
- auto& menu = *(*it).value;
- menu.close();
- m_menus.remove(it);
- remove_child(menu);
- return make<Messages::WindowServer::DestroyMenuResponse>();
-}
-
-OwnPtr<Messages::WindowServer::SetApplicationMenubarResponse> ClientConnection::handle(const Messages::WindowServer::SetApplicationMenubar& message)
-{
- int menubar_id = message.menubar_id();
- auto it = m_menubars.find(menubar_id);
- if (it == m_menubars.end()) {
- did_misbehave("SetApplicationMenubar: Bad menubar ID");
- return nullptr;
- }
- auto& menubar = *(*it).value;
- m_app_menubar = menubar.make_weak_ptr();
- WindowManager::the().notify_client_changed_app_menubar(*this);
- return make<Messages::WindowServer::SetApplicationMenubarResponse>();
-}
-
-OwnPtr<Messages::WindowServer::AddMenuToMenubarResponse> ClientConnection::handle(const Messages::WindowServer::AddMenuToMenubar& message)
-{
- int menubar_id = message.menubar_id();
- int menu_id = message.menu_id();
- auto it = m_menubars.find(menubar_id);
- auto jt = m_menus.find(menu_id);
- if (it == m_menubars.end()) {
- did_misbehave("AddMenuToMenubar: Bad menubar ID");
- return nullptr;
- }
- if (jt == m_menus.end()) {
- did_misbehave("AddMenuToMenubar: Bad menu ID");
- return nullptr;
- }
- auto& menubar = *(*it).value;
- auto& menu = *(*jt).value;
- menubar.add_menu(menu);
- return make<Messages::WindowServer::AddMenuToMenubarResponse>();
-}
-
-OwnPtr<Messages::WindowServer::AddMenuItemResponse> ClientConnection::handle(const Messages::WindowServer::AddMenuItem& message)
-{
- int menu_id = message.menu_id();
- unsigned identifier = message.identifier();
- auto it = m_menus.find(menu_id);
- if (it == m_menus.end()) {
- dbg() << "AddMenuItem: Bad menu ID: " << menu_id;
- return nullptr;
- }
- auto& menu = *(*it).value;
- auto menu_item = make<MenuItem>(menu, identifier, message.text(), message.shortcut(), message.enabled(), message.checkable(), message.checked());
- if (message.icon_buffer_id() != -1) {
- auto icon_buffer = SharedBuffer::create_from_shbuf_id(message.icon_buffer_id());
- if (!icon_buffer)
- return nullptr;
- // FIXME: Verify that the icon buffer can accomodate a 16x16 bitmap view.
- auto shared_icon = Gfx::Bitmap::create_with_shared_buffer(Gfx::BitmapFormat::RGBA32, icon_buffer.release_nonnull(), { 16, 16 });
- menu_item->set_icon(shared_icon);
- }
- menu_item->set_submenu_id(message.submenu_id());
- menu_item->set_exclusive(message.exclusive());
- menu.add_item(move(menu_item));
- return make<Messages::WindowServer::AddMenuItemResponse>();
-}
-
-OwnPtr<Messages::WindowServer::PopupMenuResponse> ClientConnection::handle(const Messages::WindowServer::PopupMenu& message)
-{
- int menu_id = message.menu_id();
- auto position = message.screen_position();
- auto it = m_menus.find(menu_id);
- if (it == m_menus.end()) {
- did_misbehave("PopupMenu: Bad menu ID");
- return nullptr;
- }
- auto& menu = *(*it).value;
- menu.popup(position);
- return make<Messages::WindowServer::PopupMenuResponse>();
-}
-
-OwnPtr<Messages::WindowServer::DismissMenuResponse> ClientConnection::handle(const Messages::WindowServer::DismissMenu& message)
-{
- int menu_id = message.menu_id();
- auto it = m_menus.find(menu_id);
- if (it == m_menus.end()) {
- did_misbehave("DismissMenu: Bad menu ID");
- return nullptr;
- }
- auto& menu = *(*it).value;
- menu.close();
- return make<Messages::WindowServer::DismissMenuResponse>();
-}
-
-OwnPtr<Messages::WindowServer::UpdateMenuItemResponse> ClientConnection::handle(const Messages::WindowServer::UpdateMenuItem& message)
-{
- int menu_id = message.menu_id();
- auto it = m_menus.find(menu_id);
- if (it == m_menus.end()) {
- did_misbehave("UpdateMenuItem: Bad menu ID");
- return nullptr;
- }
- auto& menu = *(*it).value;
- auto* menu_item = menu.item_with_identifier(message.identifier());
- if (!menu_item) {
- did_misbehave("UpdateMenuItem: Bad menu item identifier");
- return nullptr;
- }
- menu_item->set_text(message.text());
- menu_item->set_shortcut_text(message.shortcut());
- menu_item->set_enabled(message.enabled());
- menu_item->set_checkable(message.checkable());
- if (message.checkable())
- menu_item->set_checked(message.checked());
- return make<Messages::WindowServer::UpdateMenuItemResponse>();
-}
-
-OwnPtr<Messages::WindowServer::AddMenuSeparatorResponse> ClientConnection::handle(const Messages::WindowServer::AddMenuSeparator& message)
-{
- int menu_id = message.menu_id();
- auto it = m_menus.find(menu_id);
- if (it == m_menus.end()) {
- did_misbehave("AddMenuSeparator: Bad menu ID");
- return nullptr;
- }
- auto& menu = *(*it).value;
- menu.add_item(make<MenuItem>(menu, MenuItem::Separator));
- return make<Messages::WindowServer::AddMenuSeparatorResponse>();
-}
-
-OwnPtr<Messages::WindowServer::MoveWindowToFrontResponse> ClientConnection::handle(const Messages::WindowServer::MoveWindowToFront& message)
-{
- auto it = m_windows.find(message.window_id());
- if (it == m_windows.end()) {
- did_misbehave("MoveWindowToFront: Bad window ID");
- return nullptr;
- }
- WindowManager::the().move_to_front_and_make_active(*(*it).value);
- return make<Messages::WindowServer::MoveWindowToFrontResponse>();
-}
-
-OwnPtr<Messages::WindowServer::SetFullscreenResponse> ClientConnection::handle(const Messages::WindowServer::SetFullscreen& message)
-{
- auto it = m_windows.find(message.window_id());
- if (it == m_windows.end()) {
- did_misbehave("SetFullscreen: Bad window ID");
- return nullptr;
- }
- it->value->set_fullscreen(message.fullscreen());
- return make<Messages::WindowServer::SetFullscreenResponse>();
-}
-
-OwnPtr<Messages::WindowServer::SetWindowOpacityResponse> ClientConnection::handle(const Messages::WindowServer::SetWindowOpacity& message)
-{
- auto it = m_windows.find(message.window_id());
- if (it == m_windows.end()) {
- did_misbehave("SetWindowOpacity: Bad window ID");
- return nullptr;
- }
- it->value->set_opacity(message.opacity());
- return make<Messages::WindowServer::SetWindowOpacityResponse>();
-}
-
-void ClientConnection::handle(const Messages::WindowServer::AsyncSetWallpaper& message)
-{
- Compositor::the().set_wallpaper(message.path(), [&](bool success) {
- post_message(Messages::WindowClient::AsyncSetWallpaperFinished(success));
- });
-}
-
-OwnPtr<Messages::WindowServer::SetBackgroundColorResponse> ClientConnection::handle(const Messages::WindowServer::SetBackgroundColor& message)
-{
- Compositor::the().set_background_color(message.background_color());
- return make<Messages::WindowServer::SetBackgroundColorResponse>();
-}
-
-OwnPtr<Messages::WindowServer::SetWallpaperModeResponse> ClientConnection::handle(const Messages::WindowServer::SetWallpaperMode& message)
-{
- Compositor::the().set_wallpaper_mode(message.mode());
- return make<Messages::WindowServer::SetWallpaperModeResponse>();
-}
-
-OwnPtr<Messages::WindowServer::GetWallpaperResponse> ClientConnection::handle(const Messages::WindowServer::GetWallpaper&)
-{
- return make<Messages::WindowServer::GetWallpaperResponse>(Compositor::the().wallpaper_path());
-}
-
-OwnPtr<Messages::WindowServer::SetResolutionResponse> ClientConnection::handle(const Messages::WindowServer::SetResolution& message)
-{
- return make<Messages::WindowServer::SetResolutionResponse>(WindowManager::the().set_resolution(message.resolution().width(), message.resolution().height()), WindowManager::the().resolution());
-}
-
-OwnPtr<Messages::WindowServer::SetWindowTitleResponse> ClientConnection::handle(const Messages::WindowServer::SetWindowTitle& message)
-{
- auto it = m_windows.find(message.window_id());
- if (it == m_windows.end()) {
- did_misbehave("SetWindowTitle: Bad window ID");
- return nullptr;
- }
- it->value->set_title(message.title());
- return make<Messages::WindowServer::SetWindowTitleResponse>();
-}
-
-OwnPtr<Messages::WindowServer::GetWindowTitleResponse> ClientConnection::handle(const Messages::WindowServer::GetWindowTitle& message)
-{
- auto it = m_windows.find(message.window_id());
- if (it == m_windows.end()) {
- did_misbehave("GetWindowTitle: Bad window ID");
- return nullptr;
- }
- return make<Messages::WindowServer::GetWindowTitleResponse>(it->value->title());
-}
-
-OwnPtr<Messages::WindowServer::SetWindowIconBitmapResponse> ClientConnection::handle(const Messages::WindowServer::SetWindowIconBitmap& message)
-{
- auto it = m_windows.find(message.window_id());
- if (it == m_windows.end()) {
- did_misbehave("SetWindowIconBitmap: Bad window ID");
- return nullptr;
- }
- auto& window = *(*it).value;
-
- if (message.icon().is_valid()) {
- window.set_icon(*message.icon().bitmap());
- } else {
- window.set_default_icon();
- }
-
- window.frame().invalidate_title_bar();
- WindowManager::the().tell_wm_listeners_window_icon_changed(window);
- return make<Messages::WindowServer::SetWindowIconBitmapResponse>();
-}
-
-OwnPtr<Messages::WindowServer::SetWindowRectResponse> ClientConnection::handle(const Messages::WindowServer::SetWindowRect& message)
-{
- int window_id = message.window_id();
- auto it = m_windows.find(window_id);
- if (it == m_windows.end()) {
- did_misbehave("SetWindowRect: Bad window ID");
- return nullptr;
- }
- auto& window = *(*it).value;
- if (window.is_fullscreen()) {
- dbg() << "ClientConnection: Ignoring SetWindowRect request for fullscreen window";
- return nullptr;
- }
- auto normalized_rect = normalize_window_rect(message.rect(), window.type());
- window.set_rect(normalized_rect);
- window.request_update(normalized_rect);
- return make<Messages::WindowServer::SetWindowRectResponse>(normalized_rect);
-}
-
-OwnPtr<Messages::WindowServer::GetWindowRectResponse> ClientConnection::handle(const Messages::WindowServer::GetWindowRect& message)
-{
- int window_id = message.window_id();
- auto it = m_windows.find(window_id);
- if (it == m_windows.end()) {
- did_misbehave("GetWindowRect: Bad window ID");
- return nullptr;
- }
- return make<Messages::WindowServer::GetWindowRectResponse>(it->value->rect());
-}
-
-OwnPtr<Messages::WindowServer::SetClipboardContentsResponse> ClientConnection::handle(const Messages::WindowServer::SetClipboardContents& message)
-{
- auto shared_buffer = SharedBuffer::create_from_shbuf_id(message.shbuf_id());
- if (!shared_buffer) {
- did_misbehave("SetClipboardContents: Bad shared buffer ID");
- return nullptr;
- }
- Clipboard::the().set_data(*shared_buffer, message.content_size(), message.content_type());
- return make<Messages::WindowServer::SetClipboardContentsResponse>();
-}
-
-OwnPtr<Messages::WindowServer::GetClipboardContentsResponse> ClientConnection::handle(const Messages::WindowServer::GetClipboardContents&)
-{
- auto& clipboard = Clipboard::the();
-
- i32 shbuf_id = -1;
- if (clipboard.size()) {
- // FIXME: Optimize case where an app is copy/pasting within itself.
- // We can just reuse the SharedBuffer then, since it will have the same peer PID.
- // It would be even nicer if a SharedBuffer could have an arbitrary number of clients..
- RefPtr<SharedBuffer> shared_buffer = SharedBuffer::create_with_size(clipboard.size());
- ASSERT(shared_buffer);
- memcpy(shared_buffer->data(), clipboard.data(), clipboard.size());
- shared_buffer->seal();
- shared_buffer->share_with(client_pid());
- shbuf_id = shared_buffer->shbuf_id();
-
- // FIXME: This is a workaround for the fact that SharedBuffers will go away if neither side is retaining them.
- // After we respond to GetClipboardContents, we have to wait for the client to ref the buffer on his side.
- m_last_sent_clipboard_content = move(shared_buffer);
- }
- 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.frameless(), message.resizable(), message.fullscreen());
-
- 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;
- }
- if (parent_window->window_id() == window_id) {
- did_misbehave("CreateWindow trying to make a window with itself as parent");
- 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()) {
- auto normalized_rect = normalize_window_rect(message.rect(), window->type());
- window->set_rect(normalized_rect);
- }
- if (window->type() == WindowType::Desktop) {
- window->set_rect(WindowManager::the().desktop_rect());
- window->recalculate_rect();
- }
- window->set_opacity(message.opacity());
- window->set_size_increment(message.size_increment());
- window->set_base_size(message.base_size());
- window->invalidate();
- if (window->type() == WindowType::MenuApplet)
- AppletManager::the().add_applet(*window);
- m_windows.set(window_id, move(window));
- return make<Messages::WindowServer::CreateWindowResponse>(window_id);
-}
-
-void ClientConnection::destroy_window(Window& window, Vector<i32>& destroyed_window_ids)
-{
- for (auto& child_window : window.child_windows()) {
- if (!child_window)
- continue;
- ASSERT(child_window->window_id() != window.window_id());
- destroy_window(*child_window, destroyed_window_ids);
- }
-
- destroyed_window_ids.append(window.window_id());
-
- if (window.type() == WindowType::MenuApplet)
- AppletManager::the().remove_applet(window);
-
- WindowManager::the().invalidate(window);
- remove_child(window);
- m_windows.remove(window.window_id());
-}
-
-OwnPtr<Messages::WindowServer::DestroyWindowResponse> ClientConnection::handle(const Messages::WindowServer::DestroyWindow& message)
-{
- auto it = m_windows.find(message.window_id());
- if (it == m_windows.end()) {
- did_misbehave("DestroyWindow: Bad window ID");
- return nullptr;
- }
- auto& window = *(*it).value;
- Vector<i32> destroyed_window_ids;
- destroy_window(window, destroyed_window_ids);
- return make<Messages::WindowServer::DestroyWindowResponse>(destroyed_window_ids);
-}
-
-void ClientConnection::post_paint_message(Window& window, bool ignore_occlusion)
-{
- auto rect_set = window.take_pending_paint_rects();
- if (window.is_minimized() || (!ignore_occlusion && window.is_occluded()))
- return;
-
- post_message(Messages::WindowClient::Paint(window.window_id(), window.size(), rect_set.rects()));
-}
-
-void ClientConnection::handle(const Messages::WindowServer::InvalidateRect& message)
-{
- auto it = m_windows.find(message.window_id());
- if (it == m_windows.end()) {
- did_misbehave("InvalidateRect: Bad window ID");
- return;
- }
- auto& window = *(*it).value;
- for (size_t i = 0; i < message.rects().size(); ++i)
- window.request_update(message.rects()[i].intersected({ {}, window.size() }), message.ignore_occlusion());
-}
-
-void ClientConnection::handle(const Messages::WindowServer::DidFinishPainting& message)
-{
- int window_id = message.window_id();
- auto it = m_windows.find(window_id);
- if (it == m_windows.end()) {
- did_misbehave("DidFinishPainting: Bad window ID");
- return;
- }
- auto& window = *(*it).value;
- for (auto& rect : message.rects())
- WindowManager::the().invalidate(window, rect);
-
- WindowSwitcher::the().refresh_if_needed();
-}
-
-OwnPtr<Messages::WindowServer::SetWindowBackingStoreResponse> ClientConnection::handle(const Messages::WindowServer::SetWindowBackingStore& message)
-{
- int window_id = message.window_id();
- auto it = m_windows.find(window_id);
- if (it == m_windows.end()) {
- did_misbehave("SetWindowBackingStore: Bad window ID");
- return nullptr;
- }
- auto& window = *(*it).value;
- if (window.last_backing_store() && window.last_backing_store()->shbuf_id() == message.shbuf_id()) {
- window.swap_backing_stores();
- } else {
- auto shared_buffer = SharedBuffer::create_from_shbuf_id(message.shbuf_id());
- if (!shared_buffer)
- return make<Messages::WindowServer::SetWindowBackingStoreResponse>();
- auto backing_store = Gfx::Bitmap::create_with_shared_buffer(
- message.has_alpha_channel() ? Gfx::BitmapFormat::RGBA32 : Gfx::BitmapFormat::RGB32,
- *shared_buffer,
- message.size());
- window.set_backing_store(move(backing_store));
- }
-
- if (message.flush_immediately())
- window.invalidate();
-
- return make<Messages::WindowServer::SetWindowBackingStoreResponse>();
-}
-
-OwnPtr<Messages::WindowServer::SetGlobalCursorTrackingResponse> ClientConnection::handle(const Messages::WindowServer::SetGlobalCursorTracking& message)
-{
- int window_id = message.window_id();
- auto it = m_windows.find(window_id);
- if (it == m_windows.end()) {
- did_misbehave("SetGlobalCursorTracking: Bad window ID");
- return nullptr;
- }
- it->value->set_global_cursor_tracking_enabled(message.enabled());
- return make<Messages::WindowServer::SetGlobalCursorTrackingResponse>();
-}
-
-OwnPtr<Messages::WindowServer::SetWindowOverrideCursorResponse> ClientConnection::handle(const Messages::WindowServer::SetWindowOverrideCursor& message)
-{
- auto it = m_windows.find(message.window_id());
- if (it == m_windows.end()) {
- did_misbehave("SetWindowOverrideCursor: Bad window ID");
- return nullptr;
- }
- auto& window = *(*it).value;
- window.set_override_cursor(Cursor::create((StandardCursor)message.cursor_type()));
- return make<Messages::WindowServer::SetWindowOverrideCursorResponse>();
-}
-
-OwnPtr<Messages::WindowServer::SetWindowHasAlphaChannelResponse> ClientConnection::handle(const Messages::WindowServer::SetWindowHasAlphaChannel& message)
-{
- auto it = m_windows.find(message.window_id());
- if (it == m_windows.end()) {
- did_misbehave("SetWindowHasAlphaChannel: Bad window ID");
- return nullptr;
- }
- it->value->set_has_alpha_channel(message.has_alpha_channel());
- return make<Messages::WindowServer::SetWindowHasAlphaChannelResponse>();
-}
-
-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;
- window.set_minimized(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;
- window.popup_window_menu(message.screen_position());
-}
-
-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;
- window.set_minimized(message.minimized());
-}
-
-OwnPtr<Messages::WindowServer::GreetResponse> ClientConnection::handle(const Messages::WindowServer::Greet&)
-{
- return make<Messages::WindowServer::GreetResponse>(client_id(), Screen::the().rect(), Gfx::current_system_theme_buffer_id());
-}
-
-bool ClientConnection::is_showing_modal_window() const
-{
- for (auto& it : m_windows) {
- auto& window = *it.value;
- if (window.is_visible() && window.is_modal())
- return true;
- }
- return false;
-}
-
-void ClientConnection::handle(const Messages::WindowServer::WM_SetWindowTaskbarRect& message)
-{
- auto* client = ClientConnection::from_client_id(message.client_id());
- if (!client) {
- did_misbehave("WM_SetWindowTaskbarRect: Bad client ID");
- return;
- }
- auto it = client->m_windows.find(message.window_id());
- if (it == client->m_windows.end()) {
- did_misbehave("WM_SetWindowTaskbarRect: Bad window ID");
- 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();
- if (wm.dnd_client())
- return make<Messages::WindowServer::StartDragResponse>(false);
-
- RefPtr<Gfx::Bitmap> bitmap;
- if (message.bitmap_id() != -1) {
- auto shared_buffer = SharedBuffer::create_from_shbuf_id(message.bitmap_id());
- ssize_t size_in_bytes = message.bitmap_size().area() * sizeof(Gfx::RGBA32);
- if (size_in_bytes > shared_buffer->size()) {
- did_misbehave("SetAppletBackingStore: Shared buffer is too small for applet size");
- return nullptr;
- }
- bitmap = Gfx::Bitmap::create_with_shared_buffer(Gfx::BitmapFormat::RGBA32, *shared_buffer, message.bitmap_size());
- }
-
- wm.start_dnd_drag(*this, message.text(), bitmap, message.data_type(), message.data());
- return make<Messages::WindowServer::StartDragResponse>(true);
-}
-
-OwnPtr<Messages::WindowServer::SetSystemMenuResponse> ClientConnection::handle(const Messages::WindowServer::SetSystemMenu& message)
-{
- auto it = m_menus.find(message.menu_id());
- if (it == m_menus.end()) {
- did_misbehave("SetSystemMenu called with invalid menu ID");
- return nullptr;
- }
-
- auto& menu = it->value;
- MenuManager::the().set_system_menu(menu);
- return make<Messages::WindowServer::SetSystemMenuResponse>();
-}
-
-OwnPtr<Messages::WindowServer::SetSystemThemeResponse> ClientConnection::handle(const Messages::WindowServer::SetSystemTheme& message)
-{
- bool success = WindowManager::the().update_theme(message.theme_path(), message.theme_name());
- return make<Messages::WindowServer::SetSystemThemeResponse>(success);
-}
-
-OwnPtr<Messages::WindowServer::GetSystemThemeResponse> ClientConnection::handle(const Messages::WindowServer::GetSystemTheme&)
-{
- auto wm_config = Core::ConfigFile::open("/etc/WindowServer/WindowServer.ini");
- auto name = wm_config->read_entry("Theme", "Name");
- return make<Messages::WindowServer::GetSystemThemeResponse>(name);
-}
-
-void ClientConnection::boost()
-{
- // FIXME: Re-enable this when we have a solution for boosting.
-#if 0
- if (set_process_boost(client_pid(), 10) < 0)
- perror("boost: set_process_boost");
-#endif
-}
-
-void ClientConnection::deboost()
-{
- // FIXME: Re-enable this when we have a solution for boosting.
-#if 0
- if (set_process_boost(client_pid(), 0) < 0)
- perror("deboost: set_process_boost");
-#endif
-}
-
-OwnPtr<Messages::WindowServer::SetWindowBaseSizeAndSizeIncrementResponse> ClientConnection::handle(const Messages::WindowServer::SetWindowBaseSizeAndSizeIncrement& message)
-{
- auto it = m_windows.find(message.window_id());
- if (it == m_windows.end()) {
- did_misbehave("SetWindowBaseSizeAndSizeIncrementResponse: Bad window ID");
- return nullptr;
- }
-
- auto& window = *it->value;
- window.set_base_size(message.base_size());
- window.set_size_increment(message.size_increment());
-
- return make<Messages::WindowServer::SetWindowBaseSizeAndSizeIncrementResponse>();
-}
-
-void ClientConnection::handle(const Messages::WindowServer::EnableDisplayLink&)
-{
- if (m_has_display_link)
- return;
- m_has_display_link = true;
- Compositor::the().increment_display_link_count({});
-}
-
-void ClientConnection::handle(const Messages::WindowServer::DisableDisplayLink&)
-{
- if (!m_has_display_link)
- return;
- m_has_display_link = false;
- Compositor::the().decrement_display_link_count({});
-}
-
-void ClientConnection::notify_display_link(Badge<Compositor>)
-{
- if (!m_has_display_link)
- return;
-
- post_message(Messages::WindowClient::DisplayLinkNotification());
-}
-
-}
diff --git a/Servers/WindowServer/ClientConnection.h b/Servers/WindowServer/ClientConnection.h
deleted file mode 100644
index 92c2f2fa08..0000000000
--- a/Servers/WindowServer/ClientConnection.h
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * 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/Badge.h>
-#include <AK/Function.h>
-#include <AK/HashMap.h>
-#include <AK/OwnPtr.h>
-#include <AK/WeakPtr.h>
-#include <LibCore/Object.h>
-#include <LibGfx/Bitmap.h>
-#include <LibIPC/ClientConnection.h>
-#include <WindowServer/Event.h>
-#include <WindowServer/WindowServerEndpoint.h>
-
-namespace WindowServer {
-
-class Compositor;
-class Window;
-class Menu;
-class MenuBar;
-
-class ClientConnection final
- : public IPC::ClientConnection<WindowServerEndpoint>
- , public WindowServerEndpoint {
- C_OBJECT(ClientConnection)
-public:
- ~ClientConnection() override;
- virtual void die() override;
-
- void boost();
- void deboost();
-
- static ClientConnection* from_client_id(int client_id);
- static void for_each_client(Function<void(ClientConnection&)>);
-
- MenuBar* app_menubar() { return m_app_menubar.ptr(); }
-
- bool is_showing_modal_window() const;
-
- void notify_about_new_screen_rect(const Gfx::Rect&);
- void notify_about_clipboard_contents_changed();
- void post_paint_message(Window&, bool ignore_occlusion = false);
-
- Menu* find_menu_by_id(int menu_id)
- {
- auto menu = m_menus.get(menu_id);
- if (!menu.has_value())
- return nullptr;
- return const_cast<Menu*>(menu.value().ptr());
- }
-
- void notify_display_link(Badge<Compositor>);
-
-private:
- explicit ClientConnection(Core::LocalSocket&, int client_id);
-
- void destroy_window(Window&, Vector<i32>& destroyed_window_ids);
-
- virtual OwnPtr<Messages::WindowServer::GreetResponse> handle(const Messages::WindowServer::Greet&) override;
- virtual OwnPtr<Messages::WindowServer::CreateMenubarResponse> handle(const Messages::WindowServer::CreateMenubar&) override;
- virtual OwnPtr<Messages::WindowServer::DestroyMenubarResponse> handle(const Messages::WindowServer::DestroyMenubar&) override;
- virtual OwnPtr<Messages::WindowServer::CreateMenuResponse> handle(const Messages::WindowServer::CreateMenu&) override;
- virtual OwnPtr<Messages::WindowServer::DestroyMenuResponse> handle(const Messages::WindowServer::DestroyMenu&) override;
- virtual OwnPtr<Messages::WindowServer::AddMenuToMenubarResponse> handle(const Messages::WindowServer::AddMenuToMenubar&) override;
- virtual OwnPtr<Messages::WindowServer::SetApplicationMenubarResponse> handle(const Messages::WindowServer::SetApplicationMenubar&) override;
- virtual OwnPtr<Messages::WindowServer::AddMenuItemResponse> handle(const Messages::WindowServer::AddMenuItem&) override;
- virtual OwnPtr<Messages::WindowServer::AddMenuSeparatorResponse> handle(const Messages::WindowServer::AddMenuSeparator&) override;
- virtual OwnPtr<Messages::WindowServer::UpdateMenuItemResponse> handle(const Messages::WindowServer::UpdateMenuItem&) override;
- virtual OwnPtr<Messages::WindowServer::CreateWindowResponse> handle(const Messages::WindowServer::CreateWindow&) override;
- virtual OwnPtr<Messages::WindowServer::DestroyWindowResponse> handle(const Messages::WindowServer::DestroyWindow&) override;
- virtual OwnPtr<Messages::WindowServer::SetWindowTitleResponse> handle(const Messages::WindowServer::SetWindowTitle&) override;
- virtual OwnPtr<Messages::WindowServer::GetWindowTitleResponse> handle(const Messages::WindowServer::GetWindowTitle&) override;
- virtual OwnPtr<Messages::WindowServer::SetWindowRectResponse> handle(const Messages::WindowServer::SetWindowRect&) override;
- virtual OwnPtr<Messages::WindowServer::GetWindowRectResponse> handle(const Messages::WindowServer::GetWindowRect&) override;
- virtual void handle(const Messages::WindowServer::InvalidateRect&) override;
- virtual void handle(const Messages::WindowServer::DidFinishPainting&) override;
- 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 OwnPtr<Messages::WindowServer::GetClipboardContentsResponse> handle(const Messages::WindowServer::GetClipboardContents&) override;
- virtual OwnPtr<Messages::WindowServer::SetClipboardContentsResponse> handle(const Messages::WindowServer::SetClipboardContents&) 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::SetWindowHasAlphaChannelResponse> handle(const Messages::WindowServer::SetWindowHasAlphaChannel&) override;
- virtual OwnPtr<Messages::WindowServer::MoveWindowToFrontResponse> handle(const Messages::WindowServer::MoveWindowToFront&) override;
- virtual OwnPtr<Messages::WindowServer::SetFullscreenResponse> handle(const Messages::WindowServer::SetFullscreen&) override;
- virtual void handle(const Messages::WindowServer::AsyncSetWallpaper&) override;
- virtual OwnPtr<Messages::WindowServer::SetBackgroundColorResponse> handle(const Messages::WindowServer::SetBackgroundColor&) override;
- virtual OwnPtr<Messages::WindowServer::SetWallpaperModeResponse> handle(const Messages::WindowServer::SetWallpaperMode&) override;
- virtual OwnPtr<Messages::WindowServer::GetWallpaperResponse> handle(const Messages::WindowServer::GetWallpaper&) override;
- virtual OwnPtr<Messages::WindowServer::SetResolutionResponse> handle(const Messages::WindowServer::SetResolution&) override;
- virtual OwnPtr<Messages::WindowServer::SetWindowOverrideCursorResponse> handle(const Messages::WindowServer::SetWindowOverrideCursor&) override;
- 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::SetSystemMenuResponse> handle(const Messages::WindowServer::SetSystemMenu&) override;
- virtual OwnPtr<Messages::WindowServer::SetSystemThemeResponse> handle(const Messages::WindowServer::SetSystemTheme&) override;
- virtual OwnPtr<Messages::WindowServer::GetSystemThemeResponse> handle(const Messages::WindowServer::GetSystemTheme&) override;
- virtual OwnPtr<Messages::WindowServer::SetWindowBaseSizeAndSizeIncrementResponse> handle(const Messages::WindowServer::SetWindowBaseSizeAndSizeIncrement&) override;
- 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;
- WeakPtr<MenuBar> m_app_menubar;
-
- int m_next_menubar_id { 10000 };
- int m_next_menu_id { 20000 };
- int m_next_window_id { 1982 };
-
- bool m_has_display_link { false };
-
- RefPtr<SharedBuffer> m_last_sent_clipboard_content;
-};
-
-}
diff --git a/Servers/WindowServer/Clipboard.cpp b/Servers/WindowServer/Clipboard.cpp
deleted file mode 100644
index 4d9db8b4bc..0000000000
--- a/Servers/WindowServer/Clipboard.cpp
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * 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/Clipboard.h>
-
-namespace WindowServer {
-
-Clipboard& Clipboard::the()
-{
- static Clipboard* s_the;
- if (!s_the)
- s_the = new Clipboard;
- return *s_the;
-}
-
-Clipboard::Clipboard()
-{
-}
-
-Clipboard::~Clipboard()
-{
-}
-
-const u8* Clipboard::data() const
-{
- if (!m_shared_buffer)
- return nullptr;
- return (const u8*)m_shared_buffer->data();
-}
-
-int Clipboard::size() const
-{
- if (!m_shared_buffer)
- return 0;
- return m_contents_size;
-}
-
-void Clipboard::clear()
-{
- m_shared_buffer = nullptr;
- m_contents_size = 0;
-}
-
-void Clipboard::set_data(NonnullRefPtr<SharedBuffer>&& data, int contents_size, const String& data_type)
-{
- dbg() << "Clipboard::set_data <- [" << data_type << "] " << data->data() << " (" << contents_size << " bytes)";
- m_shared_buffer = move(data);
- m_contents_size = contents_size;
- m_data_type = data_type;
-
- if (on_content_change)
- on_content_change();
-}
-
-}
diff --git a/Servers/WindowServer/Clipboard.h b/Servers/WindowServer/Clipboard.h
deleted file mode 100644
index 6cb9140234..0000000000
--- a/Servers/WindowServer/Clipboard.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * 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/Function.h>
-#include <AK/SharedBuffer.h>
-#include <AK/String.h>
-
-namespace WindowServer {
-
-class Clipboard {
-public:
- static Clipboard& the();
- ~Clipboard();
-
- bool has_data() const
- {
- return m_shared_buffer;
- }
-
- const String& data_type() const { return m_data_type; }
- const u8* data() const;
- int size() const;
-
- void clear();
- void set_data(NonnullRefPtr<SharedBuffer>&&, int contents_size, const String& data_type);
-
- Function<void()> on_content_change;
-
-private:
- Clipboard();
-
- String m_data_type;
- RefPtr<SharedBuffer> m_shared_buffer;
- int m_contents_size { 0 };
-};
-
-}
diff --git a/Servers/WindowServer/Compositor.cpp b/Servers/WindowServer/Compositor.cpp
deleted file mode 100644
index 57f87178df..0000000000
--- a/Servers/WindowServer/Compositor.cpp
+++ /dev/null
@@ -1,507 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * 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 "Compositor.h"
-#include "ClientConnection.h"
-#include "Event.h"
-#include "EventLoop.h"
-#include "Screen.h"
-#include "Window.h"
-#include "WindowManager.h"
-#include <AK/Memory.h>
-#include <LibCore/Timer.h>
-#include <LibGfx/Font.h>
-#include <LibGfx/Painter.h>
-#include <LibThread/BackgroundAction.h>
-
-namespace WindowServer {
-
-Compositor& Compositor::the()
-{
- static Compositor s_the;
- return s_the;
-}
-
-WallpaperMode mode_to_enum(const String& name)
-{
- if (name == "simple")
- return WallpaperMode::Simple;
- if (name == "tile")
- return WallpaperMode::Tile;
- if (name == "center")
- return WallpaperMode::Center;
- if (name == "scaled")
- return WallpaperMode::Scaled;
- return WallpaperMode::Simple;
-}
-
-Compositor::Compositor()
-{
- m_display_link_notify_timer = add<Core::Timer>(
- 1000 / 60, [this] {
- notify_display_links();
- });
- m_display_link_notify_timer->stop();
-
- m_compose_timer = Core::Timer::create_single_shot(
- 1000 / 60,
- [this] {
- compose();
- },
- this);
-
- m_immediate_compose_timer = Core::Timer::create_single_shot(
- 0,
- [this] {
- compose();
- },
- this);
-
- m_screen_can_set_buffer = Screen::the().can_set_buffer();
- init_bitmaps();
-}
-
-void Compositor::init_bitmaps()
-{
- auto& screen = Screen::the();
- auto size = screen.size();
-
- m_front_bitmap = Gfx::Bitmap::create_wrapper(Gfx::BitmapFormat::RGB32, size, screen.pitch(), screen.scanline(0));
-
- if (m_screen_can_set_buffer)
- m_back_bitmap = Gfx::Bitmap::create_wrapper(Gfx::BitmapFormat::RGB32, size, screen.pitch(), screen.scanline(size.height()));
- else
- m_back_bitmap = Gfx::Bitmap::create(Gfx::BitmapFormat::RGB32, size);
-
- m_front_painter = make<Gfx::Painter>(*m_front_bitmap);
- m_back_painter = make<Gfx::Painter>(*m_back_bitmap);
-
- m_buffers_are_flipped = false;
-
- invalidate();
-}
-
-void Compositor::compose()
-{
- auto& wm = WindowManager::the();
- if (m_wallpaper_mode == WallpaperMode::Unchecked)
- m_wallpaper_mode = mode_to_enum(wm.wm_config()->read_entry("Background", "Mode", "simple"));
- auto& ws = Screen::the();
-
- auto dirty_rects = move(m_dirty_rects);
-
- if (dirty_rects.size() == 0) {
- // nothing dirtied since the last compose pass.
- return;
- }
-
- dirty_rects.add(Gfx::Rect::intersection(m_last_geometry_label_rect, Screen::the().rect()));
- dirty_rects.add(Gfx::Rect::intersection(m_last_cursor_rect, Screen::the().rect()));
- dirty_rects.add(Gfx::Rect::intersection(m_last_dnd_rect, Screen::the().rect()));
- dirty_rects.add(Gfx::Rect::intersection(current_cursor_rect(), Screen::the().rect()));
-
- auto any_dirty_rect_intersects_window = [&dirty_rects](const Window& window) {
- auto window_frame_rect = window.frame().rect();
- for (auto& dirty_rect : dirty_rects.rects()) {
- if (dirty_rect.intersects(window_frame_rect))
- return true;
- }
- return false;
- };
-
- Color background_color = wm.palette().desktop_background();
- String background_color_entry = wm.wm_config()->read_entry("Background", "Color", "");
- if (!background_color_entry.is_empty()) {
- background_color = Color::from_string(background_color_entry).value_or(background_color);
- }
-
- // Paint the wallpaper.
- for (auto& dirty_rect : dirty_rects.rects()) {
- if (wm.any_opaque_window_contains_rect(dirty_rect))
- continue;
- // FIXME: If the wallpaper is opaque, no need to fill with color!
- m_back_painter->fill_rect(dirty_rect, background_color);
- if (m_wallpaper) {
- if (m_wallpaper_mode == WallpaperMode::Simple) {
- m_back_painter->blit(dirty_rect.location(), *m_wallpaper, dirty_rect);
- } else if (m_wallpaper_mode == WallpaperMode::Center) {
- Gfx::Point offset { ws.size().width() / 2 - m_wallpaper->size().width() / 2,
- ws.size().height() / 2 - m_wallpaper->size().height() / 2 };
- m_back_painter->blit_offset(dirty_rect.location(), *m_wallpaper,
- dirty_rect, offset);
- } else if (m_wallpaper_mode == WallpaperMode::Tile) {
- m_back_painter->draw_tiled_bitmap(dirty_rect, *m_wallpaper);
- } else if (m_wallpaper_mode == WallpaperMode::Scaled) {
- float hscale = (float)m_wallpaper->size().width() / (float)ws.size().width();
- float vscale = (float)m_wallpaper->size().height() / (float)ws.size().height();
-
- m_back_painter->blit_scaled(dirty_rect, *m_wallpaper, dirty_rect, hscale, vscale);
- } else {
- ASSERT_NOT_REACHED();
- }
- }
- }
-
- auto compose_window = [&](Window& window) -> IterationDecision {
- if (!any_dirty_rect_intersects_window(window))
- return IterationDecision::Continue;
- Gfx::PainterStateSaver saver(*m_back_painter);
- m_back_painter->add_clip_rect(window.frame().rect());
- RefPtr<Gfx::Bitmap> backing_store = window.backing_store();
- for (auto& dirty_rect : dirty_rects.rects()) {
- if (wm.any_opaque_window_above_this_one_contains_rect(window, dirty_rect))
- continue;
- Gfx::PainterStateSaver saver(*m_back_painter);
- m_back_painter->add_clip_rect(dirty_rect);
- if (!backing_store)
- m_back_painter->fill_rect(dirty_rect, wm.palette().window());
- if (!window.is_fullscreen())
- window.frame().paint(*m_back_painter);
- if (!backing_store)
- continue;
-
- // Decide where we would paint this window's backing store.
- // This is subtly different from widow.rect(), because window
- // size may be different from its backing store size. This
- // happens when the window has been resized and the client
- // has not yet attached a new backing store. In this case,
- // we want to try to blit the backing store at the same place
- // it was previously, and fill the rest of the window with its
- // background color.
- Gfx::Rect backing_rect;
- backing_rect.set_size(backing_store->size());
- switch (WindowManager::the().resize_direction_of_window(window)) {
- case ResizeDirection::None:
- case ResizeDirection::Right:
- case ResizeDirection::Down:
- case ResizeDirection::DownRight:
- backing_rect.set_location(window.rect().location());
- break;
- case ResizeDirection::Left:
- case ResizeDirection::Up:
- case ResizeDirection::UpLeft:
- backing_rect.set_right_without_resize(window.rect().right());
- backing_rect.set_bottom_without_resize(window.rect().bottom());
- break;
- case ResizeDirection::UpRight:
- backing_rect.set_left(window.rect().left());
- backing_rect.set_bottom_without_resize(window.rect().bottom());
- break;
- case ResizeDirection::DownLeft:
- backing_rect.set_right_without_resize(window.rect().right());
- backing_rect.set_top(window.rect().top());
- break;
- }
-
- Gfx::Rect dirty_rect_in_backing_coordinates = dirty_rect
- .intersected(window.rect())
- .intersected(backing_rect)
- .translated(-backing_rect.location());
-
- if (dirty_rect_in_backing_coordinates.is_empty())
- continue;
- auto dst = backing_rect.location().translated(dirty_rect_in_backing_coordinates.location());
-
- m_back_painter->blit(dst, *backing_store, dirty_rect_in_backing_coordinates, window.opacity());
- for (auto background_rect : window.rect().shatter(backing_rect))
- m_back_painter->fill_rect(background_rect, wm.palette().window());
- }
- return IterationDecision::Continue;
- };
-
- // Paint the window stack.
- if (auto* fullscreen_window = wm.active_fullscreen_window()) {
- compose_window(*fullscreen_window);
- } else {
- wm.for_each_visible_window_from_back_to_front([&](Window& window) {
- return compose_window(window);
- });
-
- draw_geometry_label();
- }
-
- run_animations();
-
- draw_cursor();
-
- if (m_flash_flush) {
- for (auto& rect : dirty_rects.rects())
- m_front_painter->fill_rect(rect, Color::Yellow);
- }
-
- if (m_screen_can_set_buffer)
- flip_buffers();
-
- for (auto& r : dirty_rects.rects())
- flush(r);
-}
-
-void Compositor::flush(const Gfx::Rect& a_rect)
-{
- auto rect = Gfx::Rect::intersection(a_rect, Screen::the().rect());
-
- Gfx::RGBA32* front_ptr = m_front_bitmap->scanline(rect.y()) + rect.x();
- Gfx::RGBA32* back_ptr = m_back_bitmap->scanline(rect.y()) + rect.x();
- size_t pitch = m_back_bitmap->pitch();
-
- // NOTE: The meaning of a flush depends on whether we can flip buffers or not.
- //
- // If flipping is supported, flushing means that we've flipped, and now we
- // copy the changed bits from the front buffer to the back buffer, to keep
- // them in sync.
- //
- // If flipping is not supported, flushing means that we copy the changed
- // rects from the backing bitmap to the display framebuffer.
-
- Gfx::RGBA32* to_ptr;
- const Gfx::RGBA32* from_ptr;
-
- if (m_screen_can_set_buffer) {
- to_ptr = back_ptr;
- from_ptr = front_ptr;
- } else {
- to_ptr = front_ptr;
- from_ptr = back_ptr;
- }
-
- for (int y = 0; y < rect.height(); ++y) {
- fast_u32_copy(to_ptr, from_ptr, rect.width());
- from_ptr = (const Gfx::RGBA32*)((const u8*)from_ptr + pitch);
- to_ptr = (Gfx::RGBA32*)((u8*)to_ptr + pitch);
- }
-}
-
-void Compositor::invalidate()
-{
- m_dirty_rects.clear_with_capacity();
- invalidate(Screen::the().rect());
-}
-
-void Compositor::invalidate(const Gfx::Rect& a_rect)
-{
- auto rect = Gfx::Rect::intersection(a_rect, Screen::the().rect());
- if (rect.is_empty())
- return;
-
- m_dirty_rects.add(rect);
-
- // We delay composition by a timer interval, but to not affect latency too
- // much, if a pending compose is not already scheduled, we also schedule an
- // immediate compose the next spin of the event loop.
- if (!m_compose_timer->is_active()) {
- m_compose_timer->start();
- m_immediate_compose_timer->start();
- }
-}
-
-bool Compositor::set_background_color(const String& background_color)
-{
- auto& wm = WindowManager::the();
- wm.wm_config()->write_entry("Background", "Color", background_color);
- bool ret_val = wm.wm_config()->sync();
-
- if (ret_val)
- Compositor::invalidate();
-
- return ret_val;
-}
-
-bool Compositor::set_wallpaper_mode(const String& mode)
-{
- auto& wm = WindowManager::the();
- wm.wm_config()->write_entry("Background", "Mode", mode);
- bool ret_val = wm.wm_config()->sync();
-
- if (ret_val) {
- m_wallpaper_mode = mode_to_enum(mode);
- Compositor::invalidate();
- }
-
- return ret_val;
-}
-
-bool Compositor::set_wallpaper(const String& path, Function<void(bool)>&& callback)
-{
- LibThread::BackgroundAction<RefPtr<Gfx::Bitmap>>::create(
- [path] {
- return Gfx::Bitmap::load_from_file(path);
- },
-
- [this, path, callback = move(callback)](RefPtr<Gfx::Bitmap> bitmap) {
- m_wallpaper_path = path;
- m_wallpaper = move(bitmap);
- invalidate();
- callback(true);
- });
- return true;
-}
-
-void Compositor::flip_buffers()
-{
- ASSERT(m_screen_can_set_buffer);
- swap(m_front_bitmap, m_back_bitmap);
- swap(m_front_painter, m_back_painter);
- Screen::the().set_buffer(m_buffers_are_flipped ? 0 : 1);
- m_buffers_are_flipped = !m_buffers_are_flipped;
-}
-
-void Compositor::run_animations()
-{
- static const int minimize_animation_steps = 10;
-
- WindowManager::the().for_each_window([&](Window& window) {
- if (window.in_minimize_animation()) {
- int animation_index = window.minimize_animation_index();
-
- auto from_rect = window.is_minimized() ? window.frame().rect() : window.taskbar_rect();
- auto to_rect = window.is_minimized() ? window.taskbar_rect() : window.frame().rect();
-
- float x_delta_per_step = (float)(from_rect.x() - to_rect.x()) / minimize_animation_steps;
- float y_delta_per_step = (float)(from_rect.y() - to_rect.y()) / minimize_animation_steps;
- float width_delta_per_step = (float)(from_rect.width() - to_rect.width()) / minimize_animation_steps;
- float height_delta_per_step = (float)(from_rect.height() - to_rect.height()) / minimize_animation_steps;
-
- Gfx::Rect rect {
- from_rect.x() - (int)(x_delta_per_step * animation_index),
- from_rect.y() - (int)(y_delta_per_step * animation_index),
- from_rect.width() - (int)(width_delta_per_step * animation_index),
- from_rect.height() - (int)(height_delta_per_step * animation_index)
- };
-
-#ifdef MINIMIZE_ANIMATION_DEBUG
- dbg() << "Minimize animation from " << from_rect << " to " << to_rect << " frame# " << animation_index << " " << rect;
-#endif
-
- m_back_painter->draw_rect(rect, Color::White);
-
- window.step_minimize_animation();
- if (window.minimize_animation_index() >= minimize_animation_steps)
- window.end_minimize_animation();
-
- invalidate(rect);
- }
- return IterationDecision::Continue;
- });
-}
-
-bool Compositor::set_resolution(int desired_width, int desired_height)
-{
- auto screen_rect = Screen::the().rect();
- if (screen_rect.width() == desired_width && screen_rect.height() == desired_height)
- return true;
-
- // Make sure it's impossible to set an invalid resolution
- ASSERT(desired_width >= 640 && desired_height >= 480);
- bool success = Screen::the().set_resolution(desired_width, desired_height);
- init_bitmaps();
- compose();
- return success;
-}
-
-Gfx::Rect Compositor::current_cursor_rect() const
-{
- auto& wm = WindowManager::the();
- return { Screen::the().cursor_location().translated(-wm.active_cursor().hotspot()), wm.active_cursor().size() };
-}
-
-void Compositor::invalidate_cursor()
-{
- auto& wm = WindowManager::the();
- if (wm.dnd_client())
- invalidate(wm.dnd_rect());
- invalidate(current_cursor_rect());
-}
-
-void Compositor::draw_geometry_label()
-{
- auto& wm = WindowManager::the();
- auto* window_being_moved_or_resized = wm.m_move_window ? wm.m_move_window.ptr() : (wm.m_resize_window ? wm.m_resize_window.ptr() : nullptr);
- if (!window_being_moved_or_resized) {
- m_last_geometry_label_rect = {};
- return;
- }
- auto geometry_string = window_being_moved_or_resized->rect().to_string();
- if (!window_being_moved_or_resized->size_increment().is_null()) {
- int width_steps = (window_being_moved_or_resized->width() - window_being_moved_or_resized->base_size().width()) / window_being_moved_or_resized->size_increment().width();
- int height_steps = (window_being_moved_or_resized->height() - window_being_moved_or_resized->base_size().height()) / window_being_moved_or_resized->size_increment().height();
- geometry_string = String::format("%s (%dx%d)", geometry_string.characters(), width_steps, height_steps);
- }
- auto geometry_label_rect = Gfx::Rect { 0, 0, wm.font().width(geometry_string) + 16, wm.font().glyph_height() + 10 };
- geometry_label_rect.center_within(window_being_moved_or_resized->rect());
- m_back_painter->fill_rect(geometry_label_rect, wm.palette().window());
- m_back_painter->draw_rect(geometry_label_rect, wm.palette().threed_shadow2());
- m_back_painter->draw_text(geometry_label_rect, geometry_string, Gfx::TextAlignment::Center, wm.palette().window_text());
- m_last_geometry_label_rect = geometry_label_rect;
-}
-
-void Compositor::draw_cursor()
-{
- auto& wm = WindowManager::the();
- Gfx::Rect cursor_rect = current_cursor_rect();
- m_back_painter->blit(cursor_rect.location(), wm.active_cursor().bitmap(), wm.active_cursor().rect());
-
- if (wm.dnd_client()) {
- auto dnd_rect = wm.dnd_rect();
- m_back_painter->fill_rect(dnd_rect, wm.palette().selection().with_alpha(200));
- if (!wm.dnd_text().is_empty()) {
- auto text_rect = dnd_rect;
- if (wm.dnd_bitmap())
- text_rect.move_by(wm.dnd_bitmap()->width(), 0);
- m_back_painter->draw_text(text_rect, wm.dnd_text(), Gfx::TextAlignment::CenterLeft, wm.palette().selection_text());
- }
- if (wm.dnd_bitmap()) {
- m_back_painter->blit(dnd_rect.top_left(), *wm.dnd_bitmap(), wm.dnd_bitmap()->rect());
- }
- m_last_dnd_rect = dnd_rect;
- } else {
- m_last_dnd_rect = {};
- }
- m_last_cursor_rect = cursor_rect;
-}
-
-void Compositor::notify_display_links()
-{
- ClientConnection::for_each_client([](auto& client) {
- client.notify_display_link({});
- });
-}
-
-void Compositor::increment_display_link_count(Badge<ClientConnection>)
-{
- ++m_display_link_count;
- if (m_display_link_count == 1)
- m_display_link_notify_timer->start();
-}
-
-void Compositor::decrement_display_link_count(Badge<ClientConnection>)
-{
- ASSERT(m_display_link_count);
- --m_display_link_count;
- if (!m_display_link_count)
- m_display_link_notify_timer->stop();
-}
-
-}
diff --git a/Servers/WindowServer/Compositor.h b/Servers/WindowServer/Compositor.h
deleted file mode 100644
index 99778d786c..0000000000
--- a/Servers/WindowServer/Compositor.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * 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/OwnPtr.h>
-#include <AK/RefPtr.h>
-#include <LibCore/Object.h>
-#include <LibGfx/DisjointRectSet.h>
-#include <LibGfx/Forward.h>
-
-namespace WindowServer {
-
-class ClientConnection;
-class Cursor;
-
-enum class WallpaperMode {
- Simple,
- Tile,
- Center,
- Scaled,
- Unchecked
-};
-
-class Compositor final : public Core::Object {
- C_OBJECT(Compositor)
-public:
- static Compositor& the();
-
- void compose();
- void invalidate();
- void invalidate(const Gfx::Rect&);
-
- bool set_resolution(int desired_width, int desired_height);
-
- bool set_background_color(const String& background_color);
-
- bool set_wallpaper_mode(const String& mode);
-
- bool set_wallpaper(const String& path, Function<void(bool)>&& callback);
- String wallpaper_path() const { return m_wallpaper_path; }
-
- void invalidate_cursor();
- Gfx::Rect current_cursor_rect() const;
-
- void increment_display_link_count(Badge<ClientConnection>);
- void decrement_display_link_count(Badge<ClientConnection>);
-
-private:
- Compositor();
- void init_bitmaps();
- void flip_buffers();
- void flush(const Gfx::Rect&);
- void draw_cursor();
- void draw_geometry_label();
- void draw_menubar();
- void run_animations();
- void notify_display_links();
-
- RefPtr<Core::Timer> m_compose_timer;
- RefPtr<Core::Timer> m_immediate_compose_timer;
- bool m_flash_flush { false };
- bool m_buffers_are_flipped { false };
- bool m_screen_can_set_buffer { false };
-
- RefPtr<Gfx::Bitmap> m_front_bitmap;
- RefPtr<Gfx::Bitmap> m_back_bitmap;
- OwnPtr<Gfx::Painter> m_back_painter;
- OwnPtr<Gfx::Painter> m_front_painter;
-
- Gfx::DisjointRectSet m_dirty_rects;
-
- Gfx::Rect m_last_cursor_rect;
- Gfx::Rect m_last_dnd_rect;
- Gfx::Rect m_last_geometry_label_rect;
-
- String m_wallpaper_path;
- WallpaperMode m_wallpaper_mode { WallpaperMode::Unchecked };
- RefPtr<Gfx::Bitmap> m_wallpaper;
-
- RefPtr<Core::Timer> m_display_link_notify_timer;
- size_t m_display_link_count { 0 };
-};
-
-}
diff --git a/Servers/WindowServer/Cursor.cpp b/Servers/WindowServer/Cursor.cpp
deleted file mode 100644
index 42e431f481..0000000000
--- a/Servers/WindowServer/Cursor.cpp
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * 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/Cursor.h>
-#include <WindowServer/WindowManager.h>
-
-namespace WindowServer {
-
-Cursor::Cursor(NonnullRefPtr<Gfx::Bitmap>&& bitmap, const Gfx::Point& hotspot)
- : m_bitmap(move(bitmap))
- , m_hotspot(hotspot)
-{
-}
-
-Cursor::~Cursor()
-{
-}
-
-NonnullRefPtr<Cursor> Cursor::create(NonnullRefPtr<Gfx::Bitmap>&& bitmap)
-{
- return adopt(*new Cursor(move(bitmap), bitmap->rect().center()));
-}
-
-NonnullRefPtr<Cursor> Cursor::create(NonnullRefPtr<Gfx::Bitmap>&& bitmap, const Gfx::Point& hotspot)
-{
- return adopt(*new Cursor(move(bitmap), hotspot));
-}
-
-RefPtr<Cursor> Cursor::create(StandardCursor standard_cursor)
-{
- switch (standard_cursor) {
- case StandardCursor::None:
- return nullptr;
- case StandardCursor::Arrow:
- return WindowManager::the().arrow_cursor();
- case StandardCursor::IBeam:
- return WindowManager::the().i_beam_cursor();
- case StandardCursor::ResizeHorizontal:
- return WindowManager::the().resize_horizontally_cursor();
- case StandardCursor::ResizeVertical:
- return WindowManager::the().resize_vertically_cursor();
- case StandardCursor::ResizeDiagonalTLBR:
- return WindowManager::the().resize_diagonally_tlbr_cursor();
- case StandardCursor::ResizeDiagonalBLTR:
- return WindowManager::the().resize_diagonally_bltr_cursor();
- case StandardCursor::Hand:
- return WindowManager::the().hand_cursor();
- case StandardCursor::Drag:
- return WindowManager::the().drag_cursor();
- }
- ASSERT_NOT_REACHED();
-}
-
-}
diff --git a/Servers/WindowServer/Cursor.h b/Servers/WindowServer/Cursor.h
deleted file mode 100644
index 5173bd86a1..0000000000
--- a/Servers/WindowServer/Cursor.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * 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 <LibGfx/Bitmap.h>
-
-namespace WindowServer {
-
-enum class StandardCursor {
- None = 0,
- Arrow,
- IBeam,
- ResizeHorizontal,
- ResizeVertical,
- ResizeDiagonalTLBR,
- ResizeDiagonalBLTR,
- Hand,
- Drag,
-};
-
-class Cursor : public RefCounted<Cursor> {
-public:
- static NonnullRefPtr<Cursor> create(NonnullRefPtr<Gfx::Bitmap>&&, const Gfx::Point& hotspot);
- static NonnullRefPtr<Cursor> create(NonnullRefPtr<Gfx::Bitmap>&&);
- static RefPtr<Cursor> create(StandardCursor);
- ~Cursor();
-
- Gfx::Point hotspot() const { return m_hotspot; }
- const Gfx::Bitmap& bitmap() const { return *m_bitmap; }
-
- Gfx::Rect rect() const { return m_bitmap->rect(); }
- Gfx::Size size() const { return m_bitmap->size(); }
-
-private:
- Cursor(NonnullRefPtr<Gfx::Bitmap>&&, const Gfx::Point&);
-
- RefPtr<Gfx::Bitmap> m_bitmap;
- Gfx::Point m_hotspot;
-};
-
-}
diff --git a/Servers/WindowServer/Event.h b/Servers/WindowServer/Event.h
deleted file mode 100644
index 48def26519..0000000000
--- a/Servers/WindowServer/Event.h
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * 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/String.h>
-#include <Kernel/KeyCode.h>
-#include <LibCore/Event.h>
-#include <LibGfx/Rect.h>
-#include <WindowServer/Cursor.h>
-#include <WindowServer/WindowType.h>
-
-namespace WindowServer {
-
-class Event : public Core::Event {
-public:
- enum Type {
- Invalid = 3000,
- MouseMove,
- MouseDown,
- MouseDoubleClick,
- MouseUp,
- MouseWheel,
- WindowEntered,
- WindowLeft,
- KeyDown,
- KeyUp,
- WindowActivated,
- WindowDeactivated,
- WindowCloseRequest,
- WindowResized,
- };
-
- Event() {}
- explicit Event(Type type)
- : Core::Event(type)
- {
- }
- virtual ~Event() {}
-
- bool is_mouse_event() const { return type() == MouseMove || type() == MouseDown || type() == MouseDoubleClick || type() == MouseUp || type() == MouseWheel; }
- bool is_key_event() const { return type() == KeyUp || type() == KeyDown; }
-};
-
-enum class MouseButton : u8 {
- None = 0,
- Left = 1,
- Right = 2,
- Middle = 4,
- Back = 8,
- Forward = 16,
-};
-
-class KeyEvent final : public Event {
-public:
- KeyEvent(Type type, int key, char character, u8 modifiers)
- : Event(type)
- , m_key(key)
- , m_character(character)
- , m_modifiers(modifiers)
- {
- }
-
- int key() const { return m_key; }
- bool ctrl() const { return m_modifiers & Mod_Ctrl; }
- bool alt() const { return m_modifiers & Mod_Alt; }
- bool shift() const { return m_modifiers & Mod_Shift; }
- bool logo() const { return m_modifiers & Mod_Logo; }
- u8 modifiers() const { return m_modifiers; }
- char character() const { return m_character; }
-
-private:
- friend class EventLoop;
- friend class Screen;
- int m_key { 0 };
- char m_character { 0 };
- u8 m_modifiers { 0 };
-};
-
-class MouseEvent final : public Event {
-public:
- MouseEvent(Type type, const Gfx::Point& position, unsigned buttons, MouseButton button, unsigned modifiers, int wheel_delta = 0)
- : Event(type)
- , m_position(position)
- , m_buttons(buttons)
- , m_button(button)
- , m_modifiers(modifiers)
- , m_wheel_delta(wheel_delta)
- {
- }
-
- Gfx::Point position() const { return m_position; }
- int x() const { return m_position.x(); }
- int y() const { return m_position.y(); }
- MouseButton button() const { return m_button; }
- unsigned buttons() const { return m_buttons; }
- unsigned modifiers() const { return m_modifiers; }
- int wheel_delta() const { return m_wheel_delta; }
- bool is_drag() const { return m_drag; }
- const String& drag_data_type() const { return m_drag_data_type; }
-
- void set_drag(bool b) { m_drag = b; }
- void set_drag_data_type(const String& drag_data_type) { m_drag_data_type = drag_data_type; }
-
- MouseEvent translated(const Gfx::Point& delta) const { return MouseEvent((Type)type(), m_position.translated(delta), m_buttons, m_button, m_modifiers, m_wheel_delta); }
-
-private:
- Gfx::Point m_position;
- unsigned m_buttons { 0 };
- MouseButton m_button { MouseButton::None };
- unsigned m_modifiers { 0 };
- int m_wheel_delta { 0 };
- bool m_drag { false };
- String m_drag_data_type;
-};
-
-class ResizeEvent final : public Event {
-public:
- ResizeEvent(const Gfx::Rect& old_rect, const Gfx::Rect& rect)
- : Event(Event::WindowResized)
- , m_old_rect(old_rect)
- , m_rect(rect)
- {
- }
-
- Gfx::Rect old_rect() const { return m_old_rect; }
- Gfx::Rect rect() const { return m_rect; }
-
-private:
- Gfx::Rect m_old_rect;
- Gfx::Rect m_rect;
-};
-
-}
diff --git a/Servers/WindowServer/EventLoop.cpp b/Servers/WindowServer/EventLoop.cpp
deleted file mode 100644
index 078794d6f3..0000000000
--- a/Servers/WindowServer/EventLoop.cpp
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * 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 "Clipboard.h"
-#include <Kernel/KeyCode.h>
-#include <Kernel/MousePacket.h>
-#include <LibCore/LocalSocket.h>
-#include <LibCore/Object.h>
-#include <WindowServer/ClientConnection.h>
-#include <WindowServer/Cursor.h>
-#include <WindowServer/Event.h>
-#include <WindowServer/EventLoop.h>
-#include <WindowServer/Screen.h>
-#include <WindowServer/WindowManager.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <sys/select.h>
-#include <sys/socket.h>
-#include <sys/time.h>
-#include <time.h>
-#include <unistd.h>
-
-//#define WSMESSAGELOOP_DEBUG
-
-namespace WindowServer {
-
-EventLoop::EventLoop()
- : m_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();
- ASSERT(ok);
-
- m_server->on_ready_to_accept = [this] {
- auto client_socket = m_server->accept();
- if (!client_socket) {
- dbg() << "WindowServer: accept failed.";
- return;
- }
- static int s_next_client_id = 0;
- int client_id = ++s_next_client_id;
- IPC::new_client_connection<ClientConnection>(*client_socket, client_id);
- };
-
- ASSERT(m_keyboard_fd >= 0);
- ASSERT(m_mouse_fd >= 0);
-
- m_keyboard_notifier = Core::Notifier::construct(m_keyboard_fd, Core::Notifier::Read);
- m_keyboard_notifier->on_ready_to_read = [this] { drain_keyboard(); };
-
- m_mouse_notifier = Core::Notifier::construct(m_mouse_fd, Core::Notifier::Read);
- m_mouse_notifier->on_ready_to_read = [this] { drain_mouse(); };
-
- Clipboard::the().on_content_change = [&] {
- ClientConnection::for_each_client([&](auto& client) {
- client.notify_about_clipboard_contents_changed();
- });
- };
-}
-
-EventLoop::~EventLoop()
-{
-}
-
-void EventLoop::drain_mouse()
-{
- auto& screen = Screen::the();
- MousePacket state;
- state.buttons = screen.mouse_button_state();
- unsigned buttons = state.buttons;
- MousePacket packets[32];
-
- ssize_t nread = read(m_mouse_fd, &packets, sizeof(packets));
- if (nread < 0) {
- perror("EventLoop::drain_mouse read");
- return;
- }
- size_t npackets = nread / sizeof(MousePacket);
- if (!npackets)
- return;
- for (size_t i = 0; i < npackets; ++i) {
- auto& packet = packets[i];
-#ifdef WSMESSAGELOOP_DEBUG
- dbgprintf("EventLoop: Mouse X %d, Y %d, Z %d, relative %d\n", packet.x, packet.y, packet.z, packet.is_relative);
-#endif
- buttons = packet.buttons;
-
- state.is_relative = packet.is_relative;
- if (packet.is_relative) {
- state.x += packet.x;
- state.y -= packet.y;
- state.z += packet.z;
- } else {
- state.x = packet.x;
- state.y = packet.y;
- state.z += packet.z;
- }
-
- if (buttons != state.buttons) {
- state.buttons = buttons;
-#ifdef WSMESSAGELOOP_DEBUG
- dbgprintf("EventLoop: Mouse Button Event\n");
-#endif
- screen.on_receive_mouse_data(state);
- if (state.is_relative) {
- state.x = 0;
- state.y = 0;
- state.z = 0;
- }
- }
- }
- if (state.is_relative && (state.x || state.y || state.z))
- screen.on_receive_mouse_data(state);
- if (!state.is_relative)
- screen.on_receive_mouse_data(state);
-}
-
-void EventLoop::drain_keyboard()
-{
- auto& screen = Screen::the();
- for (;;) {
- ::KeyEvent event;
- ssize_t nread = read(m_keyboard_fd, (u8*)&event, sizeof(::KeyEvent));
- if (nread == 0)
- break;
- ASSERT(nread == sizeof(::KeyEvent));
- screen.on_receive_keyboard_data(event);
- }
-}
-
-}
diff --git a/Servers/WindowServer/EventLoop.h b/Servers/WindowServer/EventLoop.h
deleted file mode 100644
index b476b5e639..0000000000
--- a/Servers/WindowServer/EventLoop.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * 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/ByteBuffer.h>
-#include <LibCore/EventLoop.h>
-#include <LibCore/LocalServer.h>
-#include <LibCore/Notifier.h>
-
-namespace WindowServer {
-
-class ClientConnection;
-
-class EventLoop {
-public:
- EventLoop();
- virtual ~EventLoop();
-
- int exec() { return m_event_loop.exec(); }
-
-private:
- void drain_mouse();
- void drain_keyboard();
-
- Core::EventLoop m_event_loop;
- int m_keyboard_fd { -1 };
- RefPtr<Core::Notifier> m_keyboard_notifier;
- int m_mouse_fd { -1 };
- RefPtr<Core::Notifier> m_mouse_notifier;
- RefPtr<Core::LocalServer> m_server;
-};
-
-}
diff --git a/Servers/WindowServer/Makefile b/Servers/WindowServer/Makefile
deleted file mode 100644
index 064e2bd0f2..0000000000
--- a/Servers/WindowServer/Makefile
+++ /dev/null
@@ -1,38 +0,0 @@
-OBJS = \
- AppletManager.o \
- Button.o \
- ClientConnection.o \
- Clipboard.o \
- Compositor.o \
- Cursor.o \
- EventLoop.o \
- Menu.o \
- MenuBar.o \
- MenuItem.o \
- MenuManager.o \
- Screen.o \
- Window.o \
- WindowFrame.o \
- WindowManager.o \
- WindowSwitcher.o \
- main.o
-
-PROGRAM = WindowServer
-
-LIB_DEPS = Gfx Core Thread Pthread IPC
-
-*.cpp: WindowServerEndpoint.h WindowClientEndpoint.h
-
-WindowServerEndpoint.h: WindowServer.ipc | IPCCOMPILER
- @echo "IPC $<"; $(IPCCOMPILER) $< > $@
-
-WindowClientEndpoint.h: WindowClient.ipc | IPCCOMPILER
- @echo "IPC $<"; $(IPCCOMPILER) $< > $@
-
-EXTRA_CLEAN = WindowServerEndpoint.h WindowClientEndpoint.h
-
-install:
- mkdir -p ../../Root/usr/include/WindowServer/
- cp *.h ../../Root/usr/include/WindowServer/
-
-include ../../Makefile.common
diff --git a/Servers/WindowServer/Menu.cpp b/Servers/WindowServer/Menu.cpp
deleted file mode 100644
index 07c460b9b2..0000000000
--- a/Servers/WindowServer/Menu.cpp
+++ /dev/null
@@ -1,570 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * Copyright (c) 2020, Shannon Booth <shannon.ml.booth@gmail.com>
- * 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 "Menu.h"
-#include "Event.h"
-#include "EventLoop.h"
-#include "MenuItem.h"
-#include "MenuManager.h"
-#include "Screen.h"
-#include "Window.h"
-#include "WindowManager.h"
-#include <LibGfx/Bitmap.h>
-#include <LibGfx/CharacterBitmap.h>
-#include <LibGfx/Font.h>
-#include <LibGfx/Painter.h>
-#include <LibGfx/StylePainter.h>
-#include <LibGfx/Triangle.h>
-#include <WindowServer/ClientConnection.h>
-#include <WindowServer/WindowClientEndpoint.h>
-
-namespace WindowServer {
-
-Menu::Menu(ClientConnection* client, int menu_id, const String& name)
- : Core::Object(client)
- , m_client(client)
- , m_menu_id(menu_id)
- , m_name(move(name))
-{
-}
-
-Menu::~Menu()
-{
-}
-
-void Menu::set_title_font(const Gfx::Font& font)
-{
- m_title_font = &font;
-}
-
-const Gfx::Font& Menu::title_font() const
-{
- return *m_title_font;
-}
-
-const Gfx::Font& Menu::font() const
-{
- return Gfx::Font::default_font();
-}
-
-static const char* s_checked_bitmap_data = {
- " "
- " # "
- " ## "
- " ### "
- " ## ### "
- " ##### "
- " ### "
- " # "
- " "
-};
-
-static const char* s_submenu_arrow_bitmap_data = {
- " "
- " # "
- " ## "
- " ### "
- " #### "
- " ### "
- " ## "
- " # "
- " "
-};
-
-static Gfx::CharacterBitmap* s_checked_bitmap;
-static const int s_checked_bitmap_width = 9;
-static const int s_checked_bitmap_height = 9;
-static const int s_submenu_arrow_bitmap_width = 9;
-static const int s_submenu_arrow_bitmap_height = 9;
-static const int s_item_icon_width = 16;
-static const int s_stripe_width = 23;
-
-int Menu::content_width() const
-{
- int widest_text = 0;
- int widest_shortcut = 0;
- for (auto& item : m_items) {
- if (item.type() != MenuItem::Text)
- continue;
- int text_width = font().width(item.text());
- if (!item.shortcut_text().is_empty()) {
- int shortcut_width = font().width(item.shortcut_text());
- widest_shortcut = max(shortcut_width, widest_shortcut);
- }
- widest_text = max(widest_text, text_width);
- }
-
- int widest_item = widest_text + s_stripe_width;
- if (widest_shortcut)
- widest_item += padding_between_text_and_shortcut() + widest_shortcut;
-
- return max(widest_item, rect_in_menubar().width()) + horizontal_padding() + frame_thickness() * 2;
-}
-
-void Menu::redraw()
-{
- if (!menu_window())
- return;
- draw();
- menu_window()->invalidate();
-}
-
-Window& Menu::ensure_menu_window()
-{
- if (m_menu_window)
- return *m_menu_window;
-
- int width = this->content_width();
-
- Gfx::Point next_item_location(frame_thickness(), frame_thickness());
- for (auto& item : m_items) {
- int height = 0;
- if (item.type() == MenuItem::Text)
- height = item_height();
- else if (item.type() == MenuItem::Separator)
- height = 8;
- item.set_rect({ next_item_location, { width - frame_thickness() * 2, height } });
- next_item_location.move_by(0, height);
- }
-
- int window_height_available = Screen::the().height() - MenuManager::the().menubar_rect().height() - frame_thickness() * 2;
- int max_window_height = (window_height_available / item_height()) * item_height() + frame_thickness() * 2;
- int content_height = m_items.is_empty() ? 0 : (m_items.last().rect().bottom() + 1) + frame_thickness();
- int window_height = min(max_window_height, content_height);
- if (window_height < content_height) {
- m_scrollable = true;
- m_max_scroll_offset = item_count() - window_height / item_height() + 2;
- }
-
- auto window = Window::construct(*this, WindowType::Menu);
- window->set_rect(0, 0, width, window_height);
- m_menu_window = move(window);
- draw();
-
- return *m_menu_window;
-}
-
-int Menu::visible_item_count() const
-{
- if (!is_scrollable())
- return m_items.size();
- ASSERT(m_menu_window);
- // Make space for up/down arrow indicators
- return m_menu_window->height() / item_height() - 2;
-}
-
-void Menu::draw()
-{
- auto palette = WindowManager::the().palette();
- m_theme_index_at_last_paint = MenuManager::the().theme_index();
-
- ASSERT(menu_window());
- ASSERT(menu_window()->backing_store());
- Gfx::Painter painter(*menu_window()->backing_store());
-
- Gfx::Rect rect { {}, menu_window()->size() };
- Gfx::StylePainter::paint_window_frame(painter, rect, palette);
- painter.fill_rect(rect.shrunken(6, 6), palette.menu_base());
- int width = this->content_width();
-
- if (!s_checked_bitmap)
- s_checked_bitmap = &Gfx::CharacterBitmap::create_from_ascii(s_checked_bitmap_data, s_checked_bitmap_width, s_checked_bitmap_height).leak_ref();
-
- bool has_checkable_items = false;
- bool has_items_with_icon = false;
- for (auto& item : m_items) {
- has_checkable_items = has_checkable_items | item.is_checkable();
- has_items_with_icon = has_items_with_icon | !!item.icon();
- }
-
- Gfx::Rect stripe_rect { frame_thickness(), frame_thickness(), s_stripe_width, menu_window()->height() - frame_thickness() * 2 };
- painter.fill_rect(stripe_rect, palette.menu_stripe());
- painter.draw_line(stripe_rect.top_right(), stripe_rect.bottom_right(), palette.menu_stripe().darkened());
-
- int visible_item_count = this->visible_item_count();
-
- if (is_scrollable()) {
- bool can_go_up = m_scroll_offset > 0;
- bool can_go_down = m_scroll_offset < m_max_scroll_offset;
- Gfx::Rect up_indicator_rect { frame_thickness(), frame_thickness(), content_width(), item_height() };
- painter.draw_text(up_indicator_rect, "\xc3\xb6", Gfx::TextAlignment::Center, can_go_up ? palette.menu_base_text() : palette.color(ColorRole::DisabledText));
- Gfx::Rect down_indicator_rect { frame_thickness(), menu_window()->height() - item_height() - frame_thickness(), content_width(), item_height() };
- painter.draw_text(down_indicator_rect, "\xc3\xb7", Gfx::TextAlignment::Center, can_go_down ? palette.menu_base_text() : palette.color(ColorRole::DisabledText));
- }
-
- for (int i = 0; i < visible_item_count; ++i) {
- auto& item = m_items.at(m_scroll_offset + i);
- if (item.type() == MenuItem::Text) {
- Color text_color = palette.menu_base_text();
- if (&item == hovered_item() && item.is_enabled()) {
- painter.fill_rect(item.rect(), palette.menu_selection());
- painter.draw_rect(item.rect(), palette.menu_selection().darkened());
- text_color = palette.menu_selection_text();
- } else if (!item.is_enabled()) {
- text_color = Color::MidGray;
- }
- Gfx::Rect text_rect = item.rect().translated(stripe_rect.width() + 6, 0);
- if (item.is_checkable()) {
- if (item.is_exclusive()) {
- Gfx::Rect radio_rect { item.rect().x() + 5, 0, 12, 12 };
- radio_rect.center_vertically_within(text_rect);
- Gfx::StylePainter::paint_radio_button(painter, radio_rect, palette, item.is_checked(), false);
- } else {
- Gfx::Rect checkmark_rect { item.rect().x() + 7, 0, s_checked_bitmap_width, s_checked_bitmap_height };
- checkmark_rect.center_vertically_within(text_rect);
- Gfx::Rect checkbox_rect = checkmark_rect.inflated(4, 4);
- painter.fill_rect(checkbox_rect, palette.base());
- Gfx::StylePainter::paint_frame(painter, checkbox_rect, palette, Gfx::FrameShape::Container, Gfx::FrameShadow::Sunken, 2);
- if (item.is_checked()) {
- painter.draw_bitmap(checkmark_rect.location(), *s_checked_bitmap, palette.button_text());
- }
- }
- } else if (item.icon()) {
- Gfx::Rect icon_rect { item.rect().x() + 3, 0, s_item_icon_width, s_item_icon_width };
- icon_rect.center_vertically_within(text_rect);
- painter.blit(icon_rect.location(), *item.icon(), item.icon()->rect());
- }
- painter.draw_text(text_rect, item.text(), Gfx::TextAlignment::CenterLeft, text_color);
- if (!item.shortcut_text().is_empty()) {
- painter.draw_text(item.rect().translated(-right_padding(), 0), item.shortcut_text(), Gfx::TextAlignment::CenterRight, text_color);
- }
- if (item.is_submenu()) {
- static auto& submenu_arrow_bitmap = Gfx::CharacterBitmap::create_from_ascii(s_submenu_arrow_bitmap_data, s_submenu_arrow_bitmap_width, s_submenu_arrow_bitmap_height).leak_ref();
- Gfx::Rect submenu_arrow_rect {
- item.rect().right() - s_submenu_arrow_bitmap_width - 2,
- 0,
- s_submenu_arrow_bitmap_width,
- s_submenu_arrow_bitmap_height
- };
- submenu_arrow_rect.center_vertically_within(item.rect());
- painter.draw_bitmap(submenu_arrow_rect.location(), submenu_arrow_bitmap, text_color);
- }
- } else if (item.type() == MenuItem::Separator) {
- Gfx::Point p1(item.rect().translated(stripe_rect.width() + 4, 0).x(), item.rect().center().y() - 1);
- Gfx::Point p2(width - 7, item.rect().center().y() - 1);
- painter.draw_line(p1, p2, palette.threed_shadow1());
- painter.draw_line(p1.translated(0, 1), p2.translated(0, 1), palette.threed_highlight());
- }
- }
-}
-
-MenuItem* Menu::hovered_item() const
-{
- if (m_hovered_item_index == -1)
- return nullptr;
- return const_cast<MenuItem*>(&item(m_hovered_item_index));
-}
-
-void Menu::update_for_new_hovered_item()
-{
- if (hovered_item() && hovered_item()->is_submenu()) {
- MenuManager::the().close_everyone_not_in_lineage(*hovered_item()->submenu());
- hovered_item()->submenu()->popup(hovered_item()->rect().top_right().translated(menu_window()->rect().location()), true);
- } else {
- MenuManager::the().close_everyone_not_in_lineage(*this);
- MenuManager::the().set_current_menu(this);
- menu_window()->set_visible(true);
- }
- redraw();
-}
-
-void Menu::open_hovered_item()
-{
- ASSERT(menu_window());
- ASSERT(menu_window()->is_visible());
- if (!hovered_item())
- return;
- if (hovered_item()->is_enabled())
- did_activate(*hovered_item());
- clear_hovered_item();
-}
-
-void Menu::descend_into_submenu_at_hovered_item()
-{
- ASSERT(hovered_item());
- ASSERT(hovered_item()->is_submenu());
- auto submenu = hovered_item()->submenu();
- submenu->m_hovered_item_index = 0;
- ASSERT(submenu->hovered_item()->type() != MenuItem::Separator);
- submenu->update_for_new_hovered_item();
- m_in_submenu = true;
-}
-
-void Menu::handle_mouse_move_event(const MouseEvent& mouse_event)
-{
- ASSERT(menu_window());
- if (hovered_item() && hovered_item()->is_submenu()) {
-
- auto item = *hovered_item();
- auto submenu_top_left = item.rect().location() + Gfx::Point { item.rect().width(), 0 };
- auto submenu_bottom_left = submenu_top_left + Gfx::Point { 0, item.submenu()->menu_window()->height() };
-
- auto safe_hover_triangle = Gfx::Triangle { m_last_position_in_hover, submenu_top_left, submenu_bottom_left };
- m_last_position_in_hover = mouse_event.position();
-
- // Don't update the hovered item if mouse is moving towards a submenu
- if (safe_hover_triangle.contains(mouse_event.position()))
- return;
- }
-
- int index = item_index_at(mouse_event.position());
- if (m_hovered_item_index == index)
- return;
- m_hovered_item_index = index;
-
- // FIXME: Tell parent menu (if it exists) that it is currently in a submenu
- m_in_submenu = false;
- update_for_new_hovered_item();
- return;
-}
-
-void Menu::event(Core::Event& event)
-{
- if (event.type() == Event::MouseMove) {
- handle_mouse_move_event(static_cast<const MouseEvent&>(event));
- return;
- }
-
- if (event.type() == Event::MouseUp) {
- open_hovered_item();
- return;
- }
-
- if (event.type() == Event::MouseWheel && is_scrollable()) {
- ASSERT(menu_window());
- auto& mouse_event = static_cast<const MouseEvent&>(event);
- m_scroll_offset += mouse_event.wheel_delta();
- m_scroll_offset = clamp(m_scroll_offset, 0, m_max_scroll_offset);
-
- int index = item_index_at(mouse_event.position());
- if (m_hovered_item_index == index)
- return;
-
- m_hovered_item_index = index;
- update_for_new_hovered_item();
- return;
- }
-
- if (event.type() == Event::KeyDown) {
- auto key = static_cast<KeyEvent&>(event).key();
-
- if (!(key == Key_Up || key == Key_Down || key == Key_Left || key == Key_Right || key == Key_Return))
- return;
-
- ASSERT(menu_window());
- ASSERT(menu_window()->is_visible());
-
- // Default to the first item on key press if one has not been selected yet
- if (!hovered_item()) {
- m_hovered_item_index = 0;
- update_for_new_hovered_item();
- return;
- }
-
- // Pass the event for the submenu that we are currently in to handle
- if (m_in_submenu && key != Key_Left) {
- ASSERT(hovered_item()->is_submenu());
- hovered_item()->submenu()->dispatch_event(event);
- return;
- }
-
- if (key == Key_Return) {
- if (!hovered_item()->is_enabled())
- return;
- if (hovered_item()->is_submenu())
- descend_into_submenu_at_hovered_item();
- else
- open_hovered_item();
- return;
- }
-
- if (key == Key_Up) {
- ASSERT(m_items.at(0).type() != MenuItem::Separator);
-
- if (is_scrollable() && m_hovered_item_index == 0)
- return;
-
- auto original_index = m_hovered_item_index;
- do {
- if (m_hovered_item_index == 0)
- m_hovered_item_index = m_items.size() - 1;
- else
- --m_hovered_item_index;
- if (m_hovered_item_index == original_index)
- return;
- } while (hovered_item()->type() == MenuItem::Separator || !hovered_item()->is_enabled());
-
- ASSERT(m_hovered_item_index >= 0 && m_hovered_item_index <= static_cast<int>(m_items.size()) - 1);
-
- if (is_scrollable() && m_hovered_item_index < m_scroll_offset)
- --m_scroll_offset;
-
- update_for_new_hovered_item();
- return;
- }
-
- if (key == Key_Down) {
- ASSERT(m_items.at(0).type() != MenuItem::Separator);
-
- if (is_scrollable() && m_hovered_item_index == static_cast<int>(m_items.size()) - 1)
- return;
-
- auto original_index = m_hovered_item_index;
- do {
- if (m_hovered_item_index == static_cast<int>(m_items.size()) - 1)
- m_hovered_item_index = 0;
- else
- ++m_hovered_item_index;
- if (m_hovered_item_index == original_index)
- return;
- } while (hovered_item()->type() == MenuItem::Separator || !hovered_item()->is_enabled());
-
- ASSERT(m_hovered_item_index >= 0 && m_hovered_item_index <= static_cast<int>(m_items.size()) - 1);
-
- if (is_scrollable() && m_hovered_item_index >= (m_scroll_offset + visible_item_count()))
- ++m_scroll_offset;
-
- update_for_new_hovered_item();
- return;
- }
-
- if (key == Key_Left) {
- if (!m_in_submenu)
- return;
-
- ASSERT(hovered_item()->is_submenu());
- hovered_item()->submenu()->clear_hovered_item();
- m_in_submenu = false;
- return;
- }
-
- if (key == Key_Right) {
- if (hovered_item()->is_enabled() && hovered_item()->is_submenu())
- descend_into_submenu_at_hovered_item();
- return;
- }
- }
- Core::Object::event(event);
-}
-
-void Menu::clear_hovered_item()
-{
- if (!hovered_item())
- return;
- m_hovered_item_index = -1;
- m_in_submenu = false;
- redraw();
-}
-
-void Menu::did_activate(MenuItem& item)
-{
- if (item.type() == MenuItem::Type::Separator)
- return;
-
- if (on_item_activation)
- on_item_activation(item);
-
- MenuManager::the().close_bar();
-
- if (m_client)
- m_client->post_message(Messages::WindowClient::MenuItemActivated(m_menu_id, item.identifier()));
-}
-
-MenuItem* Menu::item_with_identifier(unsigned identifer)
-{
- for (auto& item : m_items) {
- if (item.identifier() == identifer)
- return &item;
- }
- return nullptr;
-}
-
-int Menu::item_index_at(const Gfx::Point& position)
-{
- int i = 0;
- for (auto& item : m_items) {
- if (item.rect().contains(position))
- return i;
- ++i;
- }
- return -1;
-}
-
-void Menu::close()
-{
- MenuManager::the().close_menu_and_descendants(*this);
-}
-
-void Menu::redraw_if_theme_changed()
-{
- if (m_theme_index_at_last_paint != MenuManager::the().theme_index())
- redraw();
-}
-
-void Menu::popup(const Gfx::Point& position, bool is_submenu)
-{
- if (is_empty()) {
- dbg() << "Menu: Empty menu popup";
- return;
- }
-
- auto& window = ensure_menu_window();
- redraw_if_theme_changed();
-
- const int margin = 30;
- Gfx::Point adjusted_pos = position;
-
- if (adjusted_pos.x() + window.width() >= Screen::the().width() - margin) {
- adjusted_pos = adjusted_pos.translated(-window.width(), 0);
- }
- if (adjusted_pos.y() + window.height() >= Screen::the().height() - margin) {
- adjusted_pos = adjusted_pos.translated(0, -window.height());
- }
-
- if (adjusted_pos.y() < MenuManager::the().menubar_rect().height())
- adjusted_pos.set_y(MenuManager::the().menubar_rect().height());
-
- window.move_to(adjusted_pos);
- window.set_visible(true);
- MenuManager::the().set_current_menu(this, is_submenu);
-}
-
-bool Menu::is_menu_ancestor_of(const Menu& other) const
-{
- for (auto& item : m_items) {
- if (!item.is_submenu())
- continue;
- auto& submenu = *const_cast<MenuItem&>(item).submenu();
- if (&submenu == &other)
- return true;
- if (submenu.is_menu_ancestor_of(other))
- return true;
- }
- return false;
-}
-
-}
diff --git a/Servers/WindowServer/Menu.h b/Servers/WindowServer/Menu.h
deleted file mode 100644
index de9325616c..0000000000
--- a/Servers/WindowServer/Menu.h
+++ /dev/null
@@ -1,158 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * 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/NonnullOwnPtrVector.h>
-#include <AK/String.h>
-#include <AK/WeakPtr.h>
-#include <LibCore/Object.h>
-#include <LibGfx/Font.h>
-#include <LibGfx/Forward.h>
-#include <LibGfx/Rect.h>
-#include <WindowServer/Cursor.h>
-#include <WindowServer/MenuItem.h>
-#include <WindowServer/Window.h>
-
-namespace WindowServer {
-
-class ClientConnection;
-class MenuBar;
-class Event;
-
-class Menu final : public Core::Object {
- C_OBJECT(Menu)
-public:
- Menu(ClientConnection*, int menu_id, const String& name);
- virtual ~Menu() override;
-
- ClientConnection* client() { return m_client; }
- const ClientConnection* client() const { return m_client; }
- int menu_id() const { return m_menu_id; }
-
- MenuBar* menubar() { return m_menubar; }
- const MenuBar* menubar() const { return m_menubar; }
- void set_menubar(MenuBar* menubar) { m_menubar = menubar; }
-
- bool is_empty() const { return m_items.is_empty(); }
- int item_count() const { return m_items.size(); }
- const MenuItem& item(int index) const { return m_items.at(index); }
- MenuItem& item(int index) { return m_items.at(index); }
-
- void add_item(NonnullOwnPtr<MenuItem>&& item) { m_items.append(move(item)); }
-
- String name() const { return m_name; }
-
- template<typename Callback>
- void for_each_item(Callback callback) const
- {
- for (auto& item : m_items)
- callback(item);
- }
-
- Gfx::Rect text_rect_in_menubar() const { return m_text_rect_in_menubar; }
- void set_text_rect_in_menubar(const Gfx::Rect& rect) { m_text_rect_in_menubar = rect; }
-
- Gfx::Rect rect_in_menubar() const { return m_rect_in_menubar; }
- void set_rect_in_menubar(const Gfx::Rect& rect) { m_rect_in_menubar = rect; }
-
- Window* menu_window() { return m_menu_window.ptr(); }
- Window& ensure_menu_window();
-
- Window* window_menu_of() { return m_window_menu_of; }
- void set_window_menu_of(Window& window) { m_window_menu_of = window.make_weak_ptr(); }
- bool is_window_menu_open() { return m_is_window_menu_open; }
- void set_window_menu_open(bool is_open) { m_is_window_menu_open = is_open; }
-
- int content_width() const;
-
- int item_height() const { return 20; }
- int frame_thickness() const { return 3; }
- int horizontal_padding() const { return left_padding() + right_padding(); }
- int left_padding() const { return 14; }
- int right_padding() const { return 14; }
-
- void draw();
- const Gfx::Font& font() const;
- const Gfx::Font& title_font() const;
- void set_title_font(const Gfx::Font& font);
-
- MenuItem* item_with_identifier(unsigned);
- void redraw();
-
- MenuItem* hovered_item() const;
- void clear_hovered_item();
-
- Function<void(MenuItem&)> on_item_activation;
-
- void close();
-
- void popup(const Gfx::Point&, bool is_submenu = false);
-
- bool is_menu_ancestor_of(const Menu&) const;
-
- void redraw_if_theme_changed();
-
- bool is_scrollable() const { return m_scrollable; }
- int scroll_offset() const { return m_scroll_offset; }
-
-private:
- virtual void event(Core::Event&) override;
-
- RefPtr<Gfx::Font> m_title_font { &Gfx::Font::default_font() };
-
- void handle_mouse_move_event(const MouseEvent&);
- int visible_item_count() const;
-
- int item_index_at(const Gfx::Point&);
- int padding_between_text_and_shortcut() const { return 50; }
- void did_activate(MenuItem&);
- void open_hovered_item();
- void update_for_new_hovered_item();
- void descend_into_submenu_at_hovered_item();
-
- ClientConnection* m_client { nullptr };
- int m_menu_id { 0 };
- String m_name;
- Gfx::Rect m_rect_in_menubar;
- Gfx::Rect m_text_rect_in_menubar;
- MenuBar* m_menubar { nullptr };
- NonnullOwnPtrVector<MenuItem> m_items;
- RefPtr<Window> m_menu_window;
-
- WeakPtr<Window> m_window_menu_of;
- bool m_is_window_menu_open = { false };
- Gfx::Point m_last_position_in_hover;
- int m_theme_index_at_last_paint { -1 };
- int m_hovered_item_index { -1 };
- bool m_in_submenu { false };
-
- bool m_scrollable { false };
- int m_scroll_offset { 0 };
- int m_max_scroll_offset { 0 };
-};
-
-}
diff --git a/Servers/WindowServer/MenuBar.cpp b/Servers/WindowServer/MenuBar.cpp
deleted file mode 100644
index 27dbdcbebf..0000000000
--- a/Servers/WindowServer/MenuBar.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * 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 "MenuBar.h"
-#include "Menu.h"
-#include "MenuItem.h"
-#include <LibGfx/Bitmap.h>
-
-namespace WindowServer {
-
-MenuBar::MenuBar(ClientConnection& client, int menubar_id)
- : m_client(client)
- , m_menubar_id(menubar_id)
-{
-}
-
-MenuBar::~MenuBar()
-{
-}
-
-void MenuBar::add_menu(Menu& menu)
-{
- menu.set_menubar(this);
-
- // NOTE: We assume that the first menu is the App menu, which has a bold font.
- if (m_menus.is_empty())
- menu.set_title_font(Gfx::Font::default_bold_font());
-
- m_menus.append(&menu);
-}
-
-}
diff --git a/Servers/WindowServer/MenuBar.h b/Servers/WindowServer/MenuBar.h
deleted file mode 100644
index 31dff9ac0f..0000000000
--- a/Servers/WindowServer/MenuBar.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * 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 "Menu.h"
-#include <AK/Vector.h>
-#include <AK/WeakPtr.h>
-#include <AK/Weakable.h>
-
-namespace WindowServer {
-
-class MenuBar : public Weakable<MenuBar> {
-public:
- MenuBar(ClientConnection& client, int menubar_id);
- ~MenuBar();
-
- ClientConnection& client() { return m_client; }
- const ClientConnection& client() const { return m_client; }
- int menubar_id() const { return m_menubar_id; }
- void add_menu(Menu&);
-
- template<typename Callback>
- void for_each_menu(Callback callback)
- {
- for (auto& menu : m_menus) {
- if (callback(*menu) == IterationDecision::Break)
- return;
- }
- }
-
-private:
- ClientConnection& m_client;
- int m_menubar_id { 0 };
- Vector<Menu*> m_menus;
-};
-
-}
diff --git a/Servers/WindowServer/MenuItem.cpp b/Servers/WindowServer/MenuItem.cpp
deleted file mode 100644
index eba593c136..0000000000
--- a/Servers/WindowServer/MenuItem.cpp
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * 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 "MenuItem.h"
-#include "ClientConnection.h"
-#include "Menu.h"
-#include "WindowManager.h"
-#include <LibGfx/Bitmap.h>
-
-namespace WindowServer {
-
-MenuItem::MenuItem(Menu& menu, unsigned identifier, const String& text, const String& shortcut_text, bool enabled, bool checkable, bool checked, const Gfx::Bitmap* icon)
- : m_menu(menu)
- , m_type(Text)
- , m_enabled(enabled)
- , m_checkable(checkable)
- , m_checked(checked)
- , m_identifier(identifier)
- , m_text(text)
- , m_shortcut_text(shortcut_text)
- , m_icon(icon)
-{
-}
-
-MenuItem::MenuItem(Menu& menu, Type type)
- : m_menu(menu)
- , m_type(type)
-{
-}
-
-MenuItem::~MenuItem()
-{
-}
-
-void MenuItem::set_enabled(bool enabled)
-{
- if (m_enabled == enabled)
- return;
- m_enabled = enabled;
- m_menu.redraw();
-}
-
-void MenuItem::set_checked(bool checked)
-{
- if (m_checked == checked)
- return;
- m_checked = checked;
- m_menu.redraw();
-}
-
-Menu* MenuItem::submenu()
-{
- ASSERT(is_submenu());
- ASSERT(m_menu.client());
- return m_menu.client()->find_menu_by_id(m_submenu_id);
-}
-
-Gfx::Rect MenuItem::rect() const
-{
- if (!m_menu.is_scrollable())
- return m_rect;
- return m_rect.translated(0, m_menu.item_height() - (m_menu.scroll_offset() * m_menu.item_height()));
-}
-
-void MenuItem::set_icon(const Gfx::Bitmap* icon)
-{
- if (m_icon == icon)
- return;
- m_icon = icon;
- m_menu.redraw();
-}
-
-}
diff --git a/Servers/WindowServer/MenuItem.h b/Servers/WindowServer/MenuItem.h
deleted file mode 100644
index 3f297adb43..0000000000
--- a/Servers/WindowServer/MenuItem.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * 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/Function.h>
-#include <AK/String.h>
-#include <LibGfx/Forward.h>
-#include <LibGfx/Rect.h>
-
-namespace WindowServer {
-
-class Menu;
-
-class MenuItem {
-public:
- enum Type {
- None,
- Text,
- Separator,
- };
-
- MenuItem(Menu&, unsigned identifier, const String& text, const String& shortcut_text = {}, bool enabled = true, bool checkable = false, bool checked = false, const Gfx::Bitmap* icon = nullptr);
- MenuItem(Menu&, Type);
- ~MenuItem();
-
- Type type() const { return m_type; }
-
- bool is_enabled() const { return m_enabled; }
- void set_enabled(bool);
-
- bool is_checkable() const { return m_checkable; }
- void set_checkable(bool checkable) { m_checkable = checkable; }
-
- bool is_checked() const { return m_checked; }
- void set_checked(bool);
-
- String text() const { return m_text; }
- void set_text(const String& text) { m_text = text; }
-
- String shortcut_text() const { return m_shortcut_text; }
- void set_shortcut_text(const String& text) { m_shortcut_text = text; }
-
- void set_rect(const Gfx::Rect& rect) { m_rect = rect; }
- Gfx::Rect rect() const;
-
- unsigned identifier() const { return m_identifier; }
-
- const Gfx::Bitmap* icon() const { return m_icon; }
- void set_icon(const Gfx::Bitmap*);
-
- bool is_submenu() const { return m_submenu_id != -1; }
- int submenu_id() const { return m_submenu_id; }
- void set_submenu_id(int submenu_id) { m_submenu_id = submenu_id; }
-
- Menu* submenu();
-
- bool is_exclusive() const { return m_exclusive; }
- void set_exclusive(bool exclusive) { m_exclusive = exclusive; }
-
-private:
- Menu& m_menu;
- Type m_type { None };
- bool m_enabled { true };
- bool m_checkable { false };
- bool m_checked { false };
- unsigned m_identifier { 0 };
- String m_text;
- String m_shortcut_text;
- Gfx::Rect m_rect;
- RefPtr<Gfx::Bitmap> m_icon;
- int m_submenu_id { -1 };
- bool m_exclusive { false };
-};
-
-}
diff --git a/Servers/WindowServer/MenuManager.cpp b/Servers/WindowServer/MenuManager.cpp
deleted file mode 100644
index 2470d4f1fa..0000000000
--- a/Servers/WindowServer/MenuManager.cpp
+++ /dev/null
@@ -1,404 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * Copyright (c) 2020, Shannon Booth <shannon.ml.booth@gmail.com>
- * 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 <AK/Badge.h>
-#include <AK/FileSystemPath.h>
-#include <AK/QuickSort.h>
-#include <LibCore/DirIterator.h>
-#include <LibGfx/Font.h>
-#include <LibGfx/Painter.h>
-#include <WindowServer/AppletManager.h>
-#include <WindowServer/MenuManager.h>
-#include <WindowServer/Screen.h>
-#include <WindowServer/WindowManager.h>
-#include <unistd.h>
-
-//#define DEBUG_MENUS
-
-namespace WindowServer {
-
-static MenuManager* s_the;
-
-MenuManager& MenuManager::the()
-{
- ASSERT(s_the);
- return *s_the;
-}
-
-MenuManager::MenuManager()
-{
- s_the = this;
- m_needs_window_resize = true;
-
- // NOTE: This ensures that the system menu has the correct dimensions.
- set_current_menubar(nullptr);
-
- m_window = Window::construct(*this, WindowType::Menubar);
- m_window->set_rect(menubar_rect());
-}
-
-MenuManager::~MenuManager()
-{
-}
-
-bool MenuManager::is_open(const Menu& menu) const
-{
- for (size_t i = 0; i < m_open_menu_stack.size(); ++i) {
- if (&menu == m_open_menu_stack[i].ptr())
- return true;
- }
- return false;
-}
-
-void MenuManager::draw()
-{
- auto& wm = WindowManager::the();
- auto palette = wm.palette();
- auto menubar_rect = this->menubar_rect();
-
- if (m_needs_window_resize) {
- m_window->set_rect(menubar_rect);
- AppletManager::the().calculate_applet_rects(window());
- m_needs_window_resize = false;
- }
-
- Gfx::Painter painter(*window().backing_store());
-
- painter.fill_rect(menubar_rect, palette.window());
- painter.draw_line({ 0, menubar_rect.bottom() }, { menubar_rect.right(), menubar_rect.bottom() }, palette.threed_shadow1());
-
- for_each_active_menubar_menu([&](Menu& menu) {
- Color text_color = palette.window_text();
- if (is_open(menu)) {
- painter.fill_rect(menu.rect_in_menubar(), palette.menu_selection());
- painter.draw_rect(menu.rect_in_menubar(), palette.menu_selection().darkened());
- text_color = palette.menu_selection_text();
- }
- painter.draw_text(
- menu.text_rect_in_menubar(),
- menu.name(),
- menu.title_font(),
- Gfx::TextAlignment::CenterLeft,
- text_color);
- return IterationDecision::Continue;
- });
-
- AppletManager::the().draw();
-}
-
-void MenuManager::refresh()
-{
- if (!m_window)
- return;
- draw();
- window().invalidate();
-}
-
-void MenuManager::event(Core::Event& event)
-{
- if (static_cast<Event&>(event).is_mouse_event()) {
- handle_mouse_event(static_cast<MouseEvent&>(event));
- return;
- }
-
- if (static_cast<Event&>(event).is_key_event()) {
- auto& key_event = static_cast<const KeyEvent&>(event);
-
- if (key_event.type() == Event::KeyUp && key_event.key() == Key_Escape) {
- close_everyone();
- return;
- }
-
- if (event.type() == Event::KeyDown) {
- for_each_active_menubar_menu([&](Menu& menu) {
- if (is_open(menu))
- menu.dispatch_event(event);
- return IterationDecision::Continue;
- });
- }
- }
-
- return Core::Object::event(event);
-}
-
-void MenuManager::handle_mouse_event(MouseEvent& mouse_event)
-{
- auto* active_window = WindowManager::the().active_window();
- bool handled_menubar_event = false;
- for_each_active_menubar_menu([&](Menu& menu) {
- if (menu.rect_in_menubar().contains(mouse_event.position())) {
- handled_menubar_event = &menu == m_system_menu || !active_window || !active_window->is_modal();
- if (handled_menubar_event)
- handle_menu_mouse_event(menu, mouse_event);
- return IterationDecision::Break;
- }
- return IterationDecision::Continue;
- });
- if (handled_menubar_event)
- return;
-
- if (has_open_menu()) {
- auto* topmost_menu = m_open_menu_stack.last().ptr();
- ASSERT(topmost_menu);
- auto* window = topmost_menu->menu_window();
- if (!window) {
- dbg() << "MenuManager::handle_mouse_event: No menu window";
- return;
- }
- ASSERT(window->is_visible());
-
- bool event_is_inside_current_menu = window->rect().contains(mouse_event.position());
- if (event_is_inside_current_menu) {
- WindowManager::the().set_hovered_window(window);
- auto translated_event = mouse_event.translated(-window->position());
- WindowManager::the().deliver_mouse_event(*window, translated_event);
- return;
- }
-
- if (topmost_menu->hovered_item())
- topmost_menu->clear_hovered_item();
- if (mouse_event.type() == Event::MouseDown || mouse_event.type() == Event::MouseUp) {
- auto* window_menu_of = topmost_menu->window_menu_of();
- if (window_menu_of) {
- bool event_is_inside_taskbar_button = window_menu_of->taskbar_rect().contains(mouse_event.position());
- if (event_is_inside_taskbar_button && !topmost_menu->is_window_menu_open()) {
- topmost_menu->set_window_menu_open(true);
- return;
- }
- }
-
- if (mouse_event.type() == Event::MouseDown) {
- close_bar();
- topmost_menu->set_window_menu_open(false);
- }
- }
-
- if (mouse_event.type() == Event::MouseMove) {
- for (auto& menu : m_open_menu_stack) {
- if (!menu)
- continue;
- if (!menu->menu_window()->rect().contains(mouse_event.position()))
- continue;
- WindowManager::the().set_hovered_window(menu->menu_window());
- auto translated_event = mouse_event.translated(-menu->menu_window()->position());
- WindowManager::the().deliver_mouse_event(*menu->menu_window(), translated_event);
- break;
- }
- }
- return;
- }
-
- AppletManager::the().dispatch_event(static_cast<Event&>(mouse_event));
-}
-
-void MenuManager::handle_menu_mouse_event(Menu& menu, const MouseEvent& event)
-{
- bool is_hover_with_any_menu_open = event.type() == MouseEvent::MouseMove
- && has_open_menu()
- && (m_open_menu_stack.first()->menubar() || m_open_menu_stack.first() == m_system_menu.ptr());
- bool is_mousedown_with_left_button = event.type() == MouseEvent::MouseDown && event.button() == MouseButton::Left;
- bool should_open_menu = &menu != m_current_menu && (is_hover_with_any_menu_open || is_mousedown_with_left_button);
-
- if (is_mousedown_with_left_button)
- m_bar_open = !m_bar_open;
-
- if (should_open_menu && m_bar_open) {
- open_menu(menu);
- return;
- }
-
- if (!m_bar_open)
- close_everyone();
-}
-
-void MenuManager::set_needs_window_resize()
-{
- m_needs_window_resize = true;
-}
-
-void MenuManager::close_all_menus_from_client(Badge<ClientConnection>, ClientConnection& client)
-{
- if (!has_open_menu())
- return;
- if (m_open_menu_stack.first()->client() != &client)
- return;
- close_everyone();
-}
-
-void MenuManager::close_everyone()
-{
- for (auto& menu : m_open_menu_stack) {
- if (menu && menu->menu_window())
- menu->menu_window()->set_visible(false);
- menu->clear_hovered_item();
- }
- m_open_menu_stack.clear();
- m_current_menu = nullptr;
- refresh();
-}
-
-void MenuManager::close_everyone_not_in_lineage(Menu& menu)
-{
- Vector<Menu*> menus_to_close;
- for (auto& open_menu : m_open_menu_stack) {
- if (!open_menu)
- continue;
- if (&menu == open_menu.ptr() || open_menu->is_menu_ancestor_of(menu))
- continue;
- menus_to_close.append(open_menu);
- }
- close_menus(menus_to_close);
-}
-
-void MenuManager::close_menus(const Vector<Menu*>& menus)
-{
- for (auto& menu : menus) {
- if (menu == m_current_menu)
- m_current_menu = nullptr;
- if (menu->menu_window())
- menu->menu_window()->set_visible(false);
- menu->clear_hovered_item();
- m_open_menu_stack.remove_first_matching([&](auto& entry) {
- return entry == menu;
- });
- }
- refresh();
-}
-
-static void collect_menu_subtree(Menu& menu, Vector<Menu*>& menus)
-{
- menus.append(&menu);
- for (int i = 0; i < menu.item_count(); ++i) {
- auto& item = menu.item(i);
- if (!item.is_submenu())
- continue;
- collect_menu_subtree(*const_cast<MenuItem&>(item).submenu(), menus);
- }
-}
-
-void MenuManager::close_menu_and_descendants(Menu& menu)
-{
- Vector<Menu*> menus_to_close;
- collect_menu_subtree(menu, menus_to_close);
- close_menus(menus_to_close);
-}
-
-void MenuManager::toggle_menu(Menu& menu)
-{
- if (is_open(menu)) {
- close_menu_and_descendants(menu);
- return;
- }
- open_menu(menu);
-}
-
-void MenuManager::open_menu(Menu& menu)
-{
- if (is_open(menu))
- return;
- if (!menu.is_empty()) {
- menu.redraw_if_theme_changed();
- auto& menu_window = menu.ensure_menu_window();
- menu_window.move_to({ menu.rect_in_menubar().x(), menu.rect_in_menubar().bottom() + 2 });
- menu_window.set_visible(true);
- }
- set_current_menu(&menu);
- refresh();
-}
-
-void MenuManager::set_current_menu(Menu* menu, bool is_submenu)
-{
- if (menu == m_current_menu)
- return;
-
- if (!is_submenu) {
- if (menu)
- close_everyone_not_in_lineage(*menu);
- else
- close_everyone();
- }
-
- if (!menu) {
- m_current_menu = nullptr;
- return;
- }
-
- m_current_menu = menu->make_weak_ptr();
- if (m_open_menu_stack.find([menu](auto& other) { return menu == other.ptr(); }).is_end())
- m_open_menu_stack.append(menu->make_weak_ptr());
-}
-
-void MenuManager::close_bar()
-{
- close_everyone();
- m_bar_open = false;
-}
-
-Gfx::Rect MenuManager::menubar_rect() const
-{
- return { 0, 0, Screen::the().rect().width(), 18 };
-}
-
-void MenuManager::set_current_menubar(MenuBar* menubar)
-{
- if (menubar)
- m_current_menubar = menubar->make_weak_ptr();
- else
- m_current_menubar = nullptr;
-#ifdef DEBUG_MENUS
- dbg() << "[WM] Current menubar is now " << menubar;
-#endif
- Gfx::Point next_menu_location { MenuManager::menubar_menu_margin() / 2, 0 };
- for_each_active_menubar_menu([&](Menu& menu) {
- int text_width = menu.title_font().width(menu.name());
- menu.set_rect_in_menubar({ next_menu_location.x() - MenuManager::menubar_menu_margin() / 2, 0, text_width + MenuManager::menubar_menu_margin(), menubar_rect().height() - 1 });
- menu.set_text_rect_in_menubar({ next_menu_location, { text_width, menubar_rect().height() } });
- next_menu_location.move_by(menu.rect_in_menubar().width(), 0);
- return IterationDecision::Continue;
- });
- refresh();
-}
-
-void MenuManager::close_menubar(MenuBar& menubar)
-{
- if (current_menubar() == &menubar)
- set_current_menubar(nullptr);
-}
-
-void MenuManager::set_system_menu(Menu& menu)
-{
- m_system_menu = menu.make_weak_ptr();
- set_current_menubar(m_current_menubar);
-}
-
-void MenuManager::did_change_theme()
-{
- ++m_theme_index;
- refresh();
-}
-
-}
diff --git a/Servers/WindowServer/MenuManager.h b/Servers/WindowServer/MenuManager.h
deleted file mode 100644
index f4d5d5aad8..0000000000
--- a/Servers/WindowServer/MenuManager.h
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * 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 "Menu.h"
-#include "MenuBar.h"
-#include "Window.h"
-#include <AK/HashMap.h>
-#include <LibCore/Object.h>
-
-namespace WindowServer {
-
-class MenuManager final : public Core::Object {
- C_OBJECT(MenuManager)
-public:
- static MenuManager& the();
-
- MenuManager();
- virtual ~MenuManager() override;
-
- void refresh();
-
- bool is_open(const Menu&) const;
- bool has_open_menu() const { return !m_open_menu_stack.is_empty(); }
-
- Gfx::Rect menubar_rect() const;
- static int menubar_menu_margin() { return 16; }
-
- void set_needs_window_resize();
-
- Menu* current_menu() { return m_current_menu.ptr(); }
- void set_current_menu(Menu*, bool is_submenu = false);
- void open_menu(Menu&);
- void toggle_menu(Menu&);
-
- MenuBar* current_menubar() { return m_current_menubar.ptr(); }
- void set_current_menubar(MenuBar*);
- void close_menubar(MenuBar&);
-
- void close_bar();
- void close_everyone();
- void close_everyone_not_in_lineage(Menu&);
- void close_menu_and_descendants(Menu&);
-
- void close_all_menus_from_client(Badge<ClientConnection>, ClientConnection&);
-
- void toggle_system_menu()
- {
- if (m_system_menu)
- toggle_menu(*m_system_menu);
- }
-
- Menu* system_menu() { return m_system_menu; }
- void set_system_menu(Menu&);
-
- int theme_index() const { return m_theme_index; }
-
- Window& window() { return *m_window; }
-
- template<typename Callback>
- void for_each_active_menubar_menu(Callback callback)
- {
- if (system_menu()) {
- if (callback(*system_menu()) == IterationDecision::Break)
- return;
- }
- if (m_current_menubar)
- m_current_menubar->for_each_menu(callback);
- }
-
- void did_change_theme();
-
-private:
- void close_menus(const Vector<Menu*>&);
-
- const Window& window() const { return *m_window; }
-
- virtual void event(Core::Event&) override;
- void handle_mouse_event(MouseEvent&);
- void handle_menu_mouse_event(Menu&, const MouseEvent&);
-
- void draw();
-
- RefPtr<Window> m_window;
-
- WeakPtr<Menu> m_current_menu;
- Vector<WeakPtr<Menu>> m_open_menu_stack;
-
- WeakPtr<Menu> m_system_menu;
-
- bool m_needs_window_resize { false };
- bool m_bar_open { false };
-
- int m_theme_index { 0 };
-
- WeakPtr<MenuBar> m_current_menubar;
-};
-
-}
diff --git a/Servers/WindowServer/Screen.cpp b/Servers/WindowServer/Screen.cpp
deleted file mode 100644
index 3f0fbb04fd..0000000000
--- a/Servers/WindowServer/Screen.cpp
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * 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 "Screen.h"
-#include "Compositor.h"
-#include "Event.h"
-#include "EventLoop.h"
-#include "WindowManager.h"
-#include <Kernel/FB.h>
-#include <Kernel/MousePacket.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <sys/mman.h>
-#include <unistd.h>
-
-namespace WindowServer {
-
-static Screen* s_the;
-
-Screen& Screen::the()
-{
- ASSERT(s_the);
- return *s_the;
-}
-
-Screen::Screen(unsigned desired_width, unsigned desired_height)
-{
- ASSERT(!s_the);
- s_the = this;
- m_framebuffer_fd = open("/dev/fb0", O_RDWR | O_CLOEXEC);
- if (m_framebuffer_fd < 0) {
- perror("failed to open /dev/fb0");
- ASSERT_NOT_REACHED();
- }
-
- if (fb_set_buffer(m_framebuffer_fd, 0) == 0) {
- m_can_set_buffer = true;
- }
-
- set_resolution(desired_width, desired_height);
- m_cursor_location = rect().center();
-}
-
-Screen::~Screen()
-{
-}
-
-bool Screen::set_resolution(int width, int height)
-{
- FBResolution resolution { 0, (unsigned)width, (unsigned)height };
- int rc = fb_set_resolution(m_framebuffer_fd, &resolution);
-#ifdef WSSCREEN_DEBUG
- dbg() << "fb_set_resolution() - return code " << rc;
-#endif
- if (rc == 0) {
- on_change_resolution(resolution.pitch, resolution.width, resolution.height);
- return true;
- }
- if (rc == -1) {
- dbg() << "Invalid resolution " << width << "x" << height;
- on_change_resolution(resolution.pitch, resolution.width, resolution.height);
- return false;
- }
- ASSERT_NOT_REACHED();
-}
-
-void Screen::on_change_resolution(int pitch, int width, int height)
-{
- if (m_framebuffer) {
- size_t previous_size_in_bytes = m_size_in_bytes;
- int rc = munmap(m_framebuffer, previous_size_in_bytes);
- ASSERT(rc == 0);
- }
-
- int rc = fb_get_size_in_bytes(m_framebuffer_fd, &m_size_in_bytes);
- ASSERT(rc == 0);
-
- m_framebuffer = (Gfx::RGBA32*)mmap(nullptr, m_size_in_bytes, PROT_READ | PROT_WRITE, MAP_SHARED, m_framebuffer_fd, 0);
- ASSERT(m_framebuffer && m_framebuffer != (void*)-1);
-
- m_pitch = pitch;
- m_width = width;
- m_height = height;
-
- m_cursor_location.constrain(rect());
-}
-
-void Screen::set_buffer(int index)
-{
- ASSERT(m_can_set_buffer);
- int rc = fb_set_buffer(m_framebuffer_fd, index);
- ASSERT(rc == 0);
-}
-
-void Screen::on_receive_mouse_data(const MousePacket& packet)
-{
- auto prev_location = m_cursor_location;
- if (packet.is_relative) {
- m_cursor_location.move_by(packet.x, packet.y);
-#ifdef WSSCREEN_DEBUG
- dbgprintf("Screen: New Relative mouse point @ X %d, Y %d\n", m_cursor_location.x(), m_cursor_location.y());
-#endif
- } else {
- m_cursor_location = { packet.x * m_width / 0xffff, packet.y * m_height / 0xffff };
-#ifdef WSSCREEN_DEBUG
- dbgprintf("Screen: New Absolute mouse point @ X %d, Y %d\n", m_cursor_location.x(), m_cursor_location.y());
-#endif
- }
-
- m_cursor_location.constrain(rect());
-
- unsigned buttons = packet.buttons;
- unsigned prev_buttons = m_mouse_button_state;
- m_mouse_button_state = buttons;
- unsigned changed_buttons = prev_buttons ^ buttons;
- auto post_mousedown_or_mouseup_if_needed = [&](MouseButton button) {
- if (!(changed_buttons & (unsigned)button))
- return;
- auto message = make<MouseEvent>(buttons & (unsigned)button ? Event::MouseDown : Event::MouseUp, m_cursor_location, buttons, button, m_modifiers);
- Core::EventLoop::current().post_event(WindowManager::the(), move(message));
- };
- post_mousedown_or_mouseup_if_needed(MouseButton::Left);
- post_mousedown_or_mouseup_if_needed(MouseButton::Right);
- post_mousedown_or_mouseup_if_needed(MouseButton::Middle);
- post_mousedown_or_mouseup_if_needed(MouseButton::Back);
- post_mousedown_or_mouseup_if_needed(MouseButton::Forward);
- if (m_cursor_location != prev_location) {
- auto message = make<MouseEvent>(Event::MouseMove, m_cursor_location, buttons, MouseButton::None, m_modifiers);
- Core::EventLoop::current().post_event(WindowManager::the(), move(message));
- }
-
- if (packet.z) {
- auto message = make<MouseEvent>(Event::MouseWheel, m_cursor_location, buttons, MouseButton::None, m_modifiers, packet.z);
- Core::EventLoop::current().post_event(WindowManager::the(), move(message));
- }
-
- if (m_cursor_location != prev_location)
- Compositor::the().invalidate_cursor();
-}
-
-void Screen::on_receive_keyboard_data(::KeyEvent kernel_event)
-{
- m_modifiers = kernel_event.modifiers();
- auto message = make<KeyEvent>(kernel_event.is_press() ? Event::KeyDown : Event::KeyUp, kernel_event.key, kernel_event.character, kernel_event.modifiers());
- Core::EventLoop::current().post_event(WindowManager::the(), move(message));
-}
-
-}
diff --git a/Servers/WindowServer/Screen.h b/Servers/WindowServer/Screen.h
deleted file mode 100644
index d522ea7b96..0000000000
--- a/Servers/WindowServer/Screen.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * 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 <Kernel/KeyCode.h>
-#include <LibGfx/Color.h>
-#include <LibGfx/Rect.h>
-#include <LibGfx/Size.h>
-
-struct MousePacket;
-
-namespace WindowServer {
-
-class Screen {
-public:
- Screen(unsigned width, unsigned height);
- ~Screen();
-
- bool set_resolution(int width, int height);
- bool can_set_buffer() { return m_can_set_buffer; }
- void set_buffer(int index);
-
- int width() const { return m_width; }
- int height() const { return m_height; }
- size_t pitch() const { return m_pitch; }
- Gfx::RGBA32* scanline(int y);
-
- static Screen& the();
-
- Gfx::Size size() const { return { width(), height() }; }
- Gfx::Rect rect() const { return { 0, 0, width(), height() }; }
-
- Gfx::Point cursor_location() const { return m_cursor_location; }
- unsigned mouse_button_state() const { return m_mouse_button_state; }
-
- void on_receive_mouse_data(const MousePacket&);
- void on_receive_keyboard_data(::KeyEvent);
-
-private:
- void on_change_resolution(int pitch, int width, int height);
-
- size_t m_size_in_bytes;
-
- Gfx::RGBA32* m_framebuffer { nullptr };
- bool m_can_set_buffer { false };
-
- int m_pitch { 0 };
- int m_width { 0 };
- int m_height { 0 };
- int m_framebuffer_fd { -1 };
-
- Gfx::Point m_cursor_location;
- unsigned m_mouse_button_state { 0 };
- unsigned m_modifiers { 0 };
-};
-
-inline Gfx::RGBA32* Screen::scanline(int y)
-{
- return reinterpret_cast<Gfx::RGBA32*>(((u8*)m_framebuffer) + (y * m_pitch));
-}
-
-}
diff --git a/Servers/WindowServer/Window.cpp b/Servers/WindowServer/Window.cpp
deleted file mode 100644
index 4d506e1dc7..0000000000
--- a/Servers/WindowServer/Window.cpp
+++ /dev/null
@@ -1,524 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * 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 "Window.h"
-#include "ClientConnection.h"
-#include "Event.h"
-#include "EventLoop.h"
-#include "Screen.h"
-#include "WindowClientEndpoint.h"
-#include "WindowManager.h"
-#include <AK/Badge.h>
-
-namespace WindowServer {
-
-static String default_window_icon_path()
-{
- return "/res/icons/16x16/window.png";
-}
-
-static Gfx::Bitmap& default_window_icon()
-{
- static Gfx::Bitmap* s_icon;
- if (!s_icon)
- s_icon = Gfx::Bitmap::load_from_file(default_window_icon_path()).leak_ref();
- return *s_icon;
-}
-
-static Gfx::Bitmap& minimize_icon()
-{
- static Gfx::Bitmap* s_icon;
- if (!s_icon)
- s_icon = Gfx::Bitmap::load_from_file("/res/icons/16x16/window-minimize.png").leak_ref();
- return *s_icon;
-}
-
-static Gfx::Bitmap& maximize_icon()
-{
- static Gfx::Bitmap* s_icon;
- if (!s_icon)
- s_icon = Gfx::Bitmap::load_from_file("/res/icons/16x16/window-maximize.png").leak_ref();
- return *s_icon;
-}
-
-static Gfx::Bitmap& restore_icon()
-{
- static Gfx::Bitmap* s_icon;
- if (!s_icon)
- s_icon = Gfx::Bitmap::load_from_file("/res/icons/16x16/window-restore.png").leak_ref();
- return *s_icon;
-}
-
-static Gfx::Bitmap& close_icon()
-{
- static Gfx::Bitmap* s_icon;
- if (!s_icon)
- s_icon = Gfx::Bitmap::load_from_file("/res/icons/16x16/window-close.png").leak_ref();
- return *s_icon;
-}
-
-Window::Window(Core::Object& parent, WindowType type)
- : Core::Object(&parent)
- , m_type(type)
- , m_icon(default_window_icon())
- , m_frame(*this)
-{
- WindowManager::the().add_window(*this);
-}
-
-Window::Window(ClientConnection& client, WindowType window_type, int window_id, bool modal, bool minimizable, bool frameless, bool resizable, bool fullscreen)
- : Core::Object(&client)
- , m_client(&client)
- , m_type(window_type)
- , m_modal(modal)
- , m_minimizable(minimizable)
- , m_frameless(frameless)
- , m_resizable(resizable)
- , m_fullscreen(fullscreen)
- , m_window_id(window_id)
- , m_client_id(client.client_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;
- }
-
- WindowManager::the().add_window(*this);
-}
-
-Window::~Window()
-{
- // Detach from client at the start of teardown since we don't want
- // to confuse things by trying to send messages to it.
- m_client = nullptr;
-
- WindowManager::the().remove_window(*this);
-}
-
-void Window::set_title(const String& title)
-{
- if (m_title == title)
- return;
- m_title = title;
- WindowManager::the().notify_title_changed(*this);
-}
-
-void Window::set_rect(const Gfx::Rect& rect)
-{
- ASSERT(!rect.is_empty());
- Gfx::Rect old_rect;
- if (m_rect == rect)
- return;
- old_rect = m_rect;
- m_rect = rect;
- if (!m_client && (!m_backing_store || old_rect.size() != rect.size())) {
- m_backing_store = Gfx::Bitmap::create(Gfx::BitmapFormat::RGB32, m_rect.size());
- }
- m_frame.notify_window_rect_changed(old_rect, rect);
-}
-
-void Window::set_rect_without_repaint(const Gfx::Rect& rect)
-{
- ASSERT(!rect.is_empty());
- if (m_rect == rect)
- return;
- auto old_rect = m_rect;
- m_rect = rect;
-
- if (old_rect.size() == m_rect.size()) {
- auto delta = m_rect.location() - old_rect.location();
- for (auto& child_window : m_child_windows) {
- if (child_window)
- child_window->move_by(delta);
- }
- }
-
- m_frame.notify_window_rect_changed(old_rect, rect);
-}
-
-void Window::handle_mouse_event(const MouseEvent& event)
-{
- set_automatic_cursor_tracking_enabled(event.buttons() != 0);
-
- switch (event.type()) {
- case Event::MouseMove:
- m_client->post_message(Messages::WindowClient::MouseMove(m_window_id, event.position(), (u32)event.button(), event.buttons(), event.modifiers(), event.wheel_delta(), event.is_drag(), event.drag_data_type()));
- break;
- case Event::MouseDown:
- m_client->post_message(Messages::WindowClient::MouseDown(m_window_id, event.position(), (u32)event.button(), event.buttons(), event.modifiers(), event.wheel_delta()));
- break;
- case Event::MouseDoubleClick:
- m_client->post_message(Messages::WindowClient::MouseDoubleClick(m_window_id, event.position(), (u32)event.button(), event.buttons(), event.modifiers(), event.wheel_delta()));
- break;
- case Event::MouseUp:
- m_client->post_message(Messages::WindowClient::MouseUp(m_window_id, event.position(), (u32)event.button(), event.buttons(), event.modifiers(), event.wheel_delta()));
- break;
- case Event::MouseWheel:
- m_client->post_message(Messages::WindowClient::MouseWheel(m_window_id, event.position(), (u32)event.button(), event.buttons(), event.modifiers(), event.wheel_delta()));
- break;
- default:
- ASSERT_NOT_REACHED();
- }
-}
-
-void Window::update_menu_item_text(PopupMenuItem item)
-{
- if (m_window_menu) {
- m_window_menu->item((int)item).set_text(item == PopupMenuItem::Minimize ? (m_minimized ? "Unminimize" : "Minimize") : (m_maximized ? "Restore" : "Maximize"));
- m_window_menu->redraw();
- }
-}
-
-void Window::update_menu_item_enabled(PopupMenuItem item)
-{
- if (m_window_menu) {
- m_window_menu->item((int)item).set_enabled(item == PopupMenuItem::Minimize ? m_minimizable : m_resizable);
- m_window_menu->redraw();
- }
-}
-
-void Window::set_minimized(bool minimized)
-{
- if (m_minimized == minimized)
- return;
- if (minimized && !m_minimizable)
- return;
- if (is_blocked_by_modal_window())
- return;
- m_minimized = minimized;
- update_menu_item_text(PopupMenuItem::Minimize);
- start_minimize_animation();
- if (!minimized)
- request_update({ {}, size() });
- invalidate();
- WindowManager::the().notify_minimization_state_changed(*this);
-}
-
-void Window::set_minimizable(bool minimizable)
-{
- if (m_minimizable == minimizable)
- return;
- m_minimizable = minimizable;
- update_menu_item_enabled(PopupMenuItem::Minimize);
- // TODO: Hide/show (or alternatively change enabled state of) window minimize button dynamically depending on value of m_minimizable
-}
-
-void Window::set_opacity(float opacity)
-{
- if (m_opacity == opacity)
- return;
- m_opacity = opacity;
- WindowManager::the().notify_opacity_changed(*this);
-}
-
-void Window::set_occluded(bool occluded)
-{
- if (m_occluded == occluded)
- return;
- m_occluded = occluded;
- WindowManager::the().notify_occlusion_state_changed(*this);
-}
-
-void Window::set_maximized(bool maximized)
-{
- if (m_maximized == maximized)
- return;
- if (maximized && !is_resizable())
- return;
- if (is_blocked_by_modal_window())
- return;
- set_tiled(WindowTileType::None);
- m_maximized = maximized;
- update_menu_item_text(PopupMenuItem::Maximize);
- auto old_rect = m_rect;
- if (maximized) {
- m_unmaximized_rect = m_rect;
- set_rect(WindowManager::the().maximized_window_rect(*this));
- } else {
- set_rect(m_unmaximized_rect);
- }
- m_frame.did_set_maximized({}, maximized);
- Core::EventLoop::current().post_event(*this, make<ResizeEvent>(old_rect, m_rect));
-}
-
-void Window::set_resizable(bool resizable)
-{
- if (m_resizable == resizable)
- return;
- m_resizable = resizable;
- update_menu_item_enabled(PopupMenuItem::Maximize);
- // TODO: Hide/show (or alternatively change enabled state of) window maximize button dynamically depending on value of is_resizable()
-}
-
-void Window::event(Core::Event& event)
-{
- if (!m_client) {
- ASSERT(parent());
- event.ignore();
- return;
- }
-
- if (is_blocked_by_modal_window())
- return;
-
- if (static_cast<Event&>(event).is_mouse_event())
- return handle_mouse_event(static_cast<const MouseEvent&>(event));
-
- switch (event.type()) {
- case Event::WindowEntered:
- m_client->post_message(Messages::WindowClient::WindowEntered(m_window_id));
- break;
- case Event::WindowLeft:
- m_client->post_message(Messages::WindowClient::WindowLeft(m_window_id));
- break;
- case Event::KeyDown:
- m_client->post_message(
- Messages::WindowClient::KeyDown(m_window_id,
- (u8) static_cast<const KeyEvent&>(event).character(),
- (u32) static_cast<const KeyEvent&>(event).key(),
- static_cast<const KeyEvent&>(event).modifiers()));
- break;
- case Event::KeyUp:
- m_client->post_message(
- Messages::WindowClient::KeyUp(m_window_id,
- (u8) static_cast<const KeyEvent&>(event).character(),
- (u32) static_cast<const KeyEvent&>(event).key(),
- static_cast<const KeyEvent&>(event).modifiers()));
- break;
- case Event::WindowActivated:
- m_client->post_message(Messages::WindowClient::WindowActivated(m_window_id));
- break;
- case Event::WindowDeactivated:
- m_client->post_message(Messages::WindowClient::WindowDeactivated(m_window_id));
- break;
- case Event::WindowCloseRequest:
- m_client->post_message(Messages::WindowClient::WindowCloseRequest(m_window_id));
- break;
- case Event::WindowResized:
- m_client->post_message(
- Messages::WindowClient::WindowResized(
- m_window_id,
- static_cast<const ResizeEvent&>(event).old_rect(),
- static_cast<const ResizeEvent&>(event).rect()));
- break;
- default:
- break;
- }
-}
-
-void Window::set_global_cursor_tracking_enabled(bool enabled)
-{
- m_global_cursor_tracking_enabled = enabled;
-}
-
-void Window::set_visible(bool b)
-{
- if (m_visible == b)
- return;
- m_visible = b;
- invalidate();
-}
-
-void Window::invalidate()
-{
- WindowManager::the().invalidate(*this);
-}
-
-void Window::invalidate(const Gfx::Rect& rect)
-{
- WindowManager::the().invalidate(*this, rect);
-}
-
-bool Window::is_active() const
-{
- return WindowManager::the().active_window() == this;
-}
-
-bool Window::is_blocked_by_modal_window() const
-{
- bool is_any_modal = false;
- const Window* next = this;
- while (!is_any_modal && next) {
- is_any_modal = next->is_modal();
- next = next->parent_window();
- }
-
- return !is_any_modal && client() && client()->is_showing_modal_window();
-}
-
-void Window::set_default_icon()
-{
- m_icon = default_window_icon();
-}
-
-void Window::request_update(const Gfx::Rect& rect, bool ignore_occlusion)
-{
- if (m_pending_paint_rects.is_empty()) {
- deferred_invoke([this, ignore_occlusion](auto&) {
- client()->post_paint_message(*this, ignore_occlusion);
- });
- }
- m_pending_paint_rects.add(rect);
-}
-
-void Window::popup_window_menu(const Gfx::Point& position)
-{
- if (!m_window_menu) {
- m_window_menu = Menu::construct(nullptr, -1, "(Window Menu)");
- m_window_menu->set_window_menu_of(*this);
-
- auto minimize_item = make<MenuItem>(*m_window_menu, 1, m_minimized ? "Unminimize" : "Minimize");
- m_window_menu_minimize_item = minimize_item.ptr();
- m_window_menu->add_item(move(minimize_item));
-
- auto maximize_item = make<MenuItem>(*m_window_menu, 2, m_maximized ? "Restore" : "Maximize");
- m_window_menu_maximize_item = maximize_item.ptr();
- m_window_menu->add_item(move(maximize_item));
-
- m_window_menu->add_item(make<MenuItem>(*m_window_menu, MenuItem::Type::Separator));
-
- auto close_item = make<MenuItem>(*m_window_menu, 3, "Close");
- close_item->set_icon(&close_icon());
- m_window_menu->add_item(move(close_item));
-
- m_window_menu->item((int)PopupMenuItem::Minimize).set_enabled(m_minimizable);
- m_window_menu->item((int)PopupMenuItem::Maximize).set_enabled(m_resizable);
-
- m_window_menu->on_item_activation = [&](auto& item) {
- switch (item.identifier()) {
- case 1:
- set_minimized(!m_minimized);
- if (!m_minimized)
- WindowManager::the().move_to_front_and_make_active(*this);
- break;
- case 2:
- set_maximized(!m_maximized);
- if (m_minimized)
- set_minimized(false);
- WindowManager::the().move_to_front_and_make_active(*this);
- break;
- case 3:
- request_close();
- break;
- }
- };
- }
- m_window_menu_minimize_item->set_icon(m_minimized ? nullptr : &minimize_icon());
- m_window_menu_maximize_item->set_icon(m_maximized ? &restore_icon() : &maximize_icon());
-
- m_window_menu->popup(position);
-}
-
-void Window::request_close()
-{
- Event close_request(Event::WindowCloseRequest);
- event(close_request);
-}
-
-void Window::set_fullscreen(bool fullscreen)
-{
- if (m_fullscreen == fullscreen)
- return;
- m_fullscreen = fullscreen;
- Gfx::Rect new_window_rect = m_rect;
- if (m_fullscreen) {
- m_saved_nonfullscreen_rect = m_rect;
- new_window_rect = Screen::the().rect();
- } else if (!m_saved_nonfullscreen_rect.is_empty()) {
- new_window_rect = m_saved_nonfullscreen_rect;
- }
- Core::EventLoop::current().post_event(*this, make<ResizeEvent>(m_rect, new_window_rect));
- set_rect(new_window_rect);
-}
-
-Gfx::Rect Window::tiled_rect(WindowTileType tiled) const
-{
- int frame_width = (m_frame.rect().width() - m_rect.width()) / 2;
- switch (tiled) {
- case WindowTileType::None:
- return m_untiled_rect;
- case WindowTileType::Left:
- return Gfx::Rect(0,
- WindowManager::the().maximized_window_rect(*this).y(),
- Screen::the().width() / 2 - frame_width,
- WindowManager::the().maximized_window_rect(*this).height());
- case WindowTileType::Right:
- return Gfx::Rect(Screen::the().width() / 2 + frame_width,
- WindowManager::the().maximized_window_rect(*this).y(),
- Screen::the().width() / 2 - frame_width,
- WindowManager::the().maximized_window_rect(*this).height());
- default:
- ASSERT_NOT_REACHED();
- }
-}
-
-void Window::set_tiled(WindowTileType tiled)
-{
- if (m_tiled == tiled)
- return;
-
- m_tiled = tiled;
- auto old_rect = m_rect;
- if (tiled != WindowTileType::None)
- m_untiled_rect = m_rect;
- set_rect(tiled_rect(tiled));
- Core::EventLoop::current().post_event(*this, make<ResizeEvent>(old_rect, m_rect));
-}
-
-void Window::detach_client(Badge<ClientConnection>)
-{
- m_client = nullptr;
-}
-
-void Window::recalculate_rect()
-{
- if (!is_resizable())
- return;
-
- auto old_rect = m_rect;
- if (m_tiled != WindowTileType::None)
- set_rect(tiled_rect(m_tiled));
- else if (is_maximized())
- set_rect(WindowManager::the().maximized_window_rect(*this));
- 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);
-}
-
-}
diff --git a/Servers/WindowServer/Window.h b/Servers/WindowServer/Window.h
deleted file mode 100644
index 09856c96dd..0000000000
--- a/Servers/WindowServer/Window.h
+++ /dev/null
@@ -1,286 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * 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/InlineLinkedList.h>
-#include <AK/String.h>
-#include <AK/WeakPtr.h>
-#include <LibCore/Object.h>
-#include <LibGfx/Bitmap.h>
-#include <LibGfx/DisjointRectSet.h>
-#include <LibGfx/Rect.h>
-#include <WindowServer/WindowFrame.h>
-#include <WindowServer/WindowType.h>
-
-namespace WindowServer {
-
-class ClientConnection;
-class Cursor;
-class Menu;
-class MenuItem;
-class MouseEvent;
-
-enum WMEventMask {
- WindowRectChanges = 1 << 0,
- WindowStateChanges = 1 << 1,
- WindowIconChanges = 1 << 2,
- WindowRemovals = 1 << 3,
-};
-
-enum class WindowTileType {
- None = 0,
- Left,
- Right,
-};
-
-enum class PopupMenuItem {
- Minimize = 0,
- Maximize,
-};
-
-class Window final : public Core::Object
- , public InlineLinkedListNode<Window> {
- C_OBJECT(Window)
-public:
- Window(ClientConnection&, WindowType, int window_id, bool modal, bool minimizable, bool frameless, bool resizable, bool fullscreen);
- Window(Core::Object&, WindowType);
- virtual ~Window() override;
-
- void popup_window_menu(const Gfx::Point&);
- 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);
-
- bool is_minimizable() const { return m_minimizable; }
- void set_minimizable(bool);
-
- bool is_resizable() const { return m_resizable && !m_fullscreen; }
- void set_resizable(bool);
-
- bool is_maximized() const { return m_maximized; }
- void set_maximized(bool);
-
- bool is_fullscreen() const { return m_fullscreen; }
- void set_fullscreen(bool);
-
- WindowTileType tiled() const { return m_tiled; }
- void set_tiled(WindowTileType);
-
- bool is_occluded() const { return m_occluded; }
- void set_occluded(bool);
-
- bool is_movable() const
- {
- return m_type == WindowType::Normal;
- }
-
- WindowFrame& frame() { return m_frame; }
- const WindowFrame& frame() const { return m_frame; }
-
- bool is_blocked_by_modal_window() const;
-
- bool listens_to_wm_events() const { return m_listens_to_wm_events; }
-
- ClientConnection* client() { return m_client; }
- const ClientConnection* client() const { return m_client; }
-
- WindowType type() const { return m_type; }
- int window_id() const { return m_window_id; }
-
- bool is_internal() const { return m_client_id == -1; }
- i32 client_id() const { return m_client_id; }
-
- String title() const { return m_title; }
- void set_title(const String&);
-
- float opacity() const { return m_opacity; }
- void set_opacity(float);
-
- int x() const { return m_rect.x(); }
- int y() const { return m_rect.y(); }
- int width() const { return m_rect.width(); }
- int height() const { return m_rect.height(); }
-
- bool is_active() const;
-
- bool is_visible() const { return m_visible; }
- void set_visible(bool);
-
- bool is_modal() const { return m_modal; }
-
- Gfx::Rect rect() const { return m_rect; }
- void set_rect(const Gfx::Rect&);
- void set_rect(int x, int y, int width, int height) { set_rect({ x, y, width, height }); }
- void set_rect_without_repaint(const Gfx::Rect&);
-
- void set_taskbar_rect(const Gfx::Rect& rect) { m_taskbar_rect = rect; }
- const Gfx::Rect& taskbar_rect() const { return m_taskbar_rect; }
-
- void move_to(const Gfx::Point& position) { set_rect({ position, size() }); }
- void move_to(int x, int y) { move_to({ x, y }); }
-
- void move_by(const Gfx::Point& delta) { set_position_without_repaint(position().translated(delta)); }
-
- Gfx::Point position() const { return m_rect.location(); }
- void set_position(const Gfx::Point& position) { set_rect({ position.x(), position.y(), width(), height() }); }
- void set_position_without_repaint(const Gfx::Point& position) { set_rect_without_repaint({ position.x(), position.y(), width(), height() }); }
-
- Gfx::Size size() const { return m_rect.size(); }
-
- void invalidate();
- void invalidate(const Gfx::Rect&);
-
- virtual void event(Core::Event&) override;
-
- // Only used by WindowType::MenuApplet. Perhaps it could be a Window subclass? I don't know.
- void set_rect_in_menubar(const Gfx::Rect& rect) { m_rect_in_menubar = rect; }
- const Gfx::Rect& rect_in_menubar() const { return m_rect_in_menubar; }
-
- const Gfx::Bitmap* backing_store() const { return m_backing_store.ptr(); }
- Gfx::Bitmap* backing_store() { return m_backing_store.ptr(); }
-
- void set_backing_store(RefPtr<Gfx::Bitmap>&& backing_store)
- {
- m_last_backing_store = move(m_backing_store);
- m_backing_store = move(backing_store);
- }
-
- void swap_backing_stores()
- {
- swap(m_backing_store, m_last_backing_store);
- }
-
- Gfx::Bitmap* last_backing_store() { return m_last_backing_store.ptr(); }
-
- void set_global_cursor_tracking_enabled(bool);
- void set_automatic_cursor_tracking_enabled(bool enabled) { m_automatic_cursor_tracking_enabled = enabled; }
- bool global_cursor_tracking() const { return m_global_cursor_tracking_enabled || m_automatic_cursor_tracking_enabled; }
-
- bool has_alpha_channel() const { return m_has_alpha_channel; }
- void set_has_alpha_channel(bool value) { m_has_alpha_channel = value; }
-
- Gfx::Size size_increment() const { return m_size_increment; }
- void set_size_increment(const Gfx::Size& increment) { m_size_increment = increment; }
-
- Gfx::Size base_size() const { return m_base_size; }
- void set_base_size(const Gfx::Size& size) { m_base_size = size; }
-
- const Gfx::Bitmap& icon() const { return *m_icon; }
- void set_icon(NonnullRefPtr<Gfx::Bitmap>&& icon) { m_icon = move(icon); }
-
- void set_default_icon();
-
- const Cursor* override_cursor() const { return m_override_cursor.ptr(); }
- void set_override_cursor(RefPtr<Cursor>&& cursor) { m_override_cursor = move(cursor); }
-
- void request_update(const Gfx::Rect&, bool ignore_occlusion = false);
- Gfx::DisjointRectSet take_pending_paint_rects() { return move(m_pending_paint_rects); }
-
- bool in_minimize_animation() const { return m_minimize_animation_step != -1; }
-
- int minimize_animation_index() const { return m_minimize_animation_step; }
- void step_minimize_animation() { m_minimize_animation_step += 1; }
- void start_minimize_animation() { m_minimize_animation_step = 0; }
- void end_minimize_animation() { m_minimize_animation_step = -1; }
-
- Gfx::Rect tiled_rect(WindowTileType) const;
- void recalculate_rect();
-
- // For InlineLinkedList.
- // FIXME: Maybe make a ListHashSet and then WindowManager can just use that.
- Window* m_next { nullptr };
- Window* m_prev { nullptr };
-
- 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&);
-
- Vector<WeakPtr<Window>>& child_windows() { return m_child_windows; }
- const Vector<WeakPtr<Window>>& child_windows() const { return m_child_windows; }
-
- void set_frameless(bool frameless) { m_frameless = frameless; }
- bool is_frameless() const { return m_frameless; }
-
-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;
- Gfx::Rect m_taskbar_rect;
- WindowType m_type { WindowType::Normal };
- bool m_global_cursor_tracking_enabled { false };
- bool m_automatic_cursor_tracking_enabled { false };
- bool m_visible { true };
- bool m_has_alpha_channel { false };
- bool m_modal { false };
- bool m_minimizable { false };
- bool m_frameless { false };
- bool m_resizable { false };
- bool m_listens_to_wm_events { false };
- bool m_minimized { false };
- bool m_maximized { false };
- bool m_fullscreen { false };
- WindowTileType m_tiled { WindowTileType::None };
- Gfx::Rect m_untiled_rect;
- bool m_occluded { false };
- RefPtr<Gfx::Bitmap> m_backing_store;
- RefPtr<Gfx::Bitmap> m_last_backing_store;
- int m_window_id { -1 };
- i32 m_client_id { -1 };
- float m_opacity { 1 };
- Gfx::Size m_size_increment;
- Gfx::Size m_base_size;
- NonnullRefPtr<Gfx::Bitmap> m_icon;
- RefPtr<Cursor> m_override_cursor;
- WindowFrame m_frame;
- unsigned m_wm_event_mask { 0 };
- Gfx::DisjointRectSet m_pending_paint_rects;
- Gfx::Rect m_unmaximized_rect;
- Gfx::Rect m_rect_in_menubar;
- RefPtr<Menu> m_window_menu;
- MenuItem* m_window_menu_minimize_item { nullptr };
- MenuItem* m_window_menu_maximize_item { nullptr };
- int m_minimize_animation_step { -1 };
-};
-
-}
diff --git a/Servers/WindowServer/WindowClient.ipc b/Servers/WindowServer/WindowClient.ipc
deleted file mode 100644
index 3c94ccf89e..0000000000
--- a/Servers/WindowServer/WindowClient.ipc
+++ /dev/null
@@ -1,40 +0,0 @@
-endpoint WindowClient = 4
-{
- Paint(i32 window_id, Gfx::Size window_size, Vector<Gfx::Rect> rects) =|
- MouseMove(i32 window_id, Gfx::Point mouse_position, u32 button, u32 buttons, u32 modifiers, i32 wheel_delta, bool is_drag, String drag_data_type) =|
- MouseDown(i32 window_id, Gfx::Point mouse_position, u32 button, u32 buttons, u32 modifiers, i32 wheel_delta) =|
- MouseDoubleClick(i32 window_id, Gfx::Point mouse_position, u32 button, u32 buttons, u32 modifiers, i32 wheel_delta) =|
- MouseUp(i32 window_id, Gfx::Point mouse_position, u32 button, u32 buttons, u32 modifiers, i32 wheel_delta) =|
- MouseWheel(i32 window_id, Gfx::Point mouse_position, u32 button, u32 buttons, u32 modifiers, i32 wheel_delta) =|
- WindowEntered(i32 window_id) =|
- WindowLeft(i32 window_id) =|
- KeyDown(i32 window_id, u8 character, u32 key, u32 modifiers) =|
- KeyUp(i32 window_id, u8 character, u32 key, u32 modifiers) =|
- WindowActivated(i32 window_id) =|
- WindowDeactivated(i32 window_id) =|
- WindowStateChanged(i32 window_id, bool minimized, bool occluded) =|
- WindowCloseRequest(i32 window_id) =|
- WindowResized(i32 window_id, Gfx::Rect old_rect, Gfx::Rect new_rect) =|
-
- MenuItemActivated(i32 menu_id, i32 identifier) =|
-
- ScreenRectChanged(Gfx::Rect rect) =|
-
- ClipboardContentsChanged(String content_type) =|
-
- WM_WindowRemoved(i32 wm_id, i32 client_id, i32 window_id) =|
- WM_WindowStateChanged(i32 wm_id, i32 client_id, i32 window_id, bool is_active, bool is_minimized, bool is_frameless, i32 window_type, String title, Gfx::Rect rect) =|
- WM_WindowIconBitmapChanged(i32 wm_id, i32 client_id, i32 window_id, i32 icon_buffer_id, Gfx::Size icon_size) =|
- WM_WindowRectChanged(i32 wm_id, i32 client_id, i32 window_id, Gfx::Rect rect) =|
-
- AsyncSetWallpaperFinished(bool success) =|
-
- DragAccepted() =|
- DragCancelled() =|
-
- DragDropped(i32 window_id, Gfx::Point mouse_position, String text, String data_type, String data) =|
-
- UpdateSystemTheme(i32 system_theme_buffer_id) =|
-
- DisplayLinkNotification() =|
-}
diff --git a/Servers/WindowServer/WindowFrame.cpp b/Servers/WindowServer/WindowFrame.cpp
deleted file mode 100644
index 2d6b8cad73..0000000000
--- a/Servers/WindowServer/WindowFrame.cpp
+++ /dev/null
@@ -1,414 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * 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 <AK/Badge.h>
-#include <LibGfx/CharacterBitmap.h>
-#include <LibGfx/Font.h>
-#include <LibGfx/Painter.h>
-#include <LibGfx/StylePainter.h>
-#include <WindowServer/Button.h>
-#include <WindowServer/Compositor.h>
-#include <WindowServer/Event.h>
-#include <WindowServer/Window.h>
-#include <WindowServer/WindowFrame.h>
-#include <WindowServer/WindowManager.h>
-
-namespace WindowServer {
-
-static const int window_titlebar_height = 19;
-
-static const char* s_close_button_bitmap_data = {
- "## ##"
- "### ###"
- " ###### "
- " #### "
- " #### "
- " ###### "
- "### ###"
- "## ##"
- " "
-};
-
-static Gfx::CharacterBitmap* s_close_button_bitmap;
-static const int s_close_button_bitmap_width = 8;
-static const int s_close_button_bitmap_height = 9;
-
-static const char* s_minimize_button_bitmap_data = {
- " "
- " "
- " "
- " ###### "
- " #### "
- " ## "
- " "
- " "
- " "
-};
-
-static Gfx::CharacterBitmap* s_minimize_button_bitmap;
-static const int s_minimize_button_bitmap_width = 8;
-static const int s_minimize_button_bitmap_height = 9;
-
-static const char* s_maximize_button_bitmap_data = {
- " "
- " "
- " "
- " ## "
- " #### "
- " ###### "
- " "
- " "
- " "
-};
-
-static Gfx::CharacterBitmap* s_maximize_button_bitmap;
-static const int s_maximize_button_bitmap_width = 8;
-static const int s_maximize_button_bitmap_height = 9;
-
-static const char* s_unmaximize_button_bitmap_data = {
- " "
- " ## "
- " #### "
- " ###### "
- " "
- " ###### "
- " #### "
- " ## "
- " "
-};
-
-static Gfx::CharacterBitmap* s_unmaximize_button_bitmap;
-static const int s_unmaximize_button_bitmap_width = 8;
-static const int s_unmaximize_button_bitmap_height = 9;
-
-WindowFrame::WindowFrame(Window& window)
- : m_window(window)
-{
- if (!s_close_button_bitmap)
- s_close_button_bitmap = &Gfx::CharacterBitmap::create_from_ascii(s_close_button_bitmap_data, s_close_button_bitmap_width, s_close_button_bitmap_height).leak_ref();
-
- if (!s_minimize_button_bitmap)
- s_minimize_button_bitmap = &Gfx::CharacterBitmap::create_from_ascii(s_minimize_button_bitmap_data, s_minimize_button_bitmap_width, s_minimize_button_bitmap_height).leak_ref();
-
- if (!s_maximize_button_bitmap)
- s_maximize_button_bitmap = &Gfx::CharacterBitmap::create_from_ascii(s_maximize_button_bitmap_data, s_maximize_button_bitmap_width, s_maximize_button_bitmap_height).leak_ref();
-
- if (!s_unmaximize_button_bitmap)
- s_unmaximize_button_bitmap = &Gfx::CharacterBitmap::create_from_ascii(s_unmaximize_button_bitmap_data, s_unmaximize_button_bitmap_width, s_unmaximize_button_bitmap_height).leak_ref();
-
- m_buttons.append(make<Button>(*this, *s_close_button_bitmap, [this](auto&) {
- m_window.request_close();
- }));
-
- if (window.is_resizable()) {
- auto button = make<Button>(*this, *s_maximize_button_bitmap, [this](auto&) {
- m_window.set_maximized(!m_window.is_maximized());
- });
- m_maximize_button = button.ptr();
- m_buttons.append(move(button));
- }
-
- if (window.is_minimizable()) {
- auto button = make<Button>(*this, *s_minimize_button_bitmap, [this](auto&) {
- m_window.set_minimized(true);
- });
- m_minimize_button = button.ptr();
- m_buttons.append(move(button));
- }
-}
-
-WindowFrame::~WindowFrame()
-{
-}
-
-void WindowFrame::did_set_maximized(Badge<Window>, bool maximized)
-{
- ASSERT(m_maximize_button);
- m_maximize_button->set_bitmap(maximized ? *s_unmaximize_button_bitmap : *s_maximize_button_bitmap);
-}
-
-Gfx::Rect WindowFrame::title_bar_rect() const
-{
- if (m_window.type() == WindowType::Notification)
- return { m_window.width() + 3, 3, window_titlebar_height, m_window.height() };
- return { 4, 4, m_window.width(), window_titlebar_height };
-}
-
-Gfx::Rect WindowFrame::title_bar_icon_rect() const
-{
- auto titlebar_rect = title_bar_rect();
- return {
- titlebar_rect.x() + 1,
- titlebar_rect.y() + 2,
- 16,
- titlebar_rect.height(),
- };
-}
-
-Gfx::Rect WindowFrame::title_bar_text_rect() const
-{
- auto titlebar_rect = title_bar_rect();
- auto titlebar_icon_rect = title_bar_icon_rect();
- return {
- titlebar_rect.x() + 2 + titlebar_icon_rect.width() + 2,
- titlebar_rect.y(),
- titlebar_rect.width() - 4 - titlebar_icon_rect.width() - 2,
- titlebar_rect.height()
- };
-}
-
-WindowFrame::FrameColors WindowFrame::compute_frame_colors() const
-{
- auto& wm = WindowManager::the();
- auto palette = wm.palette();
- if (&m_window == wm.m_highlight_window)
- return { palette.highlight_window_title(), palette.highlight_window_border1(), palette.highlight_window_border2() };
- if (&m_window == wm.m_move_window)
- return { palette.moving_window_title(), palette.moving_window_border1(), palette.moving_window_border2() };
- if (&m_window == wm.m_active_window)
- return { palette.active_window_title(), palette.active_window_border1(), palette.active_window_border2() };
- return { palette.inactive_window_title(), palette.inactive_window_border1(), palette.inactive_window_border2() };
-}
-
-void WindowFrame::paint_notification_frame(Gfx::Painter& painter)
-{
- auto palette = WindowManager::the().palette();
- Gfx::Rect outer_rect = { {}, rect().size() };
-
- Gfx::StylePainter::paint_window_frame(painter, outer_rect, palette);
-
- auto titlebar_rect = title_bar_rect();
- painter.fill_rect_with_gradient(Gfx::Orientation::Vertical, titlebar_rect, palette.active_window_border1(), palette.active_window_border2());
-
- int stripe_top = m_buttons.last().relative_rect().bottom() + 4;
- int stripe_bottom = m_window.height() - 3;
- if (stripe_top && stripe_bottom && stripe_top < stripe_bottom) {
- for (int i = 2; i <= window_titlebar_height - 2; i += 2) {
- painter.draw_line({ titlebar_rect.x() + i, stripe_top }, { titlebar_rect.x() + i, stripe_bottom }, palette.active_window_border1());
- }
- }
-}
-
-void WindowFrame::paint_normal_frame(Gfx::Painter& painter)
-{
- auto palette = WindowManager::the().palette();
- auto& window = m_window;
- Gfx::Rect outer_rect = { {}, rect().size() };
-
- Gfx::StylePainter::paint_window_frame(painter, outer_rect, palette);
-
- auto titlebar_rect = title_bar_rect();
- auto titlebar_icon_rect = title_bar_icon_rect();
- auto titlebar_inner_rect = title_bar_text_rect();
- auto titlebar_title_rect = titlebar_inner_rect;
- titlebar_title_rect.set_width(Gfx::Font::default_bold_font().width(window.title()));
-
- auto [title_color, border_color, border_color2] = compute_frame_colors();
-
- auto& wm = WindowManager::the();
- painter.draw_line(titlebar_rect.bottom_left().translated(0, 1), titlebar_rect.bottom_right().translated(0, 1), palette.button());
- painter.draw_line(titlebar_rect.bottom_left().translated(0, 2), titlebar_rect.bottom_right().translated(0, 2), palette.button());
-
- auto leftmost_button_rect = m_buttons.is_empty() ? Gfx::Rect() : m_buttons.last().relative_rect();
-
- painter.fill_rect_with_gradient(titlebar_rect, border_color, border_color2);
-
- int stripe_left = titlebar_title_rect.right() + 4;
- int stripe_right = leftmost_button_rect.left() - 3;
- if (stripe_left && stripe_right && stripe_left < stripe_right) {
- for (int i = 2; i <= titlebar_inner_rect.height() - 2; i += 2) {
- painter.draw_line({ stripe_left, titlebar_inner_rect.y() + i }, { stripe_right, titlebar_inner_rect.y() + i }, border_color);
- }
- }
-
- auto clipped_title_rect = titlebar_title_rect;
- clipped_title_rect.set_width(stripe_right - clipped_title_rect.x());
- if (!clipped_title_rect.is_empty()) {
- painter.draw_text(clipped_title_rect.translated(1, 2), window.title(), wm.window_title_font(), Gfx::TextAlignment::CenterLeft, border_color.darkened(0.4), Gfx::TextElision::Right);
- // FIXME: The translated(0, 1) wouldn't be necessary if we could center text based on its baseline.
- painter.draw_text(clipped_title_rect.translated(0, 1), window.title(), wm.window_title_font(), Gfx::TextAlignment::CenterLeft, title_color, Gfx::TextElision::Right);
- }
-
- painter.blit(titlebar_icon_rect.location(), window.icon(), window.icon().rect());
-}
-
-void WindowFrame::paint(Gfx::Painter& painter)
-{
- if (m_window.is_frameless())
- return;
-
- Gfx::PainterStateSaver saver(painter);
- painter.translate(rect().location());
-
- if (m_window.type() == WindowType::Notification)
- paint_notification_frame(painter);
- else if (m_window.type() == WindowType::Normal)
- paint_normal_frame(painter);
- else
- return;
-
- for (auto& button : m_buttons) {
- button.paint(painter);
- }
-}
-
-static Gfx::Rect frame_rect_for_window(Window& window, const Gfx::Rect& rect)
-{
- if (window.is_frameless())
- return rect;
-
- auto type = window.type();
-
- switch (type) {
- case WindowType::Normal:
- return {
- rect.x() - 4,
- rect.y() - window_titlebar_height - 6,
- rect.width() + 8,
- rect.height() + 10 + window_titlebar_height
- };
- case WindowType::Notification:
- return {
- rect.x() - 3,
- rect.y() - 3,
- rect.width() + 6 + window_titlebar_height,
- rect.height() + 6
- };
- default:
- return rect;
- }
-}
-
-static Gfx::Rect frame_rect_for_window(Window& window)
-{
- return frame_rect_for_window(window, window.rect());
-}
-
-Gfx::Rect WindowFrame::rect() const
-{
- return frame_rect_for_window(m_window);
-}
-
-void WindowFrame::invalidate_title_bar()
-{
- WindowManager::the().invalidate(title_bar_rect().translated(rect().location()));
-}
-
-void WindowFrame::notify_window_rect_changed(const Gfx::Rect& old_rect, const Gfx::Rect& new_rect)
-{
- int window_button_width = 15;
- int window_button_height = 15;
- int pos;
- if (m_window.type() == WindowType::Notification)
- pos = title_bar_rect().top() + 2;
- else
- pos = title_bar_text_rect().right() + 1;
-
- for (auto& button : m_buttons) {
- if (m_window.type() == WindowType::Notification) {
- Gfx::Rect rect { 0, pos, window_button_width, window_button_height };
- rect.center_horizontally_within(title_bar_rect());
- button.set_relative_rect(rect);
- pos += window_button_width;
- } else {
- pos -= window_button_width;
- Gfx::Rect rect { pos, 0, window_button_width, window_button_height };
- rect.center_vertically_within(title_bar_text_rect());
- button.set_relative_rect(rect);
- }
- }
-
- auto& wm = WindowManager::the();
- wm.invalidate(frame_rect_for_window(m_window, old_rect));
- wm.invalidate(frame_rect_for_window(m_window, new_rect));
- wm.notify_rect_changed(m_window, old_rect, new_rect);
-}
-
-void WindowFrame::on_mouse_event(const MouseEvent& event)
-{
- ASSERT(!m_window.is_fullscreen());
-
- if (m_window.is_blocked_by_modal_window())
- return;
-
- auto& wm = WindowManager::the();
- if (m_window.type() != WindowType::Normal && m_window.type() != WindowType::Notification)
- return;
-
- if (m_window.type() == WindowType::Normal && event.type() == Event::MouseDown && (event.button() == MouseButton::Left || event.button() == MouseButton::Right) && title_bar_icon_rect().contains(event.position())) {
- wm.move_to_front_and_make_active(m_window);
- m_window.popup_window_menu(title_bar_rect().bottom_left().translated(rect().location()));
- return;
- }
-
- // This is slightly hackish, but expand the title bar rect by two pixels downwards,
- // so that mouse events between the title bar and window contents don't act like
- // mouse events on the border.
- auto adjusted_title_bar_rect = title_bar_rect();
- adjusted_title_bar_rect.set_height(adjusted_title_bar_rect.height() + 2);
-
- if (adjusted_title_bar_rect.contains(event.position())) {
- wm.clear_resize_candidate();
-
- if (event.type() == Event::MouseDown)
- wm.move_to_front_and_make_active(m_window);
-
- for (auto& button : m_buttons) {
- if (button.relative_rect().contains(event.position()))
- return button.on_mouse_event(event.translated(-button.relative_rect().location()));
- }
- if (event.type() == Event::MouseDown) {
- if (m_window.type() == WindowType::Normal && event.button() == MouseButton::Right) {
- m_window.popup_window_menu(event.position().translated(rect().location()));
- return;
- }
- if (m_window.is_movable() && event.button() == MouseButton::Left)
- wm.start_window_move(m_window, event.translated(rect().location()));
- }
- return;
- }
-
- if (m_window.is_resizable() && event.type() == Event::MouseMove && event.buttons() == 0) {
- constexpr ResizeDirection direction_for_hot_area[3][3] = {
- { ResizeDirection::UpLeft, ResizeDirection::Up, ResizeDirection::UpRight },
- { ResizeDirection::Left, ResizeDirection::None, ResizeDirection::Right },
- { ResizeDirection::DownLeft, ResizeDirection::Down, ResizeDirection::DownRight },
- };
- Gfx::Rect outer_rect = { {}, rect().size() };
- ASSERT(outer_rect.contains(event.position()));
- int window_relative_x = event.x() - outer_rect.x();
- int window_relative_y = event.y() - outer_rect.y();
- int hot_area_row = min(2, window_relative_y / (outer_rect.height() / 3));
- int hot_area_column = min(2, window_relative_x / (outer_rect.width() / 3));
- wm.set_resize_candidate(m_window, direction_for_hot_area[hot_area_row][hot_area_column]);
- Compositor::the().invalidate_cursor();
- return;
- }
-
- if (m_window.is_resizable() && event.type() == Event::MouseDown && event.button() == MouseButton::Left)
- wm.start_window_resize(m_window, event.translated(rect().location()));
-}
-}
diff --git a/Servers/WindowServer/WindowFrame.h b/Servers/WindowServer/WindowFrame.h
deleted file mode 100644
index 021edb9d0f..0000000000
--- a/Servers/WindowServer/WindowFrame.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * 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/Forward.h>
-#include <AK/NonnullOwnPtrVector.h>
-#include <LibGfx/Forward.h>
-
-namespace WindowServer {
-
-class Button;
-class MouseEvent;
-class Window;
-
-class WindowFrame {
-public:
- WindowFrame(Window&);
- ~WindowFrame();
-
- Gfx::Rect rect() const;
- void paint(Gfx::Painter&);
- void on_mouse_event(const MouseEvent&);
- void notify_window_rect_changed(const Gfx::Rect& old_rect, const Gfx::Rect& new_rect);
- void invalidate_title_bar();
-
- Gfx::Rect title_bar_rect() const;
- Gfx::Rect title_bar_icon_rect() const;
- Gfx::Rect title_bar_text_rect() const;
-
- void did_set_maximized(Badge<Window>, bool);
-
-private:
- void paint_notification_frame(Gfx::Painter&);
- void paint_normal_frame(Gfx::Painter&);
-
- struct FrameColors {
- Color title_color;
- Color border_color;
- Color border_color2;
- };
-
- FrameColors compute_frame_colors() const;
-
- Window& m_window;
- NonnullOwnPtrVector<Button> m_buttons;
- Button* m_maximize_button { nullptr };
- Button* m_minimize_button { nullptr };
-};
-
-}
diff --git a/Servers/WindowServer/WindowManager.cpp b/Servers/WindowServer/WindowManager.cpp
deleted file mode 100644
index 2b168107d1..0000000000
--- a/Servers/WindowServer/WindowManager.cpp
+++ /dev/null
@@ -1,1317 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * 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 "WindowManager.h"
-#include "Compositor.h"
-#include "EventLoop.h"
-#include "Menu.h"
-#include "MenuBar.h"
-#include "MenuItem.h"
-#include "Screen.h"
-#include "Window.h"
-#include <AK/LogStream.h>
-#include <AK/SharedBuffer.h>
-#include <AK/StdLibExtras.h>
-#include <AK/Vector.h>
-#include <LibGfx/CharacterBitmap.h>
-#include <LibGfx/Font.h>
-#include <LibGfx/Painter.h>
-#include <LibGfx/StylePainter.h>
-#include <LibGfx/SystemTheme.h>
-#include <WindowServer/AppletManager.h>
-#include <WindowServer/Button.h>
-#include <WindowServer/ClientConnection.h>
-#include <WindowServer/Cursor.h>
-#include <WindowServer/WindowClientEndpoint.h>
-#include <errno.h>
-#include <serenity.h>
-#include <stdio.h>
-#include <time.h>
-#include <unistd.h>
-
-//#define WINDOWMANAGER_DEBUG
-//#define RESIZE_DEBUG
-//#define MOVE_DEBUG
-//#define DOUBLECLICK_DEBUG
-
-namespace WindowServer {
-
-static WindowManager* s_the;
-
-WindowManager& WindowManager::the()
-{
- ASSERT(s_the);
- return *s_the;
-}
-
-WindowManager::WindowManager(const Gfx::PaletteImpl& palette)
- : m_palette(palette)
-{
- s_the = this;
-
- reload_config(false);
-
- invalidate();
- Compositor::the().compose();
-}
-
-WindowManager::~WindowManager()
-{
-}
-
-NonnullRefPtr<Cursor> WindowManager::get_cursor(const String& name, const Gfx::Point& hotspot)
-{
- auto path = m_wm_config->read_entry("Cursor", name, "/res/cursors/arrow.png");
- auto gb = Gfx::Bitmap::load_from_file(path);
- if (gb)
- return Cursor::create(*gb, hotspot);
- return Cursor::create(*Gfx::Bitmap::load_from_file("/res/cursors/arrow.png"));
-}
-
-NonnullRefPtr<Cursor> WindowManager::get_cursor(const String& name)
-{
- auto path = m_wm_config->read_entry("Cursor", name, "/res/cursors/arrow.png");
- auto gb = Gfx::Bitmap::load_from_file(path);
-
- if (gb)
- return Cursor::create(*gb);
- return Cursor::create(*Gfx::Bitmap::load_from_file("/res/cursors/arrow.png"));
-}
-
-void WindowManager::reload_config(bool set_screen)
-{
- m_wm_config = Core::ConfigFile::open("/etc/WindowServer/WindowServer.ini");
-
- m_double_click_speed = m_wm_config->read_num_entry("Input", "DoubleClickSpeed", 250);
-
- if (set_screen) {
- set_resolution(m_wm_config->read_num_entry("Screen", "Width", 1920), m_wm_config->read_num_entry("Screen", "Height", 1080));
- }
-
- m_arrow_cursor = get_cursor("Arrow", { 2, 2 });
- m_hand_cursor = get_cursor("Hand", { 8, 4 });
- m_resize_horizontally_cursor = get_cursor("ResizeH");
- m_resize_vertically_cursor = get_cursor("ResizeV");
- m_resize_diagonally_tlbr_cursor = get_cursor("ResizeDTLBR");
- m_resize_diagonally_bltr_cursor = get_cursor("ResizeDBLTR");
- m_i_beam_cursor = get_cursor("IBeam");
- m_disallowed_cursor = get_cursor("Disallowed");
- m_move_cursor = get_cursor("Move");
- m_drag_cursor = get_cursor("Drag");
-}
-
-const Gfx::Font& WindowManager::font() const
-{
- return Gfx::Font::default_font();
-}
-
-const Gfx::Font& WindowManager::window_title_font() const
-{
- return Gfx::Font::default_bold_font();
-}
-
-bool WindowManager::set_resolution(int width, int height)
-{
- bool success = Compositor::the().set_resolution(width, height);
- MenuManager::the().set_needs_window_resize();
- ClientConnection::for_each_client([&](ClientConnection& client) {
- client.notify_about_new_screen_rect(Screen::the().rect());
- });
- if (success) {
- for_each_window([](Window& window) {
- if (window.type() == WindowType::Desktop)
- window.set_rect(WindowManager::the().desktop_rect());
- window.recalculate_rect();
- return IterationDecision::Continue;
- });
- }
- if (m_wm_config) {
- if (success) {
- dbg() << "Saving resolution: " << Gfx::Size(width, height) << " to config file at " << m_wm_config->file_name();
- m_wm_config->write_num_entry("Screen", "Width", width);
- m_wm_config->write_num_entry("Screen", "Height", height);
- m_wm_config->sync();
- } else {
- dbg() << "Saving fallback resolution: " << resolution() << " to config file at " << m_wm_config->file_name();
- m_wm_config->write_num_entry("Screen", "Width", resolution().width());
- m_wm_config->write_num_entry("Screen", "Height", resolution().height());
- m_wm_config->sync();
- }
- }
- return success;
-}
-
-Gfx::Size WindowManager::resolution() const
-{
- return Screen::the().size();
-}
-
-void WindowManager::add_window(Window& window)
-{
- bool is_first_window = m_windows_in_order.is_empty();
-
- m_windows_in_order.append(&window);
-
- if (window.is_fullscreen()) {
- Core::EventLoop::current().post_event(window, make<ResizeEvent>(window.rect(), Screen::the().rect()));
- window.set_rect(Screen::the().rect());
- }
-
- if (window.type() != WindowType::Desktop || is_first_window)
- set_active_window(&window);
-
- if (m_switcher.is_visible() && window.type() != WindowType::WindowSwitcher)
- m_switcher.refresh();
-
- recompute_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;
- });
- }
-
- tell_wm_listeners_window_state_changed(window);
-}
-
-void WindowManager::move_to_front_and_make_active(Window& window)
-{
- if (window.is_blocked_by_modal_window())
- return;
-
- if (m_windows_in_order.tail() != &window)
- invalidate(window);
- m_windows_in_order.remove(&window);
- m_windows_in_order.append(&window);
-
- recompute_occlusions();
-
- set_active_window(&window);
-
- if (m_switcher.is_visible()) {
- m_switcher.refresh();
- m_switcher.select_window(window);
- set_highlight_window(&window);
- }
-
- for (auto& child_window : window.child_windows()) {
- if (child_window)
- move_to_front_and_make_active(*child_window);
- }
-}
-
-void WindowManager::remove_window(Window& window)
-{
- invalidate(window);
- m_windows_in_order.remove(&window);
- if (window.is_active())
- pick_new_active_window();
- if (m_switcher.is_visible() && window.type() != WindowType::WindowSwitcher)
- m_switcher.refresh();
-
- recompute_occlusions();
-
- for_each_window_listening_to_wm_events([&window](Window& listener) {
- if (!(listener.wm_event_mask() & WMEventMask::WindowRemovals))
- return IterationDecision::Continue;
- if (!window.is_internal())
- listener.client()->post_message(Messages::WindowClient::WM_WindowRemoved(listener.window_id(), window.client_id(), window.window_id()));
- return IterationDecision::Continue;
- });
-}
-
-void WindowManager::tell_wm_listener_about_window(Window& listener, Window& window)
-{
- if (!(listener.wm_event_mask() & WMEventMask::WindowStateChanges))
- return;
- if (window.is_internal())
- return;
- listener.client()->post_message(Messages::WindowClient::WM_WindowStateChanged(listener.window_id(), window.client_id(), window.window_id(), window.is_active(), window.is_minimized(), window.is_frameless(), (i32)window.type(), window.title(), window.rect()));
-}
-
-void WindowManager::tell_wm_listener_about_window_rect(Window& listener, Window& window)
-{
- if (!(listener.wm_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()));
-}
-
-void WindowManager::tell_wm_listener_about_window_icon(Window& listener, Window& window)
-{
- if (!(listener.wm_event_mask() & WMEventMask::WindowIconChanges))
- return;
- if (window.is_internal())
- return;
- if (window.icon().shbuf_id() == -1)
- return;
-#ifdef WINDOWMANAGER_DEBUG
- dbg() << "WindowServer: Sharing icon buffer " << window.icon().shbuf_id() << " with PID " << listener.client()->client_pid();
-#endif
- if (shbuf_allow_pid(window.icon().shbuf_id(), listener.client()->client_pid()) < 0) {
- ASSERT_NOT_REACHED();
- }
- listener.client()->post_message(Messages::WindowClient::WM_WindowIconBitmapChanged(listener.window_id(), window.client_id(), window.window_id(), window.icon().shbuf_id(), window.icon().size()));
-}
-
-void WindowManager::tell_wm_listeners_window_state_changed(Window& window)
-{
- for_each_window_listening_to_wm_events([&](Window& listener) {
- tell_wm_listener_about_window(listener, window);
- return IterationDecision::Continue;
- });
-}
-
-void WindowManager::tell_wm_listeners_window_icon_changed(Window& window)
-{
- for_each_window_listening_to_wm_events([&](Window& listener) {
- tell_wm_listener_about_window_icon(listener, window);
- return IterationDecision::Continue;
- });
-}
-
-void WindowManager::tell_wm_listeners_window_rect_changed(Window& window)
-{
- for_each_window_listening_to_wm_events([&](Window& listener) {
- tell_wm_listener_about_window_rect(listener, window);
- return IterationDecision::Continue;
- });
-}
-
-void WindowManager::notify_title_changed(Window& window)
-{
- if (window.type() != WindowType::Normal)
- return;
-#ifdef WINDOWMANAGER_DEBUG
- dbg() << "[WM] Window{" << &window << "} title set to \"" << window.title() << '"';
-#endif
- invalidate(window.frame().rect());
- if (m_switcher.is_visible())
- m_switcher.refresh();
-
- tell_wm_listeners_window_state_changed(window);
-}
-
-void WindowManager::notify_rect_changed(Window& window, const Gfx::Rect& old_rect, const Gfx::Rect& new_rect)
-{
- UNUSED_PARAM(old_rect);
- UNUSED_PARAM(new_rect);
-#ifdef RESIZE_DEBUG
- dbg() << "[WM] Window " << &window << " rect changed " << old_rect << " -> " << new_rect;
-#endif
- if (m_switcher.is_visible() && window.type() != WindowType::WindowSwitcher)
- m_switcher.refresh();
-
- recompute_occlusions();
-
- tell_wm_listeners_window_rect_changed(window);
-
- MenuManager::the().refresh();
-}
-
-void WindowManager::recompute_occlusions()
-{
- for_each_visible_window_from_back_to_front([&](Window& window) {
- if (m_switcher.is_visible()) {
- window.set_occluded(false);
- } else {
- if (any_opaque_window_above_this_one_contains_rect(window, window.frame().rect()))
- window.set_occluded(true);
- else
- window.set_occluded(false);
- }
- return IterationDecision::Continue;
- });
-}
-
-void WindowManager::notify_opacity_changed(Window&)
-{
- recompute_occlusions();
-}
-
-void WindowManager::notify_minimization_state_changed(Window& window)
-{
- tell_wm_listeners_window_state_changed(window);
-
- if (window.client())
- window.client()->post_message(Messages::WindowClient::WindowStateChanged(window.window_id(), window.is_minimized(), window.is_occluded()));
-
- if (window.is_active() && window.is_minimized())
- pick_new_active_window();
-}
-
-void WindowManager::notify_occlusion_state_changed(Window& window)
-{
- if (window.client())
- window.client()->post_message(Messages::WindowClient::WindowStateChanged(window.window_id(), window.is_minimized(), window.is_occluded()));
-}
-
-void WindowManager::pick_new_active_window()
-{
- bool new_window_picked = false;
- for_each_visible_window_of_type_from_front_to_back(WindowType::Normal, [&](Window& candidate) {
- set_active_window(&candidate);
- new_window_picked = true;
- return IterationDecision::Break;
- });
- if (!new_window_picked)
- set_active_window(nullptr);
-}
-
-void WindowManager::start_window_move(Window& window, const MouseEvent& event)
-{
-#ifdef MOVE_DEBUG
- dbg() << "[WM] Begin moving Window{" << &window << "}";
-#endif
- move_to_front_and_make_active(window);
- m_move_window = window.make_weak_ptr();
- m_move_origin = event.position();
- m_move_window_origin = window.position();
- invalidate(window);
-}
-
-void WindowManager::start_window_resize(Window& window, const Gfx::Point& position, MouseButton button)
-{
- move_to_front_and_make_active(window);
- constexpr ResizeDirection direction_for_hot_area[3][3] = {
- { ResizeDirection::UpLeft, ResizeDirection::Up, ResizeDirection::UpRight },
- { ResizeDirection::Left, ResizeDirection::None, ResizeDirection::Right },
- { ResizeDirection::DownLeft, ResizeDirection::Down, ResizeDirection::DownRight },
- };
- Gfx::Rect outer_rect = window.frame().rect();
- ASSERT(outer_rect.contains(position));
- int window_relative_x = position.x() - outer_rect.x();
- int window_relative_y = position.y() - outer_rect.y();
- int hot_area_row = min(2, window_relative_y / (outer_rect.height() / 3));
- int hot_area_column = min(2, window_relative_x / (outer_rect.width() / 3));
- m_resize_direction = direction_for_hot_area[hot_area_row][hot_area_column];
- if (m_resize_direction == ResizeDirection::None) {
- ASSERT(!m_resize_window);
- return;
- }
-
-#ifdef RESIZE_DEBUG
- dbg() << "[WM] Begin resizing Window{" << &window << "}";
-#endif
- m_resizing_mouse_button = button;
- m_resize_window = window.make_weak_ptr();
- ;
- m_resize_origin = position;
- m_resize_window_original_rect = window.rect();
-
- invalidate(window);
-}
-
-void WindowManager::start_window_resize(Window& window, const MouseEvent& event)
-{
- start_window_resize(window, event.position(), event.button());
-}
-
-bool WindowManager::process_ongoing_window_move(MouseEvent& event, Window*& hovered_window)
-{
- if (!m_move_window)
- return false;
- if (event.type() == Event::MouseUp && event.button() == MouseButton::Left) {
-#ifdef MOVE_DEBUG
- dbg() << "[WM] Finish moving Window{" << m_move_window << "}";
-#endif
-
- invalidate(*m_move_window);
- if (m_move_window->rect().contains(event.position()))
- hovered_window = m_move_window;
- if (m_move_window->is_resizable()) {
- process_event_for_doubleclick(*m_move_window, event);
- if (event.type() == Event::MouseDoubleClick) {
-#if defined(DOUBLECLICK_DEBUG)
- dbg() << "[WM] Click up became doubleclick!";
-#endif
- m_move_window->set_maximized(!m_move_window->is_maximized());
- }
- }
- m_move_window = nullptr;
- return true;
- }
- if (event.type() == Event::MouseMove) {
-
-#ifdef MOVE_DEBUG
- dbg() << "[WM] Moving, origin: " << m_move_origin << ", now: " << event.position();
- if (m_move_window->is_maximized()) {
- dbg() << " [!] The window is still maximized. Not moving yet.";
- }
-
-#endif
-
- const int maximization_deadzone = 2;
-
- if (m_move_window->is_maximized()) {
- auto pixels_moved_from_start = event.position().pixels_moved(m_move_origin);
- // dbg() << "[WM] " << pixels_moved_from_start << " moved since start of window move";
- if (pixels_moved_from_start > 5) {
- // dbg() << "[WM] de-maximizing window";
- m_move_origin = event.position();
- if (m_move_origin.y() <= maximization_deadzone)
- return true;
- auto width_before_resize = m_move_window->width();
- m_move_window->set_maximized(false);
- m_move_window->move_to(m_move_origin.x() - (m_move_window->width() * ((float)m_move_origin.x() / width_before_resize)), m_move_origin.y());
- m_move_window_origin = m_move_window->position();
- }
- } else {
- bool is_resizable = m_move_window->is_resizable();
- auto pixels_moved_from_start = event.position().pixels_moved(m_move_origin);
- const int tiling_deadzone = 5;
-
- if (is_resizable && event.y() <= maximization_deadzone) {
- m_move_window->set_tiled(WindowTileType::None);
- m_move_window->set_maximized(true);
- return true;
- }
- if (is_resizable && event.x() <= tiling_deadzone) {
- m_move_window->set_tiled(WindowTileType::Left);
- } else if (is_resizable && event.x() >= Screen::the().width() - tiling_deadzone) {
- m_move_window->set_tiled(WindowTileType::Right);
- } else if (pixels_moved_from_start > 5 || m_move_window->tiled() == WindowTileType::None) {
- m_move_window->set_tiled(WindowTileType::None);
- Gfx::Point pos = m_move_window_origin.translated(event.position() - m_move_origin);
- m_move_window->set_position_without_repaint(pos);
- if (m_move_window->rect().contains(event.position()))
- hovered_window = m_move_window;
- }
- return true;
- }
- }
- return false;
-}
-
-bool WindowManager::process_ongoing_window_resize(const MouseEvent& event, Window*& hovered_window)
-{
- if (!m_resize_window)
- return false;
-
- if (event.type() == Event::MouseUp && event.button() == m_resizing_mouse_button) {
-#ifdef RESIZE_DEBUG
- dbg() << "[WM] Finish resizing Window{" << m_resize_window << "}";
-#endif
- Core::EventLoop::current().post_event(*m_resize_window, make<ResizeEvent>(m_resize_window->rect(), m_resize_window->rect()));
- invalidate(*m_resize_window);
- if (m_resize_window->rect().contains(event.position()))
- hovered_window = m_resize_window;
- m_resize_window = nullptr;
- m_resizing_mouse_button = MouseButton::None;
- return true;
- }
-
- if (event.type() != Event::MouseMove)
- return false;
-
- auto old_rect = m_resize_window->rect();
-
- int diff_x = event.x() - m_resize_origin.x();
- int diff_y = event.y() - m_resize_origin.y();
-
- int change_w = 0;
- int change_h = 0;
-
- switch (m_resize_direction) {
- case ResizeDirection::DownRight:
- change_w = diff_x;
- change_h = diff_y;
- break;
- case ResizeDirection::Right:
- change_w = diff_x;
- break;
- case ResizeDirection::UpRight:
- change_w = diff_x;
- change_h = -diff_y;
- break;
- case ResizeDirection::Up:
- change_h = -diff_y;
- break;
- case ResizeDirection::UpLeft:
- change_w = -diff_x;
- change_h = -diff_y;
- break;
- case ResizeDirection::Left:
- change_w = -diff_x;
- break;
- case ResizeDirection::DownLeft:
- change_w = -diff_x;
- change_h = diff_y;
- break;
- case ResizeDirection::Down:
- change_h = diff_y;
- break;
- default:
- ASSERT_NOT_REACHED();
- }
-
- auto new_rect = m_resize_window_original_rect;
-
- // First, size the new rect.
- Gfx::Size minimum_size { 50, 50 };
-
- new_rect.set_width(max(minimum_size.width(), new_rect.width() + change_w));
- new_rect.set_height(max(minimum_size.height(), new_rect.height() + change_h));
-
- if (!m_resize_window->size_increment().is_null()) {
- int horizontal_incs = (new_rect.width() - m_resize_window->base_size().width()) / m_resize_window->size_increment().width();
- new_rect.set_width(m_resize_window->base_size().width() + horizontal_incs * m_resize_window->size_increment().width());
- int vertical_incs = (new_rect.height() - m_resize_window->base_size().height()) / m_resize_window->size_increment().height();
- new_rect.set_height(m_resize_window->base_size().height() + vertical_incs * m_resize_window->size_increment().height());
- }
-
- // Second, set its position so that the sides of the window
- // that end up moving are the same ones as the user is dragging,
- // no matter which part of the logic above caused us to decide
- // to resize by this much.
- switch (m_resize_direction) {
- case ResizeDirection::DownRight:
- case ResizeDirection::Right:
- case ResizeDirection::Down:
- break;
- case ResizeDirection::Left:
- case ResizeDirection::Up:
- case ResizeDirection::UpLeft:
- new_rect.set_right_without_resize(m_resize_window_original_rect.right());
- new_rect.set_bottom_without_resize(m_resize_window_original_rect.bottom());
- break;
- case ResizeDirection::UpRight:
- new_rect.set_bottom_without_resize(m_resize_window_original_rect.bottom());
- break;
- case ResizeDirection::DownLeft:
- new_rect.set_right_without_resize(m_resize_window_original_rect.right());
- break;
- default:
- ASSERT_NOT_REACHED();
- }
-
- if (new_rect.contains(event.position()))
- hovered_window = m_resize_window;
-
- if (m_resize_window->rect() == new_rect)
- return true;
-#ifdef RESIZE_DEBUG
- dbg() << "[WM] Resizing, original: " << m_resize_window_original_rect << ", now: " << new_rect;
-#endif
- m_resize_window->set_rect(new_rect);
- Core::EventLoop::current().post_event(*m_resize_window, make<ResizeEvent>(old_rect, new_rect));
- return true;
-}
-
-bool WindowManager::process_ongoing_drag(MouseEvent& event, Window*& hovered_window)
-{
- if (!m_dnd_client)
- return false;
-
- if (event.type() == Event::MouseMove) {
- // We didn't let go of the drag yet, see if we should send some drag move events..
- for_each_visible_window_from_front_to_back([&](Window& window) {
- if (!window.rect().contains(event.position()))
- return IterationDecision::Continue;
- hovered_window = &window;
- auto translated_event = event.translated(-window.position());
- translated_event.set_drag(true);
- translated_event.set_drag_data_type(m_dnd_data_type);
- deliver_mouse_event(window, translated_event);
- return IterationDecision::Break;
- });
- }
-
- if (!(event.type() == Event::MouseUp && event.button() == MouseButton::Left))
- return true;
-
- hovered_window = nullptr;
- for_each_visible_window_from_front_to_back([&](auto& window) {
- if (window.frame().rect().contains(event.position())) {
- hovered_window = &window;
- return IterationDecision::Break;
- }
- return IterationDecision::Continue;
- });
-
- if (hovered_window) {
- m_dnd_client->post_message(Messages::WindowClient::DragAccepted());
- if (hovered_window->client()) {
- auto translated_event = event.translated(-hovered_window->position());
- hovered_window->client()->post_message(Messages::WindowClient::DragDropped(hovered_window->window_id(), translated_event.position(), m_dnd_text, m_dnd_data_type, m_dnd_data));
- }
- } else {
- m_dnd_client->post_message(Messages::WindowClient::DragCancelled());
- }
-
- end_dnd_drag();
- return true;
-}
-
-void WindowManager::set_cursor_tracking_button(Button* button)
-{
- m_cursor_tracking_button = button ? button->make_weak_ptr() : nullptr;
-}
-
-auto WindowManager::DoubleClickInfo::metadata_for_button(MouseButton button) -> ClickMetadata&
-{
- switch (button) {
- case MouseButton::Left:
- return m_left;
- case MouseButton::Right:
- return m_right;
- case MouseButton::Middle:
- return m_middle;
- case MouseButton::Back:
- return m_back;
- case MouseButton::Forward:
- return m_forward;
- default:
- ASSERT_NOT_REACHED();
- }
-}
-
-// #define DOUBLECLICK_DEBUG
-
-void WindowManager::process_event_for_doubleclick(Window& window, MouseEvent& event)
-{
- // We only care about button presses (because otherwise it's not a doubleclick, duh!)
- ASSERT(event.type() == Event::MouseUp);
-
- if (&window != m_double_click_info.m_clicked_window) {
- // we either haven't clicked anywhere, or we haven't clicked on this
- // window. set the current click window, and reset the timers.
-#if defined(DOUBLECLICK_DEBUG)
- dbg() << "Initial mouseup on window " << &window << " (previous was " << m_double_click_info.m_clicked_window << ')';
-#endif
- m_double_click_info.m_clicked_window = window.make_weak_ptr();
- m_double_click_info.reset();
- }
-
- auto& metadata = m_double_click_info.metadata_for_button(event.button());
-
- // if the clock is invalid, we haven't clicked with this button on this
- // window yet, so there's nothing to do.
- if (!metadata.clock.is_valid()) {
- metadata.clock.start();
- } else {
- int elapsed_since_last_click = metadata.clock.elapsed();
- metadata.clock.start();
- if (elapsed_since_last_click < m_double_click_speed) {
- auto diff = event.position() - metadata.last_position;
- auto distance_travelled_squared = diff.x() * diff.x() + diff.y() * diff.y();
- if (distance_travelled_squared > (m_max_distance_for_double_click * m_max_distance_for_double_click)) {
- // too far; try again
- metadata.clock.start();
- } else {
-#if defined(DOUBLECLICK_DEBUG)
- dbg() << "Transforming MouseUp to MouseDoubleClick (" << elapsed_since_last_click << " < " << m_double_click_speed << ")!";
-#endif
- event = MouseEvent(Event::MouseDoubleClick, event.position(), event.buttons(), event.button(), event.modifiers(), event.wheel_delta());
- // invalidate this now we've delivered a doubleclick, otherwise
- // tripleclick will deliver two doubleclick events (incorrectly).
- metadata.clock = {};
- }
- } else {
- // too slow; try again
- metadata.clock.start();
- }
- }
-
- metadata.last_position = event.position();
-}
-
-void WindowManager::deliver_mouse_event(Window& window, MouseEvent& event)
-{
- window.dispatch_event(event);
- if (event.type() == Event::MouseUp) {
- process_event_for_doubleclick(window, event);
- if (event.type() == Event::MouseDoubleClick)
- window.dispatch_event(event);
- }
-}
-
-void WindowManager::process_mouse_event(MouseEvent& event, Window*& hovered_window)
-{
- hovered_window = nullptr;
-
- if (process_ongoing_drag(event, hovered_window))
- return;
-
- if (process_ongoing_window_move(event, hovered_window))
- return;
-
- if (process_ongoing_window_resize(event, hovered_window))
- return;
-
- if (m_cursor_tracking_button)
- return m_cursor_tracking_button->on_mouse_event(event.translated(-m_cursor_tracking_button->screen_rect().location()));
-
- // This is quite hackish, but it's how the Button hover effect is implemented.
- if (m_hovered_button && event.type() == Event::MouseMove)
- m_hovered_button->on_mouse_event(event.translated(-m_hovered_button->screen_rect().location()));
-
- HashTable<Window*> windows_who_received_mouse_event_due_to_cursor_tracking;
-
- for (auto* window = m_windows_in_order.tail(); window; window = window->prev()) {
- if (!window->global_cursor_tracking())
- continue;
- ASSERT(window->is_visible()); // Maybe this should be supported? Idk. Let's catch it and think about it later.
- ASSERT(!window->is_minimized()); // Maybe this should also be supported? Idk.
- windows_who_received_mouse_event_due_to_cursor_tracking.set(window);
- auto translated_event = event.translated(-window->position());
- deliver_mouse_event(*window, translated_event);
- }
-
- // FIXME: Now that the menubar has a dedicated window, is this special-casing really necessary?
- if (MenuManager::the().has_open_menu() || (!active_window_is_modal() && menubar_rect().contains(event.position()))) {
- clear_resize_candidate();
- MenuManager::the().dispatch_event(event);
- return;
- }
-
- Window* event_window_with_frame = nullptr;
-
- if (m_active_input_window) {
- // At this point, we have delivered the start of an input sequence to a
- // client application. We must keep delivering to that client
- // application until the input sequence is done.
- //
- // This prevents e.g. moving on one window out of the bounds starting
- // a move in that other unrelated window, and other silly shenanigans.
- if (!windows_who_received_mouse_event_due_to_cursor_tracking.contains(m_active_input_window)) {
- auto translated_event = event.translated(-m_active_input_window->position());
- deliver_mouse_event(*m_active_input_window, translated_event);
- windows_who_received_mouse_event_due_to_cursor_tracking.set(m_active_input_window.ptr());
- }
- if (event.type() == Event::MouseUp && event.buttons() == 0) {
- m_active_input_window = nullptr;
- }
-
- for_each_visible_window_from_front_to_back([&](auto& window) {
- if (window.frame().rect().contains(event.position())) {
- hovered_window = &window;
- return IterationDecision::Break;
- }
- return IterationDecision::Continue;
- });
- } else {
- for_each_visible_window_from_front_to_back([&](Window& window) {
- auto window_frame_rect = window.frame().rect();
- if (!window_frame_rect.contains(event.position()))
- return IterationDecision::Continue;
-
- if (&window != m_resize_candidate.ptr())
- clear_resize_candidate();
-
- // First check if we should initiate a move or resize (Logo+LMB or Logo+RMB).
- // In those cases, the event is swallowed by the window manager.
- if (window.is_movable()) {
- if (!window.is_fullscreen() && m_keyboard_modifiers == Mod_Logo && event.type() == Event::MouseDown && event.button() == MouseButton::Left) {
- hovered_window = &window;
- start_window_move(window, event);
- m_moved_or_resized_since_logo_keydown = true;
- return IterationDecision::Break;
- }
- if (window.is_resizable() && m_keyboard_modifiers == Mod_Logo && event.type() == Event::MouseDown && event.button() == MouseButton::Right && !window.is_blocked_by_modal_window()) {
- hovered_window = &window;
- start_window_resize(window, event);
- m_moved_or_resized_since_logo_keydown = true;
- return IterationDecision::Break;
- }
- }
-
- if (m_keyboard_modifiers == Mod_Logo && event.type() == Event::MouseWheel) {
- float opacity_change = -event.wheel_delta() * 0.05f;
- float new_opacity = window.opacity() + opacity_change;
- if (new_opacity < 0.05f)
- new_opacity = 0.05f;
- if (new_opacity > 1.0f)
- new_opacity = 1.0f;
- window.set_opacity(new_opacity);
- window.invalidate();
- return IterationDecision::Break;
- }
-
- // Well okay, let's see if we're hitting the frame or the window inside the frame.
- if (window.rect().contains(event.position())) {
- if (event.type() == Event::MouseDown) {
- if (window.type() == WindowType::Normal)
- move_to_front_and_make_active(window);
- else if (window.type() == WindowType::Desktop)
- set_active_window(&window);
- }
-
- hovered_window = &window;
- if (!window.global_cursor_tracking() && !windows_who_received_mouse_event_due_to_cursor_tracking.contains(&window)) {
- auto translated_event = event.translated(-window.position());
- deliver_mouse_event(window, translated_event);
- if (event.type() == Event::MouseDown) {
- m_active_input_window = window.make_weak_ptr();
- }
- }
- return IterationDecision::Break;
- }
-
- // We are hitting the frame, pass the event along to WindowFrame.
- window.frame().on_mouse_event(event.translated(-window_frame_rect.location()));
- event_window_with_frame = &window;
- return IterationDecision::Break;
- });
-
- // Clicked outside of any window
- if (!hovered_window && !event_window_with_frame && event.type() == Event::MouseDown)
- set_active_window(nullptr);
- }
-
- if (event_window_with_frame != m_resize_candidate.ptr())
- clear_resize_candidate();
-}
-
-void WindowManager::clear_resize_candidate()
-{
- if (m_resize_candidate)
- Compositor::the().invalidate_cursor();
- m_resize_candidate = nullptr;
-}
-
-bool WindowManager::any_opaque_window_contains_rect(const Gfx::Rect& rect)
-{
- bool found_containing_window = false;
- for_each_visible_window_from_back_to_front([&](Window& window) {
- if (window.is_minimized())
- return IterationDecision::Continue;
- if (window.opacity() < 1.0f)
- return IterationDecision::Continue;
- if (window.has_alpha_channel()) {
- // FIXME: Just because the window has an alpha channel doesn't mean it's not opaque.
- // Maybe there's some way we could know this?
- return IterationDecision::Continue;
- }
- if (window.frame().rect().contains(rect)) {
- found_containing_window = true;
- return IterationDecision::Break;
- }
- return IterationDecision::Continue;
- });
- return found_containing_window;
-};
-
-bool WindowManager::any_opaque_window_above_this_one_contains_rect(const Window& a_window, const Gfx::Rect& rect)
-{
- bool found_containing_window = false;
- bool checking = false;
- for_each_visible_window_from_back_to_front([&](Window& window) {
- if (&window == &a_window) {
- checking = true;
- return IterationDecision::Continue;
- }
- if (!checking)
- return IterationDecision::Continue;
- if (!window.is_visible())
- return IterationDecision::Continue;
- if (window.is_minimized())
- return IterationDecision::Continue;
- if (window.opacity() < 1.0f)
- return IterationDecision::Continue;
- if (window.has_alpha_channel())
- return IterationDecision::Continue;
- if (window.frame().rect().contains(rect)) {
- found_containing_window = true;
- return IterationDecision::Break;
- }
- return IterationDecision::Continue;
- });
- return found_containing_window;
-};
-
-Gfx::Rect WindowManager::menubar_rect() const
-{
- if (active_fullscreen_window())
- return {};
- return MenuManager::the().menubar_rect();
-}
-
-Gfx::Rect WindowManager::desktop_rect() const
-{
- if (active_fullscreen_window())
- return {};
- return {
- 0,
- menubar_rect().bottom() + 1,
- Screen::the().width(),
- Screen::the().height() - menubar_rect().height() - 28
- };
-}
-
-void WindowManager::event(Core::Event& event)
-{
- if (static_cast<Event&>(event).is_mouse_event()) {
- Window* hovered_window = nullptr;
- process_mouse_event(static_cast<MouseEvent&>(event), hovered_window);
- set_hovered_window(hovered_window);
- return;
- }
-
- if (static_cast<Event&>(event).is_key_event()) {
- auto& key_event = static_cast<const KeyEvent&>(event);
- m_keyboard_modifiers = key_event.modifiers();
-
- if (key_event.type() == Event::KeyDown && key_event.key() == Key_Escape && m_dnd_client) {
- m_dnd_client->post_message(Messages::WindowClient::DragCancelled());
- end_dnd_drag();
- return;
- }
-
- if (key_event.key() == Key_Logo) {
- if (key_event.type() == Event::KeyUp) {
- if (!m_moved_or_resized_since_logo_keydown && !m_switcher.is_visible() && !m_move_window && !m_resize_window) {
- MenuManager::the().toggle_system_menu();
- return;
- }
-
- } else if (key_event.type() == Event::KeyDown) {
- m_moved_or_resized_since_logo_keydown = false;
- }
- }
-
- if (MenuManager::the().current_menu()) {
- MenuManager::the().dispatch_event(event);
- return;
- }
-
- if (key_event.type() == Event::KeyDown && ((key_event.modifiers() == Mod_Logo && key_event.key() == Key_Tab) || (key_event.modifiers() == (Mod_Logo | Mod_Shift) && key_event.key() == Key_Tab)))
- m_switcher.show();
- if (m_switcher.is_visible()) {
- m_switcher.on_key_event(key_event);
- return;
- }
-
- if (m_active_window) {
- if (key_event.type() == Event::KeyDown && key_event.modifiers() == Mod_Logo) {
- if (key_event.key() == Key_Down) {
- m_moved_or_resized_since_logo_keydown = true;
- if (m_active_window->is_resizable() && m_active_window->is_maximized()) {
- m_active_window->set_maximized(false);
- return;
- }
- if (m_active_window->is_minimizable())
- m_active_window->set_minimized(true);
- return;
- }
- if (m_active_window->is_resizable()) {
- if (key_event.key() == Key_Up) {
- m_moved_or_resized_since_logo_keydown = true;
- m_active_window->set_maximized(!m_active_window->is_maximized());
- return;
- }
- if (key_event.key() == Key_Left) {
- m_moved_or_resized_since_logo_keydown = true;
- if (m_active_window->tiled() != WindowTileType::None) {
- m_active_window->set_tiled(WindowTileType::None);
- return;
- }
- if (m_active_window->is_maximized())
- m_active_window->set_maximized(false);
- m_active_window->set_tiled(WindowTileType::Left);
- return;
- }
- if (key_event.key() == Key_Right) {
- m_moved_or_resized_since_logo_keydown = true;
- if (m_active_window->tiled() != WindowTileType::None) {
- m_active_window->set_tiled(WindowTileType::None);
- return;
- }
- if (m_active_window->is_maximized())
- m_active_window->set_maximized(false);
- m_active_window->set_tiled(WindowTileType::Right);
- return;
- }
- }
- }
- m_active_window->dispatch_event(event);
- return;
- }
- }
-
- Core::Object::event(event);
-}
-
-void WindowManager::set_highlight_window(Window* window)
-{
- if (window == m_highlight_window)
- return;
- if (auto* previous_highlight_window = m_highlight_window.ptr())
- invalidate(*previous_highlight_window);
- m_highlight_window = window ? window->make_weak_ptr() : nullptr;
- if (m_highlight_window)
- invalidate(*m_highlight_window);
-}
-
-static bool window_type_can_become_active(WindowType type)
-{
- return type == WindowType::Normal || type == WindowType::Desktop;
-}
-
-void WindowManager::set_active_window(Window* window)
-{
- if (window && window->is_blocked_by_modal_window())
- return;
-
- if (window && !window_type_can_become_active(window->type()))
- return;
-
- if (window == m_active_window)
- return;
-
- auto* previously_active_window = m_active_window.ptr();
-
- ClientConnection* previously_active_client = nullptr;
- ClientConnection* active_client = nullptr;
-
- if (previously_active_window) {
- previously_active_client = previously_active_window->client();
- Core::EventLoop::current().post_event(*previously_active_window, make<Event>(Event::WindowDeactivated));
- invalidate(*previously_active_window);
- m_active_window = nullptr;
- m_active_input_window = nullptr;
- tell_wm_listeners_window_state_changed(*previously_active_window);
- }
-
- if (window) {
- m_active_window = window->make_weak_ptr();
- active_client = m_active_window->client();
- Core::EventLoop::current().post_event(*m_active_window, make<Event>(Event::WindowActivated));
- invalidate(*m_active_window);
-
- auto* client = window->client();
- ASSERT(client);
- MenuManager::the().set_current_menubar(client->app_menubar());
- tell_wm_listeners_window_state_changed(*m_active_window);
- } else {
- MenuManager::the().set_current_menubar(nullptr);
- }
-
- if (active_client != previously_active_client) {
- if (previously_active_client)
- previously_active_client->deboost();
- if (active_client)
- active_client->boost();
- }
-}
-
-void WindowManager::set_hovered_window(Window* window)
-{
- if (m_hovered_window == window)
- return;
-
- if (m_hovered_window)
- Core::EventLoop::current().post_event(*m_hovered_window, make<Event>(Event::WindowLeft));
-
- m_hovered_window = window ? window->make_weak_ptr() : nullptr;
-
- if (m_hovered_window)
- Core::EventLoop::current().post_event(*m_hovered_window, make<Event>(Event::WindowEntered));
-}
-
-void WindowManager::invalidate()
-{
- Compositor::the().invalidate();
-}
-
-void WindowManager::invalidate(const Gfx::Rect& rect)
-{
- Compositor::the().invalidate(rect);
-}
-
-void WindowManager::invalidate(const Window& window)
-{
- invalidate(window.frame().rect());
-}
-
-void WindowManager::invalidate(const Window& window, const Gfx::Rect& rect)
-{
- if (window.type() == WindowType::MenuApplet) {
- AppletManager::the().invalidate_applet(window, rect);
- return;
- }
-
- if (rect.is_empty()) {
- invalidate(window);
- return;
- }
- auto outer_rect = window.frame().rect();
- auto inner_rect = rect;
- inner_rect.move_by(window.position());
- // FIXME: This seems slightly wrong; the inner rect shouldn't intersect the border part of the outer rect.
- inner_rect.intersect(outer_rect);
- invalidate(inner_rect);
-}
-
-const ClientConnection* WindowManager::active_client() const
-{
- if (m_active_window)
- return m_active_window->client();
- return nullptr;
-}
-
-void WindowManager::notify_client_changed_app_menubar(ClientConnection& client)
-{
- if (active_client() == &client)
- MenuManager::the().set_current_menubar(client.app_menubar());
-}
-
-const Cursor& WindowManager::active_cursor() const
-{
- if (m_dnd_client)
- return *m_drag_cursor;
-
- if (m_move_window)
- return *m_move_cursor;
-
- if (m_resize_window || m_resize_candidate) {
- switch (m_resize_direction) {
- case ResizeDirection::Up:
- case ResizeDirection::Down:
- return *m_resize_vertically_cursor;
- case ResizeDirection::Left:
- case ResizeDirection::Right:
- return *m_resize_horizontally_cursor;
- case ResizeDirection::UpLeft:
- case ResizeDirection::DownRight:
- return *m_resize_diagonally_tlbr_cursor;
- case ResizeDirection::UpRight:
- case ResizeDirection::DownLeft:
- return *m_resize_diagonally_bltr_cursor;
- case ResizeDirection::None:
- break;
- }
- }
-
- if (m_hovered_window && m_hovered_window->override_cursor())
- return *m_hovered_window->override_cursor();
-
- return *m_arrow_cursor;
-}
-
-void WindowManager::set_hovered_button(Button* button)
-{
- m_hovered_button = button ? button->make_weak_ptr() : nullptr;
-}
-
-void WindowManager::set_resize_candidate(Window& window, ResizeDirection direction)
-{
- m_resize_candidate = window.make_weak_ptr();
- m_resize_direction = direction;
-}
-
-ResizeDirection WindowManager::resize_direction_of_window(const Window& window)
-{
- if (&window != m_resize_window)
- return ResizeDirection::None;
- return m_resize_direction;
-}
-
-Gfx::Rect WindowManager::maximized_window_rect(const Window& window) const
-{
- Gfx::Rect rect = Screen::the().rect();
-
- // Subtract window title bar (leaving the border)
- rect.set_y(rect.y() + window.frame().title_bar_rect().height());
- rect.set_height(rect.height() - window.frame().title_bar_rect().height());
-
- // Subtract menu bar
- rect.set_y(rect.y() + menubar_rect().height());
- rect.set_height(rect.height() - menubar_rect().height());
-
- // Subtract taskbar window height if present
- const_cast<WindowManager*>(this)->for_each_visible_window_of_type_from_back_to_front(WindowType::Taskbar, [&rect](Window& taskbar_window) {
- rect.set_height(rect.height() - taskbar_window.height());
- return IterationDecision::Break;
- });
-
- return rect;
-}
-
-void WindowManager::start_dnd_drag(ClientConnection& client, const String& text, Gfx::Bitmap* bitmap, const String& data_type, const String& data)
-{
- ASSERT(!m_dnd_client);
- m_dnd_client = client.make_weak_ptr();
- m_dnd_text = text;
- m_dnd_bitmap = bitmap;
- m_dnd_data_type = data_type;
- m_dnd_data = data;
- Compositor::the().invalidate_cursor();
- m_active_input_window = nullptr;
-}
-
-void WindowManager::end_dnd_drag()
-{
- ASSERT(m_dnd_client);
- Compositor::the().invalidate_cursor();
- m_dnd_client = nullptr;
- m_dnd_text = {};
- m_dnd_bitmap = nullptr;
-}
-
-Gfx::Rect WindowManager::dnd_rect() const
-{
- int bitmap_width = m_dnd_bitmap ? m_dnd_bitmap->width() : 0;
- int bitmap_height = m_dnd_bitmap ? m_dnd_bitmap->height() : 0;
- int width = font().width(m_dnd_text) + bitmap_width;
- int height = max((int)font().glyph_height(), bitmap_height);
- auto location = Compositor::the().current_cursor_rect().center().translated(8, 8);
- return Gfx::Rect(location, { width, height }).inflated(4, 4);
-}
-
-bool WindowManager::update_theme(String theme_path, String theme_name)
-{
- auto new_theme = Gfx::load_system_theme(theme_path);
- if (!new_theme)
- return false;
- ASSERT(new_theme);
- Gfx::set_system_theme(*new_theme);
- m_palette = Gfx::PaletteImpl::create_with_shared_buffer(*new_theme);
- Compositor::the().set_background_color(palette().desktop_background().to_string());
- HashTable<ClientConnection*> notified_clients;
- for_each_window([&](Window& window) {
- if (window.client()) {
- if (!notified_clients.contains(window.client())) {
- window.client()->post_message(Messages::WindowClient::UpdateSystemTheme(Gfx::current_system_theme_buffer_id()));
- notified_clients.set(window.client());
- }
- }
- return IterationDecision::Continue;
- });
- MenuManager::the().did_change_theme();
- auto wm_config = Core::ConfigFile::open("/etc/WindowServer/WindowServer.ini");
- wm_config->write_entry("Theme", "Name", theme_name);
- wm_config->sync();
- invalidate();
- return true;
-}
-
-}
diff --git a/Servers/WindowServer/WindowManager.h b/Servers/WindowServer/WindowManager.h
deleted file mode 100644
index 0c7ec8429f..0000000000
--- a/Servers/WindowServer/WindowManager.h
+++ /dev/null
@@ -1,416 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * 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/HashMap.h>
-#include <AK/HashTable.h>
-#include <AK/InlineLinkedList.h>
-#include <AK/WeakPtr.h>
-#include <LibCore/ConfigFile.h>
-#include <LibCore/ElapsedTimer.h>
-#include <LibGfx/Color.h>
-#include <LibGfx/DisjointRectSet.h>
-#include <LibGfx/Painter.h>
-#include <LibGfx/Palette.h>
-#include <LibGfx/Rect.h>
-#include <WindowServer/Cursor.h>
-#include <WindowServer/Event.h>
-#include <WindowServer/MenuBar.h>
-#include <WindowServer/MenuManager.h>
-#include <WindowServer/Window.h>
-#include <WindowServer/WindowSwitcher.h>
-#include <WindowServer/WindowType.h>
-
-namespace WindowServer {
-
-class Screen;
-class MouseEvent;
-class Window;
-class ClientConnection;
-class WindowSwitcher;
-class Button;
-
-enum class ResizeDirection {
- None,
- Left,
- UpLeft,
- Up,
- UpRight,
- Right,
- DownRight,
- Down,
- DownLeft
-};
-
-class WindowManager : public Core::Object {
- C_OBJECT(WindowManager)
-
- friend class Compositor;
- friend class WindowFrame;
- friend class WindowSwitcher;
-
-public:
- static WindowManager& the();
-
- explicit WindowManager(const Gfx::PaletteImpl&);
- virtual ~WindowManager() override;
-
- Palette palette() const { return Palette(*m_palette); }
-
- RefPtr<Core::ConfigFile> wm_config() const
- {
- return m_wm_config;
- }
- void reload_config(bool);
-
- void add_window(Window&);
- void remove_window(Window&);
-
- void notify_title_changed(Window&);
- void notify_rect_changed(Window&, const Gfx::Rect& oldRect, const Gfx::Rect& newRect);
- void notify_minimization_state_changed(Window&);
- void notify_opacity_changed(Window&);
- void notify_occlusion_state_changed(Window&);
- void notify_client_changed_app_menubar(ClientConnection&);
-
- Gfx::Rect maximized_window_rect(const Window&) const;
-
- ClientConnection* dnd_client() { return m_dnd_client.ptr(); }
- const String& dnd_text() const { return m_dnd_text; }
- const String& dnd_data_type() const { return m_dnd_data_type; }
- const String& dnd_data() const { return m_dnd_data; }
- const Gfx::Bitmap* dnd_bitmap() const { return m_dnd_bitmap; }
- Gfx::Rect dnd_rect() const;
-
- void start_dnd_drag(ClientConnection&, const String& text, Gfx::Bitmap*, const String& data_type, const String& data);
- void end_dnd_drag();
-
- Window* active_window() { return m_active_window.ptr(); }
- const ClientConnection* active_client() const;
- bool active_window_is_modal() const { return m_active_window && m_active_window->is_modal(); }
-
- Window* highlight_window() { return m_highlight_window.ptr(); }
- void set_highlight_window(Window*);
-
- void move_to_front_and_make_active(Window&);
-
- Gfx::Rect menubar_rect() const;
- Gfx::Rect desktop_rect() const;
-
- const Cursor& active_cursor() const;
- const Cursor& arrow_cursor() const { return *m_arrow_cursor; }
- const Cursor& hand_cursor() const { return *m_hand_cursor; }
- const Cursor& resize_horizontally_cursor() const { return *m_resize_horizontally_cursor; }
- const Cursor& resize_vertically_cursor() const { return *m_resize_vertically_cursor; }
- const Cursor& resize_diagonally_tlbr_cursor() const { return *m_resize_diagonally_tlbr_cursor; }
- const Cursor& resize_diagonally_bltr_cursor() const { return *m_resize_diagonally_bltr_cursor; }
- const Cursor& i_beam_cursor() const { return *m_i_beam_cursor; }
- const Cursor& disallowed_cursor() const { return *m_disallowed_cursor; }
- const Cursor& move_cursor() const { return *m_move_cursor; }
- const Cursor& drag_cursor() const { return *m_drag_cursor; }
-
- void invalidate(const Window&);
- void invalidate(const Window&, const Gfx::Rect&);
- void invalidate(const Gfx::Rect&);
- void invalidate();
- void flush(const Gfx::Rect&);
-
- const Gfx::Font& font() const;
- const Gfx::Font& window_title_font() const;
-
- bool set_resolution(int width, int height);
- Gfx::Size resolution() const;
-
- void set_active_window(Window*);
- void set_hovered_button(Button*);
-
- Button* cursor_tracking_button() { return m_cursor_tracking_button.ptr(); }
- void set_cursor_tracking_button(Button*);
-
- void set_resize_candidate(Window&, ResizeDirection);
- void clear_resize_candidate();
- ResizeDirection resize_direction_of_window(const Window&);
-
- bool any_opaque_window_contains_rect(const Gfx::Rect&);
- bool any_opaque_window_above_this_one_contains_rect(const Window&, const Gfx::Rect&);
-
- 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 start_window_resize(Window&, const Gfx::Point&, MouseButton);
- void start_window_resize(Window&, const MouseEvent&);
-
- const Window* active_fullscreen_window() const { return (m_active_window && m_active_window->is_fullscreen()) ? m_active_window : nullptr; }
- Window* active_fullscreen_window() { return (m_active_window && m_active_window->is_fullscreen()) ? m_active_window : nullptr; }
-
- bool update_theme(String theme_path, String theme_name);
-
- void set_hovered_window(Window*);
- void deliver_mouse_event(Window& window, MouseEvent& event);
-
-private:
- NonnullRefPtr<Cursor> get_cursor(const String& name);
- NonnullRefPtr<Cursor> get_cursor(const String& name, const Gfx::Point& hotspot);
-
- void process_mouse_event(MouseEvent&, Window*& hovered_window);
- void process_event_for_doubleclick(Window& window, MouseEvent& event);
- bool process_ongoing_window_resize(const MouseEvent&, Window*& hovered_window);
- bool process_ongoing_window_move(MouseEvent&, Window*& hovered_window);
- bool process_ongoing_drag(MouseEvent&, Window*& hovered_window);
- void start_window_move(Window&, const MouseEvent&);
- template<typename Callback>
- IterationDecision for_each_visible_window_of_type_from_back_to_front(WindowType, Callback, bool ignore_highlight = false);
- template<typename Callback>
- IterationDecision for_each_visible_window_of_type_from_front_to_back(WindowType, Callback, bool ignore_highlight = false);
- template<typename Callback>
- IterationDecision for_each_visible_window_from_front_to_back(Callback);
- 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);
-
- 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 pick_new_active_window();
-
- void recompute_occlusions();
-
- RefPtr<Cursor> m_arrow_cursor;
- RefPtr<Cursor> m_hand_cursor;
- RefPtr<Cursor> m_resize_horizontally_cursor;
- RefPtr<Cursor> m_resize_vertically_cursor;
- RefPtr<Cursor> m_resize_diagonally_tlbr_cursor;
- RefPtr<Cursor> m_resize_diagonally_bltr_cursor;
- RefPtr<Cursor> m_i_beam_cursor;
- RefPtr<Cursor> m_disallowed_cursor;
- RefPtr<Cursor> m_move_cursor;
- RefPtr<Cursor> m_drag_cursor;
-
- InlineLinkedList<Window> m_windows_in_order;
-
- struct DoubleClickInfo {
- struct ClickMetadata {
- Core::ElapsedTimer clock;
- Gfx::Point last_position;
- };
-
- ClickMetadata& metadata_for_button(MouseButton);
-
- void reset()
- {
- m_left = {};
- m_right = {};
- m_middle = {};
- m_back = {};
- m_forward = {};
- }
-
- WeakPtr<Window> m_clicked_window;
-
- private:
- ClickMetadata m_left;
- ClickMetadata m_right;
- ClickMetadata m_middle;
- ClickMetadata m_back;
- ClickMetadata m_forward;
- };
- DoubleClickInfo m_double_click_info;
- int m_double_click_speed { 0 };
- int m_max_distance_for_double_click { 4 };
-
- WeakPtr<Window> m_active_window;
- WeakPtr<Window> m_hovered_window;
- WeakPtr<Window> m_highlight_window;
- WeakPtr<Window> m_active_input_window;
-
- WeakPtr<Window> m_move_window;
- Gfx::Point m_move_origin;
- Gfx::Point m_move_window_origin;
-
- WeakPtr<Window> m_resize_window;
- WeakPtr<Window> m_resize_candidate;
- MouseButton m_resizing_mouse_button { MouseButton::None };
- Gfx::Rect m_resize_window_original_rect;
- Gfx::Point m_resize_origin;
- ResizeDirection m_resize_direction { ResizeDirection::None };
-
- bool m_moved_or_resized_since_logo_keydown { false };
-
- u8 m_keyboard_modifiers { 0 };
-
- WindowSwitcher m_switcher;
-
- WeakPtr<Button> m_cursor_tracking_button;
- WeakPtr<Button> m_hovered_button;
-
- NonnullRefPtr<Gfx::PaletteImpl> m_palette;
-
- RefPtr<Core::ConfigFile> m_wm_config;
-
- WeakPtr<ClientConnection> m_dnd_client;
- String m_dnd_text;
- String m_dnd_data_type;
- String m_dnd_data;
- RefPtr<Gfx::Bitmap> m_dnd_bitmap;
-};
-
-template<typename Callback>
-IterationDecision WindowManager::for_each_visible_window_of_type_from_back_to_front(WindowType type, Callback callback, bool ignore_highlight)
-{
- bool do_highlight_window_at_end = false;
- for (auto& window : m_windows_in_order) {
- if (!window.is_visible())
- continue;
- if (window.is_minimized())
- continue;
- if (window.type() != type)
- continue;
- if (!ignore_highlight && m_highlight_window == &window) {
- do_highlight_window_at_end = true;
- continue;
- }
- if (callback(window) == IterationDecision::Break)
- return IterationDecision::Break;
- }
- if (do_highlight_window_at_end) {
- if (callback(*m_highlight_window) == IterationDecision::Break)
- return IterationDecision::Break;
- }
- return IterationDecision::Continue;
-}
-
-template<typename Callback>
-IterationDecision WindowManager::for_each_visible_window_from_back_to_front(Callback callback)
-{
- if (for_each_visible_window_of_type_from_back_to_front(WindowType::Desktop, callback) == IterationDecision::Break)
- return IterationDecision::Break;
- if (for_each_visible_window_of_type_from_back_to_front(WindowType::Normal, callback) == IterationDecision::Break)
- return IterationDecision::Break;
- if (for_each_visible_window_of_type_from_back_to_front(WindowType::Taskbar, callback) == IterationDecision::Break)
- return IterationDecision::Break;
- if (for_each_visible_window_of_type_from_back_to_front(WindowType::Tooltip, callback) == IterationDecision::Break)
- return IterationDecision::Break;
- if (for_each_visible_window_of_type_from_back_to_front(WindowType::Notification, callback) == IterationDecision::Break)
- return IterationDecision::Break;
- if (for_each_visible_window_of_type_from_back_to_front(WindowType::Menubar, callback) == IterationDecision::Break)
- return IterationDecision::Break;
- if (for_each_visible_window_of_type_from_back_to_front(WindowType::Menu, callback) == IterationDecision::Break)
- return IterationDecision::Break;
- return for_each_visible_window_of_type_from_back_to_front(WindowType::WindowSwitcher, callback);
-}
-
-template<typename Callback>
-IterationDecision WindowManager::for_each_visible_window_of_type_from_front_to_back(WindowType type, Callback callback, bool ignore_highlight)
-{
- if (!ignore_highlight && m_highlight_window && m_highlight_window->type() == type && m_highlight_window->is_visible()) {
- if (callback(*m_highlight_window) == IterationDecision::Break)
- return IterationDecision::Break;
- }
-
- for (auto* window = m_windows_in_order.tail(); window; window = window->prev()) {
- if (!window->is_visible())
- continue;
- if (window->is_minimized())
- continue;
- if (window->type() != type)
- continue;
- if (!ignore_highlight && window == m_highlight_window)
- continue;
- if (callback(*window) == IterationDecision::Break)
- return IterationDecision::Break;
- }
- return IterationDecision::Continue;
-}
-
-template<typename Callback>
-IterationDecision WindowManager::for_each_visible_window_from_front_to_back(Callback callback)
-{
- if (for_each_visible_window_of_type_from_front_to_back(WindowType::WindowSwitcher, callback) == IterationDecision::Break)
- return IterationDecision::Break;
- if (for_each_visible_window_of_type_from_front_to_back(WindowType::Menu, callback) == IterationDecision::Break)
- return IterationDecision::Break;
- if (for_each_visible_window_of_type_from_front_to_back(WindowType::Menubar, callback) == IterationDecision::Break)
- return IterationDecision::Break;
- if (for_each_visible_window_of_type_from_front_to_back(WindowType::Notification, callback) == IterationDecision::Break)
- return IterationDecision::Break;
- if (for_each_visible_window_of_type_from_front_to_back(WindowType::Tooltip, callback) == IterationDecision::Break)
- return IterationDecision::Break;
- if (for_each_visible_window_of_type_from_front_to_back(WindowType::Taskbar, callback) == IterationDecision::Break)
- return IterationDecision::Break;
- if (for_each_visible_window_of_type_from_front_to_back(WindowType::Normal, callback) == IterationDecision::Break)
- return IterationDecision::Break;
- return for_each_visible_window_of_type_from_front_to_back(WindowType::Desktop, callback);
-}
-
-template<typename Callback>
-void WindowManager::for_each_window_listening_to_wm_events(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)
- return;
- }
-}
-
-template<typename Callback>
-void WindowManager::for_each_window(Callback callback)
-{
- for (auto* window = m_windows_in_order.tail(); window; window = window->prev()) {
- if (callback(*window) == IterationDecision::Break)
- return;
- }
-}
-
-template<typename Callback>
-IterationDecision WindowManager::for_each_window_of_type_from_front_to_back(WindowType type, Callback callback, bool ignore_highlight)
-{
- if (!ignore_highlight && m_highlight_window && m_highlight_window->type() == type && m_highlight_window->is_visible()) {
- if (callback(*m_highlight_window) == IterationDecision::Break)
- return IterationDecision::Break;
- }
-
- for (auto* window = m_windows_in_order.tail(); window; window = window->prev()) {
- if (window->type() != type)
- continue;
- if (!ignore_highlight && window == m_highlight_window)
- continue;
- if (callback(*window) == IterationDecision::Break)
- return IterationDecision::Break;
- }
- return IterationDecision::Continue;
-}
-
-}
diff --git a/Servers/WindowServer/WindowServer.ipc b/Servers/WindowServer/WindowServer.ipc
deleted file mode 100644
index 214afa7567..0000000000
--- a/Servers/WindowServer/WindowServer.ipc
+++ /dev/null
@@ -1,97 +0,0 @@
-endpoint WindowServer = 2
-{
- Greet() => (i32 client_id, Gfx::Rect screen_rect, i32 system_theme_buffer_id)
-
- CreateMenubar() => (i32 menubar_id)
- DestroyMenubar(i32 menubar_id) => ()
-
- CreateMenu(String menu_title) => (i32 menu_id)
- DestroyMenu(i32 menu_id) => ()
-
- AddMenuToMenubar(i32 menubar_id, i32 menu_id) => ()
- SetApplicationMenubar(i32 menubar_id) => ()
-
- SetSystemMenu(i32 menu_id) => ()
-
- AddMenuItem(
- i32 menu_id,
- i32 identifier,
- i32 submenu_id,
- String text,
- bool enabled,
- bool checkable,
- bool checked,
- String shortcut,
- i32 icon_buffer_id,
- bool exclusive) => ()
-
- AddMenuSeparator(i32 menu_id) => ()
-
- UpdateMenuItem(i32 menu_id, i32 identifier, i32 submenu_id, String text, bool enabled, bool checkable, bool checked, String shortcut) => ()
-
- CreateWindow(
- Gfx::Rect rect,
- bool has_alpha_channel,
- bool modal,
- bool minimizable,
- bool resizable,
- bool fullscreen,
- bool frameless,
- float opacity,
- Gfx::Size base_size,
- Gfx::Size size_increment,
- i32 type,
- String title,
- i32 parent_window_id) => (i32 window_id)
-
- DestroyWindow(i32 window_id) => (Vector<i32> destroyed_window_ids)
-
- SetWindowTitle(i32 window_id, String title) => ()
- GetWindowTitle(i32 window_id) => (String title)
-
- SetWindowRect(i32 window_id, Gfx::Rect rect) => (Gfx::Rect rect)
- GetWindowRect(i32 window_id) => (Gfx::Rect rect)
-
- InvalidateRect(i32 window_id, Vector<Gfx::Rect> rects, bool ignore_occlusion) =|
- DidFinishPainting(i32 window_id, Vector<Gfx::Rect> rects) =|
-
- SetGlobalCursorTracking(i32 window_id, bool enabled) => ()
- SetWindowOpacity(i32 window_id, float opacity) => ()
-
- SetWindowBackingStore(i32 window_id, i32 bpp, i32 pitch, i32 shbuf_id, bool has_alpha_channel, Gfx::Size size, bool flush_immediately) => ()
- GetClipboardContents() => (i32 shbuf_id, i32 content_size, String content_type)
- SetClipboardContents(i32 shbuf_id, i32 content_size, String content_type) => ()
-
- 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::Point screen_position) =|
- WM_SetWindowTaskbarRect(i32 client_id, i32 window_id, Gfx::Rect rect) =|
-
- SetWindowHasAlphaChannel(i32 window_id, bool has_alpha_channel) => ()
- MoveWindowToFront(i32 window_id) => ()
- SetFullscreen(i32 window_id, bool fullscreen) => ()
- PopupMenu(i32 menu_id, Gfx::Point screen_position) => ()
- DismissMenu(i32 menu_id) => ()
-
- AsyncSetWallpaper(String path) =|
-
- SetBackgroundColor(String background_color) => ()
- SetWallpaperMode(String mode) => ()
-
- SetResolution(Gfx::Size resolution) => (bool success, Gfx::Size resolution)
- SetWindowIconBitmap(i32 window_id, Gfx::ShareableBitmap icon) => ()
-
- GetWallpaper() => (String path)
- SetWindowOverrideCursor(i32 window_id, i32 cursor_type) => ()
-
- StartDrag(String text, String data_type, String data, i32 bitmap_id, Gfx::Size bitmap_size) => (bool started)
-
- SetSystemTheme(String theme_path, String theme_name) => (bool success)
- GetSystemTheme() => (String theme_name)
-
- SetWindowBaseSizeAndSizeIncrement(i32 window_id, Gfx::Size base_size, Gfx::Size size_increment) => ()
-
- EnableDisplayLink() =|
- DisableDisplayLink() =|
-}
diff --git a/Servers/WindowServer/WindowSwitcher.cpp b/Servers/WindowServer/WindowSwitcher.cpp
deleted file mode 100644
index fbf53184da..0000000000
--- a/Servers/WindowServer/WindowSwitcher.cpp
+++ /dev/null
@@ -1,256 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * 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 <LibGfx/Bitmap.h>
-#include <LibGfx/Font.h>
-#include <LibGfx/StylePainter.h>
-#include <WindowServer/Event.h>
-#include <WindowServer/Screen.h>
-#include <WindowServer/WindowManager.h>
-#include <WindowServer/WindowSwitcher.h>
-
-namespace WindowServer {
-
-static WindowSwitcher* s_the;
-
-WindowSwitcher& WindowSwitcher::the()
-{
- ASSERT(s_the);
- return *s_the;
-}
-
-WindowSwitcher::WindowSwitcher()
-{
- s_the = this;
-}
-
-WindowSwitcher::~WindowSwitcher()
-{
-}
-
-void WindowSwitcher::set_visible(bool visible)
-{
- if (m_visible == visible)
- return;
- m_visible = visible;
- WindowManager::the().recompute_occlusions();
- if (m_switcher_window)
- m_switcher_window->set_visible(visible);
- if (!m_visible)
- return;
- refresh();
-}
-
-Window* WindowSwitcher::selected_window()
-{
- if (m_selected_index < 0 || m_selected_index >= static_cast<int>(m_windows.size()))
- return nullptr;
- return m_windows[m_selected_index].ptr();
-}
-
-void WindowSwitcher::event(Core::Event& event)
-{
- if (!static_cast<Event&>(event).is_mouse_event())
- return;
-
- auto& mouse_event = static_cast<MouseEvent&>(event);
- int new_hovered_index = -1;
- for (size_t i = 0; i < m_windows.size(); ++i) {
- auto item_rect = this->item_rect(i);
- if (item_rect.contains(mouse_event.position())) {
- new_hovered_index = i;
- break;
- }
- }
-
- if (mouse_event.type() == Event::MouseMove) {
- if (m_hovered_index != new_hovered_index) {
- m_hovered_index = new_hovered_index;
- redraw();
- }
- }
-
- if (new_hovered_index == -1)
- return;
-
- if (mouse_event.type() == Event::MouseDown)
- select_window_at_index(new_hovered_index);
-
- event.accept();
-}
-
-void WindowSwitcher::on_key_event(const KeyEvent& event)
-{
- if (event.type() == Event::KeyUp) {
- if (event.key() == Key_Logo) {
- if (auto* window = selected_window()) {
- window->set_minimized(false);
- WindowManager::the().move_to_front_and_make_active(*window);
- }
- WindowManager::the().set_highlight_window(nullptr);
- hide();
- }
- return;
- }
-
- if (event.key() == Key_LeftShift || event.key() == Key_RightShift)
- return;
- if (event.key() != Key_Tab) {
- WindowManager::the().set_highlight_window(nullptr);
- hide();
- return;
- }
- ASSERT(!m_windows.is_empty());
-
- int new_selected_index;
-
- if (!event.shift()) {
- new_selected_index = (m_selected_index + 1) % static_cast<int>(m_windows.size());
- } else {
- new_selected_index = (m_selected_index - 1) % static_cast<int>(m_windows.size());
- if (new_selected_index < 0)
- new_selected_index = static_cast<int>(m_windows.size()) - 1;
- }
- ASSERT(new_selected_index < static_cast<int>(m_windows.size()));
-
- select_window_at_index(new_selected_index);
-}
-
-void WindowSwitcher::select_window(Window& window)
-{
- for (size_t i = 0; i < m_windows.size(); ++i) {
- if (m_windows.at(i) == &window) {
- select_window_at_index(i);
- return;
- }
- }
-}
-
-void WindowSwitcher::select_window_at_index(int index)
-{
- m_selected_index = index;
- auto* highlight_window = m_windows.at(index).ptr();
- ASSERT(highlight_window);
- WindowManager::the().set_highlight_window(highlight_window);
- redraw();
-}
-
-void WindowSwitcher::redraw()
-{
- draw();
- WindowManager::the().invalidate(m_rect);
-}
-
-Gfx::Rect WindowSwitcher::item_rect(int index) const
-{
- return {
- padding(),
- padding() + index * item_height(),
- m_rect.width() - padding() * 2,
- item_height()
- };
-}
-
-void WindowSwitcher::draw()
-{
- auto palette = WindowManager::the().palette();
- Gfx::Painter painter(*m_switcher_window->backing_store());
- painter.fill_rect({ {}, m_rect.size() }, palette.window());
- painter.draw_rect({ {}, m_rect.size() }, palette.threed_shadow2());
- for (size_t index = 0; index < m_windows.size(); ++index) {
- auto& window = *m_windows.at(index);
- auto item_rect = this->item_rect(index);
- Color text_color;
- Color rect_text_color;
- if (static_cast<int>(index) == m_selected_index) {
- painter.fill_rect(item_rect, palette.selection());
- text_color = palette.selection_text();
- rect_text_color = palette.threed_shadow1();
- } else {
- if (static_cast<int>(index) == m_hovered_index)
- Gfx::StylePainter::paint_button(painter, item_rect, palette, Gfx::ButtonStyle::CoolBar, false, true);
- text_color = palette.window_text();
- rect_text_color = palette.threed_shadow2();
- }
- item_rect.shrink(item_padding(), 0);
- Gfx::Rect thumbnail_rect = { item_rect.location().translated(0, 5), { thumbnail_width(), thumbnail_height() } };
- if (window.backing_store()) {
- painter.draw_scaled_bitmap(thumbnail_rect, *window.backing_store(), window.backing_store()->rect());
- Gfx::StylePainter::paint_frame(painter, thumbnail_rect.inflated(4, 4), palette, Gfx::FrameShape::Container, Gfx::FrameShadow::Sunken, 2);
- }
- Gfx::Rect icon_rect = { thumbnail_rect.bottom_right().translated(-window.icon().width(), -window.icon().height()), { window.icon().width(), window.icon().height() } };
- painter.fill_rect(icon_rect, palette.window());
- painter.blit(icon_rect.location(), window.icon(), window.icon().rect());
- painter.draw_text(item_rect.translated(thumbnail_width() + 12, 0), window.title(), WindowManager::the().window_title_font(), Gfx::TextAlignment::CenterLeft, text_color);
- painter.draw_text(item_rect, window.rect().to_string(), Gfx::TextAlignment::CenterRight, rect_text_color);
- }
-}
-
-void WindowSwitcher::refresh()
-{
- auto& wm = WindowManager::the();
- Window* selected_window = nullptr;
- if (m_selected_index > 0 && m_windows[m_selected_index])
- selected_window = m_windows[m_selected_index].ptr();
- if (!selected_window)
- selected_window = wm.highlight_window() ? wm.highlight_window() : wm.active_window();
- m_windows.clear();
- m_selected_index = 0;
- int window_count = 0;
- int longest_title_width = 0;
- wm.for_each_window_of_type_from_front_to_back(
- WindowType::Normal, [&](Window& window) {
- if (window.is_frameless())
- return IterationDecision::Continue;
- ++window_count;
- longest_title_width = max(longest_title_width, wm.font().width(window.title()));
- if (selected_window == &window)
- m_selected_index = m_windows.size();
- m_windows.append(window.make_weak_ptr());
- return IterationDecision::Continue;
- },
- true);
- if (m_windows.is_empty()) {
- hide();
- return;
- }
- int space_for_window_rect = 180;
- m_rect.set_width(thumbnail_width() + longest_title_width + space_for_window_rect + padding() * 2 + item_padding() * 2);
- m_rect.set_height(window_count * item_height() + padding() * 2);
- m_rect.center_within(Screen::the().rect());
- if (!m_switcher_window)
- m_switcher_window = Window::construct(*this, WindowType::WindowSwitcher);
- m_switcher_window->set_rect(m_rect);
- redraw();
-}
-
-void WindowSwitcher::refresh_if_needed()
-{
- if (m_visible)
- refresh();
-}
-
-}
diff --git a/Servers/WindowServer/WindowSwitcher.h b/Servers/WindowServer/WindowSwitcher.h
deleted file mode 100644
index 79fb3336a5..0000000000
--- a/Servers/WindowServer/WindowSwitcher.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * 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/Vector.h>
-#include <AK/WeakPtr.h>
-#include <LibCore/Object.h>
-#include <LibGfx/Forward.h>
-#include <LibGfx/Rect.h>
-
-namespace WindowServer {
-
-class KeyEvent;
-class Window;
-
-class WindowSwitcher final : public Core::Object {
- C_OBJECT(WindowSwitcher)
-public:
- static WindowSwitcher& the();
-
- WindowSwitcher();
- virtual ~WindowSwitcher() override;
-
- bool is_visible() const { return m_visible; }
- void set_visible(bool);
-
- void show() { set_visible(true); }
- void hide() { set_visible(false); }
-
- void on_key_event(const KeyEvent&);
-
- void refresh();
- void refresh_if_needed();
-
- void select_window(Window&);
-
-private:
- int thumbnail_width() const { return 40; }
- int thumbnail_height() const { return 40; }
- int item_height() const { return 10 + thumbnail_height(); }
- int padding() const { return 8; }
- int item_padding() const { return 8; }
-
- void draw();
- void redraw();
- void select_window_at_index(int index);
- Gfx::Rect item_rect(int index) const;
- Window* selected_window();
-
- virtual void event(Core::Event&) override;
-
- RefPtr<Window> m_switcher_window;
- Gfx::Rect m_rect;
- bool m_visible { false };
- Vector<WeakPtr<Window>> m_windows;
- int m_selected_index { 0 };
- int m_hovered_index { -1 };
-};
-
-}
diff --git a/Servers/WindowServer/WindowType.h b/Servers/WindowServer/WindowType.h
deleted file mode 100644
index a3c53007a1..0000000000
--- a/Servers/WindowServer/WindowType.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * 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
-
-// Keep this in sync with GUI::WindowType.
-enum class WindowType {
- Invalid = 0,
- Normal,
- Menu,
- WindowSwitcher,
- Taskbar,
- Tooltip,
- Menubar,
- MenuApplet,
- Notification,
- Desktop,
-};
diff --git a/Servers/WindowServer/main.cpp b/Servers/WindowServer/main.cpp
deleted file mode 100644
index 9165a5cf8f..0000000000
--- a/Servers/WindowServer/main.cpp
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
- * 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 "AppletManager.h"
-#include "Compositor.h"
-#include "EventLoop.h"
-#include "Screen.h"
-#include "WindowManager.h"
-#include <AK/SharedBuffer.h>
-#include <LibCore/ConfigFile.h>
-#include <LibGfx/Palette.h>
-#include <LibGfx/SystemTheme.h>
-#include <signal.h>
-#include <stdio.h>
-#include <string.h>
-
-int main(int, char**)
-{
- if (pledge("stdio video thread shared_buffer accept rpath wpath cpath unix proc fattr", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- if (unveil("/res", "r") < 0) {
- perror("unveil");
- return 1;
- }
-
- if (unveil("/tmp", "cw") < 0) {
- perror("unveil");
- return 1;
- }
-
- if (unveil("/etc/WindowServer/WindowServer.ini", "rwc") < 0) {
- perror("unveil");
- return 1;
- }
-
- if (unveil("/dev", "rw") < 0) {
- perror("unveil");
- return 1;
- }
-
- struct sigaction act;
- memset(&act, 0, sizeof(act));
- act.sa_flags = SA_NOCLDWAIT;
- act.sa_handler = SIG_IGN;
- int rc = sigaction(SIGCHLD, &act, nullptr);
- if (rc < 0) {
- perror("sigaction");
- return 1;
- }
-
- auto wm_config = Core::ConfigFile::open("/etc/WindowServer/WindowServer.ini");
- auto theme_name = wm_config->read_entry("Theme", "Name", "Default");
-
- auto theme = Gfx::load_system_theme(String::format("/res/themes/%s.ini", theme_name.characters()));
- ASSERT(theme);
- Gfx::set_system_theme(*theme);
- auto palette = Gfx::PaletteImpl::create_with_shared_buffer(*theme);
-
- WindowServer::EventLoop loop;
-
- if (pledge("stdio video thread shared_buffer accept rpath wpath cpath proc", nullptr) < 0) {
- perror("pledge");
- return 1;
- }
-
- WindowServer::Screen screen(wm_config->read_num_entry("Screen", "Width", 1024),
- wm_config->read_num_entry("Screen", "Height", 768));
- WindowServer::Compositor::the();
- auto wm = WindowServer::WindowManager::construct(*palette);
- auto am = WindowServer::AppletManager::construct();
- auto mm = WindowServer::MenuManager::construct();
-
- if (unveil("/tmp", "") < 0) {
- perror("unveil");
- return 1;
- }
-
- if (unveil("/dev", "") < 0) {
- perror("unveil");
- return 1;
- }
-
- if (unveil(nullptr, nullptr) < 0) {
- perror("unveil");
- return 1;
- }
-
- dbgprintf("Entering WindowServer main loop.\n");
- loop.exec();
- ASSERT_NOT_REACHED();
-}