WindowServer+LibGUI: Allow specifying a "launch origin" for new windows

The launch_origin_rect parameter to create_window() specifies where on
screen the window was launched from. It's optional, but if you provide
it, the new window will have a short wireframe animation from the origin
to the initial window frame rect.

GUI::Window looks for the "__libgui_launch_origin_rect" environment
variable. Put your launch origin rect in there with the format
"<x>,<y>,<width>,<height>" and the first GUI::Window shown by the app
will use that as the launch origin rect.

Also it looks pretty neat, although I'm sure we can improve it. :^)
This commit is contained in:
Andreas Kling 2021-06-27 17:07:31 +02:00
parent 75f870a93f
commit 6a132d8672
Notes: sideshowbarker 2024-07-18 11:26:51 +09:00
6 changed files with 46 additions and 4 deletions

View file

@ -122,6 +122,20 @@ void Window::show()
m_window_id = s_window_id_allocator.allocate();
Gfx::IntRect launch_origin_rect;
if (auto* launch_origin_rect_string = getenv("__libgui_launch_origin_rect")) {
auto parts = StringView(launch_origin_rect_string).split_view(',');
if (parts.size() == 4) {
launch_origin_rect = Gfx::IntRect {
parts[0].to_int().value_or(0),
parts[1].to_int().value_or(0),
parts[2].to_int().value_or(0),
parts[3].to_int().value_or(0),
};
}
unsetenv("__libgui_launch_origin_rect");
}
WindowServerConnection::the().async_create_window(
m_window_id,
m_rect_when_windowless,
@ -141,7 +155,8 @@ void Window::show()
m_resize_aspect_ratio,
(i32)m_window_type,
m_title_when_windowless,
parent_window ? parent_window->window_id() : 0);
parent_window ? parent_window->window_id() : 0,
launch_origin_rect);
m_visible = true;
apply_icon();

View file

@ -496,7 +496,8 @@ void ClientConnection::create_window(i32 window_id, Gfx::IntRect const& rect,
bool auto_position, bool has_alpha_channel, bool modal, bool minimizable, bool resizable,
bool fullscreen, bool frameless, bool accessory, float opacity, float alpha_hit_threshold,
Gfx::IntSize const& base_size, Gfx::IntSize const& size_increment, Gfx::IntSize const& minimum_size,
Optional<Gfx::IntSize> const& resize_aspect_ratio, i32 type, String const& title, i32 parent_window_id)
Optional<Gfx::IntSize> const& resize_aspect_ratio, i32 type, String const& title, i32 parent_window_id,
Gfx::IntRect const& launch_origin_rect)
{
Window* parent_window = nullptr;
if (parent_window_id) {
@ -519,6 +520,9 @@ void ClientConnection::create_window(i32 window_id, Gfx::IntRect const& rect,
auto window = Window::construct(*this, (WindowType)type, window_id, modal, minimizable, frameless, resizable, fullscreen, accessory, parent_window);
if (!launch_origin_rect.is_empty())
window->start_launch_animation(launch_origin_rect);
window->set_has_alpha_channel(has_alpha_channel);
window->set_title(title);
if (!fullscreen) {

View file

@ -101,7 +101,7 @@ private:
virtual void update_menu_item(i32, i32, i32, String const&, bool, bool, bool, bool, String const&) override;
virtual void create_window(i32, Gfx::IntRect const&, bool, bool, bool,
bool, bool, bool, bool, bool, float, float, Gfx::IntSize const&, Gfx::IntSize const&, Gfx::IntSize const&,
Optional<Gfx::IntSize> const&, i32, String const&, i32) override;
Optional<Gfx::IntSize> const&, i32, String const&, i32, Gfx::IntRect const&) override;
virtual Messages::WindowServer::DestroyWindowResponse destroy_window(i32) override;
virtual void set_window_title(i32, String const&) override;
virtual Messages::WindowServer::GetWindowTitleResponse get_window_title(i32) override;

View file

@ -365,6 +365,26 @@ void Window::start_minimize_animation()
m_animation->start();
}
void Window::start_launch_animation(Gfx::IntRect const& launch_origin_rect)
{
m_animation = Animation::create();
m_animation->set_length(150);
m_animation->on_update = [this, launch_origin_rect](float progress, Gfx::Painter& painter, Screen& screen, Gfx::DisjointRectSet& flush_rects) {
Gfx::PainterStateSaver saver(painter);
painter.set_draw_op(Gfx::Painter::DrawOp::Invert);
auto rect = interpolate_rect(launch_origin_rect, frame().rect(), progress);
painter.draw_rect(rect, Color::Transparent); // Color doesn't matter, we draw inverted
flush_rects.add(rect.intersected(screen.rect()));
Compositor::the().invalidate_screen(rect);
};
m_animation->on_stop = [this] {
m_animation = nullptr;
};
m_animation->start();
}
void Window::set_opacity(float opacity)
{
if (m_opacity == opacity)

View file

@ -259,6 +259,8 @@ public:
bool has_taskbar_rect() const { return m_have_taskbar_rect; };
void start_minimize_animation();
void start_launch_animation(Gfx::IntRect const&);
Gfx::IntRect tiled_rect(Screen*, WindowTileType) const;
void recalculate_rect();

View file

@ -44,7 +44,8 @@ endpoint WindowServer
Optional<Gfx::IntSize> resize_aspect_ratio,
i32 type,
[UTF8] String title,
i32 parent_window_id) =|
i32 parent_window_id,
Gfx::IntRect launch_origin_rect) =|
destroy_window(i32 window_id) => (Vector<i32> destroyed_window_ids)