summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSam Atkins <atkinssj@serenityos.org>2022-07-26 16:45:07 +0100
committerLinus Groh <mail@linusgroh.de>2022-07-27 00:01:42 +0100
commit11cb7c7b2807cb5bcc95c5853f909e441b8dec1b (patch)
treeae9d6c8119884a21886c973e514a5512e4b2e07d
parent0fcb6920e377aeff2a80f734f0f16f950432d164 (diff)
downloadserenity-11cb7c7b2807cb5bcc95c5853f909e441b8dec1b.zip
WindowServer: Ensure windows are wide enough to show title buttons :^)
Previously, windows without a defined minimum size (or one produced from the minimum sizes of their contents) would be shrunk down to 0 x 0, which makes the title buttons stick out the side and become impossible to interact with. This patch uses the theme metrics to calculate a minimum size that is as small as possible while still keeping the title buttons and app icon usable. This is combined with the minimum size requested by the app itself. Switching themes automatically updates the calculated minimum sizes for all existing windows. As noted, if the new theme has narrower title buttons then the old minimum is kept, but this shouldn't be noticeable unless you're looking for it.
-rw-r--r--Userland/Services/WindowServer/ConnectionFromClient.cpp63
-rw-r--r--Userland/Services/WindowServer/ConnectionFromClient.h2
-rw-r--r--Userland/Services/WindowServer/WindowManager.cpp2
3 files changed, 64 insertions, 3 deletions
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<Compositor>);
+ void notify_about_theme_change();
+
private:
explicit ConnectionFromClient(NonnullOwnPtr<Core::Stream::LocalSocket>, 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();