diff --git a/Libraries/LibGUI/DisplayLink.cpp b/Libraries/LibGUI/DisplayLink.cpp new file mode 100644 index 0000000000..a2bf46e921 --- /dev/null +++ b/Libraries/LibGUI/DisplayLink.cpp @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2020, Andreas Kling + * 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 +#include +#include +#include +#include + +namespace GUI { + +class DisplayLinkCallback : public RefCounted { +public: + DisplayLinkCallback(i32 link_id, Function callback) + : m_link_id(link_id) + , m_callback(move(callback)) + { + } + + void invoke() + { + m_callback(m_link_id); + } + +private: + i32 m_link_id { 0 }; + Function m_callback; +}; + +static HashMap>& callbacks() +{ + static HashMap>* map; + if (!map) + map = new HashMap>; + return *map; +} + +static i32 s_next_callback_id = 1; + +i32 DisplayLink::register_callback(Function callback) +{ + if (callbacks().is_empty()) + WindowServerConnection::the().post_message(Messages::WindowServer::EnableDisplayLink()); + + i32 callback_id = s_next_callback_id++; + callbacks().set(callback_id, adopt(*new DisplayLinkCallback(callback_id, move(callback)))); + + return callback_id; +} + +bool DisplayLink::unregister_callback(i32 callback_id) +{ + ASSERT(callbacks().contains(callback_id)); + callbacks().remove(callback_id); + + if (callbacks().is_empty()) + WindowServerConnection::the().post_message(Messages::WindowServer::DisableDisplayLink()); + + return true; +} + +void DisplayLink::notify(Badge) +{ + auto copy_of_callbacks = callbacks(); + for (auto& it : copy_of_callbacks) + it.value->invoke(); +} + +} diff --git a/Libraries/LibGUI/DisplayLink.h b/Libraries/LibGUI/DisplayLink.h new file mode 100644 index 0000000000..2d1803b675 --- /dev/null +++ b/Libraries/LibGUI/DisplayLink.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2020, Andreas Kling + * 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 +#include + +namespace GUI { + +class DisplayLink { +public: + static i32 register_callback(Function); + static bool unregister_callback(i32 callback_id); + + static void notify(Badge); +}; + +} diff --git a/Libraries/LibGUI/Makefile b/Libraries/LibGUI/Makefile index 648b970282..95228cfaae 100644 --- a/Libraries/LibGUI/Makefile +++ b/Libraries/LibGUI/Makefile @@ -18,6 +18,7 @@ OBJS = \ CppSyntaxHighlighter.o \ Desktop.o \ Dialog.o \ + DisplayLink.o \ DragOperation.o \ Event.o \ FilePicker.o \ diff --git a/Libraries/LibGUI/WindowServerConnection.cpp b/Libraries/LibGUI/WindowServerConnection.cpp index 343699a208..7a0abb23e3 100644 --- a/Libraries/LibGUI/WindowServerConnection.cpp +++ b/Libraries/LibGUI/WindowServerConnection.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -339,4 +340,9 @@ void WindowServerConnection::handle(const Messages::WindowClient::WindowStateCha window->notify_state_changed({}, message.minimized(), message.occluded()); } +void WindowServerConnection::handle(const Messages::WindowClient::DisplayLinkNotification&) +{ + DisplayLink::notify({}); +} + } diff --git a/Libraries/LibGUI/WindowServerConnection.h b/Libraries/LibGUI/WindowServerConnection.h index 5579be5d13..e50223a34d 100644 --- a/Libraries/LibGUI/WindowServerConnection.h +++ b/Libraries/LibGUI/WindowServerConnection.h @@ -74,6 +74,7 @@ private: virtual void handle(const Messages::WindowClient::DragCancelled&) override; virtual void handle(const Messages::WindowClient::UpdateSystemTheme&) override; virtual void handle(const Messages::WindowClient::WindowStateChanged&) override; + virtual void handle(const Messages::WindowClient::DisplayLinkNotification&) override; }; } diff --git a/Servers/WindowServer/ClientConnection.cpp b/Servers/WindowServer/ClientConnection.cpp index 74d1f234cd..793dfe6ad3 100644 --- a/Servers/WindowServer/ClientConnection.cpp +++ b/Servers/WindowServer/ClientConnection.cpp @@ -734,4 +734,22 @@ OwnPtr Client return make(); } +void ClientConnection::handle(const Messages::WindowServer::EnableDisplayLink&) +{ + m_has_display_link = true; +} + +void ClientConnection::handle(const Messages::WindowServer::DisableDisplayLink&) +{ + m_has_display_link = false; +} + +void ClientConnection::notify_display_link(Badge) +{ + if (!m_has_display_link) + return; + + post_message(Messages::WindowClient::DisplayLinkNotification()); +} + } diff --git a/Servers/WindowServer/ClientConnection.h b/Servers/WindowServer/ClientConnection.h index b17c384b21..a5ebdd5a65 100644 --- a/Servers/WindowServer/ClientConnection.h +++ b/Servers/WindowServer/ClientConnection.h @@ -26,6 +26,7 @@ #pragma once +#include #include #include #include @@ -38,6 +39,7 @@ namespace WindowServer { +class Compositor; class Window; class Menu; class MenuBar; @@ -72,6 +74,8 @@ public: return const_cast(menu.value().ptr()); } + void notify_display_link(Badge); + private: explicit ClientConnection(Core::LocalSocket&, int client_id); @@ -117,6 +121,8 @@ private: virtual OwnPtr handle(const Messages::WindowServer::SetSystemMenu&) override; virtual OwnPtr handle(const Messages::WindowServer::SetSystemTheme&) override; virtual OwnPtr handle(const Messages::WindowServer::SetWindowBaseSizeAndSizeIncrement&) override; + virtual void handle(const Messages::WindowServer::EnableDisplayLink&) override; + virtual void handle(const Messages::WindowServer::DisableDisplayLink&) override; HashMap> m_windows; HashMap> m_menubars; @@ -127,6 +133,8 @@ private: int m_next_menu_id { 20000 }; int m_next_window_id { 1982 }; + bool m_has_display_link { false }; + RefPtr m_last_sent_clipboard_content; }; diff --git a/Servers/WindowServer/Compositor.cpp b/Servers/WindowServer/Compositor.cpp index a821855a16..e5cf24182b 100644 --- a/Servers/WindowServer/Compositor.cpp +++ b/Servers/WindowServer/Compositor.cpp @@ -25,6 +25,7 @@ */ #include "Compositor.h" +#include "ClientConnection.h" #include "Event.h" #include "EventLoop.h" #include "Screen.h" @@ -69,6 +70,7 @@ Compositor::Compositor() init_bitmaps(); m_compose_timer->on_timeout = [&]() { + notify_display_links(); #if defined(COMPOSITOR_DEBUG) dbgprintf("Compositor: delayed frame callback: %d rects\n", m_dirty_rects.size()); #endif @@ -466,4 +468,11 @@ void Compositor::draw_cursor() m_last_cursor_rect = cursor_rect; } +void Compositor::notify_display_links() +{ + ClientConnection::for_each_client([](auto& client) { + client.notify_display_link({}); + }); +} + } diff --git a/Servers/WindowServer/Compositor.h b/Servers/WindowServer/Compositor.h index 56c61bea3a..ce2069bdc5 100644 --- a/Servers/WindowServer/Compositor.h +++ b/Servers/WindowServer/Compositor.h @@ -70,6 +70,7 @@ private: void draw_geometry_label(); void draw_menubar(); void run_animations(); + void notify_display_links(); RefPtr m_compose_timer; RefPtr m_immediate_compose_timer; diff --git a/Servers/WindowServer/WindowClient.ipc b/Servers/WindowServer/WindowClient.ipc index 4e3c077a7d..bd0d690b52 100644 --- a/Servers/WindowServer/WindowClient.ipc +++ b/Servers/WindowServer/WindowClient.ipc @@ -35,4 +35,6 @@ endpoint WindowClient = 4 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/WindowServer.ipc b/Servers/WindowServer/WindowServer.ipc index ee805da3a7..9e29ee34b7 100644 --- a/Servers/WindowServer/WindowServer.ipc +++ b/Servers/WindowServer/WindowServer.ipc @@ -85,4 +85,7 @@ endpoint WindowServer = 2 SetSystemTheme(String theme_path, String theme_name) => (bool success) SetWindowBaseSizeAndSizeIncrement(i32 window_id, Gfx::Size base_size, Gfx::Size size_increment) => () + + EnableDisplayLink() =| + DisableDisplayLink() =| }