diff --git a/Userland/Services/WindowServer/ConnectionFromClient.cpp b/Userland/Services/WindowServer/ConnectionFromClient.cpp index 0adbe0d78f..e4f4353574 100644 --- a/Userland/Services/WindowServer/ConnectionFromClient.cpp +++ b/Userland/Services/WindowServer/ConnectionFromClient.cpp @@ -467,6 +467,36 @@ Messages::WindowServer::GetWindowRectResponse ConnectionFromClient::get_window_r return it->value->rect(); } +static Gfx::IntSize calculate_minimum_size_for_window(Window const& window) +{ + // NOTE: Windows with a title bar have a minimum size enforced by the system, + // because we want to always keep their title buttons accessible. + if (window.type() == WindowType::Normal || window.type() == WindowType::ToolWindow) { + auto palette = WindowManager::the().palette(); + + int required_width = 0; + // Padding on left and right of window title content. + // FIXME: This seems like it should be defined in the theme. + required_width += 2 + 2; + // App icon + required_width += 16; + // Padding between icon and buttons + required_width += 2; + // Close button + required_width += palette.window_title_button_width(); + // Maximize button + if (window.is_resizable()) + required_width += palette.window_title_button_width(); + // Minimize button + if (window.is_minimizable()) + required_width += palette.window_title_button_width(); + + return { required_width, 0 }; + } + + return { 0, 0 }; +} + void ConnectionFromClient::set_window_minimum_size(i32 window_id, Gfx::IntSize const& size) { auto it = m_windows.find(window_id); @@ -480,7 +510,9 @@ void ConnectionFromClient::set_window_minimum_size(i32 window_id, Gfx::IntSize c return; } - window.set_minimum_size(size); + auto system_window_minimum_size = calculate_minimum_size_for_window(window); + window.set_minimum_size({ max(size.width(), system_window_minimum_size.width()), + max(size.height(), system_window_minimum_size.height()) }); if (window.width() < window.minimum_size().width() || window.height() < window.minimum_size().height()) { // New minimum size is larger than the current window size, resize accordingly. @@ -569,7 +601,9 @@ void ConnectionFromClient::create_window(i32 window_id, Gfx::IntRect const& rect new_rect = { WindowManager::the().get_recommended_window_position({ 100, 100 }), rect.size() }; window->set_default_positioned(true); } - window->set_minimum_size(minimum_size); + auto system_window_minimum_size = calculate_minimum_size_for_window(window); + window->set_minimum_size({ max(minimum_size.width(), system_window_minimum_size.width()), + max(minimum_size.height(), system_window_minimum_size.height()) }); bool did_size_clamp = window->apply_minimum_size(new_rect); window->set_rect(new_rect); window->nudge_into_desktop(nullptr); @@ -1284,4 +1318,29 @@ void ConnectionFromClient::remove_window_stealing(i32 window_id) window->remove_all_stealing(); } +void ConnectionFromClient::notify_about_theme_change() +{ + // Recalculate minimum size for each window, using the new theme metrics. + // FIXME: We only ever increase the minimum size, which means that if you go from a theme with large buttons + // (eg Basalt) to one with smaller buttons (eg Default) then the minimum size will remain large. This + // only happens with pre-existing windows, and it's unlikely that you will ever have windows that are + // so small, so it's probably fine, but it is technically a bug. :^) + for_each_window([](auto& window) -> IterationDecision { + auto system_window_minimum_size = calculate_minimum_size_for_window(window); + + auto old_minimum_size = window.minimum_size(); + auto new_rect = window.rect(); + + window.set_minimum_size({ max(old_minimum_size.width(), system_window_minimum_size.width()), + max(old_minimum_size.height(), system_window_minimum_size.height()) }); + if (window.apply_minimum_size(new_rect)) { + window.set_rect(new_rect); + window.refresh_client_size(); + } + + return IterationDecision::Continue; + }); + async_update_system_theme(Gfx::current_system_theme_buffer()); +} + } diff --git a/Userland/Services/WindowServer/ConnectionFromClient.h b/Userland/Services/WindowServer/ConnectionFromClient.h index d0184b2805..0b8e4bf1fb 100644 --- a/Userland/Services/WindowServer/ConnectionFromClient.h +++ b/Userland/Services/WindowServer/ConnectionFromClient.h @@ -80,6 +80,8 @@ public: void notify_display_link(Badge); + void notify_about_theme_change(); + private: explicit ConnectionFromClient(NonnullOwnPtr, int client_id); diff --git a/Userland/Services/WindowServer/WindowManager.cpp b/Userland/Services/WindowServer/WindowManager.cpp index 5635f096d9..1c66c95a01 100644 --- a/Userland/Services/WindowServer/WindowManager.cpp +++ b/Userland/Services/WindowServer/WindowManager.cpp @@ -2099,7 +2099,7 @@ void WindowManager::invalidate_after_theme_or_font_change() return IterationDecision::Continue; }); ConnectionFromClient::for_each_client([&](ConnectionFromClient& client) { - client.async_update_system_theme(Gfx::current_system_theme_buffer()); + client.notify_about_theme_change(); }); MenuManager::the().did_change_theme(); AppletManager::the().did_change_theme();