1
0
Fork 0
mirror of https://github.com/LadybirdBrowser/ladybird.git synced 2025-06-09 17:44:56 +09:00

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. :^)
This commit is contained in:
Andreas Kling 2020-03-22 21:13:23 +01:00
parent bb70d0692b
commit 424a3f5ac3
Notes: sideshowbarker 2024-07-19 08:10:47 +09:00
11 changed files with 183 additions and 0 deletions

View file

@ -0,0 +1,92 @@
/*
* Copyright (c) 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/Function.h>
#include <AK/HashMap.h>
#include <LibGUI/DisplayLink.h>
#include <LibGUI/WindowServerConnection.h>
namespace GUI {
class DisplayLinkCallback : public RefCounted<DisplayLinkCallback> {
public:
DisplayLinkCallback(i32 link_id, Function<void(i32)> callback)
: m_link_id(link_id)
, m_callback(move(callback))
{
}
void invoke()
{
m_callback(m_link_id);
}
private:
i32 m_link_id { 0 };
Function<void(i32)> m_callback;
};
static HashMap<i32, RefPtr<DisplayLinkCallback>>& callbacks()
{
static HashMap<i32, RefPtr<DisplayLinkCallback>>* map;
if (!map)
map = new HashMap<i32, RefPtr<DisplayLinkCallback>>;
return *map;
}
static i32 s_next_callback_id = 1;
i32 DisplayLink::register_callback(Function<void(i32)> 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<WindowServerConnection>)
{
auto copy_of_callbacks = callbacks();
for (auto& it : copy_of_callbacks)
it.value->invoke();
}
}

View file

@ -0,0 +1,42 @@
/*
* Copyright (c) 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 <LibGUI/Forward.h>
namespace GUI {
class DisplayLink {
public:
static i32 register_callback(Function<void(i32)>);
static bool unregister_callback(i32 callback_id);
static void notify(Badge<WindowServerConnection>);
};
}

View file

@ -18,6 +18,7 @@ OBJS = \
CppSyntaxHighlighter.o \
Desktop.o \
Dialog.o \
DisplayLink.o \
DragOperation.o \
Event.o \
FilePicker.o \

View file

@ -31,6 +31,7 @@
#include <LibGUI/Application.h>
#include <LibGUI/Clipboard.h>
#include <LibGUI/Desktop.h>
#include <LibGUI/DisplayLink.h>
#include <LibGUI/DragOperation.h>
#include <LibGUI/Event.h>
#include <LibGUI/Menu.h>
@ -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({});
}
}

View file

@ -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;
};
}

View file

@ -734,4 +734,22 @@ OwnPtr<Messages::WindowServer::SetWindowBaseSizeAndSizeIncrementResponse> Client
return make<Messages::WindowServer::SetWindowBaseSizeAndSizeIncrementResponse>();
}
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<Compositor>)
{
if (!m_has_display_link)
return;
post_message(Messages::WindowClient::DisplayLinkNotification());
}
}

View file

@ -26,6 +26,7 @@
#pragma once
#include <AK/Badge.h>
#include <AK/Function.h>
#include <AK/HashMap.h>
#include <AK/OwnPtr.h>
@ -38,6 +39,7 @@
namespace WindowServer {
class Compositor;
class Window;
class Menu;
class MenuBar;
@ -72,6 +74,8 @@ public:
return const_cast<Menu*>(menu.value().ptr());
}
void notify_display_link(Badge<Compositor>);
private:
explicit ClientConnection(Core::LocalSocket&, int client_id);
@ -117,6 +121,8 @@ private:
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::SetWindowBaseSizeAndSizeIncrementResponse> handle(const Messages::WindowServer::SetWindowBaseSizeAndSizeIncrement&) override;
virtual void handle(const Messages::WindowServer::EnableDisplayLink&) override;
virtual void handle(const Messages::WindowServer::DisableDisplayLink&) override;
HashMap<int, NonnullRefPtr<Window>> m_windows;
HashMap<int, NonnullOwnPtr<MenuBar>> 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<SharedBuffer> m_last_sent_clipboard_content;
};

View file

@ -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({});
});
}
}

View file

@ -70,6 +70,7 @@ private:
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;

View file

@ -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() =|
}

View file

@ -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() =|
}