mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 23:50:19 +00:00
WindowServer: Render the global menubar into a separate WSWindow.
Previously we were rendering the whole menubar on every compose(), even if nothing changed about it. Now it's in its own window and can be invalidated and painted separately.
This commit is contained in:
parent
d99b1a9ea0
commit
9ac17c7bc9
Notes:
sideshowbarker
2024-07-19 13:32:37 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/9ac17c7bc9e
10 changed files with 164 additions and 89 deletions
|
@ -27,6 +27,7 @@ WINDOWSERVER_OBJS = \
|
|||
WSButton.o \
|
||||
WSCPUMonitor.o \
|
||||
WSCompositor.o \
|
||||
WSMenuBarKeeper.o \
|
||||
main.o
|
||||
|
||||
APP = WindowServer
|
||||
|
|
|
@ -27,6 +27,7 @@ enum WSAPI_WindowType {
|
|||
WindowSwitcher,
|
||||
Taskbar,
|
||||
Tooltip,
|
||||
Menubar,
|
||||
};
|
||||
|
||||
struct WSAPI_WindowBackingStoreInfo {
|
||||
|
|
|
@ -159,7 +159,6 @@ void WSCompositor::compose()
|
|||
});
|
||||
|
||||
draw_geometry_label();
|
||||
draw_menubar();
|
||||
}
|
||||
|
||||
draw_cursor();
|
||||
|
@ -332,59 +331,3 @@ void WSCompositor::draw_cursor()
|
|||
m_back_painter->blit(cursor_rect.location(), wm.active_cursor().bitmap(), wm.active_cursor().rect());
|
||||
m_last_cursor_rect = cursor_rect;
|
||||
}
|
||||
|
||||
void WSCompositor::draw_menubar()
|
||||
{
|
||||
auto& wm = WSWindowManager::the();
|
||||
auto menubar_rect = wm.menubar_rect();
|
||||
|
||||
m_back_painter->fill_rect(menubar_rect, Color::LightGray);
|
||||
m_back_painter->draw_line({ 0, menubar_rect.bottom() }, { menubar_rect.right(), menubar_rect.bottom() }, Color::MidGray);
|
||||
int index = 0;
|
||||
wm.for_each_active_menubar_menu([&](WSMenu& menu) {
|
||||
Color text_color = Color::Black;
|
||||
if (&menu == wm.current_menu()) {
|
||||
m_back_painter->fill_rect(menu.rect_in_menubar(), wm.menu_selection_color());
|
||||
text_color = Color::White;
|
||||
}
|
||||
m_back_painter->draw_text(
|
||||
menu.text_rect_in_menubar(),
|
||||
menu.name(),
|
||||
index == 1 ? wm.app_menu_font() : wm.menu_font(),
|
||||
TextAlignment::CenterLeft,
|
||||
text_color);
|
||||
++index;
|
||||
return true;
|
||||
});
|
||||
|
||||
int username_width = Font::default_bold_font().width(wm.m_username);
|
||||
Rect username_rect {
|
||||
menubar_rect.right() - wm.menubar_menu_margin() / 2 - Font::default_bold_font().width(wm.m_username),
|
||||
menubar_rect.y(),
|
||||
username_width,
|
||||
menubar_rect.height()
|
||||
};
|
||||
m_back_painter->draw_text(username_rect, wm.m_username, Font::default_bold_font(), TextAlignment::CenterRight, Color::Black);
|
||||
|
||||
time_t now = time(nullptr);
|
||||
auto* tm = localtime(&now);
|
||||
auto time_text = String::format("%4u-%02u-%02u %02u:%02u:%02u",
|
||||
tm->tm_year + 1900,
|
||||
tm->tm_mon + 1,
|
||||
tm->tm_mday,
|
||||
tm->tm_hour,
|
||||
tm->tm_min,
|
||||
tm->tm_sec);
|
||||
int time_width = wm.font().width(time_text);
|
||||
Rect time_rect {
|
||||
username_rect.left() - wm.menubar_menu_margin() / 2 - time_width,
|
||||
menubar_rect.y(),
|
||||
time_width,
|
||||
menubar_rect.height()
|
||||
};
|
||||
|
||||
m_back_painter->draw_text(time_rect, time_text, wm.font(), TextAlignment::CenterRight, Color::Black);
|
||||
|
||||
Rect cpu_rect { time_rect.right() - wm.font().width(time_text) - wm.m_cpu_monitor.capacity() - 10, time_rect.y() + 1, wm.m_cpu_monitor.capacity(), time_rect.height() - 2 };
|
||||
wm.m_cpu_monitor.paint(*m_back_painter, cpu_rect);
|
||||
}
|
||||
|
|
|
@ -206,6 +206,9 @@ bool WSEventLoop::on_receive_from_client(int client_id, const WSAPI_ClientMessag
|
|||
case WSAPI_WindowType::Tooltip:
|
||||
ws_window_type = WSWindowType::Tooltip;
|
||||
break;
|
||||
case WSAPI_WindowType::Menubar:
|
||||
ws_window_type = WSWindowType::Menubar;
|
||||
break;
|
||||
case WSAPI_WindowType::Invalid:
|
||||
break; // handled below
|
||||
}
|
||||
|
|
108
Servers/WindowServer/WSMenuBarKeeper.cpp
Normal file
108
Servers/WindowServer/WSMenuBarKeeper.cpp
Normal file
|
@ -0,0 +1,108 @@
|
|||
#include <LibCore/CTimer.h>
|
||||
#include <SharedGraphics/Font.h>
|
||||
#include <SharedGraphics/Painter.h>
|
||||
#include <WindowServer/WSMenuBarKeeper.h>
|
||||
#include <WindowServer/WSWindowManager.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
WSMenuBarKeeper::WSMenuBarKeeper()
|
||||
{
|
||||
m_username = getlogin();
|
||||
|
||||
new CTimer(300, [this] {
|
||||
static time_t last_update_time;
|
||||
time_t now = time(nullptr);
|
||||
if (now != last_update_time || m_cpu_monitor.is_dirty()) {
|
||||
tick_clock();
|
||||
last_update_time = now;
|
||||
m_cpu_monitor.set_dirty(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
WSMenuBarKeeper::~WSMenuBarKeeper()
|
||||
{
|
||||
}
|
||||
|
||||
void WSMenuBarKeeper::setup()
|
||||
{
|
||||
m_window = make<WSWindow>(*this, WSWindowType::Menubar);
|
||||
m_window->set_rect(WSWindowManager::the().menubar_rect());
|
||||
}
|
||||
|
||||
void WSMenuBarKeeper::draw()
|
||||
{
|
||||
auto& wm = WSWindowManager::the();
|
||||
auto menubar_rect = wm.menubar_rect();
|
||||
|
||||
Painter painter(*window().backing_store());
|
||||
|
||||
painter.fill_rect(menubar_rect, Color::LightGray);
|
||||
painter.draw_line({ 0, menubar_rect.bottom() }, { menubar_rect.right(), menubar_rect.bottom() }, Color::MidGray);
|
||||
int index = 0;
|
||||
wm.for_each_active_menubar_menu([&](WSMenu& menu) {
|
||||
Color text_color = Color::Black;
|
||||
if (&menu == wm.current_menu()) {
|
||||
painter.fill_rect(menu.rect_in_menubar(), wm.menu_selection_color());
|
||||
text_color = Color::White;
|
||||
}
|
||||
painter.draw_text(
|
||||
menu.text_rect_in_menubar(),
|
||||
menu.name(),
|
||||
index == 1 ? wm.app_menu_font() : wm.menu_font(),
|
||||
TextAlignment::CenterLeft,
|
||||
text_color);
|
||||
++index;
|
||||
return true;
|
||||
});
|
||||
|
||||
int username_width = Font::default_bold_font().width(m_username);
|
||||
Rect username_rect {
|
||||
menubar_rect.right() - wm.menubar_menu_margin() / 2 - Font::default_bold_font().width(m_username),
|
||||
menubar_rect.y(),
|
||||
username_width,
|
||||
menubar_rect.height()
|
||||
};
|
||||
painter.draw_text(username_rect, m_username, Font::default_bold_font(), TextAlignment::CenterRight, Color::Black);
|
||||
|
||||
time_t now = time(nullptr);
|
||||
auto* tm = localtime(&now);
|
||||
auto time_text = String::format("%4u-%02u-%02u %02u:%02u:%02u",
|
||||
tm->tm_year + 1900,
|
||||
tm->tm_mon + 1,
|
||||
tm->tm_mday,
|
||||
tm->tm_hour,
|
||||
tm->tm_min,
|
||||
tm->tm_sec);
|
||||
int time_width = wm.font().width(time_text);
|
||||
Rect time_rect {
|
||||
username_rect.left() - wm.menubar_menu_margin() / 2 - time_width,
|
||||
menubar_rect.y(),
|
||||
time_width,
|
||||
menubar_rect.height()
|
||||
};
|
||||
|
||||
painter.draw_text(time_rect, time_text, wm.font(), TextAlignment::CenterRight, Color::Black);
|
||||
|
||||
Rect cpu_rect { time_rect.right() - wm.font().width(time_text) - m_cpu_monitor.capacity() - 10, time_rect.y() + 1, m_cpu_monitor.capacity(), time_rect.height() - 2 };
|
||||
m_cpu_monitor.paint(painter, cpu_rect);
|
||||
}
|
||||
|
||||
void WSMenuBarKeeper::tick_clock()
|
||||
{
|
||||
refresh();
|
||||
}
|
||||
|
||||
void WSMenuBarKeeper::refresh()
|
||||
{
|
||||
if (!m_window)
|
||||
return;
|
||||
draw();
|
||||
window().invalidate();
|
||||
}
|
||||
|
||||
void WSMenuBarKeeper::event(CEvent& event)
|
||||
{
|
||||
return CObject::event(event);
|
||||
}
|
28
Servers/WindowServer/WSMenuBarKeeper.h
Normal file
28
Servers/WindowServer/WSMenuBarKeeper.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
#pragma once
|
||||
|
||||
#include <LibCore/CObject.h>
|
||||
#include <WindowServer/WSCPUMonitor.h>
|
||||
#include <WindowServer/WSWindow.h>
|
||||
|
||||
class WSMenuBarKeeper final : public CObject {
|
||||
public:
|
||||
WSMenuBarKeeper();
|
||||
virtual ~WSMenuBarKeeper() override;
|
||||
|
||||
WSWindow& window() { return *m_window; }
|
||||
const WSWindow& window() const { return *m_window; }
|
||||
|
||||
void draw();
|
||||
void refresh();
|
||||
void setup();
|
||||
|
||||
virtual void event(CEvent&) override;
|
||||
virtual const char* class_name() const override { return "WSMenuBarKeeper"; }
|
||||
|
||||
private:
|
||||
void tick_clock();
|
||||
|
||||
OwnPtr<WSWindow> m_window;
|
||||
WSCPUMonitor m_cpu_monitor;
|
||||
String m_username;
|
||||
};
|
|
@ -138,6 +138,8 @@ static WSAPI_WindowType to_api(WSWindowType ws_type)
|
|||
return WSAPI_WindowType::Taskbar;
|
||||
case WSWindowType::Tooltip:
|
||||
return WSAPI_WindowType::Tooltip;
|
||||
case WSWindowType::Menubar:
|
||||
return WSAPI_WindowType::Menubar;
|
||||
default:
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
|
|
@ -38,8 +38,6 @@ WSWindowManager::WSWindowManager()
|
|||
{
|
||||
s_the = this;
|
||||
|
||||
m_username = getlogin();
|
||||
|
||||
reload_config(false);
|
||||
|
||||
struct AppMenuItem {
|
||||
|
@ -101,15 +99,7 @@ WSWindowManager::WSWindowManager()
|
|||
// NOTE: This ensures that the system menu has the correct dimensions.
|
||||
set_current_menubar(nullptr);
|
||||
|
||||
new CTimer(300, [this] {
|
||||
static time_t last_update_time;
|
||||
time_t now = time(nullptr);
|
||||
if (now != last_update_time || m_cpu_monitor.is_dirty()) {
|
||||
tick_clock();
|
||||
last_update_time = now;
|
||||
m_cpu_monitor.set_dirty(false);
|
||||
}
|
||||
});
|
||||
m_menubar_keeper.setup();
|
||||
|
||||
invalidate();
|
||||
WSCompositor::the().compose();
|
||||
|
@ -198,11 +188,6 @@ const Font& WSWindowManager::app_menu_font() const
|
|||
return Font::default_bold_font();
|
||||
}
|
||||
|
||||
void WSWindowManager::tick_clock()
|
||||
{
|
||||
invalidate(menubar_rect());
|
||||
}
|
||||
|
||||
void WSWindowManager::set_resolution(int width, int height)
|
||||
{
|
||||
WSCompositor::the().set_resolution(width, height);
|
||||
|
@ -252,7 +237,7 @@ void WSWindowManager::set_current_menubar(WSMenuBar* menubar)
|
|||
++index;
|
||||
return true;
|
||||
});
|
||||
invalidate(menubar_rect());
|
||||
m_menubar_keeper.refresh();
|
||||
}
|
||||
|
||||
void WSWindowManager::add_window(WSWindow& window)
|
||||
|
@ -416,6 +401,7 @@ void WSWindowManager::handle_menu_mouse_event(WSMenu& menu, const WSMouseEvent&
|
|||
menu_window.set_visible(true);
|
||||
}
|
||||
m_current_menu = menu.make_weak_ptr();
|
||||
m_menubar_keeper.refresh();
|
||||
return;
|
||||
}
|
||||
if (event.type() == WSMouseEvent::MouseDown && event.button() == MouseButton::Left) {
|
||||
|
@ -429,6 +415,7 @@ void WSWindowManager::close_current_menu()
|
|||
if (m_current_menu && m_current_menu->menu_window())
|
||||
m_current_menu->menu_window()->set_visible(false);
|
||||
m_current_menu = nullptr;
|
||||
m_menubar_keeper.refresh();
|
||||
}
|
||||
|
||||
void WSWindowManager::handle_menubar_mouse_event(const WSMouseEvent& event)
|
||||
|
@ -1004,7 +991,7 @@ void WSWindowManager::notify_client_changed_app_menubar(WSClientConnection& clie
|
|||
{
|
||||
if (active_client() == &client)
|
||||
set_current_menubar(client.app_menubar());
|
||||
invalidate(menubar_rect());
|
||||
m_menubar_keeper.refresh();
|
||||
}
|
||||
|
||||
const WSCursor& WSWindowManager::active_cursor() const
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#include "WSMenuBar.h"
|
||||
#include <AK/HashMap.h>
|
||||
#include <AK/HashTable.h>
|
||||
#include <AK/InlineLinkedList.h>
|
||||
|
@ -11,9 +10,10 @@
|
|||
#include <SharedGraphics/DisjointRectSet.h>
|
||||
#include <SharedGraphics/Painter.h>
|
||||
#include <SharedGraphics/Rect.h>
|
||||
#include <WindowServer/WSCPUMonitor.h>
|
||||
#include <WindowServer/WSCursor.h>
|
||||
#include <WindowServer/WSEvent.h>
|
||||
#include <WindowServer/WSMenuBar.h>
|
||||
#include <WindowServer/WSMenuBarKeeper.h>
|
||||
#include <WindowServer/WSWindow.h>
|
||||
#include <WindowServer/WSWindowSwitcher.h>
|
||||
#include <WindowServer/WSWindowType.h>
|
||||
|
@ -131,6 +131,14 @@ public:
|
|||
const WSWindow* active_fullscreen_window() const { return (m_active_window && m_active_window->is_fullscreen()) ? m_active_window : nullptr; }
|
||||
WSWindow* active_fullscreen_window() { return (m_active_window && m_active_window->is_fullscreen()) ? m_active_window : nullptr; }
|
||||
|
||||
template<typename Callback>
|
||||
void for_each_active_menubar_menu(Callback callback)
|
||||
{
|
||||
callback(*m_system_menu);
|
||||
if (m_current_menubar)
|
||||
m_current_menubar->for_each_menu(callback);
|
||||
}
|
||||
|
||||
private:
|
||||
Retained<WSCursor> get_cursor(const String& name);
|
||||
Retained<WSCursor> get_cursor(const String& name, const Point& hotspot);
|
||||
|
@ -159,18 +167,9 @@ private:
|
|||
template<typename Callback>
|
||||
void for_each_window(Callback);
|
||||
|
||||
template<typename Callback>
|
||||
void for_each_active_menubar_menu(Callback callback)
|
||||
{
|
||||
callback(*m_system_menu);
|
||||
if (m_current_menubar)
|
||||
m_current_menubar->for_each_menu(callback);
|
||||
}
|
||||
|
||||
void close_current_menu();
|
||||
virtual void event(CEvent&) override;
|
||||
void paint_window_frame(const WSWindow&);
|
||||
void tick_clock();
|
||||
void tell_wm_listener_about_window(WSWindow& listener, WSWindow&);
|
||||
void tell_wm_listener_about_window_icon(WSWindow& listener, WSWindow&);
|
||||
void tell_wm_listener_about_window_rect(WSWindow& listener, WSWindow&);
|
||||
|
@ -241,13 +240,11 @@ private:
|
|||
WeakPtr<WSMenu> m_current_menu;
|
||||
|
||||
WSWindowSwitcher m_switcher;
|
||||
WSMenuBarKeeper m_menubar_keeper;
|
||||
|
||||
String m_username;
|
||||
WeakPtr<WSButton> m_cursor_tracking_button;
|
||||
WeakPtr<WSButton> m_hovered_button;
|
||||
|
||||
WSCPUMonitor m_cpu_monitor;
|
||||
|
||||
RetainPtr<CConfigFile> m_wm_config;
|
||||
};
|
||||
|
||||
|
@ -285,6 +282,8 @@ IterationDecision WSWindowManager::for_each_visible_window_from_back_to_front(Ca
|
|||
return IterationDecision::Break;
|
||||
if (for_each_visible_window_of_type_from_back_to_front(WSWindowType::Tooltip, callback) == IterationDecision::Break)
|
||||
return IterationDecision::Break;
|
||||
if (for_each_visible_window_of_type_from_back_to_front(WSWindowType::Menubar, callback) == IterationDecision::Break)
|
||||
return IterationDecision::Break;
|
||||
if (for_each_visible_window_of_type_from_back_to_front(WSWindowType::Menu, callback) == IterationDecision::Break)
|
||||
return IterationDecision::Break;
|
||||
return for_each_visible_window_of_type_from_back_to_front(WSWindowType::WindowSwitcher, callback);
|
||||
|
@ -320,6 +319,8 @@ IterationDecision WSWindowManager::for_each_visible_window_from_front_to_back(Ca
|
|||
return IterationDecision::Break;
|
||||
if (for_each_visible_window_of_type_from_front_to_back(WSWindowType::Menu, callback) == IterationDecision::Break)
|
||||
return IterationDecision::Break;
|
||||
if (for_each_visible_window_of_type_from_front_to_back(WSWindowType::Menubar, callback) == IterationDecision::Break)
|
||||
return IterationDecision::Break;
|
||||
if (for_each_visible_window_of_type_from_front_to_back(WSWindowType::Taskbar, callback) == IterationDecision::Break)
|
||||
return IterationDecision::Break;
|
||||
if (for_each_visible_window_of_type_from_front_to_back(WSWindowType::Tooltip, callback) == IterationDecision::Break)
|
||||
|
|
|
@ -7,4 +7,5 @@ enum class WSWindowType {
|
|||
WindowSwitcher,
|
||||
Taskbar,
|
||||
Tooltip,
|
||||
Menubar,
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue