mirror of
https://github.com/DreamMaoMao/maomaowm.git
synced 2025-10-29 05:40:21 -04:00
feat: support fadeout animation
This commit is contained in:
parent
88b78a6679
commit
9df9ada7d9
5 changed files with 229 additions and 2 deletions
|
|
@ -58,6 +58,7 @@ See below for more features.
|
|||
- fade in animation
|
||||
- alt-tab switch window like gnome
|
||||
- niri like scroller layout
|
||||
- fadeout animation
|
||||
|
||||
## suggest tools
|
||||
```
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ fadein_begin_opacity=0.5
|
|||
animation_duration_move=500
|
||||
animation_duration_open=400
|
||||
animation_duration_tag=350
|
||||
animation_duration_close=350
|
||||
animation_curve=0.46,1.0,0.29,0.99
|
||||
|
||||
# Scroller Layout Setting
|
||||
|
|
|
|||
223
maomao.c
223
maomao.c
|
|
@ -109,6 +109,7 @@ enum {
|
|||
#ifdef IM
|
||||
LyrIMPopup,
|
||||
#endif
|
||||
LyrFadeOut,
|
||||
LyrBlock,
|
||||
NUM_LAYERS
|
||||
}; /* scene layers */
|
||||
|
|
@ -177,8 +178,10 @@ typedef struct {
|
|||
struct wlr_scene_tree *scene;
|
||||
struct wlr_scene_rect *border[4]; /* top, bottom, left, right */
|
||||
struct wlr_scene_tree *scene_surface;
|
||||
struct wlr_scene_tree *snapshot_scene;
|
||||
struct wl_list link;
|
||||
struct wl_list flink;
|
||||
struct wl_list fadeout_link;
|
||||
union {
|
||||
struct wlr_xdg_surface *xdg;
|
||||
struct wlr_xwayland_surface *xwayland;
|
||||
|
|
@ -235,6 +238,7 @@ typedef struct {
|
|||
float scroller_proportion;
|
||||
bool need_output_flush;
|
||||
struct dwl_animation animation;
|
||||
bool is_fadeout_client;
|
||||
// struct wl_event_source *timer_tick;
|
||||
|
||||
} Client;
|
||||
|
|
@ -537,6 +541,8 @@ void client_commit(Client *c);
|
|||
void apply_border(Client *c, struct wlr_box clip_box, int offset);
|
||||
void client_set_opacity(Client *c, double opacity);
|
||||
void init_baked_points(void);
|
||||
void scene_buffer_apply_opacity(struct wlr_scene_buffer *buffer, int sx, int sy,
|
||||
void *data);
|
||||
|
||||
Client *direction_select(const Arg *arg);
|
||||
void bind_to_view(const Arg *arg);
|
||||
|
|
@ -577,6 +583,7 @@ static struct wlr_xdg_activation_v1 *activation;
|
|||
static struct wlr_xdg_decoration_manager_v1 *xdg_decoration_mgr;
|
||||
static struct wl_list clients; /* tiling order */
|
||||
static struct wl_list fstack; /* focus order */
|
||||
static struct wl_list fadeout_clients;
|
||||
// static struct wlr_idle *idle;
|
||||
static struct wlr_idle_notifier_v1 *idle_notifier;
|
||||
static struct wlr_idle_inhibit_manager_v1 *idle_inhibit_mgr;
|
||||
|
|
@ -714,6 +721,48 @@ double find_animation_curve_at(double t) {
|
|||
return baked_points[up].y;
|
||||
}
|
||||
|
||||
|
||||
void fadeout_client_animation_next_tick(Client *c) {
|
||||
if (!c)
|
||||
return;
|
||||
double animation_passed =
|
||||
(double)c->animation.passed_frames / c->animation.total_frames;
|
||||
double factor = find_animation_curve_at(animation_passed);
|
||||
|
||||
uint32_t width = c->animation.initial.width +
|
||||
(c->current.width - c->animation.initial.width) * factor;
|
||||
uint32_t height = c->animation.initial.height +
|
||||
(c->current.height - c->animation.initial.height) * factor;
|
||||
|
||||
uint32_t x =
|
||||
c->animation.initial.x + (c->current.x - c->animation.initial.x) * factor;
|
||||
uint32_t y =
|
||||
c->animation.initial.y + (c->current.y - c->animation.initial.y) * factor;
|
||||
|
||||
wlr_scene_node_set_position(&c->snapshot_scene->node, 0, y);
|
||||
c->animation.current = (struct wlr_box){
|
||||
.x = x,
|
||||
.y = y,
|
||||
.width = width,
|
||||
.height = height,
|
||||
};
|
||||
|
||||
double opacity = MAX(1 - 0.4 - animation_passed, 0);
|
||||
|
||||
wlr_scene_node_for_each_buffer(&c->snapshot_scene->node,
|
||||
scene_buffer_apply_opacity, &opacity);
|
||||
|
||||
if (animation_passed == 1.0) {
|
||||
wl_list_remove(&c->fadeout_link);
|
||||
wlr_scene_node_destroy(&c->snapshot_scene->node);
|
||||
free(c);
|
||||
c = NULL;
|
||||
} else {
|
||||
c->animation.passed_frames++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void client_animation_next_tick(Client *c) {
|
||||
double animation_passed =
|
||||
(double)c->animation.passed_frames / c->animation.total_frames;
|
||||
|
|
@ -894,6 +943,7 @@ void client_apply_clip(Client *c) {
|
|||
}
|
||||
|
||||
bool client_draw_frame(Client *c) {
|
||||
|
||||
if (!c || !client_surface(c)->mapped)
|
||||
return false;
|
||||
|
||||
|
|
@ -913,6 +963,16 @@ bool client_draw_frame(Client *c) {
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool client_draw_fadeout_frame(Client *c) {
|
||||
if(!c)
|
||||
return false;
|
||||
|
||||
fadeout_client_animation_next_tick(c);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void // 0.5
|
||||
applybounds(Client *c, struct wlr_box *bbox) {
|
||||
/* set minimum possible */
|
||||
|
|
@ -3093,7 +3153,119 @@ keypressmod(struct wl_listener *listener, void *data) {
|
|||
wlr_seat_keyboard_notify_modifiers(seat, &kb->wlr_keyboard->modifiers);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static bool scene_node_snapshot(struct wlr_scene_node *node, int lx, int ly,
|
||||
struct wlr_scene_tree *snapshot_tree) {
|
||||
if (!node->enabled && node->type != WLR_SCENE_NODE_TREE) {
|
||||
return true;
|
||||
}
|
||||
|
||||
lx += node->x;
|
||||
ly += node->y;
|
||||
|
||||
struct wlr_scene_node *snapshot_node = NULL;
|
||||
switch (node->type) {
|
||||
case WLR_SCENE_NODE_TREE:;
|
||||
struct wlr_scene_tree *scene_tree = wlr_scene_tree_from_node(node);
|
||||
struct wlr_scene_node *child;
|
||||
wl_list_for_each(child, &scene_tree->children, link) {
|
||||
scene_node_snapshot(child, lx, ly, snapshot_tree);
|
||||
}
|
||||
break;
|
||||
case WLR_SCENE_NODE_RECT:;
|
||||
|
||||
struct wlr_scene_rect *scene_rect = wlr_scene_rect_from_node(node);
|
||||
|
||||
struct wlr_scene_rect *snapshot_rect =
|
||||
wlr_scene_rect_create(snapshot_tree, scene_rect->width,
|
||||
scene_rect->height, scene_rect->color);
|
||||
snapshot_rect->node.data = scene_rect->node.data;
|
||||
if (snapshot_rect == NULL) {
|
||||
return false;
|
||||
}
|
||||
snapshot_node = &snapshot_rect->node;
|
||||
break;
|
||||
case WLR_SCENE_NODE_BUFFER:;
|
||||
|
||||
struct wlr_scene_buffer *scene_buffer =
|
||||
wlr_scene_buffer_from_node(node);
|
||||
|
||||
struct wlr_scene_buffer *snapshot_buffer =
|
||||
wlr_scene_buffer_create(snapshot_tree, NULL);
|
||||
if (snapshot_buffer == NULL) {
|
||||
return false;
|
||||
}
|
||||
snapshot_node = &snapshot_buffer->node;
|
||||
snapshot_buffer->node.data = scene_buffer->node.data;
|
||||
|
||||
wlr_scene_buffer_set_dest_size(snapshot_buffer, scene_buffer->dst_width,
|
||||
scene_buffer->dst_height);
|
||||
wlr_scene_buffer_set_opaque_region(snapshot_buffer,
|
||||
&scene_buffer->opaque_region);
|
||||
wlr_scene_buffer_set_source_box(snapshot_buffer,
|
||||
&scene_buffer->src_box);
|
||||
wlr_scene_buffer_set_transform(snapshot_buffer,
|
||||
scene_buffer->transform);
|
||||
wlr_scene_buffer_set_filter_mode(snapshot_buffer,
|
||||
scene_buffer->filter_mode);
|
||||
|
||||
// Effects
|
||||
wlr_scene_buffer_set_opacity(snapshot_buffer, scene_buffer->opacity);
|
||||
|
||||
wlr_scene_buffer_set_opacity(snapshot_buffer, scene_buffer->opacity);
|
||||
|
||||
snapshot_buffer->node.data = scene_buffer->node.data;
|
||||
|
||||
struct wlr_scene_surface *scene_surface =
|
||||
wlr_scene_surface_try_from_buffer(scene_buffer);
|
||||
if (scene_surface != NULL && scene_surface->surface->buffer != NULL) {
|
||||
wlr_scene_buffer_set_buffer(snapshot_buffer,
|
||||
&scene_surface->surface->buffer->base);
|
||||
} else {
|
||||
wlr_scene_buffer_set_buffer(snapshot_buffer, scene_buffer->buffer);
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
if (snapshot_node != NULL) {
|
||||
wlr_scene_node_set_position(snapshot_node, lx, ly);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
struct wlr_scene_tree *wlr_scene_tree_snapshot(struct wlr_scene_node *node,
|
||||
struct wlr_scene_tree *parent) {
|
||||
struct wlr_scene_tree *snapshot = wlr_scene_tree_create(parent);
|
||||
if (snapshot == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Disable and enable the snapshot tree like so to atomically update
|
||||
// the scene-graph. This will prevent over-damaging or other weirdness.
|
||||
wlr_scene_node_set_enabled(&snapshot->node, false);
|
||||
|
||||
if (!scene_node_snapshot(node, 0, 0, snapshot)) {
|
||||
wlr_scene_node_destroy(&snapshot->node);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wlr_scene_node_set_enabled(&snapshot->node, true);
|
||||
|
||||
return snapshot;
|
||||
}
|
||||
|
||||
void pending_kill_client(Client *c) {
|
||||
|
||||
if(!c->snapshot_scene) {
|
||||
wlr_scene_node_destroy(&c->snapshot_scene->node);
|
||||
}
|
||||
if(c->mon) {
|
||||
c->snapshot_scene = wlr_scene_tree_snapshot(&c->scene->node, layers[LyrFadeOut]);
|
||||
wlr_scene_node_set_enabled(&c->snapshot_scene->node, false);
|
||||
}
|
||||
// c->iskilling = 1; //不可以提前标记已经杀掉,因为有些客户端可能拒绝
|
||||
client_send_close(c);
|
||||
}
|
||||
|
|
@ -3708,7 +3880,7 @@ void client_handle_opacity(Client *c) {
|
|||
|
||||
void rendermon(struct wl_listener *listener, void *data) {
|
||||
Monitor *m = wl_container_of(listener, m, frame);
|
||||
Client *c;
|
||||
Client *c,*tmp;
|
||||
struct wlr_output_state pending = {0};
|
||||
|
||||
struct timespec now;
|
||||
|
|
@ -3719,6 +3891,9 @@ void rendermon(struct wl_listener *listener, void *data) {
|
|||
need_more_frames = client_draw_frame(c) || need_more_frames;
|
||||
}
|
||||
|
||||
wl_list_for_each_safe(c, tmp, &fadeout_clients, fadeout_link) {
|
||||
need_more_frames = client_draw_fadeout_frame(c) || need_more_frames;
|
||||
}
|
||||
|
||||
wlr_scene_output_commit(m->scene_output, NULL);
|
||||
|
||||
|
|
@ -4544,6 +4719,7 @@ void setup(void) {
|
|||
*/
|
||||
wl_list_init(&clients);
|
||||
wl_list_init(&fstack);
|
||||
wl_list_init(&fadeout_clients);
|
||||
|
||||
idle_notifier = wlr_idle_notifier_v1_create(dpy);
|
||||
|
||||
|
|
@ -5419,11 +5595,49 @@ unmaplayersurfacenotify(struct wl_listener *listener, void *data) {
|
|||
motionnotify(0, NULL, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
void init_fadeout_client(Client *c) {
|
||||
|
||||
if(!c->mon || client_is_unmanaged(c))
|
||||
return;
|
||||
|
||||
if(!c->snapshot_scene) {
|
||||
wlr_scene_node_destroy(&c->snapshot_scene->node);
|
||||
}
|
||||
|
||||
Client *fadeout_cient = ecalloc(1, sizeof(*fadeout_cient));
|
||||
|
||||
wlr_scene_node_set_enabled(&c->scene->node, true);
|
||||
fadeout_cient->snapshot_scene = wlr_scene_tree_snapshot(&c->scene->node, layers[LyrFadeOut]);
|
||||
wlr_scene_node_set_enabled(&c->scene->node, false);
|
||||
|
||||
if(!fadeout_cient->snapshot_scene) {
|
||||
free(fadeout_cient);
|
||||
return;
|
||||
}
|
||||
|
||||
fadeout_cient->animation.duration = animation_duration_close;
|
||||
fadeout_cient->current = fadeout_cient->animainit_geom = c->animation.initial = c->animation.current;
|
||||
fadeout_cient->mon = c->mon;
|
||||
// 这里snap节点的坐标设置是使用的相对坐标,所以不能加上原来坐标
|
||||
// 这根普通node有区别
|
||||
fadeout_cient->current.y = c->mon->m.height - (c->animation.current.y - c->mon->m.y);
|
||||
fadeout_cient->current.x = 0; //x无偏差,垂直划出
|
||||
fadeout_cient->animation.passed_frames = 0;
|
||||
fadeout_cient->animation.total_frames =
|
||||
fadeout_cient->animation.duration / output_frame_duration_ms(c);
|
||||
fadeout_cient->is_fadeout_client =true;
|
||||
wlr_scene_node_set_enabled(&fadeout_cient->snapshot_scene->node,true);
|
||||
wl_list_insert(&fadeout_clients, &fadeout_cient->fadeout_link);
|
||||
}
|
||||
|
||||
void unmapnotify(struct wl_listener *listener, void *data) {
|
||||
/* Called when the surface is unmapped, and should no longer be shown. */
|
||||
Client *c = wl_container_of(listener, c, unmap);
|
||||
|
||||
c->iskilling = 1;
|
||||
if (c->is_fadeout_client)
|
||||
return;
|
||||
|
||||
init_fadeout_client(c);
|
||||
|
||||
if (c == grabc) {
|
||||
cursor_mode = CurNormal;
|
||||
|
|
@ -5462,10 +5676,12 @@ void unmapnotify(struct wl_listener *listener, void *data) {
|
|||
wlr_foreign_toplevel_handle_v1_destroy(c->foreign_toplevel);
|
||||
c->foreign_toplevel = NULL;
|
||||
}
|
||||
|
||||
// wl_event_source_remove(c->timer_tick);
|
||||
wlr_scene_node_destroy(&c->scene->node);
|
||||
printstatus();
|
||||
motionnotify(0, NULL, 0, 0, 0, 0);
|
||||
|
||||
}
|
||||
|
||||
void // 0.5
|
||||
|
|
@ -5855,6 +6071,9 @@ void xytonode(double x, double y, struct wlr_surface **psurface, Client **pc,
|
|||
if (layer == LyrIMPopup)
|
||||
continue;
|
||||
#endif
|
||||
if(layer == LyrFadeOut)
|
||||
continue;
|
||||
|
||||
if (!(node = wlr_scene_node_at(&layers[layer]->node, x, y, nx, ny)))
|
||||
continue;
|
||||
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ typedef struct {
|
|||
uint32_t animation_duration_move;
|
||||
uint32_t animation_duration_open;
|
||||
uint32_t animation_duration_tag;
|
||||
uint32_t animation_duration_close;
|
||||
double animation_curve[4];
|
||||
|
||||
int scroller_structs;
|
||||
|
|
@ -452,6 +453,8 @@ void parse_config_line(Config *config, const char *line) {
|
|||
config->animation_duration_open = atoi(value);
|
||||
} else if (strcmp(key, "animation_duration_tag") == 0) {
|
||||
config->animation_duration_tag = atoi(value);
|
||||
} else if (strcmp(key, "animation_duration_close") == 0) {
|
||||
config->animation_duration_close = atoi(value);
|
||||
} else if (strcmp(key, "animation_curve") == 0) {
|
||||
if (sscanf(value, "%lf,%lf,%lf,%lf", &config->animation_curve[0],
|
||||
&config->animation_curve[1], &config->animation_curve[2],
|
||||
|
|
@ -876,6 +879,7 @@ void override_config(void) {
|
|||
animation_duration_move = config.animation_duration_move;
|
||||
animation_duration_open = config.animation_duration_open;
|
||||
animation_duration_tag = config.animation_duration_tag;
|
||||
animation_duration_close = config.animation_duration_close;
|
||||
|
||||
// 复制数组类型的变量
|
||||
memcpy(animation_curve, config.animation_curve, sizeof(animation_curve));
|
||||
|
|
@ -927,6 +931,7 @@ config.fadein_begin_opacity = 0; // Begin opac window ratio for animations
|
|||
config.animation_duration_move = 500; // Animation move speed
|
||||
config.animation_duration_open = 400; // Animation open speed
|
||||
config.animation_duration_tag = 300; // Animation tag speed
|
||||
config.animation_duration_close = 300; // Animation tag speed
|
||||
|
||||
/* appearance */
|
||||
config.axis_bind_apply_timeout = 100; // 滚轮绑定动作的触发的时间间隔
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ float fadein_begin_opacity = 0; // Begin opac window ratio for animations
|
|||
uint32_t animation_duration_move = 500; // Animation move speed
|
||||
uint32_t animation_duration_open = 400; // Animation open speed
|
||||
uint32_t animation_duration_tag = 300; // Animation tag speed
|
||||
uint32_t animation_duration_close = 300; // Animation close speed
|
||||
double animation_curve[4] = {0.46, 1.0, 0.29, 0.99}; // 动画曲线
|
||||
|
||||
/* appearance */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue