maomaowm/src/animation/client.h

1043 lines
30 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

void client_actual_size(Client *c, unsigned int *width, unsigned int *height) {
*width = c->animation.current.width - c->bw;
*height = c->animation.current.height - c->bw;
}
void set_rect_size(struct wlr_scene_rect *rect, int width, int height) {
wlr_scene_rect_set_size(rect, GEZERO(width), GEZERO(height));
}
enum corner_location set_client_corner_location(Client *c) {
enum corner_location current_corner_location = CORNER_LOCATION_ALL;
struct wlr_box target_geom = animations ? c->animation.current : c->geom;
if (target_geom.x + border_radius <= c->mon->m.x) {
current_corner_location &= ~CORNER_LOCATION_LEFT; // 清除左标志位
}
if (target_geom.x + target_geom.width - border_radius >=
c->mon->m.x + c->mon->m.width) {
current_corner_location &= ~CORNER_LOCATION_RIGHT; // 清除右标志位
}
if (target_geom.y + border_radius <= c->mon->m.y) {
current_corner_location &= ~CORNER_LOCATION_TOP; // 清除上标志位
}
if (target_geom.y + target_geom.height - border_radius >=
c->mon->m.y + c->mon->m.height) {
current_corner_location &= ~CORNER_LOCATION_BOTTOM; // 清除下标志位
}
return current_corner_location;
}
int is_special_animaiton_rule(Client *c) {
int visible_client_number = 0;
Client *count_c;
wl_list_for_each(count_c, &clients, link) {
if (count_c && VISIBLEON(count_c, selmon) && !count_c->isminied &&
!count_c->iskilling && !count_c->isfloating) {
visible_client_number++;
}
}
if (is_scroller_layout(selmon) && !c->isfloating) {
return DOWN;
} else if (visible_client_number < 2 && !c->isfloating) {
return DOWN;
} else if (visible_client_number == 2 && !c->isfloating && !new_is_master) {
return RIGHT;
} else if (!c->isfloating && new_is_master) {
return LEFT;
} else {
return UNDIR;
}
}
void set_client_open_animaiton(Client *c, struct wlr_box geo) {
int slide_direction;
int horizontal, horizontal_value;
int vertical, vertical_value;
int special_direction;
int center_x, center_y;
if ((!c->animation_type_open && strcmp(animation_type_open, "fade") == 0) ||
(c->animation_type_open &&
strcmp(c->animation_type_open, "fade") == 0)) {
c->animainit_geom.width = geo.width;
c->animainit_geom.height = geo.height;
c->animainit_geom.x = geo.x;
c->animainit_geom.y = geo.y;
return;
} else if ((!c->animation_type_open &&
strcmp(animation_type_open, "zoom") == 0) ||
(c->animation_type_open &&
strcmp(c->animation_type_open, "zoom") == 0)) {
c->animainit_geom.width = geo.width * zoom_initial_ratio;
c->animainit_geom.height = geo.height * zoom_initial_ratio;
c->animainit_geom.x = geo.x + (geo.width - c->animainit_geom.width) / 2;
c->animainit_geom.y =
geo.y + (geo.height - c->animainit_geom.height) / 2;
return;
} else {
special_direction = is_special_animaiton_rule(c);
center_x = c->geom.x + c->geom.width / 2;
center_y = c->geom.y + c->geom.height / 2;
if (special_direction == UNDIR) {
horizontal = c->mon->w.x + c->mon->w.width - center_x <
center_x - c->mon->w.x
? RIGHT
: LEFT;
horizontal_value = horizontal == LEFT
? center_x - c->mon->w.x
: c->mon->w.x + c->mon->w.width - center_x;
vertical = c->mon->w.y + c->mon->w.height - center_y <
center_y - c->mon->w.y
? DOWN
: UP;
vertical_value = vertical == UP
? center_y - c->mon->w.y
: c->mon->w.y + c->mon->w.height - center_y;
slide_direction =
horizontal_value < vertical_value ? horizontal : vertical;
} else {
slide_direction = special_direction;
}
c->animainit_geom.width = c->geom.width;
c->animainit_geom.height = c->geom.height;
switch (slide_direction) {
case UP:
c->animainit_geom.x = c->geom.x;
c->animainit_geom.y = c->mon->m.y - c->geom.height;
break;
case DOWN:
c->animainit_geom.x = c->geom.x;
c->animainit_geom.y =
c->geom.y + c->mon->m.height - (c->geom.y - c->mon->m.y);
break;
case LEFT:
c->animainit_geom.x = c->mon->m.x - c->geom.width;
c->animainit_geom.y = c->geom.y;
break;
case RIGHT:
c->animainit_geom.x =
c->geom.x + c->mon->m.width - (c->geom.x - c->mon->m.x);
c->animainit_geom.y = c->geom.y;
break;
default:
c->animainit_geom.x = c->geom.x;
c->animainit_geom.y = 0 - c->geom.height;
}
}
}
void snap_scene_buffer_apply_effect(struct wlr_scene_buffer *buffer, int sx,
int sy, void *data) {
BufferData *buffer_data = (BufferData *)data;
wlr_scene_buffer_set_dest_size(buffer, buffer_data->width,
buffer_data->height);
}
void scene_buffer_apply_effect(struct wlr_scene_buffer *buffer, int sx, int sy,
void *data) {
BufferData *buffer_data = (BufferData *)data;
if (buffer_data->should_scale && buffer_data->height_scale < 1 &&
buffer_data->width_scale < 1) {
buffer_data->should_scale = false;
}
if (buffer_data->should_scale && buffer_data->height_scale == 1 &&
buffer_data->width_scale < 1) {
buffer_data->should_scale = false;
}
if (buffer_data->should_scale && buffer_data->height_scale < 1 &&
buffer_data->width_scale == 1) {
buffer_data->should_scale = false;
}
struct wlr_scene_surface *scene_surface =
wlr_scene_surface_try_from_buffer(buffer);
if (scene_surface == NULL)
return;
struct wlr_surface *surface = scene_surface->surface;
if (buffer_data->should_scale) {
unsigned int surface_width = surface->current.width;
unsigned int surface_height = surface->current.height;
surface_width = buffer_data->width_scale < 1
? surface_width
: buffer_data->width_scale * surface_width;
surface_height = buffer_data->height_scale < 1
? surface_height
: buffer_data->height_scale * surface_height;
if (surface_width > buffer_data->width &&
wlr_subsurface_try_from_wlr_surface(surface) == NULL) {
surface_width = buffer_data->width;
}
if (surface_height > buffer_data->height &&
wlr_subsurface_try_from_wlr_surface(surface) == NULL) {
surface_height = buffer_data->height;
}
if (surface_width > buffer_data->width &&
wlr_subsurface_try_from_wlr_surface(surface) != NULL) {
return;
}
if (surface_height > buffer_data->height &&
wlr_subsurface_try_from_wlr_surface(surface) != NULL) {
return;
}
if (surface_height > 0 && surface_width > 0) {
wlr_scene_buffer_set_dest_size(buffer, surface_width,
surface_height);
}
}
// TODO: blur set, opacity set
if (wlr_xdg_popup_try_from_wlr_surface(surface) != NULL)
return;
wlr_scene_buffer_set_corner_radius(buffer, border_radius,
buffer_data->corner_location);
float target_opacity = buffer_data->percent + fadein_begin_opacity;
if (target_opacity > buffer_data->opacity) {
target_opacity = buffer_data->opacity;
}
wlr_scene_buffer_set_opacity(buffer, target_opacity);
}
void buffer_set_effect(Client *c, BufferData data) {
if (!c || c->iskilling)
return;
if (c->animation.tagouting || c->animation.tagouted ||
c->animation.tagining) {
data.should_scale = false;
}
if (c == grabc)
data.should_scale = false;
if (c->isfullscreen || (no_radius_when_single && c->mon &&
c->mon->visible_tiling_clients == 1)) {
data.corner_location = CORNER_LOCATION_NONE;
}
wlr_scene_node_for_each_buffer(&c->scene_surface->node,
scene_buffer_apply_effect, &data);
}
void client_draw_shadow(Client *c) {
if (c->iskilling || !client_surface(c)->mapped)
return;
if (!shadows || (!c->isfloating && shadow_only_floating)) {
wlr_scene_shadow_set_size(c->shadow, 0, 0);
return;
}
bool hit_no_border = check_hit_no_border(c);
enum corner_location current_corner_location =
c->isfullscreen || (no_radius_when_single && c->mon &&
c->mon->visible_tiling_clients == 1)
? CORNER_LOCATION_NONE
: CORNER_LOCATION_ALL;
unsigned int bwoffset = c->bw != 0 && hit_no_border ? c->bw : 0;
uint32_t width, height;
client_actual_size(c, &width, &height);
uint32_t delta = shadows_size + c->bw - bwoffset;
/* we calculate where to clip the shadow */
struct wlr_box client_box = {
.x = bwoffset,
.y = bwoffset,
.width = width - 2 * bwoffset,
.height = height - 2 * bwoffset,
};
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, &client_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 = current_corner_location,
};
struct wlr_box absolute_shadow_box = {
.x = shadow_box.x + c->animation.current.x,
.y = shadow_box.y + c->animation.current.y,
.width = shadow_box.width,
.height = shadow_box.height,
};
int right_offset, bottom_offset, left_offset, top_offset;
if (c == grabc) {
right_offset = 0;
bottom_offset = 0;
left_offset = 0;
top_offset = 0;
} else {
right_offset =
GEZERO(absolute_shadow_box.x + absolute_shadow_box.width -
c->mon->m.x - c->mon->m.width);
bottom_offset =
GEZERO(absolute_shadow_box.y + absolute_shadow_box.height -
c->mon->m.y - c->mon->m.height);
left_offset = GEZERO(c->mon->m.x - absolute_shadow_box.x);
top_offset = GEZERO(c->mon->m.y - absolute_shadow_box.y);
}
left_offset = MIN(left_offset, shadow_box.width);
right_offset = MIN(right_offset, shadow_box.width);
top_offset = MIN(top_offset, shadow_box.height);
bottom_offset = MIN(bottom_offset, shadow_box.height);
wlr_scene_node_set_position(&c->shadow->node, shadow_box.x + left_offset,
shadow_box.y + top_offset);
wlr_scene_shadow_set_size(
c->shadow, GEZERO(shadow_box.width - left_offset - right_offset),
GEZERO(shadow_box.height - top_offset - bottom_offset));
clipped_region.area.x = clipped_region.area.x - left_offset;
clipped_region.area.y = clipped_region.area.y - top_offset;
wlr_scene_shadow_set_clipped_region(c->shadow, clipped_region);
}
void apply_border(Client *c) {
if (!c || c->iskilling || !client_surface(c)->mapped)
return;
bool hit_no_border = check_hit_no_border(c);
enum corner_location current_corner_location =
c->isfullscreen || (no_radius_when_single && c->mon &&
c->mon->visible_tiling_clients == 1)
? CORNER_LOCATION_NONE
: CORNER_LOCATION_ALL;
// Handle no-border cases
if (hit_no_border && smartgaps) {
c->bw = 0;
c->fake_no_border = true;
} else if (hit_no_border && !smartgaps) {
wlr_scene_rect_set_size(c->border, 0, 0);
wlr_scene_node_set_position(&c->scene_surface->node, c->bw, c->bw);
c->fake_no_border = true;
return;
} else if (!c->isfullscreen && VISIBLEON(c, c->mon)) {
c->bw = c->isnoborder ? 0 : borderpx;
c->fake_no_border = false;
}
struct wlr_box clip_box = c->animation.current;
// 一但在GEZERO如果使用无符号那么其他数据也会转换为无符号导致没有负数出错
int bw = (int)c->bw;
int right_offset, bottom_offset, left_offset, top_offset;
if (c == grabc) {
right_offset = 0;
bottom_offset = 0;
left_offset = 0;
top_offset = 0;
} else {
right_offset =
GEZERO(c->animation.current.x + c->animation.current.width -
c->mon->m.x - c->mon->m.width);
bottom_offset =
GEZERO(c->animation.current.y + c->animation.current.height -
c->mon->m.y - c->mon->m.height);
left_offset = GEZERO(c->mon->m.x - c->animation.current.x);
top_offset = GEZERO(c->mon->m.y - c->animation.current.y);
}
int inner_surface_width = GEZERO(clip_box.width - 2 * bw);
int inner_surface_height = GEZERO(clip_box.height - 2 * bw);
int inner_surface_x = GEZERO(bw - left_offset);
int inner_surface_y = GEZERO(bw - top_offset);
int rect_x = left_offset;
int rect_y = top_offset;
int rect_width =
GEZERO(c->animation.current.width - left_offset - right_offset);
int rect_height =
GEZERO(c->animation.current.height - top_offset - bottom_offset);
if (left_offset > c->bw)
inner_surface_width = inner_surface_width - left_offset + c->bw;
if (top_offset > c->bw)
inner_surface_height = inner_surface_height - top_offset + c->bw;
if (right_offset > 0) {
inner_surface_width =
MIN(clip_box.width, inner_surface_width + right_offset);
}
if (bottom_offset > 0) {
inner_surface_height =
MIN(clip_box.height, inner_surface_height + bottom_offset);
}
struct clipped_region clipped_region = {
.area = {inner_surface_x, inner_surface_y, inner_surface_width,
inner_surface_height},
.corner_radius = border_radius,
.corners = current_corner_location,
};
wlr_scene_node_set_position(&c->scene_surface->node, c->bw, c->bw);
wlr_scene_rect_set_size(c->border, rect_width, rect_height);
wlr_scene_node_set_position(&c->border->node, rect_x, rect_y);
wlr_scene_rect_set_corner_radius(c->border, border_radius,
current_corner_location);
wlr_scene_rect_set_clipped_region(c->border, clipped_region);
}
struct ivec2 clip_to_hide(Client *c, struct wlr_box *clip_box) {
int offsetx = 0, offsety = 0, offsetw = 0, offseth = 0;
struct ivec2 offset = {0, 0, 0, 0};
if (!ISTILED(c) && !c->animation.tagining && !c->animation.tagouted &&
!c->animation.tagouting)
return offset;
int bottom_out_offset =
GEZERO(c->animation.current.y + c->animation.current.height -
c->mon->m.y - c->mon->m.height);
int right_out_offset =
GEZERO(c->animation.current.x + c->animation.current.width -
c->mon->m.x - c->mon->m.width);
int left_out_offset = GEZERO(c->mon->m.x - c->animation.current.x);
int top_out_offset = GEZERO(c->mon->m.y - c->animation.current.y);
// 必须转换为int否计算会没有负数导致判断错误
int bw = (int)c->bw;
/*
计算窗口表面超出屏幕四个方向的偏差,避免窗口超出屏幕
需要主要border超出屏幕的时候不计算如偏差之内而是
要等窗口表面超出才开始计算偏差
*/
if (ISTILED(c) || c->animation.tagining || c->animation.tagouted ||
c->animation.tagouting) {
if (left_out_offset > 0) {
offsetx = GEZERO(left_out_offset - bw);
clip_box->x = clip_box->x + offsetx;
clip_box->width = clip_box->width - offsetx;
} else if (right_out_offset > 0) {
offsetw = GEZERO(right_out_offset - bw);
clip_box->width = clip_box->width - offsetw;
}
if (top_out_offset > 0) {
offsety = GEZERO(top_out_offset - bw);
clip_box->y = clip_box->y + offsety;
clip_box->height = clip_box->height - offsety;
} else if (bottom_out_offset > 0) {
offseth = GEZERO(bottom_out_offset - bw);
clip_box->height = clip_box->height - offseth;
}
}
// 窗口表面超出屏幕四个方向的偏差
offset.x = offsetx;
offset.y = offsety;
offset.width = offsetw;
offset.height = offseth;
if ((clip_box->width + bw <= 0 || clip_box->height + bw <= 0) &&
(ISTILED(c) || c->animation.tagouting || c->animation.tagining)) {
c->is_clip_to_hide = true;
wlr_scene_node_set_enabled(&c->scene->node, false);
} else if (c->is_clip_to_hide && VISIBLEON(c, c->mon)) {
c->is_clip_to_hide = false;
wlr_scene_node_set_enabled(&c->scene->node, true);
}
return offset;
}
void client_apply_clip(Client *c, float factor) {
if (c->iskilling || !client_surface(c)->mapped)
return;
struct wlr_box clip_box;
bool should_render_client_surface = false;
struct ivec2 offset;
BufferData buffer_data;
float opacity, percent;
enum corner_location current_corner_location =
set_client_corner_location(c);
int bw = (int)c->bw;
if (!animations) {
c->animation.running = false;
c->need_output_flush = false;
c->animainit_geom = c->current = c->pending = c->animation.current =
c->geom;
client_get_clip(c, &clip_box);
offset = clip_to_hide(c, &clip_box);
apply_border(c);
client_draw_shadow(c);
opacity = c->isfullscreen ? 1
: c == selmon->sel ? c->focused_opacity
: c->unfocused_opacity;
if (clip_box.width <= 0 || clip_box.height <= 0) {
return;
}
wlr_scene_subsurface_tree_set_clip(&c->scene_surface->node, &clip_box);
buffer_set_effect(c, (BufferData){1.0f, 1.0f, clip_box.width,
clip_box.height, opacity, opacity,
current_corner_location, true});
return;
}
percent =
c->animation.action == OPEN && animation_fade_in && !c->nofadein
? (double)c->animation.passed_frames / c->animation.total_frames
: 1.0;
opacity = c->isfullscreen ? 1
: c == selmon->sel ? c->focused_opacity
: c->unfocused_opacity;
// 获取窗口动画实时位置矩形
unsigned int width, height;
client_actual_size(c, &width, &height);
// 计算出除了边框的窗口实际剪切大小
struct wlr_box geometry;
client_get_geometry(c, &geometry);
clip_box = (struct wlr_box){
.x = geometry.x,
.y = geometry.y,
.width = width - bw,
.height = height - bw,
};
if (client_is_x11(c)) {
clip_box.x = 0;
clip_box.y = 0;
}
// 检测窗口是否需要剪切超出屏幕部分,如果需要就调整实际要剪切的矩形
offset = clip_to_hide(c, &clip_box);
// 应用窗口装饰
apply_border(c);
client_draw_shadow(c);
// 如果窗口剪切区域已经剪切到0则不渲染窗口表面
if (clip_box.width <= 0 || clip_box.height <= 0) {
should_render_client_surface = false;
wlr_scene_node_set_enabled(&c->scene_surface->node, false);
} else {
should_render_client_surface = true;
wlr_scene_node_set_enabled(&c->scene_surface->node, true);
}
// 不用在执行下面的窗口表面剪切和缩放等效果操作
if (!should_render_client_surface) {
return;
}
// 应用窗口表面剪切
wlr_scene_subsurface_tree_set_clip(&c->scene_surface->node, &clip_box);
// 获取剪切后的表面的实际大小用于计算缩放
int acutal_surface_width = geometry.width - offset.x - offset.width;
int acutal_surface_height = geometry.height - offset.y - offset.height;
if (acutal_surface_width <= 0 || acutal_surface_height <= 0)
return;
buffer_data.should_scale = true;
buffer_data.width = clip_box.width;
buffer_data.height = clip_box.height;
buffer_data.corner_location = current_corner_location;
buffer_data.percent = percent;
buffer_data.opacity = opacity;
if (factor == 1.0) {
buffer_data.width_scale = 1.0;
buffer_data.height_scale = 1.0;
} else {
buffer_data.width_scale =
(float)buffer_data.width / acutal_surface_width;
buffer_data.height_scale =
(float)buffer_data.height / acutal_surface_height;
}
buffer_set_effect(c, buffer_data);
}
void fadeout_client_animation_next_tick(Client *c) {
if (!c)
return;
BufferData buffer_data;
double animation_passed =
(double)c->animation.passed_frames / c->animation.total_frames;
int type = c->animation.action = c->animation.action;
double factor = find_animation_curve_at(animation_passed, type);
unsigned int width =
c->animation.initial.width +
(c->current.width - c->animation.initial.width) * factor;
unsigned int height =
c->animation.initial.height +
(c->current.height - c->animation.initial.height) * factor;
unsigned int x = c->animation.initial.x +
(c->current.x - c->animation.initial.x) * factor;
unsigned int y = c->animation.initial.y +
(c->current.y - c->animation.initial.y) * factor;
wlr_scene_node_set_position(&c->scene->node, x, y);
c->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 && !c->nofadeout)
wlr_scene_node_for_each_buffer(&c->scene->node,
scene_buffer_apply_opacity, &opacity);
if ((c->animation_type_close &&
strcmp(c->animation_type_close, "zoom") == 0) ||
(!c->animation_type_close &&
strcmp(animation_type_close, "zoom") == 0)) {
buffer_data.width = width;
buffer_data.height = height;
buffer_data.width_scale = animation_passed;
buffer_data.height_scale = animation_passed;
wlr_scene_node_for_each_buffer(
&c->scene->node, snap_scene_buffer_apply_effect, &buffer_data);
}
if (animation_passed == 1.0) {
wl_list_remove(&c->fadeout_link);
wlr_scene_node_destroy(&c->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;
int type = c->animation.action == NONE ? MOVE : c->animation.action;
double factor = find_animation_curve_at(animation_passed, type);
Client *pointer_c = NULL;
double sx = 0, sy = 0;
struct wlr_surface *surface = NULL;
unsigned int width =
c->animation.initial.width +
(c->current.width - c->animation.initial.width) * factor;
unsigned int height =
c->animation.initial.height +
(c->current.height - c->animation.initial.height) * factor;
unsigned int x = c->animation.initial.x +
(c->current.x - c->animation.initial.x) * factor;
unsigned int y = c->animation.initial.y +
(c->current.y - c->animation.initial.y) * factor;
wlr_scene_node_set_position(&c->scene->node, x, y);
c->animation.current = (struct wlr_box){
.x = x,
.y = y,
.width = width,
.height = height,
};
c->is_pending_open_animation = false;
if (animation_passed == 1.0) {
// clear the open action state
// To prevent him from being mistaken that
// it's still in the opening animation in resize
c->animation.action = MOVE;
c->animation.tagining = false;
c->animation.running = false;
if (c->animation.tagouting) {
c->animation.tagouting = false;
wlr_scene_node_set_enabled(&c->scene->node, false);
client_set_suspended(c, true);
c->animation.tagouted = true;
c->animation.current = c->geom;
}
xytonode(cursor->x, cursor->y, NULL, &pointer_c, NULL, &sx, &sy);
surface =
pointer_c && pointer_c == c ? client_surface(pointer_c) : NULL;
if (surface && pointer_c == selmon->sel) {
wlr_seat_pointer_notify_enter(seat, surface, sx, sy);
}
// end flush in next frame, not the current frame
c->need_output_flush = false;
} else {
c->animation.passed_frames++;
}
client_apply_clip(c, factor);
}
void init_fadeout_client(Client *c) {
if (!c->mon || client_is_unmanaged(c))
return;
if (!c->scene) {
return;
}
if ((c->animation_type_close &&
strcmp(c->animation_type_close, "none") == 0) ||
(!c->animation_type_close &&
strcmp(animation_type_close, "none") == 0)) {
return;
}
Client *fadeout_cient = ecalloc(1, sizeof(*fadeout_cient));
wlr_scene_node_set_enabled(&c->scene->node, true);
client_set_border_color(c, bordercolor);
fadeout_cient->scene =
wlr_scene_tree_snapshot(&c->scene->node, layers[LyrFadeOut]);
wlr_scene_node_set_enabled(&c->scene->node, false);
if (!fadeout_cient->scene) {
free(fadeout_cient);
return;
}
fadeout_cient->animation.duration = animation_duration_close;
fadeout_cient->geom = fadeout_cient->current =
fadeout_cient->animainit_geom = fadeout_cient->animation.initial =
c->animation.current;
fadeout_cient->mon = c->mon;
fadeout_cient->animation_type_close = c->animation_type_close;
fadeout_cient->animation.action = CLOSE;
fadeout_cient->bw = c->bw;
fadeout_cient->nofadeout = c->nofadeout;
// 这里snap节点的坐标设置是使用的相对坐标所以不能加上原来坐标
// 这跟普通node有区别
fadeout_cient->animation.initial.x = 0;
fadeout_cient->animation.initial.y = 0;
if ((!c->animation_type_close &&
strcmp(animation_type_close, "fade") == 0) ||
(c->animation_type_close &&
strcmp(c->animation_type_close, "fade") == 0)) {
fadeout_cient->current.x = 0;
fadeout_cient->current.y = 0;
fadeout_cient->current.width = 0;
fadeout_cient->current.height = 0;
} else if ((c->animation_type_close &&
strcmp(c->animation_type_close, "slide") == 0) ||
(!c->animation_type_close &&
strcmp(animation_type_close, "slide") == 0)) {
fadeout_cient->current.y =
c->geom.y + c->geom.height / 2 > c->mon->m.y + c->mon->m.height / 2
? c->mon->m.height -
(c->animation.current.y - c->mon->m.y) // down out
: c->mon->m.y - c->geom.height; // up out
fadeout_cient->current.x = 0; // x无偏差垂直划出
} else {
fadeout_cient->current.y =
(fadeout_cient->geom.height -
fadeout_cient->geom.height * zoom_end_ratio) /
2;
fadeout_cient->current.x =
(fadeout_cient->geom.width -
fadeout_cient->geom.width * zoom_end_ratio) /
2;
fadeout_cient->current.width =
fadeout_cient->geom.width * zoom_end_ratio;
fadeout_cient->current.height =
fadeout_cient->geom.height * zoom_end_ratio;
}
fadeout_cient->animation.passed_frames = 0;
fadeout_cient->animation.total_frames =
fadeout_cient->animation.duration / output_frame_duration_ms();
wlr_scene_node_set_enabled(&fadeout_cient->scene->node, true);
wl_list_insert(&fadeout_clients, &fadeout_cient->fadeout_link);
// 请求刷新屏幕
wlr_output_schedule_frame(c->mon->wlr_output);
}
void client_commit(Client *c) {
c->current = c->pending; // 设置动画的结束位置
if (c->animation.should_animate) {
if (!c->animation.running) {
c->animation.current = c->animainit_geom;
}
c->animation.initial = c->animainit_geom;
// 设置动画速度
c->animation.passed_frames = 0;
c->animation.total_frames =
c->animation.duration / output_frame_duration_ms();
// 标记动画开始
c->animation.running = true;
c->animation.should_animate = false;
} else {
// 如果动画没有开始,且被判定为不应该动画,
// 则设置总帧数为1,不然其他地方一旦获取动画
// 进度,总帧数作为分母会造成除零
// 比如动画类型为none的时候
if (!c->animation.running) {
c->animation.passed_frames = 1;
c->animation.total_frames = 1;
}
}
// 请求刷新屏幕
wlr_output_schedule_frame(c->mon->wlr_output);
}
void client_set_pending_state(Client *c) {
// 判断是否需要动画
if (!animations) {
c->animation.should_animate = false;
} else if (animations && c->animation.tagining) {
c->animation.should_animate = true;
} else if (!animations || c == grabc ||
(!c->is_pending_open_animation &&
wlr_box_equal(&c->current, &c->pending))) {
c->animation.should_animate = false;
} else {
c->animation.should_animate = true;
}
if (((c->animation_type_open &&
strcmp(c->animation_type_open, "none") == 0) ||
(!c->animation_type_open &&
strcmp(animation_type_open, "none") == 0)) &&
c->animation.action == OPEN) {
c->animation.action = MOVE;
c->is_pending_open_animation = false;
c->animation.should_animate = false;
}
// 开始动画
client_commit(c);
c->dirty = true;
}
void resize(Client *c, struct wlr_box geo, int interact) {
// 动画设置的起始函数,这里用来计算一些动画的起始值
// 动画起始位置大小是由于c->animainit_geom确定的
if (!c || !c->mon || !client_surface(c)->mapped)
return;
struct wlr_box *bbox;
struct wlr_box clip;
if (!c->mon)
return;
c->need_output_flush = true;
c->dirty = true;
// oldgeom = c->geom;
bbox = (interact || c->isfloating || c->isfullscreen) ? &sgeom : &c->mon->w;
if (is_scroller_layout(c->mon) && (!c->isfloating || c == grabc)) {
c->geom = geo;
c->geom.width = MAX(1 + 2 * (int)c->bw, c->geom.width);
c->geom.height = MAX(1 + 2 * (int)c->bw, c->geom.height);
} else { // 这里会限制不允许窗口划出屏幕
c->geom = geo;
applybounds(
c,
bbox); // 去掉这个推荐的窗口大小,因为有时推荐的窗口特别大导致平铺异常
}
if (!c->isnosizehint && !c->ismaxmizescreen && !c->isfullscreen &&
c->isfloating) {
client_set_size_bound(c);
}
if (!c->is_pending_open_animation) {
c->animation.begin_fade_in = false;
}
if (c->animation.action == OPEN && !c->animation.tagining &&
!c->animation.tagouting && wlr_box_equal(&c->geom, &c->current)) {
c->animation.action = c->animation.action;
} else if (c->animation.tagouting) {
c->animation.duration = animation_duration_tag;
c->animation.action = TAG;
} else if (c->animation.tagining) {
c->animation.duration = animation_duration_tag;
c->animation.action = TAG;
} else if (c->is_pending_open_animation) {
c->animation.duration = animation_duration_open;
c->animation.action = OPEN;
} else {
c->animation.duration = animation_duration_move;
c->animation.action = MOVE;
}
// 动画起始位置大小设置
if (c->animation.tagouting) {
c->animainit_geom = c->animation.current;
} else if (c->animation.tagining) {
c->animainit_geom.height = c->animation.current.height;
c->animainit_geom.width = c->animation.current.width;
} else if (c->is_pending_open_animation) {
set_client_open_animaiton(c, c->geom);
} else {
c->animainit_geom = c->animation.current;
}
if (c->isnoborder || c->iskilling) {
c->bw = 0;
}
// c->geom 是真实的窗口大小和位置,跟过度的动画无关,用于计算布局
c->configure_serial = client_set_size(c, c->geom.width - 2 * c->bw,
c->geom.height - 2 * c->bw);
if (c == grabc) {
c->animation.running = false;
c->need_output_flush = false;
c->animainit_geom = c->current = c->pending = c->animation.current =
c->geom;
wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y);
client_draw_shadow(c);
apply_border(c);
client_get_clip(c, &clip);
wlr_scene_subsurface_tree_set_clip(&c->scene_surface->node, &clip);
return;
}
// 如果不是工作区切换时划出去的窗口,就让动画的结束位置,就是上面的真实位置和大小
// c->pending 决定动画的终点一般在其他调用resize的函数的附近设置了
if (!c->animation.tagouting && !c->iskilling) {
c->pending = c->geom;
}
if (c->swallowedby && c->animation.action == OPEN) {
c->animainit_geom = c->swallowedby->animation.current;
}
if (c->swallowing) {
c->animainit_geom = c->geom;
}
if ((c->isglobal || c->isunglobal) && c->isfloating &&
c->animation.action == TAG) {
c->animainit_geom = c->geom;
}
// 开始应用动画设置
client_set_pending_state(c);
setborder_color(c);
}
bool client_draw_fadeout_frame(Client *c) {
if (!c)
return false;
fadeout_client_animation_next_tick(c);
return true;
}
bool client_draw_frame(Client *c) {
if (!c || !client_surface(c)->mapped)
return false;
if (c->isfullscreen) {
client_set_opacity(c, 1);
} else if (c == selmon->sel && !c->animation.running) {
client_set_opacity(c, c->focused_opacity);
} else if (!c->animation.running) {
client_set_opacity(c, c->unfocused_opacity);
}
if (!c->need_output_flush)
return false;
if (animations && c->animation.running) {
client_animation_next_tick(c);
} else {
wlr_scene_node_set_position(&c->scene->node, c->pending.x,
c->pending.y);
c->animation.current = c->animainit_geom = c->animation.initial =
c->pending = c->current = c->geom;
client_apply_clip(c, 1.0);
c->need_output_flush = false;
}
return true;
}