mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-23 08:00:20 +00:00
WindowServer, LibGUI: Variable minimum window sizes
Minimum window size can now be customised and set at runtime via the SetWindowMinimumSize WindowServer message and the set_minimum_size LibGUI::Window method. The default minimum size remains at 50x50. Some behind-the-scenes mechanics had to be added to LibGUI::Window to ensure that the minimum size is remembered if set before the window is shown. WindowServer sends a resize event to the client if it requests a size on create that's smaller than it's minimum size.
This commit is contained in:
parent
dea0d22ab3
commit
15c1f7a40d
Notes:
sideshowbarker
2024-07-18 22:13:10 +09:00
Author: https://github.com/nvella Commit: https://github.com/SerenityOS/serenity/commit/15c1f7a40d9 Pull-request: https://github.com/SerenityOS/serenity/pull/5360
7 changed files with 130 additions and 8 deletions
|
@ -150,6 +150,7 @@ void Window::show()
|
|||
m_alpha_hit_threshold,
|
||||
m_base_size,
|
||||
m_size_increment,
|
||||
m_minimum_size_when_windowless,
|
||||
m_resize_aspect_ratio,
|
||||
(i32)m_window_type,
|
||||
m_title_when_windowless,
|
||||
|
@ -259,6 +260,23 @@ void Window::set_rect(const Gfx::IntRect& a_rect)
|
|||
m_main_widget->resize(window_rect.size());
|
||||
}
|
||||
|
||||
Gfx::IntSize Window::minimum_size() const
|
||||
{
|
||||
if (!is_visible())
|
||||
return m_minimum_size_when_windowless;
|
||||
|
||||
return WindowServerConnection::the().send_sync<Messages::WindowServer::GetWindowMinimumSize>(m_window_id)->size();
|
||||
}
|
||||
|
||||
void Window::set_minimum_size(const Gfx::IntSize& size)
|
||||
{
|
||||
m_minimum_size_modified = true;
|
||||
m_minimum_size_when_windowless = size;
|
||||
|
||||
if (is_visible())
|
||||
WindowServerConnection::the().send_sync<Messages::WindowServer::SetWindowMinimumSize>(m_window_id, size);
|
||||
}
|
||||
|
||||
void Window::center_on_screen()
|
||||
{
|
||||
auto window_rect = rect();
|
||||
|
@ -278,6 +296,14 @@ void Window::center_within(const Window& other)
|
|||
void Window::set_window_type(WindowType window_type)
|
||||
{
|
||||
m_window_type = window_type;
|
||||
|
||||
if (!m_minimum_size_modified) {
|
||||
// Apply minimum size defaults.
|
||||
if (m_window_type == WindowType::Normal)
|
||||
m_minimum_size_when_windowless = { 50, 50 };
|
||||
else
|
||||
m_minimum_size_when_windowless = { 1, 1 };
|
||||
}
|
||||
}
|
||||
|
||||
void Window::set_cursor(Gfx::StandardCursor cursor)
|
||||
|
|
|
@ -108,6 +108,10 @@ public:
|
|||
|
||||
Gfx::IntPoint position() const { return rect().location(); }
|
||||
|
||||
Gfx::IntSize minimum_size() const;
|
||||
void set_minimum_size(const Gfx::IntSize&);
|
||||
void set_minimum_size(int width, int height) { set_minimum_size({ width, height }); }
|
||||
|
||||
void move_to(int x, int y) { move_to({ x, y }); }
|
||||
void move_to(const Gfx::IntPoint& point) { set_rect({ point, size() }); }
|
||||
|
||||
|
@ -248,6 +252,8 @@ private:
|
|||
WeakPtr<Widget> m_automatic_cursor_tracking_widget;
|
||||
WeakPtr<Widget> m_hovered_widget;
|
||||
Gfx::IntRect m_rect_when_windowless;
|
||||
Gfx::IntSize m_minimum_size_when_windowless { 50, 50 };
|
||||
bool m_minimum_size_modified { false };
|
||||
String m_title_when_windowless;
|
||||
Vector<Gfx::IntRect, 32> m_pending_paint_event_rects;
|
||||
Gfx::IntSize m_size_increment;
|
||||
|
|
|
@ -413,6 +413,48 @@ OwnPtr<Messages::WindowServer::GetWindowRectResponse> ClientConnection::handle(c
|
|||
return make<Messages::WindowServer::GetWindowRectResponse>(it->value->rect());
|
||||
}
|
||||
|
||||
OwnPtr<Messages::WindowServer::SetWindowMinimumSizeResponse> ClientConnection::handle(const Messages::WindowServer::SetWindowMinimumSize& message)
|
||||
{
|
||||
int window_id = message.window_id();
|
||||
auto it = m_windows.find(window_id);
|
||||
if (it == m_windows.end()) {
|
||||
did_misbehave("SetWindowMinimumSize: Bad window ID");
|
||||
return {};
|
||||
}
|
||||
auto& window = *(*it).value;
|
||||
if (window.is_fullscreen()) {
|
||||
dbgln("ClientConnection: Ignoring SetWindowMinimumSize request for fullscreen window");
|
||||
return {};
|
||||
}
|
||||
|
||||
window.set_minimum_size(message.size());
|
||||
|
||||
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.
|
||||
auto new_rect = window.rect();
|
||||
bool did_size_clamp = window.apply_minimum_size(new_rect);
|
||||
window.set_rect(new_rect);
|
||||
window.nudge_into_desktop();
|
||||
window.request_update(window.rect());
|
||||
|
||||
if (did_size_clamp)
|
||||
window.refresh_client_size();
|
||||
}
|
||||
|
||||
return make<Messages::WindowServer::SetWindowMinimumSizeResponse>();
|
||||
}
|
||||
|
||||
OwnPtr<Messages::WindowServer::GetWindowMinimumSizeResponse> ClientConnection::handle(const Messages::WindowServer::GetWindowMinimumSize& message)
|
||||
{
|
||||
int window_id = message.window_id();
|
||||
auto it = m_windows.find(window_id);
|
||||
if (it == m_windows.end()) {
|
||||
did_misbehave("GetWindowMinimumSize: Bad window ID");
|
||||
return {};
|
||||
}
|
||||
return make<Messages::WindowServer::GetWindowMinimumSizeResponse>(it->value->minimum_size());
|
||||
}
|
||||
|
||||
OwnPtr<Messages::WindowServer::GetWindowRectInMenubarResponse> ClientConnection::handle(const Messages::WindowServer::GetWindowRectInMenubar& message)
|
||||
{
|
||||
int window_id = message.window_id();
|
||||
|
@ -454,9 +496,13 @@ OwnPtr<Messages::WindowServer::CreateWindowResponse> ClientConnection::handle(co
|
|||
rect = { WindowManager::the().get_recommended_window_position({ 100, 100 }), message.rect().size() };
|
||||
window->set_default_positioned(true);
|
||||
}
|
||||
window->apply_minimum_size(rect);
|
||||
window->set_minimum_size(message.minimum_size());
|
||||
bool did_size_clamp = window->apply_minimum_size(rect);
|
||||
window->set_rect(rect);
|
||||
window->nudge_into_desktop();
|
||||
|
||||
if (did_size_clamp)
|
||||
window->refresh_client_size();
|
||||
}
|
||||
if (window->type() == WindowType::Desktop) {
|
||||
window->set_rect(WindowManager::the().desktop_rect());
|
||||
|
|
|
@ -109,6 +109,8 @@ private:
|
|||
virtual void handle(const Messages::WindowServer::StartWindowResize&) override;
|
||||
virtual OwnPtr<Messages::WindowServer::SetWindowRectResponse> handle(const Messages::WindowServer::SetWindowRect&) override;
|
||||
virtual OwnPtr<Messages::WindowServer::GetWindowRectResponse> handle(const Messages::WindowServer::GetWindowRect&) override;
|
||||
virtual OwnPtr<Messages::WindowServer::SetWindowMinimumSizeResponse> handle(const Messages::WindowServer::SetWindowMinimumSize&) override;
|
||||
virtual OwnPtr<Messages::WindowServer::GetWindowMinimumSizeResponse> handle(const Messages::WindowServer::GetWindowMinimumSize&) override;
|
||||
virtual OwnPtr<Messages::WindowServer::GetWindowRectInMenubarResponse> handle(const Messages::WindowServer::GetWindowRectInMenubar&) override;
|
||||
virtual void handle(const Messages::WindowServer::InvalidateRect&) override;
|
||||
virtual void handle(const Messages::WindowServer::DidFinishPainting&) override;
|
||||
|
|
|
@ -37,6 +37,8 @@
|
|||
|
||||
namespace WindowServer {
|
||||
|
||||
const static Gfx::IntSize s_default_normal_minimum_size = { 50, 50 };
|
||||
|
||||
static String default_window_icon_path()
|
||||
{
|
||||
return "/res/icons/16x16/window.png";
|
||||
|
@ -88,6 +90,10 @@ Window::Window(Core::Object& parent, WindowType type)
|
|||
, m_icon(default_window_icon())
|
||||
, m_frame(*this)
|
||||
{
|
||||
// Set default minimum size for Normal windows
|
||||
if (m_type == WindowType::Normal)
|
||||
m_minimum_size = s_default_normal_minimum_size;
|
||||
|
||||
WindowManager::the().add_window(*this);
|
||||
}
|
||||
|
||||
|
@ -112,6 +118,10 @@ Window::Window(ClientConnection& client, WindowType window_type, int window_id,
|
|||
m_listens_to_wm_events = true;
|
||||
}
|
||||
|
||||
// Set default minimum size for Normal windows
|
||||
if (m_type == WindowType::Normal)
|
||||
m_minimum_size = s_default_normal_minimum_size;
|
||||
|
||||
if (parent_window)
|
||||
set_parent_window(*parent_window);
|
||||
WindowManager::the().add_window(*this);
|
||||
|
@ -176,14 +186,16 @@ void Window::set_rect_without_repaint(const Gfx::IntRect& rect)
|
|||
m_frame.notify_window_rect_changed(old_rect, rect); // recomputes occlusions
|
||||
}
|
||||
|
||||
void Window::apply_minimum_size(Gfx::IntRect& rect)
|
||||
bool Window::apply_minimum_size(Gfx::IntRect& rect)
|
||||
{
|
||||
Gfx::IntSize minimum_size { 1, 1 };
|
||||
if (type() == WindowType::Normal)
|
||||
minimum_size = { 50, 50 };
|
||||
int new_width = max(m_minimum_size.width(), rect.width());
|
||||
int new_height = max(m_minimum_size.height(), rect.height());
|
||||
bool did_size_clamp = new_width != rect.width() || new_height != rect.height();
|
||||
|
||||
rect.set_width(max(minimum_size.width(), rect.width()));
|
||||
rect.set_height(max(minimum_size.height(), rect.height()));
|
||||
rect.set_width(new_width);
|
||||
rect.set_height(new_height);
|
||||
|
||||
return did_size_clamp;
|
||||
}
|
||||
|
||||
void Window::nudge_into_desktop(bool force_titlebar_visible)
|
||||
|
@ -218,6 +230,20 @@ void Window::nudge_into_desktop(bool force_titlebar_visible)
|
|||
set_rect(new_window_rect);
|
||||
}
|
||||
|
||||
void Window::set_minimum_size(const Gfx::IntSize& size)
|
||||
{
|
||||
ASSERT(!size.is_empty());
|
||||
|
||||
if (m_minimum_size == size)
|
||||
return;
|
||||
|
||||
// Disallow setting minimum zero widths or heights.
|
||||
if (size.width() == 0 || size.height() == 0)
|
||||
return;
|
||||
|
||||
m_minimum_size = size;
|
||||
}
|
||||
|
||||
void Window::handle_mouse_event(const MouseEvent& event)
|
||||
{
|
||||
set_automatic_cursor_tracking_enabled(event.buttons() != 0);
|
||||
|
@ -523,6 +549,11 @@ bool Window::invalidate_no_notify(const Gfx::IntRect& rect, bool with_frame)
|
|||
return true;
|
||||
}
|
||||
|
||||
void Window::refresh_client_size()
|
||||
{
|
||||
client()->post_message(Messages::WindowClient::WindowResized(m_window_id, m_rect));
|
||||
}
|
||||
|
||||
void Window::prepare_dirty_rects()
|
||||
{
|
||||
if (m_invalidated_all) {
|
||||
|
|
|
@ -169,9 +169,13 @@ public:
|
|||
void set_rect(const Gfx::IntRect&);
|
||||
void set_rect(int x, int y, int width, int height) { set_rect({ x, y, width, height }); }
|
||||
void set_rect_without_repaint(const Gfx::IntRect&);
|
||||
void apply_minimum_size(Gfx::IntRect&);
|
||||
bool apply_minimum_size(Gfx::IntRect&);
|
||||
void nudge_into_desktop(bool force_titlebar_visible = true);
|
||||
|
||||
Gfx::IntSize minimum_size() const { return m_minimum_size; }
|
||||
void set_minimum_size(const Gfx::IntSize&);
|
||||
void set_minimum_size(int width, int height) { set_minimum_size({ width, height }); }
|
||||
|
||||
void set_taskbar_rect(const Gfx::IntRect&);
|
||||
const Gfx::IntRect& taskbar_rect() const { return m_taskbar_rect; }
|
||||
|
||||
|
@ -190,6 +194,8 @@ public:
|
|||
void invalidate(const Gfx::IntRect&, bool with_frame = false);
|
||||
bool invalidate_no_notify(const Gfx::IntRect& rect, bool with_frame = false);
|
||||
|
||||
void refresh_client_size();
|
||||
|
||||
void prepare_dirty_rects();
|
||||
void clear_dirty_rects();
|
||||
Gfx::DisjointRectSet& dirty_rects() { return m_dirty_rects; }
|
||||
|
@ -375,6 +381,7 @@ private:
|
|||
float m_alpha_hit_threshold { 0.0f };
|
||||
Gfx::IntSize m_size_increment;
|
||||
Gfx::IntSize m_base_size;
|
||||
Gfx::IntSize m_minimum_size { 1, 1 };
|
||||
NonnullRefPtr<Gfx::Bitmap> m_icon;
|
||||
RefPtr<Cursor> m_cursor;
|
||||
WindowFrame m_frame;
|
||||
|
|
|
@ -44,6 +44,7 @@ endpoint WindowServer = 2
|
|||
float alpha_hit_threshold,
|
||||
Gfx::IntSize base_size,
|
||||
Gfx::IntSize size_increment,
|
||||
Gfx::IntSize minimum_size,
|
||||
Optional<Gfx::IntSize> resize_aspect_ratio,
|
||||
i32 type,
|
||||
[UTF8] String title,
|
||||
|
@ -59,6 +60,9 @@ endpoint WindowServer = 2
|
|||
SetWindowRect(i32 window_id, Gfx::IntRect rect) => (Gfx::IntRect rect)
|
||||
GetWindowRect(i32 window_id) => (Gfx::IntRect rect)
|
||||
|
||||
SetWindowMinimumSize(i32 window_id, Gfx::IntSize size) => ()
|
||||
GetWindowMinimumSize(i32 window_id) => (Gfx::IntSize size)
|
||||
|
||||
GetWindowRectInMenubar(i32 window_id) => (Gfx::IntRect rect)
|
||||
|
||||
StartWindowResize(i32 window_id) =|
|
||||
|
|
Loading…
Reference in a new issue