From 9ac17c7bc9e847ca3ede7c7913de24515c5f8a99 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Fri, 21 Jun 2019 08:19:43 +0200 Subject: [PATCH] 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. --- Servers/WindowServer/Makefile | 1 + Servers/WindowServer/WSAPITypes.h | 1 + Servers/WindowServer/WSCompositor.cpp | 57 ------------ Servers/WindowServer/WSEventLoop.cpp | 3 + Servers/WindowServer/WSMenuBarKeeper.cpp | 108 +++++++++++++++++++++++ Servers/WindowServer/WSMenuBarKeeper.h | 28 ++++++ Servers/WindowServer/WSWindow.cpp | 2 + Servers/WindowServer/WSWindowManager.cpp | 23 ++--- Servers/WindowServer/WSWindowManager.h | 29 +++--- Servers/WindowServer/WSWindowType.h | 1 + 10 files changed, 164 insertions(+), 89 deletions(-) create mode 100644 Servers/WindowServer/WSMenuBarKeeper.cpp create mode 100644 Servers/WindowServer/WSMenuBarKeeper.h diff --git a/Servers/WindowServer/Makefile b/Servers/WindowServer/Makefile index 2756f391a92..f92f14e2308 100644 --- a/Servers/WindowServer/Makefile +++ b/Servers/WindowServer/Makefile @@ -27,6 +27,7 @@ WINDOWSERVER_OBJS = \ WSButton.o \ WSCPUMonitor.o \ WSCompositor.o \ + WSMenuBarKeeper.o \ main.o APP = WindowServer diff --git a/Servers/WindowServer/WSAPITypes.h b/Servers/WindowServer/WSAPITypes.h index 0a1a6ea9a6a..ad2b9fd1ca8 100644 --- a/Servers/WindowServer/WSAPITypes.h +++ b/Servers/WindowServer/WSAPITypes.h @@ -27,6 +27,7 @@ enum WSAPI_WindowType { WindowSwitcher, Taskbar, Tooltip, + Menubar, }; struct WSAPI_WindowBackingStoreInfo { diff --git a/Servers/WindowServer/WSCompositor.cpp b/Servers/WindowServer/WSCompositor.cpp index 1fc1e4c4f03..e21beaf3fff 100644 --- a/Servers/WindowServer/WSCompositor.cpp +++ b/Servers/WindowServer/WSCompositor.cpp @@ -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); -} diff --git a/Servers/WindowServer/WSEventLoop.cpp b/Servers/WindowServer/WSEventLoop.cpp index 479b7defac2..8c103c8b5a2 100644 --- a/Servers/WindowServer/WSEventLoop.cpp +++ b/Servers/WindowServer/WSEventLoop.cpp @@ -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 } diff --git a/Servers/WindowServer/WSMenuBarKeeper.cpp b/Servers/WindowServer/WSMenuBarKeeper.cpp new file mode 100644 index 00000000000..b6167995fc9 --- /dev/null +++ b/Servers/WindowServer/WSMenuBarKeeper.cpp @@ -0,0 +1,108 @@ +#include +#include +#include +#include +#include +#include +#include + +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(*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); +} diff --git a/Servers/WindowServer/WSMenuBarKeeper.h b/Servers/WindowServer/WSMenuBarKeeper.h new file mode 100644 index 00000000000..19f4cbecac1 --- /dev/null +++ b/Servers/WindowServer/WSMenuBarKeeper.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include +#include + +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 m_window; + WSCPUMonitor m_cpu_monitor; + String m_username; +}; diff --git a/Servers/WindowServer/WSWindow.cpp b/Servers/WindowServer/WSWindow.cpp index d478331649b..1eec834d73c 100644 --- a/Servers/WindowServer/WSWindow.cpp +++ b/Servers/WindowServer/WSWindow.cpp @@ -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(); } diff --git a/Servers/WindowServer/WSWindowManager.cpp b/Servers/WindowServer/WSWindowManager.cpp index a796617b446..4714ed14b6c 100644 --- a/Servers/WindowServer/WSWindowManager.cpp +++ b/Servers/WindowServer/WSWindowManager.cpp @@ -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 diff --git a/Servers/WindowServer/WSWindowManager.h b/Servers/WindowServer/WSWindowManager.h index 839f2292b9d..1d60e070023 100644 --- a/Servers/WindowServer/WSWindowManager.h +++ b/Servers/WindowServer/WSWindowManager.h @@ -1,6 +1,5 @@ #pragma once -#include "WSMenuBar.h" #include #include #include @@ -11,9 +10,10 @@ #include #include #include -#include #include #include +#include +#include #include #include #include @@ -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 + 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 get_cursor(const String& name); Retained get_cursor(const String& name, const Point& hotspot); @@ -159,18 +167,9 @@ private: template void for_each_window(Callback); - template - 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 m_current_menu; WSWindowSwitcher m_switcher; + WSMenuBarKeeper m_menubar_keeper; - String m_username; WeakPtr m_cursor_tracking_button; WeakPtr m_hovered_button; - WSCPUMonitor m_cpu_monitor; - RetainPtr 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) diff --git a/Servers/WindowServer/WSWindowType.h b/Servers/WindowServer/WSWindowType.h index 897e81f74e8..9f1528ad848 100644 --- a/Servers/WindowServer/WSWindowType.h +++ b/Servers/WindowServer/WSWindowType.h @@ -7,4 +7,5 @@ enum class WSWindowType { WindowSwitcher, Taskbar, Tooltip, + Menubar, };