Skip to content

Commit f192eb9

Browse files
committed
fix: animate workspace slide on floating toplevels
1 parent 13d0afb commit f192eb9

3 files changed

Lines changed: 169 additions & 93 deletions

File tree

TODO.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
- Per-window animation overrides
33
- Ensure animations and blur work together without visual artifacts
44
- Custom animation shaders for windows (e.g. open/close animations)
5-
- Floating toplevels do not animate their position on workspace switch
65

76
# Effects
87
- Effects per window state (e.g. unfocused, focused, ...)

src/touch.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
#include "layer.h"
44
#include "once.h"
55
#include "server.h"
6-
#include "touch.h"
76
#include "toplevel.h"
7+
#include "touch.h"
88
#include "tree.h"
99
#include <wayland-util.h>
1010
#include <wlr/types/wlr_cursor.h>

src/workspace.c

Lines changed: 168 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,90 @@ static struct wlr_ext_workspace_handle_v1 *find_workspace_by_name(const char *na
2424
return NULL;
2525
}
2626

27+
static struct wlr_box window_target_rect(node_t *n) {
28+
if (n && n->client && n->client->state == STATE_FLOATING)
29+
return n->client->floating_rectangle;
30+
return n ? n->client->tiled_rectangle : (struct wlr_box){
31+
0,
32+
0,
33+
0,
34+
0
35+
};
36+
}
37+
38+
typedef struct {
39+
desktop_t *desk;
40+
node_t *tree_cursor;
41+
struct toplevel_t *tl_cursor;
42+
struct xwayland_toplevel_t *xw_cursor;
43+
} desktop_window_iter_t;
44+
45+
static bool node_is_outside_tree(node_t *n, desktop_t *d) {
46+
for (node_t *p = n; p; p = p->parent)
47+
if (p == d->root)
48+
return false;
49+
return true;
50+
}
51+
52+
static bool desktop_window_iter_advance(desktop_window_iter_t *it, node_t **out_node,
53+
struct wlr_scene_tree **out_tree) {
54+
if (!it)
55+
return false;
56+
57+
while (true) {
58+
if (it->tree_cursor) {
59+
node_t *n = it->tree_cursor;
60+
it->tree_cursor = it->desk->root ? next_leaf(n, it->desk->root) : NULL;
61+
if (n && n->client) {
62+
struct wlr_scene_tree *tree = client_get_scene_tree(n->client);
63+
if (tree) {
64+
*out_node = n;
65+
*out_tree = tree;
66+
return true;
67+
}
68+
}
69+
continue;
70+
}
71+
72+
if (it->tl_cursor) {
73+
struct toplevel_t *tl = it->tl_cursor;
74+
it->tl_cursor = (tl->link.next == &server.toplevels) ? NULL : wl_container_of(tl->link.next, tl,
75+
link);
76+
if (tl->mapped && tl->scene_tree && tl->node && tl->node->client &&
77+
tl->node->desktop == it->desk && node_is_outside_tree(tl->node, it->desk)) {
78+
*out_node = tl->node;
79+
*out_tree = tl->scene_tree;
80+
return true;
81+
}
82+
continue;
83+
}
84+
85+
if (it->xw_cursor) {
86+
struct xwayland_toplevel_t *xw = it->xw_cursor;
87+
it->xw_cursor = (xw->link.next == &server.xwayland.views) ? NULL : wl_container_of(xw->link.next,
88+
xw, link);
89+
if (xw->mapped && xw->scene_tree && xw->node && xw->node->client &&
90+
xw->node->desktop == it->desk && node_is_outside_tree(xw->node, it->desk)) {
91+
*out_node = xw->node;
92+
*out_tree = xw->scene_tree;
93+
return true;
94+
}
95+
continue;
96+
}
97+
98+
return false;
99+
}
100+
}
101+
102+
static void desktop_window_iter_init(desktop_window_iter_t *it, desktop_t *d) {
103+
memset(it, 0, sizeof(*it));
104+
it->desk = d;
105+
if (d && d->root)
106+
it->tree_cursor = first_extrema(d->root);
107+
it->tl_cursor = wl_container_of(server.toplevels.next, (struct toplevel_t *)0, link);
108+
it->xw_cursor = wl_container_of(server.xwayland.views.next, (struct xwayland_toplevel_t *)0, link);
109+
}
110+
27111
struct desktop_t *find_desktop_by_name(const char *name) {
28112
if (!name || name[0] == '\0')
29113
return NULL;
@@ -273,28 +357,27 @@ static void workspace_switch_animate(output_t *output, desktop_t *old_desk, desk
273357
}
274358

275359
// create slide-out animations for old desktop windows
276-
if (old_desk && old_desk->root) {
277-
node_t *n = first_extrema(old_desk->root);
278-
while (n) {
279-
if (n->client) {
280-
struct wlr_scene_tree *tree = client_get_scene_tree(n->client);
281-
if (tree && tree->node.enabled) {
282-
struct wlr_box from = {
283-
tree->node.x,
284-
tree->node.y,
285-
0,
286-
0
287-
};
288-
struct wlr_box to = {
289-
from.x + num_steps * dx,
290-
from.y + num_steps * dy,
291-
0,
292-
0
293-
};
294-
animation_start_workspace_slide(output, n, tree, from, to, true);
295-
}
296-
}
297-
n = next_leaf(n, old_desk->root);
360+
{
361+
desktop_window_iter_t it;
362+
desktop_window_iter_init(&it, old_desk);
363+
node_t *n;
364+
struct wlr_scene_tree *tree;
365+
while (desktop_window_iter_advance(&it, &n, &tree)) {
366+
if (!tree || !tree->node.enabled)
367+
continue;
368+
struct wlr_box from = {
369+
tree->node.x,
370+
tree->node.y,
371+
0,
372+
0
373+
};
374+
struct wlr_box to = {
375+
from.x + num_steps * dx,
376+
from.y + num_steps * dy,
377+
0,
378+
0
379+
};
380+
animation_start_workspace_slide(output, n, tree, from, to, true);
298381
}
299382
}
300383

@@ -306,69 +389,64 @@ static void workspace_switch_animate(output_t *output, desktop_t *old_desk, desk
306389
update_all_toplevels_visibility(output, new_desk);
307390

308391
// re-enable old desktop windows for slide-out animation
309-
if (old_desk && old_desk->root) {
310-
node_t *n = first_extrema(old_desk->root);
311-
while (n) {
312-
if (n->client) {
313-
struct wlr_scene_tree *tree = client_get_scene_tree(n->client);
314-
if (tree) {
315-
n->client->flags.shown = true;
316-
wlr_scene_node_set_enabled(&tree->node, true);
317-
}
318-
}
319-
n = next_leaf(n, old_desk->root);
392+
{
393+
desktop_window_iter_t it;
394+
desktop_window_iter_init(&it, old_desk);
395+
node_t *n;
396+
struct wlr_scene_tree *tree;
397+
while (desktop_window_iter_advance(&it, &n, &tree)) {
398+
if (!tree)
399+
continue;
400+
n->client->flags.shown = true;
401+
wlr_scene_node_set_enabled(&tree->node, true);
320402
}
321403
}
322404

323405
// enable and animate intermediate desktop windows (between old and new)
324406
int k = 1;
325407
desktop_t *intermediate = forward ? old_desk->prev : old_desk->next;
326408
while (intermediate && intermediate != new_desk) {
327-
if (intermediate->root) {
328-
arrange(output, intermediate, true);
329-
node_t *n = first_extrema(intermediate->root);
330-
while (n) {
331-
if (n->client) {
332-
struct wlr_scene_tree *tree = client_get_scene_tree(n->client);
333-
if (tree) {
334-
n->client->flags.shown = true;
335-
wlr_scene_node_set_enabled(&tree->node, true);
336-
struct wlr_box target = n->client->tiled_rectangle;
337-
struct wlr_box from = {
338-
target.x - k * dx,
339-
target.y - k * dy,
340-
0,
341-
0
342-
};
343-
struct wlr_box to = {
344-
target.x + (num_steps - k) * dx,
345-
target.y + (num_steps - k) * dy,
346-
0,
347-
0
348-
};
349-
wlr_scene_node_set_position(&tree->node, from.x, from.y);
350-
animation_start_workspace_slide(output, n, tree, from, to, true);
351-
}
352-
}
353-
n = next_leaf(n, intermediate->root);
354-
}
409+
arrange(output, intermediate, true);
410+
desktop_window_iter_t it;
411+
desktop_window_iter_init(&it, intermediate);
412+
node_t *n;
413+
struct wlr_scene_tree *tree;
414+
while (desktop_window_iter_advance(&it, &n, &tree)) {
415+
if (!tree)
416+
continue;
417+
n->client->flags.shown = true;
418+
wlr_scene_node_set_enabled(&tree->node, true);
419+
struct wlr_box target = window_target_rect(n);
420+
struct wlr_box from = {
421+
target.x - k * dx,
422+
target.y - k * dy,
423+
0,
424+
0
425+
};
426+
struct wlr_box to = {
427+
target.x + (num_steps - k) * dx,
428+
target.y + (num_steps - k) * dy,
429+
0,
430+
0
431+
};
432+
wlr_scene_node_set_position(&tree->node, from.x, from.y);
433+
animation_start_workspace_slide(output, n, tree, from, to, true);
355434
}
356435
k++;
357436
intermediate = forward ? intermediate->prev : intermediate->next;
358437
}
359438

360-
if (new_desk && new_desk->root) {
361-
node_t *n = first_extrema(new_desk->root);
362-
while (n) {
363-
if (n->client) {
364-
struct wlr_scene_tree *tree = client_get_scene_tree(n->client);
365-
if (tree) {
366-
wlr_scene_node_set_enabled(&tree->node, true);
367-
wlr_scene_node_set_position(&tree->node, tree->node.x - num_steps * dx,
368-
tree->node.y - num_steps * dy);
369-
}
370-
}
371-
n = next_leaf(n, new_desk->root);
439+
{
440+
desktop_window_iter_t it;
441+
desktop_window_iter_init(&it, new_desk);
442+
node_t *n;
443+
struct wlr_scene_tree *tree;
444+
while (desktop_window_iter_advance(&it, &n, &tree)) {
445+
if (!tree)
446+
continue;
447+
wlr_scene_node_set_enabled(&tree->node, true);
448+
wlr_scene_node_set_position(&tree->node, tree->node.x - num_steps * dx,
449+
tree->node.y - num_steps * dy);
372450
}
373451
}
374452

@@ -380,24 +458,23 @@ static void workspace_switch_animate(output_t *output, desktop_t *old_desk, desk
380458
}
381459

382460
// override transaction's animation for new windows
383-
if (new_desk && new_desk->root) {
384-
node_t *n = first_extrema(new_desk->root);
385-
while (n) {
386-
if (n->client) {
387-
struct wlr_scene_tree *tree = client_get_scene_tree(n->client);
388-
if (tree) {
389-
struct wlr_box target = n->client->tiled_rectangle;
390-
struct wlr_box from = {
391-
target.x - num_steps * dx,
392-
target.y - num_steps * dy,
393-
0,
394-
0
395-
};
396-
wlr_scene_node_set_position(&tree->node, from.x, from.y);
397-
animation_start_workspace_slide(output, n, tree, from, target, false);
398-
}
399-
}
400-
n = next_leaf(n, new_desk->root);
461+
{
462+
desktop_window_iter_t it;
463+
desktop_window_iter_init(&it, new_desk);
464+
node_t *n;
465+
struct wlr_scene_tree *tree;
466+
while (desktop_window_iter_advance(&it, &n, &tree)) {
467+
if (!tree)
468+
continue;
469+
struct wlr_box target = window_target_rect(n);
470+
struct wlr_box from = {
471+
target.x - num_steps * dx,
472+
target.y - num_steps * dy,
473+
0,
474+
0
475+
};
476+
wlr_scene_node_set_position(&tree->node, from.x, from.y);
477+
animation_start_workspace_slide(output, n, tree, from, target, false);
401478
}
402479
}
403480

0 commit comments

Comments
 (0)