From 424a3f5ac3c659d57d38aba36f4062c8ecbc4044 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sun, 22 Mar 2020 21:13:23 +0100 Subject: [PATCH] WindowServer+LibGUI: Add a way to get notified at display refresh rate This patch adds GUI::DisplayLink, a mechanism for registering callbacks that will fire at the display refresh rate. Note that we don't actually know the screen refresh rate, but this is instead completely driven by WindowServer's compositing timer. For all current intents and purposes it does the job well enough. :^) --- Libraries/LibGUI/DisplayLink.cpp | 92 +++++++++++++++++++++ Libraries/LibGUI/DisplayLink.h | 42 ++++++++++ Libraries/LibGUI/Makefile | 1 + Libraries/LibGUI/WindowServerConnection.cpp | 6 ++ Libraries/LibGUI/WindowServerConnection.h | 1 + Servers/WindowServer/ClientConnection.cpp | 18 ++++ Servers/WindowServer/ClientConnection.h | 8 ++ Servers/WindowServer/Compositor.cpp | 9 ++ Servers/WindowServer/Compositor.h | 1 + Servers/WindowServer/WindowClient.ipc | 2 + Servers/WindowServer/WindowServer.ipc | 3 + 11 files changed, 183 insertions(+) create mode 100644 Libraries/LibGUI/DisplayLink.cpp create mode 100644 Libraries/LibGUI/DisplayLink.h 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() =| }