mirror of
https://codeberg.org/dwl/dwl-patches.git
synced 2026-11-03 11:52:25 +00:00
add: zoom and bezier animation support
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
### Description
|
||||
Add simple animation support with a [cubic-bezier](https://en.wikipedia.org/wiki/B%C3%A9zier_curve) curve.
|
||||
|
||||
### Download
|
||||
- [git branch](/pi66/dwl-patches/src/branch/animation)
|
||||
- [animation-0.9.patch](/dwl/dwl-patches/raw/branch/main/patches/animation/animation-0.9.patch)
|
||||
- [animation-d29259c.patch](/dwl/dwl-patches/raw/branch/main/patches/animation/animation-d29259c.patch)
|
||||
|
||||
### Authors
|
||||
- [Pi66](https://codeberg.org/pi66)
|
||||
@@ -0,0 +1,210 @@
|
||||
From 63675bf00dc9570424317f2ea87371d753ff5fae Mon Sep 17 00:00:00 2001
|
||||
From: pi66 <pixel2176@proton.me>
|
||||
Date: Mon, 28 Sep 2026 18:03:22 +0100
|
||||
Subject: [PATCH] add: zoom and bezier animation support
|
||||
|
||||
---
|
||||
config.def.h | 4 ++
|
||||
dwl.c | 127 +++++++++++++++++++++++++++++++++++++++++++++------
|
||||
2 files changed, 117 insertions(+), 14 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index 13c5322..b0c17e8 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -15,6 +15,10 @@ static const float urgentcolor[] = COLOR(0xff0000ff);
|
||||
/* This conforms to the xdg-protocol. Set the alpha to zero to restore the old behavior */
|
||||
static const float fullscreen_bg[] = {0.0f, 0.0f, 0.0f, 1.0f}; /* You can also use glsl colors */
|
||||
|
||||
+/* animation */
|
||||
+static const unsigned int animation_duration = 300; /* ms */
|
||||
+static const float animation_curve[4] = {0.0f, 0.85f, 0.2f, 1.0f}; /* cubic-bezier x1, y1, x2, y2 */
|
||||
+
|
||||
/* tagging - TAGCOUNT must be no greater than 31 */
|
||||
#define TAGCOUNT (9)
|
||||
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index 4cfd0fd..c2276bb 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -159,6 +159,12 @@ typedef struct {
|
||||
unsigned int bw;
|
||||
uint32_t tags;
|
||||
int isfloating, isurgent, isfullscreen;
|
||||
+
|
||||
+ /* Animation */
|
||||
+ struct wlr_box anim_from, anim_to, anim_cur;
|
||||
+ uint32_t anim_start;
|
||||
+ int animating;
|
||||
+ int anim_zoom;
|
||||
} Client;
|
||||
|
||||
typedef struct {
|
||||
@@ -260,6 +266,10 @@ typedef struct {
|
||||
} SessionLock;
|
||||
|
||||
/* function declarations */
|
||||
+static uint32_t animation_now_ms(void);
|
||||
+static float animation_bezier(float t);
|
||||
+static int animation_tick(void *data);
|
||||
+static void animation_apply(Client *c, struct wlr_box g);
|
||||
static void applybounds(Client *c, struct wlr_box *bbox);
|
||||
static void applyrules(Client *c);
|
||||
static void arrange(Monitor *m);
|
||||
@@ -374,6 +384,7 @@ static void xytonode(double x, double y, struct wlr_surface **psurface,
|
||||
static void zoom(const Arg *arg);
|
||||
|
||||
/* variables */
|
||||
+static struct wl_event_source *animation_timer;
|
||||
static pid_t child_pid = -1;
|
||||
static int locked;
|
||||
static void *exclusive_focus;
|
||||
@@ -485,6 +496,87 @@ static struct wlr_xwayland *xwayland;
|
||||
#include "ime.h"
|
||||
|
||||
/* function implementations */
|
||||
+uint32_t
|
||||
+animation_now_ms(void)
|
||||
+{
|
||||
+ struct timespec t;
|
||||
+
|
||||
+ clock_gettime(CLOCK_MONOTONIC, &t);
|
||||
+ return t.tv_sec * 1000 + t.tv_nsec / 1000000;
|
||||
+}
|
||||
+
|
||||
+float
|
||||
+animation_bezier(float t)
|
||||
+{
|
||||
+ float x1 = animation_curve[0], y1 = animation_curve[1];
|
||||
+ float x2 = animation_curve[2], y2 = animation_curve[3];
|
||||
+ float lo = 0, hi = 1, s = t, x;
|
||||
+ int i;
|
||||
+
|
||||
+ for (i = 0; i < 20; i++) {
|
||||
+ x = 3*(1-s)*(1-s)*s*x1 + 3*(1-s)*s*s*x2 + s*s*s;
|
||||
+ if (x < t)
|
||||
+ lo = s;
|
||||
+ else
|
||||
+ hi = s;
|
||||
+ s = (lo + hi) / 2;
|
||||
+ }
|
||||
+ return 3*(1-s)*(1-s)*s*y1 + 3*(1-s)*s*s*y2 + s*s*s;
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+animation_tick(void *data)
|
||||
+{
|
||||
+ Client *c;
|
||||
+ float t, p;
|
||||
+ int more = 0;
|
||||
+
|
||||
+ wl_list_for_each(c, &clients, link) {
|
||||
+ if (!c->animating)
|
||||
+ continue;
|
||||
+ t = (animation_now_ms() - c->anim_start) / (float)animation_duration;
|
||||
+ if (t >= 1) {
|
||||
+ t = 1;
|
||||
+ c->animating = 0;
|
||||
+ c->anim_zoom = 0;
|
||||
+ }
|
||||
+ p = animation_bezier(t);
|
||||
+ c->anim_cur.x = (int)(c->anim_from.x + (c->anim_to.x - c->anim_from.x) * p);
|
||||
+ c->anim_cur.y = (int)(c->anim_from.y + (c->anim_to.y - c->anim_from.y) * p);
|
||||
+ c->anim_cur.width = (int)(c->anim_from.width + (c->anim_to.width - c->anim_from.width) * p);
|
||||
+ c->anim_cur.height = (int)(c->anim_from.height + (c->anim_to.height - c->anim_from.height) * p);
|
||||
+
|
||||
+ animation_apply(c, c->anim_cur);
|
||||
+ more |= c->animating;
|
||||
+ }
|
||||
+ if (more)
|
||||
+ wl_event_source_timer_update(animation_timer, 16);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+animation_apply(Client *c, struct wlr_box g)
|
||||
+{
|
||||
+ struct wlr_box clip, save = c->geom;
|
||||
+
|
||||
+ c->geom = g;
|
||||
+
|
||||
+ wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y);
|
||||
+ wlr_scene_node_set_position(&c->scene_surface->node, c->bw, c->bw);
|
||||
+ wlr_scene_rect_set_size(c->border[0], c->geom.width, c->bw);
|
||||
+ wlr_scene_rect_set_size(c->border[1], c->geom.width, c->bw);
|
||||
+ wlr_scene_rect_set_size(c->border[2], c->bw, c->geom.height - 2 * c->bw);
|
||||
+ wlr_scene_rect_set_size(c->border[3], c->bw, c->geom.height - 2 * c->bw);
|
||||
+ wlr_scene_node_set_position(&c->border[1]->node, 0, c->geom.height - c->bw);
|
||||
+ wlr_scene_node_set_position(&c->border[2]->node, 0, c->bw);
|
||||
+ wlr_scene_node_set_position(&c->border[3]->node, c->geom.width - c->bw, c->bw);
|
||||
+
|
||||
+ client_get_clip(c, &clip);
|
||||
+ wlr_scene_subsurface_tree_set_clip(&c->scene_surface->node, &clip);
|
||||
+
|
||||
+ c->geom = save;
|
||||
+}
|
||||
+
|
||||
void
|
||||
applybounds(Client *c, struct wlr_box *bbox)
|
||||
{
|
||||
@@ -2365,7 +2457,6 @@ void
|
||||
resize(Client *c, struct wlr_box geo, int interact)
|
||||
{
|
||||
struct wlr_box *bbox;
|
||||
- struct wlr_box clip;
|
||||
|
||||
if (!c->mon || !client_surface(c)->mapped)
|
||||
return;
|
||||
@@ -2375,21 +2466,28 @@ resize(Client *c, struct wlr_box geo, int interact)
|
||||
client_set_bounds(c, geo.width, geo.height);
|
||||
c->geom = geo;
|
||||
applybounds(c, bbox);
|
||||
+ client_set_size(c, c->geom.width - 2 * c->bw, c->geom.height - 2 * c->bw);
|
||||
|
||||
- /* Update scene-graph, including borders */
|
||||
- wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y);
|
||||
- wlr_scene_node_set_position(&c->scene_surface->node, c->bw, c->bw);
|
||||
- wlr_scene_rect_set_size(c->border[0], c->geom.width, c->bw);
|
||||
- wlr_scene_rect_set_size(c->border[1], c->geom.width, c->bw);
|
||||
- wlr_scene_rect_set_size(c->border[2], c->bw, c->geom.height - 2 * c->bw);
|
||||
- wlr_scene_rect_set_size(c->border[3], c->bw, c->geom.height - 2 * c->bw);
|
||||
- wlr_scene_node_set_position(&c->border[1]->node, 0, c->geom.height - c->bw);
|
||||
- wlr_scene_node_set_position(&c->border[2]->node, 0, c->bw);
|
||||
- wlr_scene_node_set_position(&c->border[3]->node, c->geom.width - c->bw, c->bw);
|
||||
+ if (interact) {
|
||||
+ c->animating = 0;
|
||||
+ c->anim_cur = c->geom;
|
||||
+ animation_apply(c, c->geom);
|
||||
+ return;
|
||||
+ }
|
||||
|
||||
- client_set_size(c, c->geom.width - 2 * c->bw, c->geom.height - 2 * c->bw);
|
||||
- client_get_clip(c, &clip);
|
||||
- wlr_scene_subsurface_tree_set_clip(&c->scene_surface->node, &clip);
|
||||
+ if (!c->animating && c->anim_cur.width == 0) {
|
||||
+ c->anim_cur.width = c->geom.width / 2;
|
||||
+ c->anim_cur.height = c->geom.height / 2;
|
||||
+ c->anim_cur.x = c->geom.x + (c->geom.width - c->anim_cur.width) / 2;
|
||||
+ c->anim_cur.y = c->geom.y + (c->geom.height - c->anim_cur.height) / 2;
|
||||
+ c->anim_zoom = 1;
|
||||
+ }
|
||||
+
|
||||
+ c->anim_from = c->anim_cur;
|
||||
+ c->anim_to = c->geom;
|
||||
+ c->anim_start = animation_now_ms();
|
||||
+ c->animating = 1;
|
||||
+ wl_event_source_timer_update(animation_timer, 1);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -2615,6 +2713,7 @@ setup(void)
|
||||
* clients from the Unix socket, managing Wayland globals, and so on. */
|
||||
dpy = wl_display_create();
|
||||
event_loop = wl_display_get_event_loop(dpy);
|
||||
+ animation_timer = wl_event_loop_add_timer(event_loop, animation_tick, NULL);
|
||||
|
||||
/* The backend is a wlroots feature which abstracts the underlying input and
|
||||
* output hardware. The autocreate option will choose the most suitable
|
||||
--
|
||||
2.55.0
|
||||
|
||||
@@ -0,0 +1,210 @@
|
||||
From 91ca9657e49f501f2765eb2afa01785bbe88a2c2 Mon Sep 17 00:00:00 2001
|
||||
From: pi66 <pixel2176@proton.me>
|
||||
Date: Mon, 28 Sep 2026 18:10:19 +0100
|
||||
Subject: [PATCH] add: zoom and bezier animation support
|
||||
|
||||
---
|
||||
config.def.h | 4 ++
|
||||
dwl.c | 127 +++++++++++++++++++++++++++++++++++++++++++++------
|
||||
2 files changed, 117 insertions(+), 14 deletions(-)
|
||||
|
||||
diff --git a/config.def.h b/config.def.h
|
||||
index a4019d3..d37aa10 100644
|
||||
--- a/config.def.h
|
||||
+++ b/config.def.h
|
||||
@@ -15,6 +15,10 @@ static const float urgentcolor[] = COLOR(0xff0000ff);
|
||||
/* This conforms to the xdg-protocol. Set the alpha to zero to restore the old behavior */
|
||||
static const float fullscreen_bg[] = {0.0f, 0.0f, 0.0f, 1.0f}; /* You can also use glsl colors */
|
||||
|
||||
+/* animation */
|
||||
+static const unsigned int animation_duration = 300; /* ms */
|
||||
+static const float animation_curve[4] = {0.0f, 0.85f, 0.2f, 1.0f}; /* cubic-bezier x1, y1, x2, y2 */
|
||||
+
|
||||
/* tagging - TAGCOUNT must be no greater than 31 */
|
||||
#define TAGCOUNT (9)
|
||||
|
||||
diff --git a/dwl.c b/dwl.c
|
||||
index e07a269..570f862 100644
|
||||
--- a/dwl.c
|
||||
+++ b/dwl.c
|
||||
@@ -159,6 +159,12 @@ typedef struct {
|
||||
unsigned int bw;
|
||||
uint32_t tags;
|
||||
int isfloating, isurgent, isfullscreen;
|
||||
+
|
||||
+ /* Animation */
|
||||
+ struct wlr_box anim_from, anim_to, anim_cur;
|
||||
+ uint32_t anim_start;
|
||||
+ int animating;
|
||||
+ int anim_zoom;
|
||||
} Client;
|
||||
|
||||
typedef struct {
|
||||
@@ -261,6 +267,10 @@ typedef struct {
|
||||
} SessionLock;
|
||||
|
||||
/* function declarations */
|
||||
+static uint32_t animation_now_ms(void);
|
||||
+static float animation_bezier(float t);
|
||||
+static int animation_tick(void *data);
|
||||
+static void animation_apply(Client *c, struct wlr_box g);
|
||||
static void applybounds(Client *c, struct wlr_box *bbox);
|
||||
static void applyrules(Client *c);
|
||||
static void arrange(Monitor *m);
|
||||
@@ -376,6 +386,7 @@ static void xytonode(double x, double y, struct wlr_surface **psurface,
|
||||
static void zoom(const Arg *arg);
|
||||
|
||||
/* variables */
|
||||
+static struct wl_event_source *animation_timer;
|
||||
static pid_t child_pid = -1;
|
||||
static int locked;
|
||||
static Client *focused_client;
|
||||
@@ -486,6 +497,87 @@ static struct wlr_xwayland *xwayland;
|
||||
#include "ime.h"
|
||||
|
||||
/* function implementations */
|
||||
+uint32_t
|
||||
+animation_now_ms(void)
|
||||
+{
|
||||
+ struct timespec t;
|
||||
+
|
||||
+ clock_gettime(CLOCK_MONOTONIC, &t);
|
||||
+ return t.tv_sec * 1000 + t.tv_nsec / 1000000;
|
||||
+}
|
||||
+
|
||||
+float
|
||||
+animation_bezier(float t)
|
||||
+{
|
||||
+ float x1 = animation_curve[0], y1 = animation_curve[1];
|
||||
+ float x2 = animation_curve[2], y2 = animation_curve[3];
|
||||
+ float lo = 0, hi = 1, s = t, x;
|
||||
+ int i;
|
||||
+
|
||||
+ for (i = 0; i < 20; i++) {
|
||||
+ x = 3*(1-s)*(1-s)*s*x1 + 3*(1-s)*s*s*x2 + s*s*s;
|
||||
+ if (x < t)
|
||||
+ lo = s;
|
||||
+ else
|
||||
+ hi = s;
|
||||
+ s = (lo + hi) / 2;
|
||||
+ }
|
||||
+ return 3*(1-s)*(1-s)*s*y1 + 3*(1-s)*s*s*y2 + s*s*s;
|
||||
+}
|
||||
+
|
||||
+int
|
||||
+animation_tick(void *data)
|
||||
+{
|
||||
+ Client *c;
|
||||
+ float t, p;
|
||||
+ int more = 0;
|
||||
+
|
||||
+ wl_list_for_each(c, &clients, link) {
|
||||
+ if (!c->animating)
|
||||
+ continue;
|
||||
+ t = (animation_now_ms() - c->anim_start) / (float)animation_duration;
|
||||
+ if (t >= 1) {
|
||||
+ t = 1;
|
||||
+ c->animating = 0;
|
||||
+ c->anim_zoom = 0;
|
||||
+ }
|
||||
+ p = animation_bezier(t);
|
||||
+ c->anim_cur.x = (int)(c->anim_from.x + (c->anim_to.x - c->anim_from.x) * p);
|
||||
+ c->anim_cur.y = (int)(c->anim_from.y + (c->anim_to.y - c->anim_from.y) * p);
|
||||
+ c->anim_cur.width = (int)(c->anim_from.width + (c->anim_to.width - c->anim_from.width) * p);
|
||||
+ c->anim_cur.height = (int)(c->anim_from.height + (c->anim_to.height - c->anim_from.height) * p);
|
||||
+
|
||||
+ animation_apply(c, c->anim_cur);
|
||||
+ more |= c->animating;
|
||||
+ }
|
||||
+ if (more)
|
||||
+ wl_event_source_timer_update(animation_timer, 16);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+void
|
||||
+animation_apply(Client *c, struct wlr_box g)
|
||||
+{
|
||||
+ struct wlr_box clip, save = c->geom;
|
||||
+
|
||||
+ c->geom = g;
|
||||
+
|
||||
+ wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y);
|
||||
+ wlr_scene_node_set_position(&c->scene_surface->node, c->bw, c->bw);
|
||||
+ wlr_scene_rect_set_size(c->border[0], c->geom.width, c->bw);
|
||||
+ wlr_scene_rect_set_size(c->border[1], c->geom.width, c->bw);
|
||||
+ wlr_scene_rect_set_size(c->border[2], c->bw, c->geom.height - 2 * c->bw);
|
||||
+ wlr_scene_rect_set_size(c->border[3], c->bw, c->geom.height - 2 * c->bw);
|
||||
+ wlr_scene_node_set_position(&c->border[1]->node, 0, c->geom.height - c->bw);
|
||||
+ wlr_scene_node_set_position(&c->border[2]->node, 0, c->bw);
|
||||
+ wlr_scene_node_set_position(&c->border[3]->node, c->geom.width - c->bw, c->bw);
|
||||
+
|
||||
+ client_get_clip(c, &clip);
|
||||
+ wlr_scene_subsurface_tree_set_clip(&c->scene_surface->node, &clip);
|
||||
+
|
||||
+ c->geom = save;
|
||||
+}
|
||||
+
|
||||
void
|
||||
applybounds(Client *c, struct wlr_box *bbox)
|
||||
{
|
||||
@@ -2378,7 +2470,6 @@ void
|
||||
resize(Client *c, struct wlr_box geo, int interact)
|
||||
{
|
||||
struct wlr_box *bbox;
|
||||
- struct wlr_box clip;
|
||||
|
||||
if (!c->mon || !client_surface(c)->mapped)
|
||||
return;
|
||||
@@ -2388,21 +2479,28 @@ resize(Client *c, struct wlr_box geo, int interact)
|
||||
client_set_bounds(c, geo.width, geo.height);
|
||||
c->geom = geo;
|
||||
applybounds(c, bbox);
|
||||
+ client_set_size(c, c->geom.width - 2 * c->bw, c->geom.height - 2 * c->bw);
|
||||
|
||||
- /* Update scene-graph, including borders */
|
||||
- wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y);
|
||||
- wlr_scene_node_set_position(&c->scene_surface->node, c->bw, c->bw);
|
||||
- wlr_scene_rect_set_size(c->border[0], c->geom.width, c->bw);
|
||||
- wlr_scene_rect_set_size(c->border[1], c->geom.width, c->bw);
|
||||
- wlr_scene_rect_set_size(c->border[2], c->bw, c->geom.height - 2 * c->bw);
|
||||
- wlr_scene_rect_set_size(c->border[3], c->bw, c->geom.height - 2 * c->bw);
|
||||
- wlr_scene_node_set_position(&c->border[1]->node, 0, c->geom.height - c->bw);
|
||||
- wlr_scene_node_set_position(&c->border[2]->node, 0, c->bw);
|
||||
- wlr_scene_node_set_position(&c->border[3]->node, c->geom.width - c->bw, c->bw);
|
||||
+ if (interact) {
|
||||
+ c->animating = 0;
|
||||
+ c->anim_cur = c->geom;
|
||||
+ animation_apply(c, c->geom);
|
||||
+ return;
|
||||
+ }
|
||||
|
||||
- client_set_size(c, c->geom.width - 2 * c->bw, c->geom.height - 2 * c->bw);
|
||||
- client_get_clip(c, &clip);
|
||||
- wlr_scene_subsurface_tree_set_clip(&c->scene_surface->node, &clip);
|
||||
+ if (!c->animating && c->anim_cur.width == 0) {
|
||||
+ c->anim_cur.width = c->geom.width / 2;
|
||||
+ c->anim_cur.height = c->geom.height / 2;
|
||||
+ c->anim_cur.x = c->geom.x + (c->geom.width - c->anim_cur.width) / 2;
|
||||
+ c->anim_cur.y = c->geom.y + (c->geom.height - c->anim_cur.height) / 2;
|
||||
+ c->anim_zoom = 1;
|
||||
+ }
|
||||
+
|
||||
+ c->anim_from = c->anim_cur;
|
||||
+ c->anim_to = c->geom;
|
||||
+ c->anim_start = animation_now_ms();
|
||||
+ c->animating = 1;
|
||||
+ wl_event_source_timer_update(animation_timer, 1);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -2628,6 +2726,7 @@ setup(void)
|
||||
* clients from the Unix socket, managing Wayland globals, and so on. */
|
||||
dpy = wl_display_create();
|
||||
event_loop = wl_display_get_event_loop(dpy);
|
||||
+ animation_timer = wl_event_loop_add_timer(event_loop, animation_tick, NULL);
|
||||
|
||||
/* The backend is a wlroots feature which abstracts the underlying input and
|
||||
* output hardware. The autocreate option will choose the most suitable
|
||||
--
|
||||
2.55.0
|
||||
|
||||
Reference in New Issue
Block a user