project: optimize project struct

This commit is contained in:
DreamMaoMao 2025-07-06 19:10:35 +08:00
parent 44adbc3b4b
commit f67a7a1c8b
4 changed files with 1671 additions and 1660 deletions

1000
src/animation/client.h Normal file

File diff suppressed because it is too large Load diff

233
src/animation/common.h Normal file
View file

@ -0,0 +1,233 @@
struct dvec2 calculate_animation_curve_at(double t, int type) {
struct dvec2 point;
double *animation_curve;
if (type == MOVE) {
animation_curve = animation_curve_move;
} else if (type == OPEN) {
animation_curve = animation_curve_open;
} else if (type == TAG) {
animation_curve = animation_curve_tag;
} else if (type == CLOSE) {
animation_curve = animation_curve_close;
} else {
animation_curve = animation_curve_move;
}
point.x = 3 * t * (1 - t) * (1 - t) * animation_curve[0] +
3 * t * t * (1 - t) * animation_curve[2] + t * t * t;
point.y = 3 * t * (1 - t) * (1 - t) * animation_curve[1] +
3 * t * t * (1 - t) * animation_curve[3] + t * t * t;
return point;
}
void init_baked_points(void) {
baked_points_move = calloc(BAKED_POINTS_COUNT, sizeof(*baked_points_move));
baked_points_open = calloc(BAKED_POINTS_COUNT, sizeof(*baked_points_open));
baked_points_tag = calloc(BAKED_POINTS_COUNT, sizeof(*baked_points_tag));
baked_points_close =
calloc(BAKED_POINTS_COUNT, sizeof(*baked_points_close));
for (unsigned int i = 0; i < BAKED_POINTS_COUNT; i++) {
baked_points_move[i] = calculate_animation_curve_at(
(double)i / (BAKED_POINTS_COUNT - 1), MOVE);
}
for (unsigned int i = 0; i < BAKED_POINTS_COUNT; i++) {
baked_points_open[i] = calculate_animation_curve_at(
(double)i / (BAKED_POINTS_COUNT - 1), OPEN);
}
for (unsigned int i = 0; i < BAKED_POINTS_COUNT; i++) {
baked_points_tag[i] = calculate_animation_curve_at(
(double)i / (BAKED_POINTS_COUNT - 1), TAG);
}
for (unsigned int i = 0; i < BAKED_POINTS_COUNT; i++) {
baked_points_close[i] = calculate_animation_curve_at(
(double)i / (BAKED_POINTS_COUNT - 1), CLOSE);
}
}
double find_animation_curve_at(double t, int type) {
unsigned int down = 0;
unsigned int up = BAKED_POINTS_COUNT - 1;
unsigned int middle = (up + down) / 2;
struct dvec2 *baked_points;
if (type == MOVE) {
baked_points = baked_points_move;
} else if (type == OPEN) {
baked_points = baked_points_open;
} else if (type == TAG) {
baked_points = baked_points_tag;
} else if (type == CLOSE) {
baked_points = baked_points_close;
} else {
baked_points = baked_points_move;
}
while (up - down != 1) {
if (baked_points[middle].x <= t) {
down = middle;
} else {
up = middle;
}
middle = (up + down) / 2;
}
return baked_points[up].y;
}
double output_frame_duration_ms() {
int32_t refresh_total = 0;
Monitor *m;
wl_list_for_each(m, &mons, link) {
if (!m->wlr_output->enabled) {
continue;
}
refresh_total += m->wlr_output->refresh;
}
return 1000000.0 / refresh_total;
}
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;
}
wlr_scene_rect_set_clipped_region(scene_rect,
snapshot_rect->clipped_region);
wlr_scene_rect_set_backdrop_blur(scene_rect, false);
// wlr_scene_rect_set_backdrop_blur_optimized(
// scene_rect, snapshot_rect->backdrop_blur_optimized);
wlr_scene_rect_set_corner_radius(
scene_rect, snapshot_rect->corner_radius, snapshot_rect->corners);
wlr_scene_rect_set_color(scene_rect, snapshot_rect->color);
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_corner_radius(snapshot_buffer,
scene_buffer->corner_radius,
scene_buffer->corners);
// wlr_scene_buffer_set_backdrop_blur_optimized(
// snapshot_buffer, scene_buffer->backdrop_blur_optimized);
// wlr_scene_buffer_set_backdrop_blur_ignore_transparent(
// snapshot_buffer, scene_buffer->backdrop_blur_ignore_transparent);
wlr_scene_buffer_set_backdrop_blur(snapshot_buffer, false);
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;
}
case WLR_SCENE_NODE_SHADOW: {
struct wlr_scene_shadow *scene_shadow =
wlr_scene_shadow_from_node(node);
struct wlr_scene_shadow *snapshot_shadow = wlr_scene_shadow_create(
snapshot_tree, scene_shadow->width, scene_shadow->height,
scene_shadow->corner_radius, scene_shadow->blur_sigma,
scene_shadow->color);
if (snapshot_shadow == NULL) {
return false;
}
snapshot_node = &snapshot_shadow->node;
wlr_scene_shadow_set_clipped_region(snapshot_shadow,
scene_shadow->clipped_region);
snapshot_shadow->node.data = scene_shadow->node.data;
wlr_scene_node_set_enabled(&snapshot_shadow->node, false);
break;
}
case WLR_SCENE_NODE_OPTIMIZED_BLUR:
return true;
}
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;
}

421
src/animation/layer.h Normal file
View file

@ -0,0 +1,421 @@
void layer_actual_size(LayerSurface *l, unsigned int *width,
unsigned int *height) {
struct wlr_box box;
if (l->animation.running) {
*width = l->animation.current.width;
*height = l->animation.current.height;
} else {
get_layer_target_geometry(l, &box);
*width = box.width;
*height = box.height;
}
}
void get_layer_target_geometry(LayerSurface *l, struct wlr_box *target_box) {
if (!l || !l->mapped)
return;
const struct wlr_layer_surface_v1_state *state = &l->layer_surface->current;
// 限制区域
// waybar一般都是大于0,表示要占用多少区域,所以计算位置也要用全部区域作为基准
// 如果是-1可能表示独占所有可用空间
// 如果是0应该是表示使用exclusive_zone外的可用区域
struct wlr_box bounds;
if (state->exclusive_zone > 0 || state->exclusive_zone == -1)
bounds = l->mon->m;
else
bounds = l->mon->w;
// 初始化几何位置
struct wlr_box box = {.width = state->desired_width,
.height = state->desired_height};
// 水平方向定位
const uint32_t both_horiz =
ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
if (box.width == 0) {
box.x = bounds.x;
} else if ((state->anchor & both_horiz) == both_horiz) {
box.x = bounds.x + ((bounds.width - box.width) / 2);
} else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT) {
box.x = bounds.x;
} else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT) {
box.x = bounds.x + (bounds.width - box.width);
} else {
box.x = bounds.x + ((bounds.width - box.width) / 2);
}
// 垂直方向定位
const uint32_t both_vert =
ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;
if (box.height == 0) {
box.y = bounds.y;
} else if ((state->anchor & both_vert) == both_vert) {
box.y = bounds.y + ((bounds.height - box.height) / 2);
} else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP) {
box.y = bounds.y;
} else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM) {
box.y = bounds.y + (bounds.height - box.height);
} else {
box.y = bounds.y + ((bounds.height - box.height) / 2);
}
// 应用边距
if (box.width == 0) {
box.x += state->margin.left;
box.width = bounds.width - (state->margin.left + state->margin.right);
} else {
if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT) {
box.x += state->margin.left;
} else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT) {
box.x -= state->margin.right;
}
}
if (box.height == 0) {
box.y += state->margin.top;
box.height = bounds.height - (state->margin.top + state->margin.bottom);
} else {
if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP) {
box.y += state->margin.top;
} else if (state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM) {
box.y -= state->margin.bottom;
}
}
target_box->x = box.x;
target_box->y = box.y;
target_box->width = box.width;
target_box->height = box.height;
}
void set_layer_open_animaiton(LayerSurface *l, struct wlr_box geo) {
int slide_direction;
int horizontal, horizontal_value;
int vertical, vertical_value;
int center_x, center_y;
if (!l || !l->mapped)
return;
center_x = l->geom.x + l->geom.width / 2;
center_y = l->geom.y + l->geom.height / 2;
horizontal =
l->mon->w.x + l->mon->w.width - center_x < center_x - l->mon->w.x
? RIGHT
: LEFT;
horizontal_value = horizontal == LEFT
? center_x - l->mon->w.x
: l->mon->w.x + l->mon->w.width - center_x;
vertical =
l->mon->w.y + l->mon->w.height - center_y < center_y - l->mon->w.y
? DOWN
: UP;
vertical_value = vertical == UP ? center_y - l->mon->w.y
: l->mon->w.y + l->mon->w.height - center_y;
slide_direction = horizontal_value < vertical_value ? horizontal : vertical;
l->animainit_geom.width = l->geom.width;
l->animainit_geom.height = l->geom.height;
switch (slide_direction) {
case UP:
l->animainit_geom.x = l->geom.x;
l->animainit_geom.y = l->mon->m.y - l->geom.height;
break;
case DOWN:
l->animainit_geom.x = l->geom.x;
l->animainit_geom.y =
l->geom.y + l->mon->m.height - (l->geom.y - l->mon->m.y);
break;
case LEFT:
l->animainit_geom.x = l->mon->m.x - l->geom.width;
l->animainit_geom.y = l->geom.y;
break;
case RIGHT:
l->animainit_geom.x =
l->geom.x + l->mon->m.width - (l->geom.x - l->mon->m.x);
l->animainit_geom.y = l->geom.y;
break;
default:
l->animainit_geom.x = l->geom.x;
l->animainit_geom.y = 0 - l->geom.height;
}
}
void layer_draw_shadow(LayerSurface *l) {
if (!l->mapped || !l->shadow)
return;
if (!shadows || !layer_shadows || l->noshadow) {
wlr_scene_shadow_set_size(l->shadow, 0, 0);
return;
}
uint32_t width, height;
layer_actual_size(l, &width, &height);
uint32_t delta = shadows_size;
/* we calculate where to clip the shadow */
struct wlr_box layer_box = {
.x = 0,
.y = 0,
.width = width,
.height = height,
};
struct wlr_box shadow_box = {
.x = shadows_position_x,
.y = shadows_position_y,
.width = width + 2 * delta,
.height = height + 2 * delta,
};
struct wlr_box intersection_box;
wlr_box_intersection(&intersection_box, &layer_box, &shadow_box);
/* clipped region takes shadow relative coords, so we translate everything
* by its position */
intersection_box.x -= shadows_position_x;
intersection_box.y -= shadows_position_y;
struct clipped_region clipped_region = {
.area = intersection_box,
.corner_radius = border_radius,
.corners = border_radius_location_default,
};
wlr_scene_node_set_position(&l->shadow->node, shadow_box.x, shadow_box.y);
wlr_scene_shadow_set_size(l->shadow, shadow_box.width, shadow_box.height);
wlr_scene_shadow_set_clipped_region(l->shadow, clipped_region);
}
void fadeout_layer_animation_next_tick(LayerSurface *l) {
if (!l)
return;
double animation_passed =
(double)l->animation.passed_frames / l->animation.total_frames;
int type = l->animation.action = l->animation.action;
double factor = find_animation_curve_at(animation_passed, type);
unsigned int width =
l->animation.initial.width +
(l->current.width - l->animation.initial.width) * factor;
unsigned int height =
l->animation.initial.height +
(l->current.height - l->animation.initial.height) * factor;
unsigned int x = l->animation.initial.x +
(l->current.x - l->animation.initial.x) * factor;
unsigned int y = l->animation.initial.y +
(l->current.y - l->animation.initial.y) * factor;
wlr_scene_node_set_position(&l->scene->node, x, y);
l->animation.current = (struct wlr_box){
.x = x,
.y = y,
.width = width,
.height = height,
};
double opacity = MAX(fadeout_begin_opacity - animation_passed, 0);
if (animation_fade_out)
wlr_scene_node_for_each_buffer(&l->scene->node,
scene_buffer_apply_opacity, &opacity);
if (animation_passed == 1.0) {
wl_list_remove(&l->fadeout_link);
wlr_scene_node_destroy(&l->scene->node);
free(l);
l = NULL;
} else {
l->animation.passed_frames++;
}
}
void layer_animation_next_tick(LayerSurface *l) {
if (!l || !l->mapped)
return;
double animation_passed =
(double)l->animation.passed_frames / l->animation.total_frames;
int type = l->animation.action == NONE ? MOVE : l->animation.action;
double factor = find_animation_curve_at(animation_passed, type);
unsigned int width =
l->animation.initial.width +
(l->current.width - l->animation.initial.width) * factor;
unsigned int height =
l->animation.initial.height +
(l->current.height - l->animation.initial.height) * factor;
unsigned int x = l->animation.initial.x +
(l->current.x - l->animation.initial.x) * factor;
unsigned int y = l->animation.initial.y +
(l->current.y - l->animation.initial.y) * factor;
wlr_scene_node_set_position(&l->scene->node, x, y);
l->animation.current = (struct wlr_box){
.x = x,
.y = y,
.width = width,
.height = height,
};
if (animation_passed == 1.0) {
l->animation.running = false;
l->need_output_flush = false;
l->animation.action = MOVE;
} else {
l->animation.passed_frames++;
}
}
void init_fadeout_layers(LayerSurface *l) {
if (!layer_animations || l->noanim) {
return;
}
if (!l->mon)
return;
if (!l->scene) {
return;
}
if (l->layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM ||
l->layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND)
return;
LayerSurface *fadeout_layer = ecalloc(1, sizeof(*fadeout_layer));
wlr_scene_node_set_enabled(&l->scene->node, true);
fadeout_layer->scene =
wlr_scene_tree_snapshot(&l->scene->node, layers[LyrFadeOut]);
wlr_scene_node_set_enabled(&l->scene->node, false);
if (!fadeout_layer->scene) {
free(fadeout_layer);
return;
}
fadeout_layer->animation.duration = animation_duration_close;
fadeout_layer->geom = fadeout_layer->current =
fadeout_layer->animainit_geom = fadeout_layer->animation.initial =
l->animation.current;
fadeout_layer->mon = l->mon;
fadeout_layer->animation.action = CLOSE;
// 这里snap节点的坐标设置是使用的相对坐标所以不能加上原来坐标
// 这跟普通node有区别
fadeout_layer->animation.initial.x = 0;
fadeout_layer->animation.initial.y = 0;
fadeout_layer->current.y =
l->geom.y + l->geom.height / 2 > l->mon->m.y + l->mon->m.height / 2
? l->mon->m.height -
(l->animation.current.y - l->mon->m.y) // down out
: l->mon->m.y - l->geom.height; // up out
fadeout_layer->current.x = 0; // x无偏差垂直划出
fadeout_layer->animation.passed_frames = 0;
fadeout_layer->animation.total_frames =
fadeout_layer->animation.duration / output_frame_duration_ms();
wlr_scene_node_set_enabled(&fadeout_layer->scene->node, true);
wl_list_insert(&fadeout_layers, &fadeout_layer->fadeout_link);
}
void layer_set_pending_state(LayerSurface *l) {
if (!l || !l->mapped)
return;
l->pending = l->geom;
if (l->animation.action == OPEN)
set_layer_open_animaiton(l, l->geom);
else
l->animainit_geom = l->animation.current;
// 判断是否需要动画
if (!animations || !layer_animations || l->noanim ||
l->layer_surface->current.layer ==
ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND ||
l->layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM) {
l->animation.should_animate = false;
} else {
l->animation.should_animate = true;
}
l->animation.duration = animation_duration_open;
l->animation.action = OPEN;
// 开始动画
layer_commit(l);
l->dirty = true;
}
void layer_commit(LayerSurface *l) {
if (!l || !l->mapped)
return;
l->current = l->pending; // 设置动画的结束位置
if (l->animation.should_animate) {
if (!l->animation.running) {
l->animation.current = l->animainit_geom;
}
l->animation.initial = l->animainit_geom;
// 设置动画速度
l->animation.passed_frames = 0;
l->animation.total_frames =
l->animation.duration / output_frame_duration_ms();
// 标记动画开始
l->animation.running = true;
l->animation.should_animate = false;
}
// 请求刷新屏幕
wlr_output_schedule_frame(l->mon->wlr_output);
}
bool layer_draw_frame(LayerSurface *l) {
if (!l || !l->mapped)
return false;
if (!l->need_output_flush)
return false;
if (l->layer_surface->current.layer != ZWLR_LAYER_SHELL_V1_LAYER_TOP &&
l->layer_surface->current.layer != ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY) {
return false;
}
if (animations && layer_animations && l->animation.running && !l->noanim) {
layer_animation_next_tick(l);
layer_draw_shadow(l);
} else {
layer_draw_shadow(l);
l->need_output_flush = false;
}
return true;
}
bool layer_draw_fadeout_frame(LayerSurface *l) {
if (!l)
return false;
fadeout_layer_animation_next_tick(l);
return true;
}

File diff suppressed because it is too large Load diff