From 6a132d8672d9569543f40bb5a72d8457e7c01d10 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sun, 27 Jun 2021 17:07:31 +0200 Subject: [PATCH] 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 ",,," 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. :^) --- Userland/Libraries/LibGUI/Window.cpp | 17 +++++++++++++++- .../WindowServer/ClientConnection.cpp | 6 +++++- .../Services/WindowServer/ClientConnection.h | 2 +- Userland/Services/WindowServer/Window.cpp | 20 +++++++++++++++++++ Userland/Services/WindowServer/Window.h | 2 ++ .../Services/WindowServer/WindowServer.ipc | 3 ++- 6 files changed, 46 insertions(+), 4 deletions(-) diff --git a/Userland/Libraries/LibGUI/Window.cpp b/Userland/Libraries/LibGUI/Window.cpp index 2c3d2a23a4..1302e08b90 100644 --- a/Userland/Libraries/LibGUI/Window.cpp +++ b/Userland/Libraries/LibGUI/Window.cpp @@ -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(); diff --git a/Userland/Services/WindowServer/ClientConnection.cpp b/Userland/Services/WindowServer/ClientConnection.cpp index 0c25327f17..b7ad467f53 100644 --- a/Userland/Services/WindowServer/ClientConnection.cpp +++ b/Userland/Services/WindowServer/ClientConnection.cpp @@ -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 const& resize_aspect_ratio, i32 type, String const& title, i32 parent_window_id) + Optional 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) { diff --git a/Userland/Services/WindowServer/ClientConnection.h b/Userland/Services/WindowServer/ClientConnection.h index 40df34b717..40e27ca1bd 100644 --- a/Userland/Services/WindowServer/ClientConnection.h +++ b/Userland/Services/WindowServer/ClientConnection.h @@ -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 const&, i32, String const&, i32) override; + Optional 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; diff --git a/Userland/Services/WindowServer/Window.cpp b/Userland/Services/WindowServer/Window.cpp index 98a33c34e9..3253f0dba8 100644 --- a/Userland/Services/WindowServer/Window.cpp +++ b/Userland/Services/WindowServer/Window.cpp @@ -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) diff --git a/Userland/Services/WindowServer/Window.h b/Userland/Services/WindowServer/Window.h index 2eaa624985..2b94efa820 100644 --- a/Userland/Services/WindowServer/Window.h +++ b/Userland/Services/WindowServer/Window.h @@ -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(); diff --git a/Userland/Services/WindowServer/WindowServer.ipc b/Userland/Services/WindowServer/WindowServer.ipc index 6f3efe54c0..99ea7a6f4e 100644 --- a/Userland/Services/WindowServer/WindowServer.ipc +++ b/Userland/Services/WindowServer/WindowServer.ipc @@ -44,7 +44,8 @@ endpoint WindowServer Optional 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 destroyed_window_ids)