WindowServer+Taskbar: Animate window frames on minimize/unminimize

We now show a quick window outline animation when going in/out of
minimized state. It's a simple 10 frame animation at 60fps, just to
give a visual cue of what's happening with the window.

The Taskbar sends over the corresponding button rect for each window
to the WindowServer using a new WM_SetWindowTaskbarRect message.

Note that when unminimizing, we still *show* the window right away,
and don't hold off until the animation has finished. This avoids
making the desktop feel slow/sluggish. :^)
This commit is contained in:
Andreas Kling 2019-12-03 21:34:34 +01:00
parent 51262e7e2d
commit d111b6ead4
Notes: sideshowbarker 2024-07-19 10:58:22 +09:00
8 changed files with 78 additions and 0 deletions

View File

@ -16,3 +16,13 @@ void TaskbarButton::context_menu_event(GContextMenuEvent&)
{
GWindowServerConnection::the().post_message(WindowServer::WM_PopupWindowMenu(m_identifier.client_id(), m_identifier.window_id(), screen_relative_rect().location()));
}
void TaskbarButton::resize_event(GResizeEvent& event)
{
GWindowServerConnection::the().post_message(
WindowServer::WM_SetWindowTaskbarRect(
m_identifier.client_id(),
m_identifier.window_id(),
screen_relative_rect()));
return GButton::resize_event(event);
}

View File

@ -11,6 +11,7 @@ public:
private:
virtual void context_menu_event(GContextMenuEvent&) override;
virtual void resize_event(GResizeEvent&) override;
WindowIdentifier m_identifier;
};

View File

@ -612,3 +612,19 @@ bool WSClientConnection::is_showing_modal_window() const
}
return false;
}
void WSClientConnection::handle(const WindowServer::WM_SetWindowTaskbarRect& message)
{
auto* client = WSClientConnection::from_client_id(message.client_id());
if (!client) {
did_misbehave("WM_SetWindowTaskbarRect: Bad client ID");
return;
}
auto it = client->m_windows.find(message.window_id());
if (it == client->m_windows.end()) {
did_misbehave("WM_SetWindowTaskbarRect: Bad window ID");
return;
}
auto& window = *(*it).value;
window.set_taskbar_rect(message.rect());
}

View File

@ -86,6 +86,7 @@ private:
virtual OwnPtr<WindowServer::PopupMenuResponse> handle(const WindowServer::PopupMenu&) override;
virtual OwnPtr<WindowServer::DismissMenuResponse> handle(const WindowServer::DismissMenu&) override;
virtual OwnPtr<WindowServer::SetWindowIconBitmapResponse> handle(const WindowServer::SetWindowIconBitmap&) override;
virtual void handle(const WindowServer::WM_SetWindowTaskbarRect&) override;
HashMap<int, NonnullRefPtr<WSWindow>> m_windows;
HashMap<int, NonnullOwnPtr<WSMenuBar>> m_menubars;

View File

@ -212,6 +212,42 @@ void WSCompositor::compose()
draw_geometry_label();
}
static const int minimize_animation_steps = 10;
wm.for_each_window([&](WSWindow& window) {
if (window.in_minimize_animation()) {
int animation_index = window.minimize_animation_index();
auto from_rect = window.is_minimized() ? window.frame().rect() : window.taskbar_rect();
auto to_rect = window.is_minimized() ? window.taskbar_rect() : window.frame().rect();
float x_delta_per_step = (float)(from_rect.x() - to_rect.x()) / minimize_animation_steps;
float y_delta_per_step = (float)(from_rect.y() - to_rect.y()) / minimize_animation_steps;
float width_delta_per_step = (float)(from_rect.width() - to_rect.width()) / minimize_animation_steps;
float height_delta_per_step = (float)(from_rect.height() - to_rect.height()) / minimize_animation_steps;
Rect rect {
from_rect.x() - (int)(x_delta_per_step * animation_index),
from_rect.y() - (int)(y_delta_per_step * animation_index),
from_rect.width() - (int)(width_delta_per_step * animation_index),
from_rect.height() - (int)(height_delta_per_step * animation_index)
};
#ifdef MINIMIZE_ANIMATION_DEBUG
dbg() << "Minimize animation from " << from_rect << " to " << to_rect << " frame# " << animation_index << " " << rect;
#endif
m_back_painter->draw_rect(rect, Color::White);
window.step_minimize_animation();
if (window.minimize_animation_index() >= minimize_animation_steps)
window.end_minimize_animation();
invalidate(rect);
}
return IterationDecision::Continue;
});
draw_cursor();
if (m_flash_flush) {

View File

@ -103,6 +103,7 @@ void WSWindow::set_minimized(bool minimized)
if (m_minimized == minimized)
return;
m_minimized = minimized;
start_minimize_animation();
if (!minimized)
request_update({ {}, size() });
invalidate();

View File

@ -102,6 +102,9 @@ public:
void set_rect_from_window_manager_resize(const Rect&);
void set_taskbar_rect(const Rect& rect) { m_taskbar_rect = rect; }
const Rect& taskbar_rect() const { return m_taskbar_rect; }
void move_to(const Point& position) { set_rect({ position, size() }); }
void move_to(int x, int y) { move_to({ x, y }); }
@ -152,6 +155,13 @@ public:
void request_update(const Rect&);
DisjointRectSet take_pending_paint_rects() { return move(m_pending_paint_rects); }
bool in_minimize_animation() const { return m_minimize_animation_step != -1; }
int minimize_animation_index() const { return m_minimize_animation_step; }
void step_minimize_animation() { m_minimize_animation_step += 1; }
void start_minimize_animation() { m_minimize_animation_step = 0; }
void end_minimize_animation() { m_minimize_animation_step = -1; }
// For InlineLinkedList.
// FIXME: Maybe make a ListHashSet and then WSWindowManager can just use that.
WSWindow* m_next { nullptr };
@ -164,6 +174,7 @@ private:
String m_title;
Rect m_rect;
Rect m_saved_nonfullscreen_rect;
Rect m_taskbar_rect;
WSWindowType m_type { WSWindowType::Normal };
bool m_global_cursor_tracking_enabled { false };
bool m_automatic_cursor_tracking_enabled { false };
@ -190,4 +201,5 @@ private:
DisjointRectSet m_pending_paint_rects;
Rect m_unmaximized_rect;
RefPtr<WSMenu> m_window_menu;
int m_minimize_animation_step { -1 };
};

View File

@ -52,6 +52,7 @@ endpoint WindowServer = 2
WM_SetWindowMinimized(i32 client_id, i32 window_id, bool minimized) =|
WM_StartWindowResize(i32 client_id, i32 window_id) =|
WM_PopupWindowMenu(i32 client_id, i32 window_id, Point screen_position) =|
WM_SetWindowTaskbarRect(i32 client_id, i32 window_id, Rect rect) =|
SetWindowHasAlphaChannel(i32 window_id, bool has_alpha_channel) => ()
MoveWindowToFront(i32 window_id) => ()