diff options
author | Andreas Kling <kling@serenityos.org> | 2020-05-08 21:57:44 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-05-08 21:57:44 +0200 |
commit | cf3b58fbe8f836c13e44d6152d78960aff6089ef (patch) | |
tree | dcc7664f0004ee9c495f9d948cfb16d12f8a70bf /Servers/WindowServer | |
parent | 042b1f68145ad3754fd98429b405c5c1a173d3fc (diff) | |
download | serenity-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')
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(); -} |