mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 16:07:47 +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
7 changed files with 130 additions and 8 deletions
|
@ -150,6 +150,7 @@ void Window::show()
|
||||||
m_alpha_hit_threshold,
|
m_alpha_hit_threshold,
|
||||||
m_base_size,
|
m_base_size,
|
||||||
m_size_increment,
|
m_size_increment,
|
||||||
|
m_minimum_size_when_windowless,
|
||||||
m_resize_aspect_ratio,
|
m_resize_aspect_ratio,
|
||||||
(i32)m_window_type,
|
(i32)m_window_type,
|
||||||
m_title_when_windowless,
|
m_title_when_windowless,
|
||||||
|
@ -259,6 +260,23 @@ void Window::set_rect(const Gfx::IntRect& a_rect)
|
||||||
m_main_widget->resize(window_rect.size());
|
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()
|
void Window::center_on_screen()
|
||||||
{
|
{
|
||||||
auto window_rect = rect();
|
auto window_rect = rect();
|
||||||
|
@ -278,6 +296,14 @@ void Window::center_within(const Window& other)
|
||||||
void Window::set_window_type(WindowType window_type)
|
void Window::set_window_type(WindowType window_type)
|
||||||
{
|
{
|
||||||
m_window_type = 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)
|
void Window::set_cursor(Gfx::StandardCursor cursor)
|
||||||
|
|
|
@ -108,6 +108,10 @@ public:
|
||||||
|
|
||||||
Gfx::IntPoint position() const { return rect().location(); }
|
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(int x, int y) { move_to({ x, y }); }
|
||||||
void move_to(const Gfx::IntPoint& point) { set_rect({ point, size() }); }
|
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_automatic_cursor_tracking_widget;
|
||||||
WeakPtr<Widget> m_hovered_widget;
|
WeakPtr<Widget> m_hovered_widget;
|
||||||
Gfx::IntRect m_rect_when_windowless;
|
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;
|
String m_title_when_windowless;
|
||||||
Vector<Gfx::IntRect, 32> m_pending_paint_event_rects;
|
Vector<Gfx::IntRect, 32> m_pending_paint_event_rects;
|
||||||
Gfx::IntSize m_size_increment;
|
Gfx::IntSize m_size_increment;
|
||||||
|
|
|
@ -413,6 +413,48 @@ OwnPtr<Messages::WindowServer::GetWindowRectResponse> ClientConnection::handle(c
|
||||||
return make<Messages::WindowServer::GetWindowRectResponse>(it->value->rect());
|
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)
|
OwnPtr<Messages::WindowServer::GetWindowRectInMenubarResponse> ClientConnection::handle(const Messages::WindowServer::GetWindowRectInMenubar& message)
|
||||||
{
|
{
|
||||||
int window_id = message.window_id();
|
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() };
|
rect = { WindowManager::the().get_recommended_window_position({ 100, 100 }), message.rect().size() };
|
||||||
window->set_default_positioned(true);
|
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->set_rect(rect);
|
||||||
window->nudge_into_desktop();
|
window->nudge_into_desktop();
|
||||||
|
|
||||||
|
if (did_size_clamp)
|
||||||
|
window->refresh_client_size();
|
||||||
}
|
}
|
||||||
if (window->type() == WindowType::Desktop) {
|
if (window->type() == WindowType::Desktop) {
|
||||||
window->set_rect(WindowManager::the().desktop_rect());
|
window->set_rect(WindowManager::the().desktop_rect());
|
||||||
|
|
|
@ -109,6 +109,8 @@ private:
|
||||||
virtual void handle(const Messages::WindowServer::StartWindowResize&) override;
|
virtual void handle(const Messages::WindowServer::StartWindowResize&) override;
|
||||||
virtual OwnPtr<Messages::WindowServer::SetWindowRectResponse> handle(const Messages::WindowServer::SetWindowRect&) 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::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 OwnPtr<Messages::WindowServer::GetWindowRectInMenubarResponse> handle(const Messages::WindowServer::GetWindowRectInMenubar&) override;
|
||||||
virtual void handle(const Messages::WindowServer::InvalidateRect&) override;
|
virtual void handle(const Messages::WindowServer::InvalidateRect&) override;
|
||||||
virtual void handle(const Messages::WindowServer::DidFinishPainting&) override;
|
virtual void handle(const Messages::WindowServer::DidFinishPainting&) override;
|
||||||
|
|
|
@ -37,6 +37,8 @@
|
||||||
|
|
||||||
namespace WindowServer {
|
namespace WindowServer {
|
||||||
|
|
||||||
|
const static Gfx::IntSize s_default_normal_minimum_size = { 50, 50 };
|
||||||
|
|
||||||
static String default_window_icon_path()
|
static String default_window_icon_path()
|
||||||
{
|
{
|
||||||
return "/res/icons/16x16/window.png";
|
return "/res/icons/16x16/window.png";
|
||||||
|
@ -88,6 +90,10 @@ Window::Window(Core::Object& parent, WindowType type)
|
||||||
, m_icon(default_window_icon())
|
, m_icon(default_window_icon())
|
||||||
, m_frame(*this)
|
, 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);
|
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;
|
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)
|
if (parent_window)
|
||||||
set_parent_window(*parent_window);
|
set_parent_window(*parent_window);
|
||||||
WindowManager::the().add_window(*this);
|
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
|
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 };
|
int new_width = max(m_minimum_size.width(), rect.width());
|
||||||
if (type() == WindowType::Normal)
|
int new_height = max(m_minimum_size.height(), rect.height());
|
||||||
minimum_size = { 50, 50 };
|
bool did_size_clamp = new_width != rect.width() || new_height != rect.height();
|
||||||
|
|
||||||
rect.set_width(max(minimum_size.width(), rect.width()));
|
rect.set_width(new_width);
|
||||||
rect.set_height(max(minimum_size.height(), rect.height()));
|
rect.set_height(new_height);
|
||||||
|
|
||||||
|
return did_size_clamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::nudge_into_desktop(bool force_titlebar_visible)
|
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);
|
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)
|
void Window::handle_mouse_event(const MouseEvent& event)
|
||||||
{
|
{
|
||||||
set_automatic_cursor_tracking_enabled(event.buttons() != 0);
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Window::refresh_client_size()
|
||||||
|
{
|
||||||
|
client()->post_message(Messages::WindowClient::WindowResized(m_window_id, m_rect));
|
||||||
|
}
|
||||||
|
|
||||||
void Window::prepare_dirty_rects()
|
void Window::prepare_dirty_rects()
|
||||||
{
|
{
|
||||||
if (m_invalidated_all) {
|
if (m_invalidated_all) {
|
||||||
|
|
|
@ -169,9 +169,13 @@ public:
|
||||||
void set_rect(const Gfx::IntRect&);
|
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(int x, int y, int width, int height) { set_rect({ x, y, width, height }); }
|
||||||
void set_rect_without_repaint(const Gfx::IntRect&);
|
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);
|
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&);
|
void set_taskbar_rect(const Gfx::IntRect&);
|
||||||
const Gfx::IntRect& taskbar_rect() const { return m_taskbar_rect; }
|
const Gfx::IntRect& taskbar_rect() const { return m_taskbar_rect; }
|
||||||
|
|
||||||
|
@ -190,6 +194,8 @@ public:
|
||||||
void invalidate(const Gfx::IntRect&, bool with_frame = false);
|
void invalidate(const Gfx::IntRect&, bool with_frame = false);
|
||||||
bool invalidate_no_notify(const Gfx::IntRect& rect, 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 prepare_dirty_rects();
|
||||||
void clear_dirty_rects();
|
void clear_dirty_rects();
|
||||||
Gfx::DisjointRectSet& dirty_rects() { return m_dirty_rects; }
|
Gfx::DisjointRectSet& dirty_rects() { return m_dirty_rects; }
|
||||||
|
@ -375,6 +381,7 @@ private:
|
||||||
float m_alpha_hit_threshold { 0.0f };
|
float m_alpha_hit_threshold { 0.0f };
|
||||||
Gfx::IntSize m_size_increment;
|
Gfx::IntSize m_size_increment;
|
||||||
Gfx::IntSize m_base_size;
|
Gfx::IntSize m_base_size;
|
||||||
|
Gfx::IntSize m_minimum_size { 1, 1 };
|
||||||
NonnullRefPtr<Gfx::Bitmap> m_icon;
|
NonnullRefPtr<Gfx::Bitmap> m_icon;
|
||||||
RefPtr<Cursor> m_cursor;
|
RefPtr<Cursor> m_cursor;
|
||||||
WindowFrame m_frame;
|
WindowFrame m_frame;
|
||||||
|
|
|
@ -44,6 +44,7 @@ endpoint WindowServer = 2
|
||||||
float alpha_hit_threshold,
|
float alpha_hit_threshold,
|
||||||
Gfx::IntSize base_size,
|
Gfx::IntSize base_size,
|
||||||
Gfx::IntSize size_increment,
|
Gfx::IntSize size_increment,
|
||||||
|
Gfx::IntSize minimum_size,
|
||||||
Optional<Gfx::IntSize> resize_aspect_ratio,
|
Optional<Gfx::IntSize> resize_aspect_ratio,
|
||||||
i32 type,
|
i32 type,
|
||||||
[UTF8] String title,
|
[UTF8] String title,
|
||||||
|
@ -59,6 +60,9 @@ endpoint WindowServer = 2
|
||||||
SetWindowRect(i32 window_id, Gfx::IntRect rect) => (Gfx::IntRect rect)
|
SetWindowRect(i32 window_id, Gfx::IntRect rect) => (Gfx::IntRect rect)
|
||||||
GetWindowRect(i32 window_id) => (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)
|
GetWindowRectInMenubar(i32 window_id) => (Gfx::IntRect rect)
|
||||||
|
|
||||||
StartWindowResize(i32 window_id) =|
|
StartWindowResize(i32 window_id) =|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue