diff --git a/README.md b/README.md index 087bf13..d512f39 100644 --- a/README.md +++ b/README.md @@ -285,3 +285,15 @@ Read The Friendly Manual on packaging software in your distribution first. - https://github.com/swaywm/sway - Sample of Wayland protocol - https://github.com/wlrfx/scenefx - Make it simple to add window effect. + + +# Sponsor +At present, I can only accept sponsorship through an encrypted connection. +If you find this project helpful to you, you can offer sponsorship in the following ways. + +image + + +Thanks to the following friends for their sponsorship of this project + +[@tonybanters](https://github.com/tonybanters) diff --git a/config.conf b/config.conf index 5483a14..6cbb3a2 100644 --- a/config.conf +++ b/config.conf @@ -26,7 +26,7 @@ focused_opacity=1.0 unfocused_opacity=1.0 # Animation Configuration(support type:zoom,slide) -# tag_animation_direction: 0-horizontal,1-vertical +# tag_animation_direction: 1-horizontal,0-vertical animations=1 layer_animations=1 animation_type_open=slide diff --git a/meson.build b/meson.build index c56650e..0565609 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('mango', ['c', 'cpp'], - version : '0.10.9', + version : '0.12.0', ) subdir('protocols') diff --git a/mmsg/arg.h b/mmsg/arg.h index ccbd65a..c3b0d7b 100644 --- a/mmsg/arg.h +++ b/mmsg/arg.h @@ -8,13 +8,13 @@ extern char *argv0; -/* use main(int argc, char *argv[]) */ +/* use main(int32_t argc, char *argv[]) */ #define ARGBEGIN \ for (argv0 = *argv, argv++, argc--; \ argv[0] && argv[0][0] == '-' && argv[0][1]; argc--, argv++) { \ char argc_; \ char **argv_; \ - int brk_; \ + int32_t brk_; \ if (argv[0][1] == '-' && argv[0][2] == '\0') { \ argv++; \ argc--; \ diff --git a/mmsg/mmsg.c b/mmsg/mmsg.c index 2bbe870..ba073aa 100644 --- a/mmsg/mmsg.c +++ b/mmsg/mmsg.c @@ -25,31 +25,31 @@ static enum { WATCH = 1 << 2 | GET, } mode = NONE; -static int Oflag; -static int Tflag; -static int Lflag; -static int oflag; -static int tflag; -static int lflag; -static int cflag; -static int vflag; -static int mflag; -static int fflag; -static int qflag; -static int dflag; -static int xflag; -static int eflag; -static int kflag; -static int bflag; -static int Aflag; +static int32_t Oflag; +static int32_t Tflag; +static int32_t Lflag; +static int32_t oflag; +static int32_t tflag; +static int32_t lflag; +static int32_t cflag; +static int32_t vflag; +static int32_t mflag; +static int32_t fflag; +static int32_t qflag; +static int32_t dflag; +static int32_t xflag; +static int32_t eflag; +static int32_t kflag; +static int32_t bflag; +static int32_t Aflag; static uint32_t occ, seltags, total_clients, urg; static char *output_name; -static int tagcount; +static int32_t tagcount; static char *tagset; static char *layout_name; -static int layoutcount, layout_idx; +static int32_t layoutcount, layout_idx; static char *client_tags; static char *dispatch_cmd; static char *dispatch_arg1; @@ -87,7 +87,7 @@ static void noop_description(void *data, struct wl_output *wl_output, // 将 n 转换为 9 位二进制字符串,结果存入 buf(至少长度 10) void bin_str_9bits(char *buf, uint32_t n) { - for (int i = 8; i >= 0; i--) { + for (int32_t i = 8; i >= 0; i--) { *buf++ = ((n >> i) & 1) ? '1' : '0'; } *buf = '\0'; // 字符串结尾 @@ -324,7 +324,7 @@ static void dwl_ipc_output_frame(void *data, if (tflag) { uint32_t mask = seltags; char *t = tagset; - int i = 0; + int32_t i = 0; for (; *t && *t >= '0' && *t <= '9'; t++) i = *t - '0' + i * 10; @@ -354,7 +354,7 @@ static void dwl_ipc_output_frame(void *data, if (cflag) { uint32_t and = ~0, xor = 0; char *t = client_tags; - int i = 0; + int32_t i = 0; for (; *t && *t >= '0' && *t <= '9'; t++) i = *t - '0' + i * 10; @@ -509,7 +509,7 @@ static void usage(void) { exit(2); } -int main(int argc, char *argv[]) { +int32_t main(int32_t argc, char *argv[]) { ARGBEGIN { case 'q': qflag = 1; diff --git a/src/animation/client.h b/src/animation/client.h index 56ca3d6..8de9b06 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -1,10 +1,10 @@ -void client_actual_size(Client *c, uint32_t *width, uint32_t *height) { - *width = c->animation.current.width - 2 * c->bw; +void client_actual_size(Client *c, int32_t *width, int32_t *height) { + *width = c->animation.current.width - 2 * (int32_t)c->bw; - *height = c->animation.current.height - 2 * c->bw; + *height = c->animation.current.height - 2 * (int32_t)c->bw; } -void set_rect_size(struct wlr_scene_rect *rect, int width, int height) { +void set_rect_size(struct wlr_scene_rect *rect, int32_t width, int32_t height) { wlr_scene_rect_set_size(rect, GEZERO(width), GEZERO(height)); } @@ -47,7 +47,7 @@ bool is_horizontal_right_stack_layout(Monitor *m) { return false; } -int is_special_animaiton_rule(Client *c) { +int32_t is_special_animaiton_rule(Client *c) { if (is_scroller_layout(c->mon) && !c->isfloating) { return DOWN; @@ -71,11 +71,11 @@ int is_special_animaiton_rule(Client *c) { } 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; + int32_t slide_direction; + int32_t horizontal, horizontal_value; + int32_t vertical, vertical_value; + int32_t special_direction; + int32_t center_x, center_y; if ((!c->animation_type_open && strcmp(animation_type_open, "fade") == 0) || (c->animation_type_open && @@ -147,15 +147,15 @@ void set_client_open_animaiton(Client *c, struct wlr_box geo) { } } -void snap_scene_buffer_apply_effect(struct wlr_scene_buffer *buffer, int sx, - int sy, void *data) { +void snap_scene_buffer_apply_effect(struct wlr_scene_buffer *buffer, int32_t sx, + int32_t 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) { +void scene_buffer_apply_effect(struct wlr_scene_buffer *buffer, int32_t sx, + int32_t sy, void *data) { BufferData *buffer_data = (BufferData *)data; if (buffer_data->should_scale && buffer_data->height_scale < 1 && @@ -183,8 +183,8 @@ void scene_buffer_apply_effect(struct wlr_scene_buffer *buffer, int sx, int sy, if (buffer_data->should_scale) { - uint32_t surface_width = surface->current.width; - uint32_t surface_height = surface->current.height; + int32_t surface_width = surface->current.width; + int32_t surface_height = surface->current.height; surface_width = buffer_data->width_scale < 1 ? surface_width @@ -271,19 +271,19 @@ void client_draw_shadow(Client *c) { ? CORNER_LOCATION_NONE : CORNER_LOCATION_ALL; - int bwoffset = c->bw != 0 && hit_no_border ? (int)c->bw : 0; + int32_t bwoffset = c->bw != 0 && hit_no_border ? (int32_t)c->bw : 0; - uint32_t width, height; + int32_t width, height; client_actual_size(c, &width, &height); - uint32_t delta = shadows_size + c->bw - bwoffset; + int32_t delta = shadows_size + (int32_t)c->bw - bwoffset; /* we calculate where to clip the shadow */ struct wlr_box client_box = { .x = bwoffset, .y = bwoffset, - .width = width + (int)c->bw - bwoffset, - .height = height + (int)c->bw - bwoffset, + .width = width + (int32_t)c->bw - bwoffset, + .height = height + (int32_t)c->bw - bwoffset, }; struct wlr_box shadow_box = { @@ -313,7 +313,7 @@ void client_draw_shadow(Client *c) { .height = shadow_box.height, }; - int right_offset, bottom_offset, left_offset, top_offset; + int32_t right_offset, bottom_offset, left_offset, top_offset; if (c == grabc) { right_offset = 0; @@ -363,7 +363,6 @@ void apply_border(Client *c) { current_corner_location = set_client_corner_location(c); } - // Handle no-border cases if (hit_no_border && smartgaps) { c->bw = 0; c->fake_no_border = true; @@ -379,9 +378,9 @@ void apply_border(Client *c) { struct wlr_box clip_box = c->animation.current; // 一但在GEZERO如果使用无符号,那么其他数据也会转换为无符号导致没有负数出错 - int bw = (int)c->bw; + int32_t bw = (int32_t)c->bw; - int right_offset, bottom_offset, left_offset, top_offset; + int32_t right_offset, bottom_offset, left_offset, top_offset; if (c == grabc) { right_offset = 0; @@ -400,25 +399,27 @@ void apply_border(Client *c) { 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); + int32_t inner_surface_width = GEZERO(clip_box.width - 2 * bw); + int32_t 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); + int32_t inner_surface_x = GEZERO(bw - left_offset); + int32_t inner_surface_y = GEZERO(bw - top_offset); - int rect_x = left_offset; - int rect_y = top_offset; + int32_t rect_x = left_offset; + int32_t rect_y = top_offset; - int rect_width = + int32_t rect_width = GEZERO(c->animation.current.width - left_offset - right_offset); - int rect_height = + int32_t 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; + inner_surface_width = + inner_surface_width - left_offset + (int32_t)c->bw; if (top_offset > c->bw) - inner_surface_height = inner_surface_height - top_offset + c->bw; + inner_surface_height = + inner_surface_height - top_offset + (int32_t)c->bw; if (right_offset > 0) { inner_surface_width = @@ -446,24 +447,24 @@ void apply_border(Client *c) { } struct ivec2 clip_to_hide(Client *c, struct wlr_box *clip_box) { - int offsetx = 0, offsety = 0, offsetw = 0, offseth = 0; + int32_t offsetx = 0, offsety = 0, offsetw = 0, offseth = 0; struct ivec2 offset = {0, 0, 0, 0}; if (!ISSCROLLTILED(c) && !c->animation.tagining && !c->animation.tagouted && !c->animation.tagouting) return offset; - int bottom_out_offset = + int32_t bottom_out_offset = GEZERO(c->animation.current.y + c->animation.current.height - c->mon->m.y - c->mon->m.height); - int right_out_offset = + int32_t 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); + int32_t left_out_offset = GEZERO(c->mon->m.x - c->animation.current.x); + int32_t top_out_offset = GEZERO(c->mon->m.y - c->animation.current.y); // 必须转换为int,否计算会没有负数导致判断错误 - int bw = (int)c->bw; + int32_t bw = (int32_t)c->bw; /* 计算窗口表面超出屏幕四个方向的偏差,避免窗口超出屏幕 @@ -547,7 +548,7 @@ void client_apply_clip(Client *c, float factor) { } // 获取窗口动画实时位置矩形 - uint32_t width, height; + int32_t width, height; client_actual_size(c, &width, &height); // 计算出除了边框的窗口实际剪切大小 @@ -590,8 +591,8 @@ void client_apply_clip(Client *c, float factor) { 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; + int32_t acutal_surface_width = geometry.width - offset.x - offset.width; + int32_t acutal_surface_height = geometry.height - offset.y - offset.height; if (acutal_surface_width <= 0 || acutal_surface_height <= 0) return; @@ -623,25 +624,24 @@ void fadeout_client_animation_next_tick(Client *c) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - uint32_t passed_time = timespec_to_ms(&now) - c->animation.time_started; + int32_t passed_time = timespec_to_ms(&now) - c->animation.time_started; double animation_passed = c->animation.duration ? (double)passed_time / (double)c->animation.duration : 1.0; - int type = c->animation.action = c->animation.action; + int32_t type = c->animation.action = c->animation.action; double factor = find_animation_curve_at(animation_passed, type); - 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; + int32_t width = c->animation.initial.width + + (c->current.width - c->animation.initial.width) * factor; + int32_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; + int32_t x = c->animation.initial.x + + (c->current.x - c->animation.initial.x) * factor; + int32_t y = c->animation.initial.y + + (c->current.y - c->animation.initial.y) * factor; wlr_scene_node_set_position(&c->scene->node, x, y); @@ -690,24 +690,23 @@ void client_animation_next_tick(Client *c) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - uint32_t passed_time = timespec_to_ms(&now) - c->animation.time_started; + int32_t passed_time = timespec_to_ms(&now) - c->animation.time_started; double animation_passed = c->animation.duration ? (double)passed_time / (double)c->animation.duration : 1.0; - int type = c->animation.action == NONE ? MOVE : c->animation.action; + int32_t 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; - 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; + int32_t width = c->animation.initial.width + + (c->current.width - c->animation.initial.width) * factor; + int32_t height = c->animation.initial.height + + (c->current.height - c->animation.initial.height) * factor; int32_t x = c->animation.initial.x + (c->current.x - c->animation.initial.x) * factor; @@ -840,8 +839,7 @@ void init_fadeout_client(Client *c) { wl_list_insert(&fadeout_clients, &fadeout_cient->fadeout_link); // 请求刷新屏幕 - if (c->mon) - wlr_output_schedule_frame(c->mon->wlr_output); + request_fresh_all_monitors(); } void client_commit(Client *c) { @@ -860,8 +858,7 @@ void client_commit(Client *c) { c->animation.should_animate = false; } // 请求刷新屏幕 - if (c->mon) - wlr_output_schedule_frame(c->mon->wlr_output); + request_fresh_all_monitors(); } void client_set_pending_state(Client *c) { @@ -910,7 +907,7 @@ void client_set_pending_state(Client *c) { c->dirty = true; } -void resize(Client *c, struct wlr_box geo, int interact) { +void resize(Client *c, struct wlr_box geo, int32_t interact) { // 动画设置的起始函数,这里用来计算一些动画的起始值 // 动画起始位置大小是由于c->animainit_geom确定的 @@ -932,8 +929,8 @@ void resize(Client *c, struct wlr_box geo, int interact) { 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); + c->geom.width = MAX(1 + 2 * (int32_t)c->bw, c->geom.width); + c->geom.height = MAX(1 + 2 * (int32_t)c->bw, c->geom.height); } else { // 这里会限制不允许窗口划出屏幕 c->geom = geo; applybounds( @@ -983,6 +980,12 @@ void resize(Client *c, struct wlr_box geo, int interact) { c->bw = 0; } + bool hit_no_border = check_hit_no_border(c); + if (hit_no_border && smartgaps) { + c->bw = 0; + c->fake_no_border = true; + } + // c->geom 是真实的窗口大小和位置,跟过度的动画无关,用于计算布局 c->configure_serial = client_set_size(c, c->geom.width - 2 * c->bw, c->geom.height - 2 * c->bw); @@ -1051,20 +1054,11 @@ void client_set_focused_opacity_animation(Client *c) { sizeof(c->opacity_animation.target_border_color)); c->opacity_animation.target_opacity = c->focused_opacity; c->opacity_animation.time_started = get_now_in_ms(); - if (c->opacity_animation.running) { - memcpy(c->opacity_animation.initial_border_color, - c->opacity_animation.current_border_color, - sizeof(c->opacity_animation.initial_border_color)); - c->opacity_animation.initial_opacity = - c->opacity_animation.current_opacity; - } else { - memcpy(c->opacity_animation.initial_border_color, border_color, - sizeof(c->opacity_animation.initial_border_color)); - memcpy(c->opacity_animation.current_border_color, border_color, - sizeof(c->opacity_animation.current_border_color)); - c->opacity_animation.initial_opacity = c->unfocused_opacity; - c->opacity_animation.current_opacity = c->unfocused_opacity; - } + memcpy(c->opacity_animation.initial_border_color, + c->opacity_animation.current_border_color, + sizeof(c->opacity_animation.initial_border_color)); + c->opacity_animation.initial_opacity = c->opacity_animation.current_opacity; + c->opacity_animation.running = true; } @@ -1084,20 +1078,10 @@ void client_set_unfocused_opacity_animation(Client *c) { c->opacity_animation.target_opacity = c->unfocused_opacity; c->opacity_animation.time_started = get_now_in_ms(); - if (c->opacity_animation.running) { - memcpy(c->opacity_animation.initial_border_color, - c->opacity_animation.current_border_color, - sizeof(c->opacity_animation.initial_border_color)); - c->opacity_animation.initial_opacity = - c->opacity_animation.current_opacity; - } else { - memcpy(c->opacity_animation.initial_border_color, border_color, - sizeof(c->opacity_animation.initial_border_color)); - memcpy(c->opacity_animation.current_border_color, border_color, - sizeof(c->opacity_animation.current_border_color)); - c->opacity_animation.initial_opacity = c->focused_opacity; - c->opacity_animation.current_opacity = c->focused_opacity; - } + memcpy(c->opacity_animation.initial_border_color, + c->opacity_animation.current_border_color, + sizeof(c->opacity_animation.initial_border_color)); + c->opacity_animation.initial_opacity = c->opacity_animation.current_opacity; c->opacity_animation.running = true; } @@ -1113,7 +1097,7 @@ bool client_apply_focus_opacity(Client *c) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - uint32_t passed_time = timespec_to_ms(&now) - c->animation.time_started; + int32_t passed_time = timespec_to_ms(&now) - c->animation.time_started; double linear_progress = c->animation.duration ? (double)passed_time / (double)c->animation.duration @@ -1132,13 +1116,18 @@ bool client_apply_focus_opacity(Client *c) { if (target_opacity > opacity) { target_opacity = opacity; } + memcpy(c->opacity_animation.current_border_color, + c->opacity_animation.target_border_color, + sizeof(c->opacity_animation.current_border_color)); + c->opacity_animation.current_opacity = target_opacity; client_set_opacity(c, target_opacity); + client_set_border_color(c, c->opacity_animation.target_border_color); } else if (animations && c->opacity_animation.running) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - uint32_t passed_time = + int32_t passed_time = timespec_to_ms(&now) - c->opacity_animation.time_started; double linear_progress = c->opacity_animation.duration @@ -1155,7 +1144,7 @@ bool client_apply_focus_opacity(Client *c) { client_set_opacity(c, c->opacity_animation.current_opacity); // Animate border color - for (int i = 0; i < 4; i++) { + for (int32_t i = 0; i < 4; i++) { c->opacity_animation.current_border_color[i] = c->opacity_animation.initial_border_color[i] + (c->opacity_animation.target_border_color[i] - @@ -1163,7 +1152,7 @@ bool client_apply_focus_opacity(Client *c) { eased_progress; } client_set_border_color(c, c->opacity_animation.current_border_color); - if (linear_progress == 1.0f) { + if (linear_progress >= 1.0f) { c->opacity_animation.running = false; } else { return true; diff --git a/src/animation/common.h b/src/animation/common.h index 6e6fa04..9f022db 100644 --- a/src/animation/common.h +++ b/src/animation/common.h @@ -1,4 +1,4 @@ -struct dvec2 calculate_animation_curve_at(double t, int type) { +struct dvec2 calculate_animation_curve_at(double t, int32_t type) { struct dvec2 point; double *animation_curve; if (type == MOVE) { @@ -41,41 +41,41 @@ void init_baked_points(void) { baked_points_opafadeout = calloc(BAKED_POINTS_COUNT, sizeof(*baked_points_opafadeout)); - for (uint32_t i = 0; i < BAKED_POINTS_COUNT; i++) { + for (int32_t i = 0; i < BAKED_POINTS_COUNT; i++) { baked_points_move[i] = calculate_animation_curve_at( (double)i / (BAKED_POINTS_COUNT - 1), MOVE); } - for (uint32_t i = 0; i < BAKED_POINTS_COUNT; i++) { + for (int32_t i = 0; i < BAKED_POINTS_COUNT; i++) { baked_points_open[i] = calculate_animation_curve_at( (double)i / (BAKED_POINTS_COUNT - 1), OPEN); } - for (uint32_t i = 0; i < BAKED_POINTS_COUNT; i++) { + for (int32_t i = 0; i < BAKED_POINTS_COUNT; i++) { baked_points_tag[i] = calculate_animation_curve_at( (double)i / (BAKED_POINTS_COUNT - 1), TAG); } - for (uint32_t i = 0; i < BAKED_POINTS_COUNT; i++) { + for (int32_t i = 0; i < BAKED_POINTS_COUNT; i++) { baked_points_close[i] = calculate_animation_curve_at( (double)i / (BAKED_POINTS_COUNT - 1), CLOSE); } - for (uint32_t i = 0; i < BAKED_POINTS_COUNT; i++) { + for (int32_t i = 0; i < BAKED_POINTS_COUNT; i++) { baked_points_focus[i] = calculate_animation_curve_at( (double)i / (BAKED_POINTS_COUNT - 1), FOCUS); } - for (uint32_t i = 0; i < BAKED_POINTS_COUNT; i++) { + for (int32_t i = 0; i < BAKED_POINTS_COUNT; i++) { baked_points_opafadein[i] = calculate_animation_curve_at( (double)i / (BAKED_POINTS_COUNT - 1), OPAFADEIN); } - for (uint32_t i = 0; i < BAKED_POINTS_COUNT; i++) { + for (int32_t i = 0; i < BAKED_POINTS_COUNT; i++) { baked_points_opafadeout[i] = calculate_animation_curve_at( (double)i / (BAKED_POINTS_COUNT - 1), OPAFADEOUT); } } -double find_animation_curve_at(double t, int type) { - uint32_t down = 0; - uint32_t up = BAKED_POINTS_COUNT - 1; +double find_animation_curve_at(double t, int32_t type) { + int32_t down = 0; + int32_t up = BAKED_POINTS_COUNT - 1; - uint32_t middle = (up + down) / 2; + int32_t middle = (up + down) / 2; struct dvec2 *baked_points; if (type == MOVE) { baked_points = baked_points_move; @@ -106,7 +106,8 @@ double find_animation_curve_at(double t, int type) { return baked_points[up].y; } -static bool scene_node_snapshot(struct wlr_scene_node *node, int lx, int ly, +static bool scene_node_snapshot(struct wlr_scene_node *node, int32_t lx, + int32_t ly, struct wlr_scene_tree *snapshot_tree) { if (!node->enabled && node->type != WLR_SCENE_NODE_TREE) { return true; @@ -249,3 +250,13 @@ struct wlr_scene_tree *wlr_scene_tree_snapshot(struct wlr_scene_node *node, return snapshot; } + +void request_fresh_all_monitors(void) { + Monitor *m = NULL; + wl_list_for_each(m, &mons, link) { + if (!m->wlr_output->enabled) { + continue; + } + wlr_output_schedule_frame(m->wlr_output); + } +} \ No newline at end of file diff --git a/src/animation/layer.h b/src/animation/layer.h index 141f132..568d52b 100644 --- a/src/animation/layer.h +++ b/src/animation/layer.h @@ -1,4 +1,4 @@ -void layer_actual_size(LayerSurface *l, uint32_t *width, uint32_t *height) { +void layer_actual_size(LayerSurface *l, int32_t *width, int32_t *height) { struct wlr_box box; if (l->animation.running) { @@ -42,7 +42,7 @@ void get_layer_target_geometry(LayerSurface *l, struct wlr_box *target_box) { .height = state->desired_height}; // 水平方向定位 - const uint32_t both_horiz = + const int32_t both_horiz = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; if (box.width == 0) { box.x = bounds.x; @@ -57,7 +57,7 @@ void get_layer_target_geometry(LayerSurface *l, struct wlr_box *target_box) { } // 垂直方向定位 - const uint32_t both_vert = + const int32_t both_vert = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; if (box.height == 0) { box.y = bounds.y; @@ -101,10 +101,10 @@ void get_layer_target_geometry(LayerSurface *l, struct wlr_box *target_box) { } void set_layer_dir_animaiton(LayerSurface *l, struct wlr_box *geo) { - int slide_direction; - int horizontal, horizontal_value; - int vertical, vertical_value; - int center_x, center_y; + int32_t slide_direction; + int32_t horizontal, horizontal_value; + int32_t vertical, vertical_value; + int32_t center_x, center_y; if (!l) return; @@ -161,10 +161,10 @@ void layer_draw_shadow(LayerSurface *l) { return; } - uint32_t width, height; + int32_t width, height; layer_actual_size(l, &width, &height); - uint32_t delta = shadows_size; + int32_t delta = shadows_size; /* we calculate where to clip the shadow */ struct wlr_box layer_box = { @@ -200,8 +200,8 @@ void layer_draw_shadow(LayerSurface *l) { wlr_scene_shadow_set_clipped_region(l->shadow, clipped_region); } -void layer_scene_buffer_apply_effect(struct wlr_scene_buffer *buffer, int sx, - int sy, void *data) { +void layer_scene_buffer_apply_effect(struct wlr_scene_buffer *buffer, + int32_t sx, int32_t sy, void *data) { BufferData *buffer_data = (BufferData *)data; struct wlr_scene_surface *scene_surface = @@ -212,8 +212,8 @@ void layer_scene_buffer_apply_effect(struct wlr_scene_buffer *buffer, int sx, struct wlr_surface *surface = scene_surface->surface; - uint32_t surface_width = surface->current.width * buffer_data->width_scale; - uint32_t surface_height = + int32_t surface_width = surface->current.width * buffer_data->width_scale; + int32_t surface_height = surface->current.height * buffer_data->height_scale; if (surface_height > 0 && surface_width > 0) { @@ -222,7 +222,8 @@ void layer_scene_buffer_apply_effect(struct wlr_scene_buffer *buffer, int sx, } void layer_fadeout_scene_buffer_apply_effect(struct wlr_scene_buffer *buffer, - int sx, int sy, void *data) { + int32_t sx, int32_t sy, + void *data) { BufferData *buffer_data = (BufferData *)data; wlr_scene_buffer_set_dest_size(buffer, buffer_data->width, buffer_data->height); @@ -235,24 +236,23 @@ void fadeout_layer_animation_next_tick(LayerSurface *l) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - uint32_t passed_time = timespec_to_ms(&now) - l->animation.time_started; + int32_t passed_time = timespec_to_ms(&now) - l->animation.time_started; double animation_passed = l->animation.duration ? (double)passed_time / (double)l->animation.duration : 1.0; - int type = l->animation.action = l->animation.action; + int32_t type = l->animation.action = l->animation.action; double factor = find_animation_curve_at(animation_passed, type); - uint32_t width = l->animation.initial.width + - (l->current.width - l->animation.initial.width) * factor; - uint32_t height = - l->animation.initial.height + - (l->current.height - l->animation.initial.height) * factor; + int32_t width = l->animation.initial.width + + (l->current.width - l->animation.initial.width) * factor; + int32_t height = l->animation.initial.height + + (l->current.height - l->animation.initial.height) * factor; - uint32_t x = l->animation.initial.x + - (l->current.x - l->animation.initial.x) * factor; - uint32_t y = l->animation.initial.y + - (l->current.y - l->animation.initial.y) * factor; + int32_t x = l->animation.initial.x + + (l->current.x - l->animation.initial.x) * factor; + int32_t y = l->animation.initial.y + + (l->current.y - l->animation.initial.y) * factor; wlr_scene_node_set_position(&l->scene->node, x, y); @@ -304,25 +304,24 @@ void layer_animation_next_tick(LayerSurface *l) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); - uint32_t passed_time = timespec_to_ms(&now) - l->animation.time_started; + int32_t passed_time = timespec_to_ms(&now) - l->animation.time_started; double animation_passed = l->animation.duration ? (double)passed_time / (double)l->animation.duration : 1.0; - int type = l->animation.action == NONE ? MOVE : l->animation.action; + int32_t type = l->animation.action == NONE ? MOVE : l->animation.action; double factor = find_animation_curve_at(animation_passed, type); - uint32_t width = l->animation.initial.width + - (l->current.width - l->animation.initial.width) * factor; - uint32_t height = - l->animation.initial.height + - (l->current.height - l->animation.initial.height) * factor; + int32_t width = l->animation.initial.width + + (l->current.width - l->animation.initial.width) * factor; + int32_t height = l->animation.initial.height + + (l->current.height - l->animation.initial.height) * factor; - uint32_t x = l->animation.initial.x + - (l->current.x - l->animation.initial.x) * factor; - uint32_t y = l->animation.initial.y + - (l->current.y - l->animation.initial.y) * factor; + int32_t x = l->animation.initial.x + + (l->current.x - l->animation.initial.x) * factor; + int32_t y = l->animation.initial.y + + (l->current.y - l->animation.initial.y) * factor; double opacity_eased_progress = find_animation_curve_at(animation_passed, OPAFADEIN); diff --git a/src/client/client.h b/src/client/client.h index a5d03d8..8995a5d 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -6,7 +6,7 @@ */ /* Leave these functions first; they're used in the others */ -static inline int client_is_x11(Client *c) { +static inline int32_t client_is_x11(Client *c) { #ifdef XWAYLAND return c->type == X11; #endif @@ -21,14 +21,15 @@ static inline struct wlr_surface *client_surface(Client *c) { return c->surface.xdg->surface; } -static inline int toplevel_from_wlr_surface(struct wlr_surface *s, Client **pc, - LayerSurface **pl) { +static inline int32_t toplevel_from_wlr_surface(struct wlr_surface *s, + Client **pc, + LayerSurface **pl) { struct wlr_xdg_surface *xdg_surface, *tmp_xdg_surface; struct wlr_surface *root_surface; struct wlr_layer_surface_v1 *layer_surface; Client *c = NULL; LayerSurface *l = NULL; - int type = -1; + int32_t type = -1; #ifdef XWAYLAND struct wlr_xwayland_surface *xsurface; #endif @@ -88,7 +89,7 @@ end: /* The others */ static inline void client_activate_surface(struct wlr_surface *s, - int activated) { + int32_t activated) { struct wlr_xdg_toplevel *toplevel; #ifdef XWAYLAND struct wlr_xwayland_surface *xsurface; @@ -113,7 +114,7 @@ static inline const char *client_get_appid(Client *c) { : "broken"; } -static inline int client_get_pid(Client *c) { +static inline int32_t client_get_pid(Client *c) { pid_t pid; #ifdef XWAYLAND if (client_is_x11(c)) @@ -169,7 +170,7 @@ static inline Client *client_get_parent(Client *c) { return p; } -static inline int client_has_children(Client *c) { +static inline int32_t client_has_children(Client *c) { #ifdef XWAYLAND if (client_is_x11(c)) return !wl_list_empty(&c->surface.xwayland->children); @@ -189,7 +190,7 @@ static inline const char *client_get_title(Client *c) { : "broken"; } -static inline int client_is_float_type(Client *c) { +static inline int32_t client_is_float_type(Client *c) { struct wlr_xdg_toplevel *toplevel; struct wlr_xdg_toplevel_state state; @@ -229,12 +230,12 @@ static inline int client_is_float_type(Client *c) { state.min_height == state.max_height)); } -static inline int client_is_rendered_on_mon(Client *c, Monitor *m) { +static inline int32_t client_is_rendered_on_mon(Client *c, Monitor *m) { /* This is needed for when you don't want to check formal assignment, * but rather actual displaying of the pixels. * Usually VISIBLEON suffices and is also faster. */ struct wlr_surface_output *s; - int unused_lx, unused_ly; + int32_t unused_lx, unused_ly; if (!wlr_scene_node_coords(&c->scene->node, &unused_lx, &unused_ly)) return 0; wl_list_for_each(s, &client_surface(c)->current_outputs, @@ -242,8 +243,8 @@ static inline int client_is_rendered_on_mon(Client *c, Monitor *m) { return 0; } -static inline int client_is_stopped(Client *c) { - int pid; +static inline int32_t client_is_stopped(Client *c) { + int32_t pid; siginfo_t in = {0}; #ifdef XWAYLAND if (client_is_x11(c)) @@ -267,7 +268,7 @@ static inline int client_is_stopped(Client *c) { return 0; } -static inline int client_is_unmanaged(Client *c) { +static inline int32_t client_is_unmanaged(Client *c) { #ifdef XWAYLAND if (client_is_x11(c)) return c->surface.xwayland->override_redirect; @@ -299,7 +300,7 @@ static inline void client_set_border_color(Client *c, wlr_scene_rect_set_color(c->border, color); } -static inline void client_set_fullscreen(Client *c, int fullscreen) { +static inline void client_set_fullscreen(Client *c, int32_t fullscreen) { #ifdef XWAYLAND if (client_is_x11(c)) { wlr_xwayland_surface_set_fullscreen(c->surface.xwayland, fullscreen); @@ -379,7 +380,7 @@ static inline void client_set_tiled(Client *c, uint32_t edges) { } } -static inline void client_set_suspended(Client *c, int suspended) { +static inline void client_set_suspended(Client *c, int32_t suspended) { #ifdef XWAYLAND if (client_is_x11(c)) return; @@ -388,7 +389,7 @@ static inline void client_set_suspended(Client *c, int suspended) { wlr_xdg_toplevel_set_suspended(c->surface.xdg->toplevel, suspended); } -static inline int client_should_ignore_focus(Client *c) { +static inline int32_t client_should_ignore_focus(Client *c) { #ifdef XWAYLAND if (client_is_x11(c)) { @@ -403,7 +404,7 @@ static inline int client_should_ignore_focus(Client *c) { return 0; } -static inline int client_is_x11_popup(Client *c) { +static inline int32_t client_is_x11_popup(Client *c) { #ifdef XWAYLAND if (client_is_x11(c)) { @@ -432,7 +433,7 @@ static inline int client_is_x11_popup(Client *c) { return 0; } -static inline int client_should_global(Client *c) { +static inline int32_t client_should_global(Client *c) { #ifdef XWAYLAND if (client_is_x11(c)) { @@ -445,7 +446,7 @@ static inline int client_should_global(Client *c) { return 0; } -static inline int client_should_overtop(Client *c) { +static inline int32_t client_should_overtop(Client *c) { #ifdef XWAYLAND if (client_is_x11(c)) { @@ -457,7 +458,7 @@ static inline int client_should_overtop(Client *c) { return 0; } -static inline int client_wants_focus(Client *c) { +static inline int32_t client_wants_focus(Client *c) { #ifdef XWAYLAND return client_is_unmanaged(c) && wlr_xwayland_surface_override_redirect_wants_focus( @@ -468,7 +469,7 @@ static inline int client_wants_focus(Client *c) { return 0; } -static inline int client_wants_fullscreen(Client *c) { +static inline int32_t client_wants_fullscreen(Client *c) { #ifdef XWAYLAND if (client_is_x11(c)) return c->surface.xwayland->fullscreen; diff --git a/src/common/util.c b/src/common/util.c index 7997205..a15cca7 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -36,8 +36,8 @@ void *ecalloc(size_t nmemb, size_t size) { return p; } -int fd_set_nonblock(int fd) { - int flags = fcntl(fd, F_GETFL); +int32_t fd_set_nonblock(int32_t fd) { + int32_t flags = fcntl(fd, F_GETFL); if (flags < 0) { perror("fcntl(F_GETFL):"); return -1; @@ -50,8 +50,8 @@ int fd_set_nonblock(int fd) { return 0; } -int regex_match(const char *pattern, const char *str) { - int errnum; +int32_t regex_match(const char *pattern, const char *str) { + int32_t errnum; PCRE2_SIZE erroffset; if (!pattern || !str) { @@ -70,7 +70,7 @@ int regex_match(const char *pattern, const char *str) { pcre2_match_data *match_data = pcre2_match_data_create_from_pattern(re, NULL); - int ret = + int32_t ret = pcre2_match(re, (PCRE2_SPTR)str, strlen(str), 0, 0, match_data, NULL); pcre2_match_data_free(match_data); diff --git a/src/common/util.h b/src/common/util.h index 2718eae..8fb6033 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -3,8 +3,8 @@ void die(const char *fmt, ...); void *ecalloc(size_t nmemb, size_t size); -int fd_set_nonblock(int fd); -int regex_match(const char *pattern_mb, const char *str_mb); +int32_t fd_set_nonblock(int32_t fd); +int32_t regex_match(const char *pattern_mb, const char *str_mb); void wl_list_append(struct wl_list *list, struct wl_list *object); uint32_t get_now_in_ms(void); uint32_t timespec_to_ms(struct timespec *ts); \ No newline at end of file diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 074b522..b795a81 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -10,8 +10,9 @@ // 整数版本 - 截断小数部分 #define CLAMP_INT(x, min, max) \ - ((int)(x) < (int)(min) ? (int)(min) \ - : ((int)(x) > (int)(max) ? (int)(max) : (int)(x))) + ((int32_t)(x) < (int32_t)(min) \ + ? (int32_t)(min) \ + : ((int32_t)(x) > (int32_t)(max) ? (int32_t)(max) : (int32_t)(x))) // 浮点数版本 - 保留小数部分 #define CLAMP_FLOAT(x, min, max) \ @@ -30,13 +31,13 @@ typedef struct { typedef struct { xkb_keysym_t keysym; MultiKeycode keycode; - int type; + int32_t type; } KeySymCode; typedef struct { uint32_t mod; KeySymCode keysymcode; - int (*func)(const Arg *); + int32_t (*func)(const Arg *); Arg arg; char mode[28]; bool iscommonmode; @@ -55,42 +56,42 @@ typedef struct { const char *id; const char *title; uint32_t tags; - int isfloating; - int isfullscreen; + int32_t isfloating; + int32_t isfullscreen; float scroller_proportion; const char *animation_type_open; const char *animation_type_close; const char *layer_animation_type_open; const char *layer_animation_type_close; - int isnoborder; - int isnoshadow; - int isnoradius; - int isnoanimation; - int isopensilent; - int istagsilent; - int isnamedscratchpad; - int isunglobal; - int isglobal; - int isoverlay; - int allow_shortcuts_inhibit; - int ignore_maximize; - int ignore_minimize; - int isnosizehint; + int32_t isnoborder; + int32_t isnoshadow; + int32_t isnoradius; + int32_t isnoanimation; + int32_t isopensilent; + int32_t istagsilent; + int32_t isnamedscratchpad; + int32_t isunglobal; + int32_t isglobal; + int32_t isoverlay; + int32_t allow_shortcuts_inhibit; + int32_t ignore_maximize; + int32_t ignore_minimize; + int32_t isnosizehint; const char *monitor; - int offsetx; - int offsety; - int width; - int height; - int nofocus; - int nofadein; - int nofadeout; - int no_force_center; - int isterm; - int allow_csd; - int force_maximize; - int force_tearing; - int noswallow; - int noblur; + int32_t offsetx; + int32_t offsety; + int32_t width; + int32_t height; + int32_t nofocus; + int32_t nofadein; + int32_t nofadeout; + int32_t no_force_center; + int32_t isterm; + int32_t allow_csd; + int32_t force_maximize; + int32_t force_tearing; + int32_t noswallow; + int32_t noblur; float focused_opacity; float unfocused_opacity; float scroller_proportion_single; @@ -100,15 +101,13 @@ typedef struct { } ConfigWinRule; typedef struct { - const char *name; // 显示器名称 - float mfact; // 主区域比例 - int nmaster; // 主区域窗口数量 - const char *layout; // 布局名称(字符串) - int rr; // 旋转和翻转(假设为整数) - float scale; // 显示器缩放比例 - int x, y; // 显示器位置 - int width, height; // 显示器分辨率 - float refresh; // 刷新率 + const char *name; // Monitor name + int32_t rr; // Rotate and flip (assume integer) + float scale; // Monitor scale factor + int32_t x, y; // Monitor position + int32_t width, height; // Monitor resolution + float refresh; // Refresh rate + int32_t vrr; // variable refresh rate } ConfigMonitorRule; // 修改后的宏定义 @@ -129,20 +128,20 @@ KeyBinding default_key_bindings[] = {CHVT(1), CHVT(2), CHVT(3), CHVT(4), typedef struct { uint32_t mod; uint32_t button; - int (*func)(const Arg *); + int32_t (*func)(const Arg *); Arg arg; } MouseBinding; typedef struct { uint32_t mod; uint32_t dir; - int (*func)(const Arg *); + int32_t (*func)(const Arg *); Arg arg; } AxisBinding; typedef struct { uint32_t fold; - int (*func)(const Arg *); + int32_t (*func)(const Arg *); Arg arg; } SwitchBinding; @@ -150,37 +149,39 @@ typedef struct { uint32_t mod; uint32_t motion; uint32_t fingers_count; - int (*func)(const Arg *); + int32_t (*func)(const Arg *); Arg arg; } GestureBinding; typedef struct { - int id; // 标签ID (1-9) - char *layout_name; // 布局名称 + int32_t id; + char *layout_name; char *monitor_name; - int no_render_border; - int no_hide; + float mfact; + int32_t nmaster; + int32_t no_render_border; + int32_t no_hide; } ConfigTagRule; typedef struct { char *layer_name; // 布局名称 char *animation_type_open; char *animation_type_close; - int noblur; - int noanim; - int noshadow; + int32_t noblur; + int32_t noanim; + int32_t noshadow; } ConfigLayerRule; typedef struct { - int animations; - int layer_animations; + int32_t animations; + int32_t layer_animations; char animation_type_open[10]; char animation_type_close[10]; char layer_animation_type_open[10]; char layer_animation_type_close[10]; - int animation_fade_in; - int animation_fade_out; - int tag_animation_direction; + int32_t animation_fade_in; + int32_t animation_fade_out; + int32_t tag_animation_direction; float zoom_initial_ratio; float zoom_end_ratio; float fadein_begin_opacity; @@ -198,66 +199,69 @@ typedef struct { double animation_curve_opafadein[4]; double animation_curve_opafadeout[4]; - int scroller_structs; + int32_t scroller_structs; float scroller_default_proportion; float scroller_default_proportion_single; - int scroller_ignore_proportion_single; - int scroller_focus_center; - int scroller_prefer_center; - int edge_scroller_pointer_focus; - int focus_cross_monitor; - int exchange_cross_monitor; - int scratchpad_cross_monitor; - int focus_cross_tag; - int view_current_to_back; - int no_border_when_single; - int no_radius_when_single; - int snap_distance; - int enable_floating_snap; - int drag_tile_to_tile; + int32_t scroller_ignore_proportion_single; + int32_t scroller_focus_center; + int32_t scroller_prefer_center; + int32_t edge_scroller_pointer_focus; + int32_t focus_cross_monitor; + int32_t exchange_cross_monitor; + int32_t scratchpad_cross_monitor; + int32_t focus_cross_tag; + int32_t view_current_to_back; + int32_t no_border_when_single; + int32_t no_radius_when_single; + int32_t snap_distance; + int32_t enable_floating_snap; + int32_t drag_tile_to_tile; uint32_t swipe_min_threshold; float focused_opacity; float unfocused_opacity; float *scroller_proportion_preset; - int scroller_proportion_preset_count; + int32_t scroller_proportion_preset_count; char **circle_layout; - int circle_layout_count; + int32_t circle_layout_count; uint32_t new_is_master; float default_mfact; uint32_t default_nmaster; - int center_master_overspread; - int center_when_single_stack; + int32_t center_master_overspread; + int32_t center_when_single_stack; uint32_t hotarea_size; + uint32_t hotarea_corner; uint32_t enable_hotarea; uint32_t ov_tab_mode; - int overviewgappi; - int overviewgappo; + int32_t overviewgappi; + int32_t overviewgappo; uint32_t cursor_hide_timeout; uint32_t axis_bind_apply_timeout; uint32_t focus_on_activate; - int idleinhibit_ignore_visible; - int sloppyfocus; - int warpcursor; + int32_t idleinhibit_ignore_visible; + int32_t sloppyfocus; + int32_t warpcursor; + int32_t drag_corner; + int32_t drag_warp_cursor; /* keyboard */ - int repeat_rate; - int repeat_delay; + int32_t repeat_rate; + int32_t repeat_delay; uint32_t numlockon; /* Trackpad */ - int disable_trackpad; - int tap_to_click; - int tap_and_drag; - int drag_lock; - int mouse_natural_scrolling; - int trackpad_natural_scrolling; - int disable_while_typing; - int left_handed; - int middle_button_emulation; + int32_t disable_trackpad; + int32_t tap_to_click; + int32_t tap_and_drag; + int32_t drag_lock; + int32_t mouse_natural_scrolling; + int32_t trackpad_natural_scrolling; + int32_t disable_while_typing; + int32_t left_handed; + int32_t middle_button_emulation; uint32_t accel_profile; double accel_speed; uint32_t scroll_method; @@ -268,21 +272,21 @@ typedef struct { double axis_scroll_factor; - int blur; - int blur_layer; - int blur_optimized; - int border_radius; + int32_t blur; + int32_t blur_layer; + int32_t blur_optimized; + int32_t border_radius; struct blur_data blur_params; - int shadows; - int shadow_only_floating; - int layer_shadows; + int32_t shadows; + int32_t shadow_only_floating; + int32_t layer_shadows; uint32_t shadows_size; float shadows_blur; - int shadows_position_x; - int shadows_position_y; + int32_t shadows_position_x; + int32_t shadows_position_y; float shadowscolor[4]; - int smartgaps; + int32_t smartgaps; uint32_t gappih; uint32_t gappiv; uint32_t gappoh; @@ -302,51 +306,50 @@ typedef struct { char autostart[3][256]; ConfigTagRule *tag_rules; // 动态数组 - int tag_rules_count; // 数量 + int32_t tag_rules_count; // 数量 ConfigLayerRule *layer_rules; // 动态数组 - int layer_rules_count; // 数量 + int32_t layer_rules_count; // 数量 ConfigWinRule *window_rules; - int window_rules_count; + int32_t window_rules_count; ConfigMonitorRule *monitor_rules; // 动态数组 - int monitor_rules_count; // 条数 + int32_t monitor_rules_count; // 条数 KeyBinding *key_bindings; - int key_bindings_count; + int32_t key_bindings_count; MouseBinding *mouse_bindings; - int mouse_bindings_count; + int32_t mouse_bindings_count; AxisBinding *axis_bindings; - int axis_bindings_count; + int32_t axis_bindings_count; SwitchBinding *switch_bindings; - int switch_bindings_count; + int32_t switch_bindings_count; GestureBinding *gesture_bindings; - int gesture_bindings_count; + int32_t gesture_bindings_count; ConfigEnv **env; - int env_count; + int32_t env_count; char **exec; - int exec_count; + int32_t exec_count; char **exec_once; - int exec_once_count; + int32_t exec_once_count; char *cursor_theme; uint32_t cursor_size; - int single_scratchpad; - int xwayland_persistence; - int syncobj_enable; - int adaptive_sync; - int allow_tearing; - int allow_shortcuts_inhibit; - int allow_lock_transparent; + int32_t single_scratchpad; + int32_t xwayland_persistence; + int32_t syncobj_enable; + int32_t allow_tearing; + int32_t allow_shortcuts_inhibit; + int32_t allow_lock_transparent; struct xkb_rule_names xkb_rules; @@ -356,7 +359,7 @@ typedef struct { struct xkb_keymap *keymap; } Config; -typedef int (*FuncType)(const Arg *); +typedef int32_t (*FuncType)(const Arg *); Config config; void parse_config_file(Config *config, const char *file_path); @@ -387,10 +390,11 @@ void trim_whitespace(char *str) { } } -int parse_double_array(const char *input, double *output, int max_count) { +int32_t parse_double_array(const char *input, double *output, + int32_t max_count) { char *dup = strdup(input); char *token; - int count = 0; + int32_t count = 0; // 先清空整个数组 memset(output, 0, max_count * sizeof(double)); @@ -401,7 +405,10 @@ int parse_double_array(const char *input, double *output, int max_count) { char *endptr; double val = strtod(token, &endptr); if (endptr == token || *endptr != '\0') { - fprintf(stderr, "Error: Invalid number in array: %s\n", token); + fprintf( + stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid number in array: %s\n", + token); free(dup); return -1; } @@ -438,7 +445,7 @@ void parse_bind_flags(const char *str, KeyBinding *kb) { const char *suffix = str + 4; // 跳过"bind" // 遍历后缀字符 - for (int i = 0; suffix[i] != '\0'; i++) { + for (int32_t i = 0; suffix[i] != '\0'; i++) { switch (suffix[i]) { case 's': kb->keysymcode.type = KEY_TYPE_SYM; @@ -453,16 +460,18 @@ void parse_bind_flags(const char *str, KeyBinding *kb) { kb->ispassapply = true; break; default: - // 忽略其他字符或可根据需要处理错误 + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Unknown bind flag: %c\n", + suffix[i]); break; } } } -int parse_circle_direction(const char *str) { +int32_t parse_circle_direction(const char *str) { // 将输入字符串转换为小写 char lowerStr[10]; - int i = 0; + int32_t i = 0; while (str[i] && i < 9) { lowerStr[i] = tolower(str[i]); i++; @@ -477,10 +486,10 @@ int parse_circle_direction(const char *str) { } } -int parse_direction(const char *str) { +int32_t parse_direction(const char *str) { // 将输入字符串转换为小写 char lowerStr[10]; - int i = 0; + int32_t i = 0; while (str[i] && i < 9) { lowerStr[i] = tolower(str[i]); i++; @@ -501,10 +510,10 @@ int parse_direction(const char *str) { } } -int parse_fold_state(const char *str) { +int32_t parse_fold_state(const char *str) { // 将输入字符串转换为小写 char lowerStr[10]; - int i = 0; + int32_t i = 0; while (str[i] && i < 9) { lowerStr[i] = tolower(str[i]); i++; @@ -520,9 +529,9 @@ int parse_fold_state(const char *str) { return INVALIDFOLD; } } -long int parse_color(const char *hex_str) { +int64_t parse_color(const char *hex_str) { char *endptr; - long int hex_num = strtol(hex_str, &endptr, 16); + int64_t hex_num = strtol(hex_str, &endptr, 16); if (*endptr != '\0') { return -1; } @@ -541,15 +550,58 @@ static bool starts_with_ignore_case(const char *str, const char *prefix) { return true; } +static char *combine_args_until_empty(char *values[], int count) { + // find the first empty string + int first_empty = count; + for (int i = 0; i < count; i++) { + // check if it's empty: empty string or only contains "0" (initialized) + if (values[i][0] == '\0' || + (strlen(values[i]) == 1 && values[i][0] == '0')) { + first_empty = i; + break; + } + } + + // if there are no valid parameters, return an empty string + if (first_empty == 0) { + return strdup(""); + } + + // calculate the total length + size_t total_len = 0; + for (int i = 0; i < first_empty; i++) { + total_len += strlen(values[i]); + } + // plus the number of commas (first_empty-1 commas) + total_len += (first_empty - 1); + + // allocate memory and concatenate + char *combined = malloc(total_len + 1); + if (combined == NULL) { + return strdup(""); + } + + combined[0] = '\0'; + for (int i = 0; i < first_empty; i++) { + if (i > 0) { + strcat(combined, ","); + } + strcat(combined, values[i]); + } + + return combined; +} + uint32_t parse_mod(const char *mod_str) { if (!mod_str || !*mod_str) { - return 0; + return UINT32_MAX; } uint32_t mod = 0; char input_copy[256]; char *token; char *saveptr = NULL; + bool match_success = false; // 复制并转换为小写 strncpy(input_copy, mod_str, sizeof(input_copy) - 1); @@ -587,41 +639,63 @@ uint32_t parse_mod(const char *mod_str) { case 108: mod |= WLR_MODIFIER_ALT; break; + default: + fprintf(stderr, + "unknown modifier keycode: \033[1m\033[31m%s\n", + token); + break; } } } else { // 完整的 modifier 检查(保留原始所有检查项) - if (strstr(token, "super") || strstr(token, "super_l") || - strstr(token, "super_r")) { + if (!strcmp(token, "super") || !strcmp(token, "super_l") || + !strcmp(token, "super_r")) { mod |= WLR_MODIFIER_LOGO; + match_success = true; } - if (strstr(token, "ctrl") || strstr(token, "ctrl_l") || - strstr(token, "ctrl_r")) { + if (!strcmp(token, "ctrl") || !strcmp(token, "ctrl_l") || + !strcmp(token, "ctrl_r")) { mod |= WLR_MODIFIER_CTRL; + match_success = true; } - if (strstr(token, "shift") || strstr(token, "shift_l") || - strstr(token, "shift_r")) { + if (!strcmp(token, "shift") || !strcmp(token, "shift_l") || + !strcmp(token, "shift_r")) { mod |= WLR_MODIFIER_SHIFT; + match_success = true; } - if (strstr(token, "alt") || strstr(token, "alt_l") || - strstr(token, "alt_r")) { + if (!strcmp(token, "alt") || !strcmp(token, "alt_l") || + !strcmp(token, "alt_r")) { mod |= WLR_MODIFIER_ALT; + match_success = true; } - if (strstr(token, "hyper") || strstr(token, "hyper_l") || - strstr(token, "hyper_r")) { + if (!strcmp(token, "hyper") || !strcmp(token, "hyper_l") || + !strcmp(token, "hyper_r")) { mod |= WLR_MODIFIER_MOD3; + match_success = true; + } + if (!strcmp(token, "none")) { + match_success = true; } } token = strtok_r(NULL, "+", &saveptr); } + if (!match_success) { + mod = UINT32_MAX; + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Unknown modifier: " + "\033[1m\033[31m%s\n", + mod_str); + } + return mod; } // 定义辅助函数:在 keymap 中查找 keysym 对应的多个 keycode -static int find_keycodes_for_keysym(struct xkb_keymap *keymap, xkb_keysym_t sym, - MultiKeycode *multi_kc) { +static int32_t find_keycodes_for_keysym(struct xkb_keymap *keymap, + xkb_keysym_t sym, + MultiKeycode *multi_kc) { xkb_keycode_t min_keycode = xkb_keymap_min_keycode(keymap); xkb_keycode_t max_keycode = xkb_keymap_max_keycode(keymap); @@ -629,16 +703,16 @@ static int find_keycodes_for_keysym(struct xkb_keymap *keymap, xkb_keysym_t sym, multi_kc->keycode2 = 0; multi_kc->keycode3 = 0; - int found_count = 0; + int32_t found_count = 0; for (xkb_keycode_t keycode = min_keycode; keycode <= max_keycode && found_count < 3; keycode++) { // 使用布局0和层级0 const xkb_keysym_t *syms; - int num_syms = + int32_t num_syms = xkb_keymap_key_get_syms_by_level(keymap, keycode, 0, 0, &syms); - for (int i = 0; i < num_syms; i++) { + for (int32_t i = 0; i < num_syms; i++) { if (syms[i] == sym) { switch (found_count) { case 0: @@ -705,8 +779,9 @@ KeySymCode parse_key(const char *key_str, bool isbindsym) { return kc; } - // 普通键名直接转换 - xkb_keysym_t sym = xkb_keysym_from_name(key_str, XKB_KEYSYM_NO_FLAGS); + // change key string to keysym, case insensitive + xkb_keysym_t sym = + xkb_keysym_from_name(key_str, XKB_KEYSYM_CASE_INSENSITIVE); if (isbindsym) { kc.type = KEY_TYPE_SYM; @@ -716,7 +791,7 @@ KeySymCode parse_key(const char *key_str, bool isbindsym) { if (sym != XKB_KEY_NoSymbol) { // 尝试找到对应的多个 keycode - int found_count = + int32_t found_count = find_keycodes_for_keysym(config.keymap, sym, &kc.keycode); if (found_count > 0) { kc.type = KEY_TYPE_CODE; @@ -730,16 +805,20 @@ KeySymCode parse_key(const char *key_str, bool isbindsym) { // 无法解析的键名 kc.type = KEY_TYPE_SYM; kc.keysym = XKB_KEY_NoSymbol; + fprintf( + stderr, + "\033[1m\033[31m[ERROR]:\033[33m Unknown key: \033[1m\033[31m%s\n", + key_str); // keycode 字段保持为0 } return kc; } -int parse_button(const char *str) { +uint32_t parse_button(const char *str) { // 将输入字符串转换为小写 char lowerStr[20]; - int i = 0; + int32_t i = 0; while (str[i] && i < 19) { lowerStr[i] = tolower(str[i]); i++; @@ -764,14 +843,18 @@ int parse_button(const char *str) { } else if (strcmp(lowerStr, "btn_task") == 0) { return BTN_TASK; } else { - return 0; + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Unknown button: " + "\033[1m\033[31m%s\n", + str); + return UINT32_MAX; } } -int parse_mouse_action(const char *str) { +int32_t parse_mouse_action(const char *str) { // 将输入字符串转换为小写 char lowerStr[20]; - int i = 0; + int32_t i = 0; while (str[i] && i < 19) { lowerStr[i] = tolower(str[i]); i++; @@ -792,7 +875,7 @@ int parse_mouse_action(const char *str) { } } -void convert_hex_to_rgba(float *color, unsigned long int hex) { +void convert_hex_to_rgba(float *color, uint32_t hex) { color[0] = ((hex >> 24) & 0xFF) / 255.0f; color[1] = ((hex >> 16) & 0xFF) / 255.0f; color[2] = ((hex >> 8) & 0xFF) / 255.0f; @@ -815,6 +898,12 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value, char *arg_value5) { FuncType func = NULL; + (*arg).i = 0; + (*arg).i2 = 0; + (*arg).f = 0.0f; + (*arg).f2 = 0.0f; + (*arg).ui = 0; + (*arg).ui2 = 0; (*arg).v = NULL; (*arg).v2 = NULL; (*arg).v3 = NULL; @@ -879,7 +968,7 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value, // 收集需要拼接的参数 const char *non_empty_params[4] = {NULL}; - int param_index = 0; + int32_t param_index = 0; if (arg_value2 && arg_value2[0] != '\0') non_empty_params[param_index++] = arg_value2; @@ -896,7 +985,7 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value, } else { // 计算总长度 size_t len = 0; - for (int i = 0; i < param_index; i++) { + for (int32_t i = 0; i < param_index; i++) { len += strlen(non_empty_params[i]); } len += (param_index - 1) + 1; // 逗号数 + null终止符 @@ -904,7 +993,7 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value, char *temp = malloc(len); if (temp) { char *cursor = temp; - for (int i = 0; i < param_index; i++) { + for (int32_t i = 0; i < param_index; i++) { if (i > 0) { *cursor++ = ','; } @@ -965,10 +1054,14 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value, (*arg).ui = atoi(arg_value); } else if (strcmp(func_name, "spawn") == 0) { func = spawn; - (*arg).v = strdup(arg_value); + char *values[] = {arg_value, arg_value2, arg_value3, arg_value4, + arg_value5}; + (*arg).v = combine_args_until_empty(values, 5); } else if (strcmp(func_name, "spawn_shell") == 0) { func = spawn_shell; - (*arg).v = strdup(arg_value); + char *values[] = {arg_value, arg_value2, arg_value3, arg_value4, + arg_value5}; + (*arg).v = combine_args_until_empty(values, 5); } else if (strcmp(func_name, "spawn_on_empty") == 0) { func = spawn_on_empty; (*arg).v = strdup(arg_value); // 注意:之后需要释放这个内存 @@ -1008,7 +1101,7 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value, token = strtok_r(arg_copy, "|", &saveptr); while (token != NULL) { - int num = atoi(token); + int32_t num = atoi(token); if (num > 0 && num <= LENGTH(tags)) { mask |= (1 << (num - 1)); } @@ -1077,6 +1170,9 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value, } else if (strcmp(func_name, "toggle_monitor") == 0) { func = toggle_monitor; (*arg).v = strdup(arg_value); + } else if (strcmp(func_name, "scroller_stack") == 0) { + func = scroller_stack; + (*arg).i = parse_direction(arg_value); } else { return NULL; } @@ -1084,7 +1180,7 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value, } void set_env() { - for (int i = 0; i < config.env_count; i++) { + for (int32_t i = 0; i < config.env_count; i++) { setenv(config.env[i]->type, config.env[i]->value, 1); } } @@ -1092,7 +1188,7 @@ void set_env() { void run_exec() { Arg arg; - for (int i = 0; i < config.exec_count; i++) { + for (int32_t i = 0; i < config.exec_count; i++) { arg.v = config.exec[i]; spawn_shell(&arg); } @@ -1101,13 +1197,13 @@ void run_exec() { void run_exec_once() { Arg arg; - for (int i = 0; i < config.exec_once_count; i++) { + for (int32_t i = 0; i < config.exec_once_count; i++) { arg.v = config.exec_once[i]; spawn_shell(&arg); } } -void parse_option(Config *config, char *key, char *value) { +bool parse_option(Config *config, char *key, char *value) { if (strcmp(key, "keymode") == 0) { snprintf(config->keymode, sizeof(config->keymode), "%.27s", value); } else if (strcmp(key, "animations") == 0) { @@ -1155,52 +1251,73 @@ void parse_option(Config *config, char *key, char *value) { } else if (strcmp(key, "animation_duration_focus") == 0) { config->animation_duration_focus = atoi(value); } else if (strcmp(key, "animation_curve_move") == 0) { - int num = parse_double_array(value, config->animation_curve_move, 4); + int32_t num = + parse_double_array(value, config->animation_curve_move, 4); if (num != 4) { - fprintf(stderr, "Error: Failed to parse animation_curve_move: %s\n", + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Failed to parse " + "animation_curve_move: %s\n", value); + return false; } } else if (strcmp(key, "animation_curve_open") == 0) { - int num = parse_double_array(value, config->animation_curve_open, 4); + int32_t num = + parse_double_array(value, config->animation_curve_open, 4); if (num != 4) { - fprintf(stderr, "Error: Failed to parse animation_curve_open: %s\n", + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Failed to parse " + "animation_curve_open: %s\n", value); + return false; } } else if (strcmp(key, "animation_curve_tag") == 0) { - int num = parse_double_array(value, config->animation_curve_tag, 4); + int32_t num = parse_double_array(value, config->animation_curve_tag, 4); if (num != 4) { - fprintf(stderr, "Error: Failed to parse animation_curve_tag: %s\n", + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Failed to parse " + "animation_curve_tag: %s\n", value); + return false; } } else if (strcmp(key, "animation_curve_close") == 0) { - int num = parse_double_array(value, config->animation_curve_close, 4); + int32_t num = + parse_double_array(value, config->animation_curve_close, 4); if (num != 4) { fprintf(stderr, - "Error: Failed to parse animation_curve_close: %s\n", + "\033[1m\033[31m[ERROR]:\033[33m Failed to parse " + "animation_curve_close: %s\n", value); + return false; } } else if (strcmp(key, "animation_curve_focus") == 0) { - int num = parse_double_array(value, config->animation_curve_focus, 4); + int32_t num = + parse_double_array(value, config->animation_curve_focus, 4); if (num != 4) { fprintf(stderr, - "Error: Failed to parse animation_curve_focus: %s\n", + "\033[1m\033[31m[ERROR]:\033[33m Failed to parse " + "animation_curve_focus: %s\n", value); + return false; } } else if (strcmp(key, "animation_curve_opafadein") == 0) { - int num = + int32_t num = parse_double_array(value, config->animation_curve_opafadein, 4); if (num != 4) { fprintf(stderr, - "Error: Failed to parse animation_curve_opafadein: %s\n", + "\033[1m\033[31m[ERROR]:\033[33m Failed to parse " + "animation_curve_opafadein: %s\n", value); + return false; } } else if (strcmp(key, "animation_curve_opafadeout") == 0) { - int num = + int32_t num = parse_double_array(value, config->animation_curve_opafadeout, 4); if (num != 4) { fprintf(stderr, - "Error: Failed to parse animation_curve_opafadeout: %s\n", + "\033[1m\033[31m[ERROR]:\033[33m Failed to parse " + "animation_curve_opafadeout: %s\n", value); + return false; } } else if (strcmp(key, "scroller_structs") == 0) { config->scroller_structs = atoi(value); @@ -1266,8 +1383,6 @@ void parse_option(Config *config, char *key, char *value) { config->xwayland_persistence = atoi(value); } else if (strcmp(key, "syncobj_enable") == 0) { config->syncobj_enable = atoi(value); - } else if (strcmp(key, "adaptive_sync") == 0) { - config->adaptive_sync = atoi(value); } else if (strcmp(key, "allow_tearing") == 0) { config->allow_tearing = atoi(value); } else if (strcmp(key, "allow_shortcuts_inhibit") == 0) { @@ -1312,41 +1427,44 @@ void parse_option(Config *config, char *key, char *value) { '\0'; // 确保字符串以 null 结尾 } else if (strcmp(key, "scroller_proportion_preset") == 0) { // 1. 统计 value 中有多少个逗号,确定需要解析的浮点数个数 - int count = 0; // 初始化为 0 + int32_t count = 0; // 初始化为 0 for (const char *p = value; *p; p++) { if (*p == ',') count++; } - int float_count = count + 1; // 浮点数的数量是逗号数量加 1 + int32_t float_count = count + 1; // 浮点数的数量是逗号数量加 1 // 2. 动态分配内存,存储浮点数 config->scroller_proportion_preset = (float *)malloc(float_count * sizeof(float)); if (!config->scroller_proportion_preset) { - fprintf(stderr, "Error: Memory allocation failed\n"); - return; + fprintf(stderr, "\033[1m\033[31m[ERROR]:\033[33m Memory " + "allocation failed\n"); + return false; } // 3. 解析 value 中的浮点数 char *value_copy = strdup(value); // 复制 value,因为 strtok 会修改原字符串 char *token = strtok(value_copy, ","); - int i = 0; + int32_t i = 0; float value_set; while (token != NULL && i < float_count) { if (sscanf(token, "%f", &value_set) != 1) { fprintf(stderr, - "Error: Invalid float value in " + "\033[1m\033[31m[ERROR]:\033[33m Invalid float " + "value in " "scroller_proportion_preset: %s\n", token); free(value_copy); free(config->scroller_proportion_preset); config->scroller_proportion_preset = NULL; - return; + return false; } - // Clamp the value between 0.0 and 1.0 (or your desired range) + // Clamp the value between 0.0 and 1.0 (or your desired + // range) config->scroller_proportion_preset[i] = CLAMP_FLOAT(value_set, 0.1f, 1.0f); @@ -1357,13 +1475,14 @@ void parse_option(Config *config, char *key, char *value) { // 4. 检查解析的浮点数数量是否匹配 if (i != float_count) { fprintf(stderr, - "Error: Invalid scroller_proportion_preset format: %s\n", + "\033[1m\033[31m[ERROR]:\033[33m Invalid " + "scroller_proportion_preset format: %s\n", value); free(value_copy); free(config->scroller_proportion_preset); // 释放已分配的内存 config->scroller_proportion_preset = NULL; // 防止野指针 config->scroller_proportion_preset_count = 0; - return; + return false; } config->scroller_proportion_preset_count = float_count; @@ -1371,26 +1490,27 @@ void parse_option(Config *config, char *key, char *value) { free(value_copy); } else if (strcmp(key, "circle_layout") == 0) { // 1. 统计 value 中有多少个逗号,确定需要解析的字符串个数 - int count = 0; // 初始化为 0 + int32_t count = 0; // 初始化为 0 for (const char *p = value; *p; p++) { if (*p == ',') count++; } - int string_count = count + 1; // 字符串的数量是逗号数量加 1 + int32_t string_count = count + 1; // 字符串的数量是逗号数量加 1 // 2. 动态分配内存,存储字符串指针 config->circle_layout = (char **)malloc(string_count * sizeof(char *)); memset(config->circle_layout, 0, string_count * sizeof(char *)); if (!config->circle_layout) { - fprintf(stderr, "Error: Memory allocation failed\n"); - return; + fprintf(stderr, "\033[1m\033[31m[ERROR]:\033[33m Memory " + "allocation failed\n"); + return false; } // 3. 解析 value 中的字符串 char *value_copy = strdup(value); // 复制 value,因为 strtok 会修改原字符串 char *token = strtok(value_copy, ","); - int i = 0; + int32_t i = 0; char *cleaned_token; while (token != NULL && i < string_count) { // 为每个字符串分配内存并复制内容 @@ -1398,17 +1518,19 @@ void parse_option(Config *config, char *key, char *value) { config->circle_layout[i] = strdup(cleaned_token); if (!config->circle_layout[i]) { fprintf(stderr, - "Error: Memory allocation failed for string: %s\n", + "\033[1m\033[31m[ERROR]:\033[33m Memory allocation " + "failed for " + "string: %s\n", token); // 释放之前分配的内存 - for (int j = 0; j < i; j++) { + for (int32_t j = 0; j < i; j++) { free(config->circle_layout[j]); } free(config->circle_layout); free(value_copy); config->circle_layout = NULL; // 防止野指针 config->circle_layout_count = 0; - return; + return false; } token = strtok(NULL, ","); i++; @@ -1416,16 +1538,19 @@ void parse_option(Config *config, char *key, char *value) { // 4. 检查解析的字符串数量是否匹配 if (i != string_count) { - fprintf(stderr, "Error: Invalid circle_layout format: %s\n", value); + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid circle_layout " + "format: %s\n", + value); // 释放之前分配的内存 - for (int j = 0; j < i; j++) { + for (int32_t j = 0; j < i; j++) { free(config->circle_layout[j]); } free(config->circle_layout); free(value_copy); config->circle_layout = NULL; // 防止野指针 config->circle_layout_count = 0; - return; + return false; } config->circle_layout_count = string_count; @@ -1443,6 +1568,8 @@ void parse_option(Config *config, char *key, char *value) { config->center_when_single_stack = atoi(value); } else if (strcmp(key, "hotarea_size") == 0) { config->hotarea_size = atoi(value); + } else if (strcmp(key, "hotarea_corner") == 0) { + config->hotarea_corner = atoi(value); } else if (strcmp(key, "enable_hotarea") == 0) { config->enable_hotarea = atoi(value); } else if (strcmp(key, "ov_tab_mode") == 0) { @@ -1465,6 +1592,10 @@ void parse_option(Config *config, char *key, char *value) { config->sloppyfocus = atoi(value); } else if (strcmp(key, "warpcursor") == 0) { config->warpcursor = atoi(value); + } else if (strcmp(key, "drag_corner") == 0) { + config->drag_corner = atoi(value); + } else if (strcmp(key, "drag_warp_cursor") == 0) { + config->drag_warp_cursor = atoi(value); } else if (strcmp(key, "smartgaps") == 0) { config->smartgaps = atoi(value); } else if (strcmp(key, "repeat_rate") == 0) { @@ -1524,78 +1655,187 @@ void parse_option(Config *config, char *key, char *value) { } else if (strcmp(key, "borderpx") == 0) { config->borderpx = atoi(value); } else if (strcmp(key, "rootcolor") == 0) { - long int color = parse_color(value); + int64_t color = parse_color(value); if (color == -1) { - fprintf(stderr, "Error: Invalid rootcolor format: %s\n", value); + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid rootcolor " + "format: " + "%s\n", + value); + return false; } else { convert_hex_to_rgba(config->rootcolor, color); } } else if (strcmp(key, "shadowscolor") == 0) { - long int color = parse_color(value); + int64_t color = parse_color(value); if (color == -1) { - fprintf(stderr, "Error: Invalid shadowscolor format: %s\n", value); + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid shadowscolor " + "format: %s\n", + value); + return false; } else { convert_hex_to_rgba(config->shadowscolor, color); } } else if (strcmp(key, "bordercolor") == 0) { - long int color = parse_color(value); + int64_t color = parse_color(value); if (color == -1) { - fprintf(stderr, "Error: Invalid bordercolor format: %s\n", value); + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid bordercolor " + "format: %s\n", + value); + return false; } else { convert_hex_to_rgba(config->bordercolor, color); } } else if (strcmp(key, "focuscolor") == 0) { - long int color = parse_color(value); + int64_t color = parse_color(value); if (color == -1) { - fprintf(stderr, "Error: Invalid focuscolor format: %s\n", value); + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid focuscolor " + "format: %s\n", + value); + return false; } else { convert_hex_to_rgba(config->focuscolor, color); } } else if (strcmp(key, "maximizescreencolor") == 0) { - long int color = parse_color(value); + int64_t color = parse_color(value); if (color == -1) { - fprintf(stderr, "Error: Invalid maximizescreencolor format: %s\n", + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid " + "maximizescreencolor " + "format: %s\n", value); + return false; } else { convert_hex_to_rgba(config->maximizescreencolor, color); } } else if (strcmp(key, "urgentcolor") == 0) { - long int color = parse_color(value); + int64_t color = parse_color(value); if (color == -1) { - fprintf(stderr, "Error: Invalid urgentcolor format: %s\n", value); + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid urgentcolor " + "format: %s\n", + value); + return false; } else { convert_hex_to_rgba(config->urgentcolor, color); } } else if (strcmp(key, "scratchpadcolor") == 0) { - long int color = parse_color(value); + int64_t color = parse_color(value); if (color == -1) { - fprintf(stderr, "Error: Invalid scratchpadcolor format: %s\n", + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid " + "scratchpadcolor " + "format: %s\n", value); + return false; } else { convert_hex_to_rgba(config->scratchpadcolor, color); } } else if (strcmp(key, "globalcolor") == 0) { - long int color = parse_color(value); + int64_t color = parse_color(value); if (color == -1) { - fprintf(stderr, "Error: Invalid globalcolor format: %s\n", value); + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid globalcolor " + "format: %s\n", + value); + return false; } else { convert_hex_to_rgba(config->globalcolor, color); } } else if (strcmp(key, "overlaycolor") == 0) { - long int color = parse_color(value); + int64_t color = parse_color(value); if (color == -1) { - fprintf(stderr, "Error: Invalid overlaycolor format: %s\n", value); + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid overlaycolor " + "format: %s\n", + value); + return false; } else { convert_hex_to_rgba(config->overlaycolor, color); } + } else if (strcmp(key, "monitorrule") == 0) { + config->monitor_rules = + realloc(config->monitor_rules, (config->monitor_rules_count + 1) * + sizeof(ConfigMonitorRule)); + if (!config->monitor_rules) { + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Failed to allocate " + "memory for monitor rules\n"); + return false; + } + + ConfigMonitorRule *rule = + &config->monitor_rules[config->monitor_rules_count]; + memset(rule, 0, sizeof(ConfigMonitorRule)); + + // 设置默认值 + rule->name = NULL; + rule->rr = 0; + rule->scale = 1.0f; + rule->x = INT32_MAX; + rule->y = INT32_MAX; + rule->width = -1; + rule->height = -1; + rule->refresh = 0.0f; + rule->vrr = 0; + + bool parse_error = false; + char *token = strtok(value, ","); + while (token != NULL) { + char *colon = strchr(token, ':'); + if (colon != NULL) { + *colon = '\0'; + char *key = token; + char *val = colon + 1; + + trim_whitespace(key); + trim_whitespace(val); + + if (strcmp(key, "name") == 0) { + rule->name = strdup(val); + } else if (strcmp(key, "rr") == 0) { + rule->rr = CLAMP_INT(atoi(val), 0, 7); + } else if (strcmp(key, "scale") == 0) { + rule->scale = CLAMP_FLOAT(atof(val), 0.001f, 1000.0f); + } else if (strcmp(key, "x") == 0) { + rule->x = atoi(val); + } else if (strcmp(key, "y") == 0) { + rule->y = atoi(val); + } else if (strcmp(key, "width") == 0) { + rule->width = CLAMP_INT(atoi(val), 1, INT32_MAX); + } else if (strcmp(key, "height") == 0) { + rule->height = CLAMP_INT(atoi(val), 1, INT32_MAX); + } else if (strcmp(key, "refresh") == 0) { + rule->refresh = CLAMP_FLOAT(atof(val), 0.001f, 1000.0f); + } else if (strcmp(key, "vrr") == 0) { + rule->vrr = CLAMP_INT(atoi(val), 0, 1); + } else { + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Unknown " + "monitor rule " + "option:\033[1m\033[31m %s\n", + key); + parse_error = true; + } + } + token = strtok(NULL, ","); + } + + config->monitor_rules_count++; + return !parse_error; } else if (strcmp(key, "tagrule") == 0) { config->tag_rules = realloc(config->tag_rules, (config->tag_rules_count + 1) * sizeof(ConfigTagRule)); if (!config->tag_rules) { - fprintf(stderr, "Error: Failed to allocate memory for tag rules\n"); - return; + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Failed to allocate " + "memory for tag rules\n"); + return false; } ConfigTagRule *rule = &config->tag_rules[config->tag_rules_count]; @@ -1605,7 +1845,12 @@ void parse_option(Config *config, char *key, char *value) { rule->id = 0; rule->layout_name = NULL; rule->monitor_name = NULL; + rule->nmaster = 0; + rule->mfact = 0.0f; + rule->no_render_border = 0; + rule->no_hide = 0; + bool parse_error = false; char *token = strtok(value, ","); while (token != NULL) { char *colon = strchr(token, ':'); @@ -1627,20 +1872,33 @@ void parse_option(Config *config, char *key, char *value) { rule->no_render_border = CLAMP_INT(atoi(val), 0, 1); } else if (strcmp(key, "no_hide") == 0) { rule->no_hide = CLAMP_INT(atoi(val), 0, 1); + } else if (strcmp(key, "nmaster") == 0) { + rule->nmaster = CLAMP_INT(atoi(val), 1, 99); + } else if (strcmp(key, "mfact") == 0) { + rule->mfact = CLAMP_FLOAT(atof(val), 0.1f, 0.9f); + } else { + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Unknown " + "tag rule " + "option:\033[1m\033[31m %s\n", + key); + parse_error = true; } } token = strtok(NULL, ","); } config->tag_rules_count++; + return !parse_error; } else if (strcmp(key, "layerrule") == 0) { config->layer_rules = realloc(config->layer_rules, (config->layer_rules_count + 1) * sizeof(ConfigLayerRule)); if (!config->layer_rules) { fprintf(stderr, - "Error: Failed to allocate memory for layer rules\n"); - return; + "\033[1m\033[31m[ERROR]:\033[33m Failed to allocate " + "memory for layer rules\n"); + return false; } ConfigLayerRule *rule = &config->layer_rules[config->layer_rules_count]; @@ -1654,6 +1912,7 @@ void parse_option(Config *config, char *key, char *value) { rule->noanim = 0; rule->noshadow = 0; + bool parse_error = false; char *token = strtok(value, ","); while (token != NULL) { char *colon = strchr(token, ':'); @@ -1677,6 +1936,13 @@ void parse_option(Config *config, char *key, char *value) { rule->noanim = CLAMP_INT(atoi(val), 0, 1); } else if (strcmp(key, "noshadow") == 0) { rule->noshadow = CLAMP_INT(atoi(val), 0, 1); + } else { + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Unknown " + "layer rule " + "option:\033[1m\033[31m %s\n", + key); + parse_error = true; } } token = strtok(NULL, ","); @@ -1688,20 +1954,22 @@ void parse_option(Config *config, char *key, char *value) { } config->layer_rules_count++; + return !parse_error; } else if (strcmp(key, "windowrule") == 0) { config->window_rules = realloc(config->window_rules, (config->window_rules_count + 1) * sizeof(ConfigWinRule)); if (!config->window_rules) { fprintf(stderr, - "Error: Failed to allocate memory for window rules\n"); - return; + "\033[1m\033[31m[ERROR]:\033[33m Failed to allocate " + "memory for window rules\n"); + return false; } ConfigWinRule *rule = &config->window_rules[config->window_rules_count]; memset(rule, 0, sizeof(ConfigWinRule)); - // int rule value, relay to a client property + // int32_t rule value, relay to a client property rule->isfloating = -1; rule->isfullscreen = -1; rule->isnoborder = -1; @@ -1751,6 +2019,7 @@ void parse_option(Config *config, char *key, char *value) { rule->globalkeybinding = (KeyBinding){0}; + bool parse_error = false; char *token = strtok(value, ","); while (token != NULL) { char *colon = strchr(token, ':'); @@ -1850,86 +2119,37 @@ void parse_option(Config *config, char *key, char *value) { rule->globalkeybinding.mod = parse_mod(mod_str); rule->globalkeybinding.keysymcode = parse_key(keysym_str, false); + if (rule->globalkeybinding.mod == UINT32_MAX) { + return false; + } + if (rule->globalkeybinding.keysymcode.type == + KEY_TYPE_SYM && + rule->globalkeybinding.keysymcode.keysym == + XKB_KEY_NoSymbol) { + return false; + } + } else { + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Unknown " + "window rule " + "option:\033[1m\033[31m %s\n", + key); + parse_error = true; } } token = strtok(NULL, ","); } config->window_rules_count++; - } else if (strcmp(key, "monitorrule") == 0) { - config->monitor_rules = - realloc(config->monitor_rules, (config->monitor_rules_count + 1) * - sizeof(ConfigMonitorRule)); - if (!config->monitor_rules) { - fprintf(stderr, - "Error: Failed to allocate memory for monitor rules\n"); - return; - } - - ConfigMonitorRule *rule = - &config->monitor_rules[config->monitor_rules_count]; - memset(rule, 0, sizeof(ConfigMonitorRule)); - - // 临时存储每个字段的原始字符串 - char raw_name[256], raw_layout[256]; - char raw_mfact[256], raw_nmaster[256], raw_rr[256]; - char raw_scale[256], raw_x[256], raw_y[256], raw_width[256], - raw_height[256], raw_refresh[256]; - - // 先读取所有字段为字符串 - int parsed = - sscanf(value, - "%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[" - "^,],%255[^,],%255[^,],%255[^,],%255[^,],%255s", - raw_name, raw_mfact, raw_nmaster, raw_layout, raw_rr, - raw_scale, raw_x, raw_y, raw_width, raw_height, raw_refresh); - - if (parsed == 11) { - // 修剪每个字段的空格 - trim_whitespace(raw_name); - trim_whitespace(raw_mfact); - trim_whitespace(raw_nmaster); - trim_whitespace(raw_layout); - trim_whitespace(raw_rr); - trim_whitespace(raw_scale); - trim_whitespace(raw_x); - trim_whitespace(raw_y); - trim_whitespace(raw_width); - trim_whitespace(raw_height); - trim_whitespace(raw_refresh); - - // 转换修剪后的字符串为特定类型 - rule->name = strdup(raw_name); - rule->layout = strdup(raw_layout); - rule->mfact = atof(raw_mfact); - rule->nmaster = atoi(raw_nmaster); - rule->rr = atoi(raw_rr); - rule->scale = atof(raw_scale); - rule->x = atoi(raw_x); - rule->y = atoi(raw_y); - rule->width = atoi(raw_width); - rule->height = atoi(raw_height); - rule->refresh = atof(raw_refresh); - - if (!rule->name || !rule->layout) { - if (rule->name) - free((void *)rule->name); - if (rule->layout) - free((void *)rule->layout); - fprintf(stderr, - "Error: Failed to allocate memory for monitor rule\n"); - return; - } - - config->monitor_rules_count++; - } else { - fprintf(stderr, "Error: Invalid monitorrule format: %s\n", value); - } + return !parse_error; } else if (strncmp(key, "env", 3) == 0) { char env_type[256], env_value[256]; if (sscanf(value, "%255[^,],%255[^\n]", env_type, env_value) < 2) { - fprintf(stderr, "Error: Invalid bind format: %s\n", value); - return; + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid bind format: " + "\033[1m\033[31m%s\n", + value); + return false; } trim_whitespace(env_type); trim_whitespace(env_value); @@ -1944,8 +2164,9 @@ void parse_option(Config *config, char *key, char *value) { free(env->type); free(env->value); free(env); - fprintf(stderr, "Error: Failed to allocate memory for env\n"); - return; + fprintf(stderr, "\033[1m\033[31m[ERROR]:\033[33m Failed to " + "allocate memory for env\n"); + return false; } config->env[config->env_count] = env; @@ -1955,15 +2176,18 @@ void parse_option(Config *config, char *key, char *value) { char **new_exec = realloc(config->exec, (config->exec_count + 1) * sizeof(char *)); if (!new_exec) { - fprintf(stderr, "Error: Failed to allocate memory for exec\n"); - return; + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Failed to allocate " + "memory for exec\n"); + return false; } config->exec = new_exec; config->exec[config->exec_count] = strdup(value); if (!config->exec[config->exec_count]) { - fprintf(stderr, "Error: Failed to duplicate exec string\n"); - return; + fprintf(stderr, "\033[1m\033[31m[ERROR]:\033[33m Failed to " + "duplicate exec string\n"); + return false; } config->exec_count++; @@ -1973,15 +2197,19 @@ void parse_option(Config *config, char *key, char *value) { char **new_exec_once = realloc( config->exec_once, (config->exec_once_count + 1) * sizeof(char *)); if (!new_exec_once) { - fprintf(stderr, "Error: Failed to allocate memory for exec_once\n"); - return; + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Failed to allocate " + "memory for exec_once\n"); + return false; } config->exec_once = new_exec_once; config->exec_once[config->exec_once_count] = strdup(value); if (!config->exec_once[config->exec_once_count]) { - fprintf(stderr, "Error: Failed to duplicate exec_once string\n"); - return; + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Failed to duplicate " + "exec_once string\n"); + return false; } config->exec_once_count++; @@ -1992,8 +2220,9 @@ void parse_option(Config *config, char *key, char *value) { (config->key_bindings_count + 1) * sizeof(KeyBinding)); if (!config->key_bindings) { fprintf(stderr, - "Error: Failed to allocate memory for key bindings\n"); - return; + "\033[1m\033[31m[ERROR]:\033[33m Failed to allocate " + "memory for key bindings\n"); + return false; } KeyBinding *binding = &config->key_bindings[config->key_bindings_count]; @@ -2004,12 +2233,16 @@ void parse_option(Config *config, char *key, char *value) { arg_value3[256] = "0\0", arg_value4[256] = "0\0", arg_value5[256] = "0\0"; if (sscanf(value, - "%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[" + "%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^" + ",],%255[" "^,],%255[^\n]", mod_str, keysym_str, func_name, arg_value, arg_value2, arg_value3, arg_value4, arg_value5) < 3) { - fprintf(stderr, "Error: Invalid bind format: %s\n", value); - return; + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid bind format: " + "\033[1m\033[31m%s\n", + value); + return false; } trim_whitespace(mod_str); trim_whitespace(keysym_str); @@ -2036,13 +2269,21 @@ void parse_option(Config *config, char *key, char *value) { binding->keysymcode = parse_key(keysym_str, binding->keysymcode.type == KEY_TYPE_SYM); binding->mod = parse_mod(mod_str); + binding->arg.i = 0; + binding->arg.i2 = 0; + binding->arg.f = 0.0f; + binding->arg.f2 = 0.0f; + binding->arg.ui = 0; + binding->arg.ui2 = 0; binding->arg.v = NULL; binding->arg.v2 = NULL; binding->arg.v3 = NULL; binding->func = parse_func_name(func_name, &binding->arg, arg_value, arg_value2, arg_value3, arg_value4, arg_value5); - if (!binding->func) { + if (!binding->func || binding->mod == UINT32_MAX || + (binding->keysymcode.type == KEY_TYPE_SYM && + binding->keysymcode.keysym == XKB_KEY_NoSymbol)) { if (binding->arg.v) { free(binding->arg.v); binding->arg.v = NULL; @@ -2055,7 +2296,13 @@ void parse_option(Config *config, char *key, char *value) { free(binding->arg.v3); binding->arg.v3 = NULL; } - fprintf(stderr, "Error: Unknown function in bind: %s\n", func_name); + if (!binding->func) + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Unknown " + "dispatch in bind: " + "\033[1m\033[31m%s\n", + func_name); + return false; } else { config->key_bindings_count++; } @@ -2066,8 +2313,9 @@ void parse_option(Config *config, char *key, char *value) { (config->mouse_bindings_count + 1) * sizeof(MouseBinding)); if (!config->mouse_bindings) { fprintf(stderr, - "Error: Failed to allocate memory for mouse bindings\n"); - return; + "\033[1m\033[31m[ERROR]:\033[33m Failed to allocate " + "memory for mouse bindings\n"); + return false; } MouseBinding *binding = @@ -2079,12 +2327,17 @@ void parse_option(Config *config, char *key, char *value) { arg_value3[256] = "0\0", arg_value4[256] = "0\0", arg_value5[256] = "0\0"; if (sscanf(value, - "%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[" + "%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^" + ",],%255[" "^,],%255[^\n]", mod_str, button_str, func_name, arg_value, arg_value2, arg_value3, arg_value4, arg_value5) < 3) { - fprintf(stderr, "Error: Invalid mousebind format: %s\n", value); - return; + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid mousebind " + "format: " + "%s\n", + value); + return false; } trim_whitespace(mod_str); trim_whitespace(button_str); @@ -2097,13 +2350,20 @@ void parse_option(Config *config, char *key, char *value) { binding->mod = parse_mod(mod_str); binding->button = parse_button(button_str); + binding->arg.i = 0; + binding->arg.i2 = 0; + binding->arg.f = 0.0f; + binding->arg.f2 = 0.0f; + binding->arg.ui = 0; + binding->arg.ui2 = 0; binding->arg.v = NULL; binding->arg.v2 = NULL; binding->arg.v3 = NULL; binding->func = parse_func_name(func_name, &binding->arg, arg_value, arg_value2, arg_value3, arg_value4, arg_value5); - if (!binding->func) { + if (!binding->func || binding->mod == UINT32_MAX || + binding->button == UINT32_MAX) { if (binding->arg.v) { free(binding->arg.v); binding->arg.v = NULL; @@ -2116,8 +2376,13 @@ void parse_option(Config *config, char *key, char *value) { free(binding->arg.v3); binding->arg.v3 = NULL; } - fprintf(stderr, "Error: Unknown function in mousebind: %s\n", - func_name); + if (!binding->func) + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Unknown " + "dispatch in " + "mousebind: \033[1m\033[31m%s\n", + func_name); + return false; } else { config->mouse_bindings_count++; } @@ -2127,8 +2392,9 @@ void parse_option(Config *config, char *key, char *value) { (config->axis_bindings_count + 1) * sizeof(AxisBinding)); if (!config->axis_bindings) { fprintf(stderr, - "Error: Failed to allocate memory for axis bindings\n"); - return; + "\033[1m\033[31m[ERROR]:\033[33m Failed to allocate " + "memory for axis bindings\n"); + return false; } AxisBinding *binding = @@ -2140,12 +2406,16 @@ void parse_option(Config *config, char *key, char *value) { arg_value3[256] = "0\0", arg_value4[256] = "0\0", arg_value5[256] = "0\0"; if (sscanf(value, - "%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[" + "%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^" + ",],%255[" "^,],%255[^\n]", mod_str, dir_str, func_name, arg_value, arg_value2, arg_value3, arg_value4, arg_value5) < 3) { - fprintf(stderr, "Error: Invalid axisbind format: %s\n", value); - return; + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid axisbind " + "format: %s\n", + value); + return false; } trim_whitespace(mod_str); @@ -2166,7 +2436,7 @@ void parse_option(Config *config, char *key, char *value) { parse_func_name(func_name, &binding->arg, arg_value, arg_value2, arg_value3, arg_value4, arg_value5); - if (!binding->func) { + if (!binding->func || binding->mod == UINT32_MAX) { if (binding->arg.v) { free(binding->arg.v); binding->arg.v = NULL; @@ -2179,8 +2449,13 @@ void parse_option(Config *config, char *key, char *value) { free(binding->arg.v3); binding->arg.v3 = NULL; } - fprintf(stderr, "Error: Unknown function in axisbind: %s\n", - func_name); + if (!binding->func) + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Unknown " + "dispatch in " + "axisbind: \033[1m\033[31m%s\n", + func_name); + return false; } else { config->axis_bindings_count++; } @@ -2191,8 +2466,9 @@ void parse_option(Config *config, char *key, char *value) { sizeof(SwitchBinding)); if (!config->switch_bindings) { fprintf(stderr, - "Error: Failed to allocate memory for switch bindings\n"); - return; + "\033[1m\033[31m[ERROR]:\033[33m Failed to allocate " + "memory for switch bindings\n"); + return false; } SwitchBinding *binding = @@ -2204,12 +2480,16 @@ void parse_option(Config *config, char *key, char *value) { arg_value3[256] = "0\0", arg_value4[256] = "0\0", arg_value5[256] = "0\0"; if (sscanf(value, - "%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[" + "%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^" + ",],%255[" "^\n]", fold_str, func_name, arg_value, arg_value2, arg_value3, arg_value4, arg_value5) < 3) { - fprintf(stderr, "Error: Invalid switchbind format: %s\n", value); - return; + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid switchbind " + "format: %s\n", + value); + return false; } trim_whitespace(fold_str); trim_whitespace(func_name); @@ -2237,8 +2517,13 @@ void parse_option(Config *config, char *key, char *value) { free(binding->arg.v3); binding->arg.v3 = NULL; } - fprintf(stderr, "Error: Unknown function in switchbind: %s\n", + + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Unknown dispatch in " + "switchbind: " + "\033[1m\033[31m%s\n", func_name); + return false; } else { config->switch_bindings_count++; } @@ -2249,8 +2534,9 @@ void parse_option(Config *config, char *key, char *value) { (config->gesture_bindings_count + 1) * sizeof(GestureBinding)); if (!config->gesture_bindings) { fprintf(stderr, - "Error: Failed to allocate memory for axis gesturebind\n"); - return; + "\033[1m\033[31m[ERROR]:\033[33m Failed to allocate " + "memory for axis gesturebind\n"); + return false; } GestureBinding *binding = @@ -2262,12 +2548,16 @@ void parse_option(Config *config, char *key, char *value) { arg_value3[256] = "0\0", arg_value4[256] = "0\0", arg_value5[256] = "0\0"; if (sscanf(value, - "%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[" + "%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^" + ",],%255[" "^,],%255[^,],%255[^\n]", mod_str, motion_str, fingers_count_str, func_name, arg_value, arg_value2, arg_value3, arg_value4, arg_value5) < 4) { - fprintf(stderr, "Error: Invalid gesturebind format: %s\n", value); - return; + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid gesturebind " + "format: %s\n", + value); + return false; } trim_whitespace(mod_str); @@ -2283,6 +2573,12 @@ void parse_option(Config *config, char *key, char *value) { binding->mod = parse_mod(mod_str); binding->motion = parse_direction(motion_str); binding->fingers_count = atoi(fingers_count_str); + binding->arg.i = 0; + binding->arg.i2 = 0; + binding->arg.f = 0.0f; + binding->arg.f2 = 0.0f; + binding->arg.ui = 0; + binding->arg.ui2 = 0; binding->arg.v = NULL; binding->arg.v2 = NULL; binding->arg.v3 = NULL; @@ -2290,7 +2586,7 @@ void parse_option(Config *config, char *key, char *value) { parse_func_name(func_name, &binding->arg, arg_value, arg_value2, arg_value3, arg_value4, arg_value5); - if (!binding->func) { + if (!binding->func || binding->mod == UINT32_MAX) { if (binding->arg.v) { free(binding->arg.v); binding->arg.v = NULL; @@ -2303,8 +2599,13 @@ void parse_option(Config *config, char *key, char *value) { free(binding->arg.v3); binding->arg.v3 = NULL; } - fprintf(stderr, "Error: Unknown function in axisbind: %s\n", - func_name); + if (!binding->func) + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Unknown " + "dispatch in " + "axisbind: \033[1m\033[31m%s\n", + func_name); + return false; } else { config->gesture_bindings_count++; } @@ -2312,22 +2613,30 @@ void parse_option(Config *config, char *key, char *value) { } else if (strncmp(key, "source", 6) == 0) { parse_config_file(config, value); } else { - fprintf(stderr, "Error: Unknown key: %s\n", key); + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Unknown keyword: " + "\033[1m\033[31m%s\n", + key); + return false; } + + return true; } -void parse_config_line(Config *config, const char *line) { +bool parse_config_line(Config *config, const char *line) { char key[256], value[256]; if (sscanf(line, "%255[^=]=%255[^\n]", key, value) != 2) { - // fprintf(stderr, "Error: Invalid line format: %s\n", line); - return; + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m Invalid line format: %s", + line); + return false; } // Then trim each part separately trim_whitespace(key); trim_whitespace(value); - parse_option(config, key, value); + return parse_option(config, key, value); } void parse_config_file(Config *config, const char *file_path) { @@ -2346,7 +2655,9 @@ void parse_config_file(Config *config, const char *file_path) { } else { const char *home = getenv("HOME"); if (!home) { - fprintf(stderr, "Error: HOME environment variable not set.\n"); + fprintf(stderr, + "\033[1m\033[31m[ERROR]:\033[33m HOME environment " + "variable not set.\n"); return; } snprintf(full_path, sizeof(full_path), "%s/.config/mango/%s", home, @@ -2360,7 +2671,8 @@ void parse_config_file(Config *config, const char *file_path) { const char *home = getenv("HOME"); if (!home) { - fprintf(stderr, "Error: HOME environment variable not set.\n"); + fprintf(stderr, "\033[1m\033[31m[ERROR]:\033[33m HOME environment " + "variable not set.\n"); return; } snprintf(full_path, sizeof(full_path), "%s%s", home, file_path + 1); @@ -2372,16 +2684,29 @@ void parse_config_file(Config *config, const char *file_path) { } if (!file) { - perror("Error opening file"); + fprintf(stderr, + "\033[1;31m\033[1;33m[ERROR]:\033[0m Failed to open " + "config file: %s\n", + file_path); return; } char line[512]; + bool parse_correct = true; + uint32_t line_count = 0; while (fgets(line, sizeof(line), file)) { + line_count++; if (line[0] == '#' || line[0] == '\n') { continue; } - parse_config_line(config, line); + parse_correct = parse_config_line(config, line); + if (!parse_correct) { + fprintf(stderr, + "\033[1;31m╰─\033[1;33m[Index]\033[0m " + "\033[1;36m%s\033[0m:\033[1;35m%d\033[0m\n" + " \033[1;36m╰─\033[0;33m%s\033[0m\n\n", + file_path, line_count, line); + } } fclose(file); @@ -2390,7 +2715,7 @@ void parse_config_file(Config *config, const char *file_path) { void free_circle_layout(Config *config) { if (config->circle_layout) { // 释放每个字符串 - for (int i = 0; i < config->circle_layout_count; i++) { + for (int32_t i = 0; i < config->circle_layout_count; i++) { if (config->circle_layout[i]) { free(config->circle_layout[i]); // 释放单个字符串 config->circle_layout[i] = NULL; // 防止野指针 @@ -2436,11 +2761,11 @@ void free_baked_points(void) { void free_config(void) { // 释放内存 - int i; + int32_t i; // 释放 window_rules if (config.window_rules) { - for (int i = 0; i < config.window_rules_count; i++) { + for (int32_t i = 0; i < config.window_rules_count; i++) { ConfigWinRule *rule = &config.window_rules[i]; if (rule->id) free((void *)rule->id); @@ -2467,18 +2792,6 @@ void free_config(void) { config.window_rules_count = 0; } - // 释放 monitor_rules - if (config.monitor_rules) { - for (int i = 0; i < config.monitor_rules_count; i++) { - ConfigMonitorRule *rule = &config.monitor_rules[i]; - free((void *)rule->name); - free((void *)rule->layout); - } - free(config.monitor_rules); - config.monitor_rules = NULL; - config.monitor_rules_count = 0; - } - // 释放 key_bindings if (config.key_bindings) { for (i = 0; i < config.key_bindings_count; i++) { @@ -2586,7 +2899,7 @@ void free_config(void) { // 释放 tag_rules if (config.tag_rules) { - for (int i = 0; i < config.tag_rules_count; i++) { + for (int32_t i = 0; i < config.tag_rules_count; i++) { if (config.tag_rules[i].layout_name) free((void *)config.tag_rules[i].layout_name); if (config.tag_rules[i].monitor_name) @@ -2597,9 +2910,20 @@ void free_config(void) { config.tag_rules_count = 0; } + // 释放 monitor_rules + if (config.monitor_rules) { + for (int32_t i = 0; i < config.monitor_rules_count; i++) { + if (config.monitor_rules[i].name) + free((void *)config.monitor_rules[i].name); + } + free(config.monitor_rules); + config.monitor_rules = NULL; + config.monitor_rules_count = 0; + } + // 释放 layer_rules if (config.layer_rules) { - for (int i = 0; i < config.layer_rules_count; i++) { + for (int32_t i = 0; i < config.layer_rules_count; i++) { if (config.layer_rules[i].layer_name) free((void *)config.layer_rules[i].layer_name); if (config.layer_rules[i].animation_type_open) @@ -2614,7 +2938,7 @@ void free_config(void) { // 释放 env if (config.env) { - for (int i = 0; i < config.env_count; i++) { + for (int32_t i = 0; i < config.env_count; i++) { if (config.env[i]->type) { free((void *)config.env[i]->type); } @@ -2728,6 +3052,7 @@ void override_config(void) { // 概述模式设置 hotarea_size = CLAMP_INT(config.hotarea_size, 1, 1000); + hotarea_corner = CLAMP_INT(config.hotarea_corner, 0, 3); enable_hotarea = CLAMP_INT(config.enable_hotarea, 0, 1); ov_tab_mode = CLAMP_INT(config.ov_tab_mode, 0, 1); overviewgappi = CLAMP_INT(config.overviewgappi, 0, 1000); @@ -2736,7 +3061,6 @@ void override_config(void) { // 杂项设置 xwayland_persistence = CLAMP_INT(config.xwayland_persistence, 0, 1); syncobj_enable = CLAMP_INT(config.syncobj_enable, 0, 1); - adaptive_sync = CLAMP_INT(config.adaptive_sync, 0, 1); allow_tearing = CLAMP_INT(config.allow_tearing, 0, 2); allow_shortcuts_inhibit = CLAMP_INT(config.allow_shortcuts_inhibit, 0, 1); allow_lock_transparent = CLAMP_INT(config.allow_lock_transparent, 0, 1); @@ -2747,6 +3071,8 @@ void override_config(void) { CLAMP_INT(config.idleinhibit_ignore_visible, 0, 1); sloppyfocus = CLAMP_INT(config.sloppyfocus, 0, 1); warpcursor = CLAMP_INT(config.warpcursor, 0, 1); + drag_corner = CLAMP_INT(config.drag_corner, 0, 4); + drag_warp_cursor = CLAMP_INT(config.drag_warp_cursor, 0, 1); focus_cross_monitor = CLAMP_INT(config.focus_cross_monitor, 0, 1); exchange_cross_monitor = CLAMP_INT(config.exchange_cross_monitor, 0, 1); scratchpad_cross_monitor = CLAMP_INT(config.scratchpad_cross_monitor, 0, 1); @@ -2889,11 +3215,12 @@ void set_value_default() { config.numlockon = numlockon; // 是否打开右边小键盘 - config.ov_tab_mode = ov_tab_mode; // alt tab切换模式 - config.hotarea_size = hotarea_size; // 热区大小,10x10 + config.ov_tab_mode = ov_tab_mode; // alt tab切换模式 + config.hotarea_size = hotarea_size; // 热区大小,10x10 + config.hotarea_corner = hotarea_corner; config.enable_hotarea = enable_hotarea; // 是否启用鼠标热区 - config.smartgaps = - smartgaps; /* 1 means no outer gap when there is only one window */ + config.smartgaps = smartgaps; /* 1 means no outer gap when there is + only one window */ config.sloppyfocus = sloppyfocus; /* focus follows mouse */ config.gappih = gappih; /* horiz inner gap between windows */ config.gappiv = gappiv; /* vert inner gap between windows */ @@ -2921,7 +3248,6 @@ void set_value_default() { config.single_scratchpad = single_scratchpad; config.xwayland_persistence = xwayland_persistence; config.syncobj_enable = syncobj_enable; - config.adaptive_sync = adaptive_sync; config.allow_tearing = allow_tearing; config.allow_shortcuts_inhibit = allow_shortcuts_inhibit; config.allow_lock_transparent = allow_lock_transparent; @@ -2944,6 +3270,8 @@ void set_value_default() { config.cursor_hide_timeout = cursor_hide_timeout; config.warpcursor = warpcursor; /* Warp cursor to focused client */ + config.drag_corner = drag_corner; + config.drag_warp_cursor = drag_warp_cursor; config.repeat_rate = repeat_rate; config.repeat_delay = repeat_delay; @@ -3144,7 +3472,8 @@ void reset_blur_params(void) { void reapply_monitor_rules(void) { ConfigMonitorRule *mr; Monitor *m = NULL; - int ji, jk; + int32_t ji, vrr; + int32_t mx, my; struct wlr_output_state state; struct wlr_output_mode *internal_mode = NULL; wlr_output_state_init(&state); @@ -3159,20 +3488,11 @@ void reapply_monitor_rules(void) { break; mr = &config.monitor_rules[ji]; - if (!mr->name || regex_match(mr->name, m->wlr_output->name)) { + if (regex_match(mr->name, m->wlr_output->name)) { - m->mfact = mr->mfact; - m->nmaster = mr->nmaster; - m->m.x = mr->x; - m->m.y = mr->y; - - if (mr->layout) { - for (jk = 0; jk < LENGTH(layouts); jk++) { - if (strcmp(layouts[jk].name, mr->layout) == 0) { - m->lt = &layouts[jk]; - } - } - } + mx = mr->x == INT32_MAX ? m->m.x : mr->x; + my = mr->y == INT32_MAX ? m->m.y : mr->y; + vrr = mr->vrr >= 0 ? mr->vrr : 0; if (mr->width > 0 && mr->height > 0 && mr->refresh > 0) { internal_mode = get_nearest_output_mode( @@ -3182,21 +3502,22 @@ void reapply_monitor_rules(void) { } else if (wlr_output_is_headless(m->wlr_output)) { wlr_output_state_set_custom_mode( &state, mr->width, mr->height, - (int)roundf(mr->refresh * 1000)); + (int32_t)roundf(mr->refresh * 1000)); } } + if (vrr) { + enable_adaptive_sync(m, &state); + } else { + wlr_output_state_set_adaptive_sync_enabled(&state, false); + } + wlr_output_state_set_scale(&state, mr->scale); wlr_output_state_set_transform(&state, mr->rr); - wlr_output_layout_add(output_layout, m->wlr_output, mr->x, - mr->y); + wlr_output_layout_add(output_layout, m->wlr_output, mx, my); } } - if (adaptive_sync) { - enable_adaptive_sync(m, &state); - } - wlr_output_commit_state(m->wlr_output, &state); wlr_output_state_finish(&state); updatemons(NULL, NULL); @@ -3279,7 +3600,7 @@ void reapply_pointer(void) { void reapply_master(void) { - int i; + int32_t i; Monitor *m = NULL; for (i = 0; i <= LENGTH(tags); i++) { wl_list_for_each(m, &mons, link) { @@ -3297,8 +3618,14 @@ void reapply_master(void) { } void parse_tagrule(Monitor *m) { - int i, jk; + int32_t i, jk; ConfigTagRule tr; + Client *c = NULL; + + for (i = 0; i <= LENGTH(tags); i++) { + m->pertag->nmasters[i] = default_nmaster; + m->pertag->mfacts[i] = default_mfact; + } for (i = 0; i < config.tag_rules_count; i++) { @@ -3315,7 +3642,23 @@ void parse_tagrule(Monitor *m) { } } - m->pertag->no_hide[tr.id] = tr.no_hide; + if (tr.no_hide >= 0) + m->pertag->no_hide[tr.id] = tr.no_hide; + if (tr.nmaster >= 1) + m->pertag->nmasters[tr.id] = tr.nmaster; + if (tr.mfact > 0.0f) + m->pertag->mfacts[tr.id] = tr.mfact; + if (tr.no_render_border >= 0) + m->pertag->no_render_border[tr.id] = tr.no_render_border; + } + } + + for (i = 1; i <= LENGTH(tags); i++) { + wl_list_for_each(c, &clients, link) { + if ((c->tags & (1 << (i - 1)) & TAGMASK) && ISTILED(c)) { + if (m->pertag->mfacts[i] > 0.0f) + c->master_mfact_per = m->pertag->mfacts[i]; + } } } } @@ -3347,10 +3690,10 @@ void reset_option(void) { reapply_tagrule(); reapply_monitor_rules(); - arrange(selmon, false); + arrange(selmon, false, false); } -int reload_config(const Arg *arg) { +int32_t reload_config(const Arg *arg) { parse_config(); reset_option(); printstatus(); diff --git a/src/config/preset.h b/src/config/preset.h index 31f514f..ae4424f 100644 --- a/src/config/preset.h +++ b/src/config/preset.h @@ -8,17 +8,17 @@ ((hex >> 8) & 0xFF) / 255.0f, (hex & 0xFF) / 255.0f} /* animaion */ -char *animation_type_open = "slide"; // 是否启用动画 //slide,zoom -char *animation_type_close = "slide"; // 是否启用动画 //slide,zoom -char *layer_animation_type_open = "slide"; // 是否启用layer动画 //slide,zoom -char *layer_animation_type_close = "slide"; // 是否启用layer动画 //slide,zoom -int animations = 1; // 是否启用动画 -int layer_animations = 0; // 是否启用layer动画 -int tag_animation_direction = HORIZONTAL; // 标签动画方向 -int animation_fade_in = 1; // Enable animation fade in -int animation_fade_out = 1; // Enable animation fade out -float zoom_initial_ratio = 0.3; // 动画起始窗口比例 -float zoom_end_ratio = 0.8; // 动画结束窗口比例 +char *animation_type_open = "slide"; // 是否启用动画 //slide,zoom +char *animation_type_close = "slide"; // 是否启用动画 //slide,zoom +char *layer_animation_type_open = "slide"; // 是否启用layer动画 //slide,zoom +char *layer_animation_type_close = "slide"; // 是否启用layer动画 //slide,zoom +int32_t animations = 1; // 是否启用动画 +int32_t layer_animations = 0; // 是否启用layer动画 +int32_t tag_animation_direction = HORIZONTAL; // 标签动画方向 +int32_t animation_fade_in = 1; // Enable animation fade in +int32_t animation_fade_out = 1; // Enable animation fade out +float zoom_initial_ratio = 0.3; // 动画起始窗口比例 +float zoom_end_ratio = 0.8; // 动画结束窗口比例 float fadein_begin_opacity = 0.5; // Begin opac window ratio for animations float fadeout_begin_opacity = 0.5; // Begin opac window ratio for animations uint32_t animation_duration_move = 500; // Animation move speed @@ -40,47 +40,48 @@ uint32_t focus_on_activate = 1; // 收到窗口激活请求是否自动跳转 uint32_t new_is_master = 1; // 新窗口是否插在头部 double default_mfact = 0.55f; // master 窗口比例 uint32_t default_nmaster = 1; // 默认master数量 -int center_master_overspread = 0; // 中心master时是否铺满 -int center_when_single_stack = 1; // 单个stack时是否居中 +int32_t center_master_overspread = 0; // 中心master时是否铺满 +int32_t center_when_single_stack = 1; // 单个stack时是否居中 /* logging */ -int log_level = WLR_ERROR; +int32_t log_level = WLR_ERROR; uint32_t numlockon = 0; // 是否打开右边小键盘 uint32_t capslock = 0; // 是否启用快捷键 -uint32_t ov_tab_mode = 0; // alt tab切换模式 -uint32_t hotarea_size = 10; // 热区大小,10x10 +uint32_t ov_tab_mode = 0; // alt tab切换模式 +uint32_t hotarea_size = 10; // 热区大小,10x10 +uint32_t hotarea_corner = BOTTOM_LEFT; uint32_t enable_hotarea = 1; // 是否启用鼠标热区 -int smartgaps = 0; /* 1 means no outer gap when there is only one window */ -int sloppyfocus = 1; /* focus follows mouse */ -uint32_t gappih = 5; /* horiz inner gap between windows */ -uint32_t gappiv = 5; /* vert inner gap between windows */ -uint32_t gappoh = 10; /* horiz outer gap between windows and screen edge */ -uint32_t gappov = 10; /* vert outer gap between windows and screen edge */ +int32_t smartgaps = 0; /* 1 means no outer gap when there is only one window */ +int32_t sloppyfocus = 1; /* focus follows mouse */ +uint32_t gappih = 5; /* horiz inner gap between windows */ +uint32_t gappiv = 5; /* vert inner gap between windows */ +uint32_t gappoh = 10; /* horiz outer gap between windows and screen edge */ +uint32_t gappov = 10; /* vert outer gap between windows and screen edge */ float scratchpad_width_ratio = 0.8; float scratchpad_height_ratio = 0.9; -int scroller_structs = 20; +int32_t scroller_structs = 20; float scroller_default_proportion = 0.9; float scroller_default_proportion_single = 1.0; -int scroller_ignore_proportion_single = 0; -int scroller_focus_center = 0; -int scroller_prefer_center = 0; -int focus_cross_monitor = 0; -int focus_cross_tag = 0; -int exchange_cross_monitor = 0; -int scratchpad_cross_monitor = 0; -int view_current_to_back = 1; -int no_border_when_single = 0; -int no_radius_when_single = 0; -int snap_distance = 30; -int enable_floating_snap = 0; -int drag_tile_to_tile = 0; +int32_t scroller_ignore_proportion_single = 1; +int32_t scroller_focus_center = 0; +int32_t scroller_prefer_center = 0; +int32_t focus_cross_monitor = 0; +int32_t focus_cross_tag = 0; +int32_t exchange_cross_monitor = 0; +int32_t scratchpad_cross_monitor = 0; +int32_t view_current_to_back = 0; +int32_t no_border_when_single = 0; +int32_t no_radius_when_single = 0; +int32_t snap_distance = 30; +int32_t enable_floating_snap = 0; +int32_t drag_tile_to_tile = 0; uint32_t cursor_size = 24; uint32_t cursor_hide_timeout = 0; uint32_t swipe_min_threshold = 1; -int idleinhibit_ignore_visible = +int32_t idleinhibit_ignore_visible = 0; /* 1 means idle inhibitors will disable idle tracking even if it's surface isn't visible */ uint32_t borderpx = 4; /* border pixel of windows */ @@ -94,21 +95,23 @@ float globalcolor[] = COLOR(0xb153a7ff); float overlaycolor[] = COLOR(0x14a57cff); // char *cursor_theme = "Bibata-Modern-Ice"; -int overviewgappi = 5; /* overview时 窗口与边缘 缝隙大小 */ -int overviewgappo = 30; /* overview时 窗口与窗口 缝隙大小 */ +int32_t overviewgappi = 5; /* overview时 窗口与边缘 缝隙大小 */ +int32_t overviewgappo = 30; /* overview时 窗口与窗口 缝隙大小 */ /* To conform the xdg-protocol, set the alpha to zero to restore the old * behavior */ float fullscreen_bg[] = {0.1, 0.1, 0.1, 1.0}; -int warpcursor = 1; /* Warp cursor to focused client */ -int xwayland_persistence = 1; /* xwayland persistence */ -int syncobj_enable = 0; -int adaptive_sync = 0; -int allow_lock_transparent = 0; -double drag_refresh_interval = 16.0; -int allow_tearing = TEARING_DISABLED; -int allow_shortcuts_inhibit = SHORTCUTS_INHIBIT_ENABLE; +int32_t warpcursor = 1; +int32_t drag_corner = 3; +int32_t drag_warp_cursor = 1; +int32_t xwayland_persistence = 1; /* xwayland persistence */ +int32_t syncobj_enable = 0; +int32_t allow_lock_transparent = 0; +double drag_tile_refresh_interval = 16.0; +double drag_floating_refresh_interval = 8.0; +int32_t allow_tearing = TEARING_DISABLED; +int32_t allow_shortcuts_inhibit = SHORTCUTS_INHIBIT_ENABLE; /* keyboard */ @@ -145,21 +148,21 @@ struct xkb_rule_names xkb_rules = { .options = xkb_rules_options, }; -int repeat_rate = 25; -int repeat_delay = 600; +int32_t repeat_rate = 25; +int32_t repeat_delay = 600; /* Trackpad */ -int disable_trackpad = 0; -int tap_to_click = 1; -int tap_and_drag = 1; -int drag_lock = 1; -int mouse_natural_scrolling = 0; -int trackpad_natural_scrolling = 0; -int disable_while_typing = 1; -int left_handed = 0; -int middle_button_emulation = 0; -int single_scratchpad = 1; -int edge_scroller_pointer_focus = 1; +int32_t disable_trackpad = 0; +int32_t tap_to_click = 1; +int32_t tap_and_drag = 1; +int32_t drag_lock = 1; +int32_t mouse_natural_scrolling = 0; +int32_t trackpad_natural_scrolling = 0; +int32_t disable_while_typing = 1; +int32_t left_handed = 0; +int32_t middle_button_emulation = 0; +int32_t single_scratchpad = 1; +int32_t edge_scroller_pointer_focus = 1; /* You can choose between: LIBINPUT_CONFIG_SCROLL_NO_SCROLL @@ -210,27 +213,26 @@ static const char *tags[] = { float focused_opacity = 1.0; float unfocused_opacity = 1.0; -int border_radius = 0; -int border_radius_location_default = CORNER_LOCATION_ALL; -int blur = 0; -int blur_layer = 0; -int blur_optimized = 1; +int32_t border_radius = 0; +int32_t border_radius_location_default = CORNER_LOCATION_ALL; +int32_t blur = 0; +int32_t blur_layer = 0; +int32_t blur_optimized = 1; struct blur_data blur_params; -int blur_params_num_passes = 1; -int blur_params_radius = 5; +int32_t blur_params_num_passes = 1; +int32_t blur_params_radius = 5; float blur_params_noise = 0.02; float blur_params_brightness = 0.9; float blur_params_contrast = 0.9; float blur_params_saturation = 1.2; -int shadows = 0; -int shadow_only_floating = 1; -int layer_shadows = 0; +int32_t shadows = 0; +int32_t shadow_only_floating = 1; +int32_t layer_shadows = 0; uint32_t shadows_size = 10; double shadows_blur = 15; -int shadows_position_x = 0; -int shadows_position_y = 0; +int32_t shadows_position_x = 0; +int32_t shadows_position_y = 0; float shadowscolor[] = COLOR(0x000000ff); -; diff --git a/src/dispatch/bind_declare.h b/src/dispatch/bind_declare.h index 5bc215a..22ef612 100644 --- a/src/dispatch/bind_declare.h +++ b/src/dispatch/bind_declare.h @@ -1,71 +1,72 @@ -int minimized(const Arg *arg); -int restore_minimized(const Arg *arg); -int toggle_scratchpad(const Arg *arg); -int focusdir(const Arg *arg); -int toggleoverview(const Arg *arg); -int set_proportion(const Arg *arg); -int switch_proportion_preset(const Arg *arg); -int zoom(const Arg *arg); -int tagsilent(const Arg *arg); -int tagtoleft(const Arg *arg); -int tagtoright(const Arg *arg); -int tagcrossmon(const Arg *arg); -int viewtoleft(const Arg *arg); -int viewtoright(const Arg *arg); -int viewtoleft_have_client(const Arg *arg); -int viewtoright_have_client(const Arg *arg); -int viewcrossmon(const Arg *arg); -int togglefloating(const Arg *arg); -int togglefullscreen(const Arg *arg); -int togglemaximizescreen(const Arg *arg); -int togglegaps(const Arg *arg); -int tagmon(const Arg *arg); -int spawn(const Arg *arg); -int spawn_shell(const Arg *arg); -int spawn_on_empty(const Arg *arg); -int setkeymode(const Arg *arg); -int switch_keyboard_layout(const Arg *arg); -int setlayout(const Arg *arg); -int switch_layout(const Arg *arg); -int setmfact(const Arg *arg); -int quit(const Arg *arg); -int moveresize(const Arg *arg); -int exchange_client(const Arg *arg); -int exchange_stack_client(const Arg *arg); -int killclient(const Arg *arg); -int toggleglobal(const Arg *arg); -int incnmaster(const Arg *arg); -int focusmon(const Arg *arg); -int focusstack(const Arg *arg); -int chvt(const Arg *arg); -int reload_config(const Arg *arg); -int smartmovewin(const Arg *arg); -int smartresizewin(const Arg *arg); -int centerwin(const Arg *arg); -int bind_to_view(const Arg *arg); -int toggletag(const Arg *arg); -int toggleview(const Arg *arg); -int tag(const Arg *arg); -int comboview(const Arg *arg); -int incgaps(const Arg *arg); -int incigaps(const Arg *arg); -int incihgaps(const Arg *arg); -int incivgaps(const Arg *arg); -int incogaps(const Arg *arg); -int incohgaps(const Arg *arg); -int incovgaps(const Arg *arg); -int defaultgaps(const Arg *arg); -int togglefakefullscreen(const Arg *arg); -int toggleoverlay(const Arg *arg); -int movewin(const Arg *arg); -int resizewin(const Arg *arg); -int toggle_named_scratchpad(const Arg *arg); -int toggle_render_border(const Arg *arg); -int create_virtual_output(const Arg *arg); -int destroy_all_virtual_output(const Arg *arg); -int focuslast(const Arg *arg); -int toggle_trackpad_enable(const Arg *arg); -int setoption(const Arg *arg); -int disable_monitor(const Arg *arg); -int enable_monitor(const Arg *arg); -int toggle_monitor(const Arg *arg); \ No newline at end of file +int32_t minimized(const Arg *arg); +int32_t restore_minimized(const Arg *arg); +int32_t toggle_scratchpad(const Arg *arg); +int32_t focusdir(const Arg *arg); +int32_t toggleoverview(const Arg *arg); +int32_t set_proportion(const Arg *arg); +int32_t switch_proportion_preset(const Arg *arg); +int32_t zoom(const Arg *arg); +int32_t tagsilent(const Arg *arg); +int32_t tagtoleft(const Arg *arg); +int32_t tagtoright(const Arg *arg); +int32_t tagcrossmon(const Arg *arg); +int32_t viewtoleft(const Arg *arg); +int32_t viewtoright(const Arg *arg); +int32_t viewtoleft_have_client(const Arg *arg); +int32_t viewtoright_have_client(const Arg *arg); +int32_t viewcrossmon(const Arg *arg); +int32_t togglefloating(const Arg *arg); +int32_t togglefullscreen(const Arg *arg); +int32_t togglemaximizescreen(const Arg *arg); +int32_t togglegaps(const Arg *arg); +int32_t tagmon(const Arg *arg); +int32_t spawn(const Arg *arg); +int32_t spawn_shell(const Arg *arg); +int32_t spawn_on_empty(const Arg *arg); +int32_t setkeymode(const Arg *arg); +int32_t switch_keyboard_layout(const Arg *arg); +int32_t setlayout(const Arg *arg); +int32_t switch_layout(const Arg *arg); +int32_t setmfact(const Arg *arg); +int32_t quit(const Arg *arg); +int32_t moveresize(const Arg *arg); +int32_t exchange_client(const Arg *arg); +int32_t exchange_stack_client(const Arg *arg); +int32_t killclient(const Arg *arg); +int32_t toggleglobal(const Arg *arg); +int32_t incnmaster(const Arg *arg); +int32_t focusmon(const Arg *arg); +int32_t focusstack(const Arg *arg); +int32_t chvt(const Arg *arg); +int32_t reload_config(const Arg *arg); +int32_t smartmovewin(const Arg *arg); +int32_t smartresizewin(const Arg *arg); +int32_t centerwin(const Arg *arg); +int32_t bind_to_view(const Arg *arg); +int32_t toggletag(const Arg *arg); +int32_t toggleview(const Arg *arg); +int32_t tag(const Arg *arg); +int32_t comboview(const Arg *arg); +int32_t incgaps(const Arg *arg); +int32_t incigaps(const Arg *arg); +int32_t incihgaps(const Arg *arg); +int32_t incivgaps(const Arg *arg); +int32_t incogaps(const Arg *arg); +int32_t incohgaps(const Arg *arg); +int32_t incovgaps(const Arg *arg); +int32_t defaultgaps(const Arg *arg); +int32_t togglefakefullscreen(const Arg *arg); +int32_t toggleoverlay(const Arg *arg); +int32_t movewin(const Arg *arg); +int32_t resizewin(const Arg *arg); +int32_t toggle_named_scratchpad(const Arg *arg); +int32_t toggle_render_border(const Arg *arg); +int32_t create_virtual_output(const Arg *arg); +int32_t destroy_all_virtual_output(const Arg *arg); +int32_t focuslast(const Arg *arg); +int32_t toggle_trackpad_enable(const Arg *arg); +int32_t setoption(const Arg *arg); +int32_t disable_monitor(const Arg *arg); +int32_t enable_monitor(const Arg *arg); +int32_t toggle_monitor(const Arg *arg); +int32_t scroller_stack(const Arg *arg); \ No newline at end of file diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 80512d7..c0e51dc 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -1,4 +1,4 @@ -int bind_to_view(const Arg *arg) { +int32_t bind_to_view(const Arg *arg) { uint32_t target = arg->ui; @@ -15,14 +15,14 @@ int bind_to_view(const Arg *arg) { return 0; } - if ((int)target == INT_MIN && selmon->pertag->curtag == 0) { + if ((int32_t)target == INT_MIN && selmon->pertag->curtag == 0) { if (view_current_to_back && selmon->pertag->prevtag) target = 1 << (selmon->pertag->prevtag - 1); else target = 0; } - if (target == 0 || (int)target == INT_MIN) { + if (target == 0 || (int32_t)target == INT_MIN) { view(&(Arg){.ui = ~0 & TAGMASK, .i = arg->i}, false); } else { view(&(Arg){.ui = target, .i = arg->i}, true); @@ -30,18 +30,33 @@ int bind_to_view(const Arg *arg) { return 0; } -int chvt(const Arg *arg) { +int32_t chvt(const Arg *arg) { + struct timespec ts; + // prevent the animation to rquest the new frame + allow_frame_scheduling = false; + + // backup current tag and monitor name if (selmon) { chvt_backup_tag = selmon->pertag->curtag; strncpy(chvt_backup_selmon, selmon->wlr_output->name, sizeof(chvt_backup_selmon) - 1); } + wlr_session_change_vt(session, arg->ui); + + // wait for DRM device to stabilize and ensure the session state is inactive + ts.tv_sec = 0; + ts.tv_nsec = 100000000; // 200ms + nanosleep(&ts, NULL); + + // allow frame scheduling, + // because session state is now inactive, rendermon will not enter + allow_frame_scheduling = true; return 1; } -int create_virtual_output(const Arg *arg) { +int32_t create_virtual_output(const Arg *arg) { if (!wlr_backend_is_multi(backend)) { wlr_log(WLR_ERROR, "Expected a multi backend"); @@ -60,7 +75,7 @@ int create_virtual_output(const Arg *arg) { return 0; } -int destroy_all_virtual_output(const Arg *arg) { +int32_t destroy_all_virtual_output(const Arg *arg) { if (!wlr_backend_is_multi(backend)) { wlr_log(WLR_ERROR, "Expected a multi backend"); @@ -79,12 +94,12 @@ int destroy_all_virtual_output(const Arg *arg) { return 0; } -int defaultgaps(const Arg *arg) { +int32_t defaultgaps(const Arg *arg) { setgaps(gappoh, gappov, gappih, gappiv); return 0; } -int exchange_client(const Arg *arg) { +int32_t exchange_client(const Arg *arg) { Client *c = selmon->sel; if (!c || c->isfloating) return 0; @@ -96,7 +111,7 @@ int exchange_client(const Arg *arg) { return 0; } -int exchange_stack_client(const Arg *arg) { +int32_t exchange_stack_client(const Arg *arg) { Client *c = selmon->sel; Client *tc = NULL; if (!c || c->isfloating || c->isfullscreen || c->ismaximizescreen) @@ -111,9 +126,10 @@ int exchange_stack_client(const Arg *arg) { return 0; } -int focusdir(const Arg *arg) { +int32_t focusdir(const Arg *arg) { Client *c = NULL; c = direction_select(arg); + c = get_focused_stack_client(c); if (c) { focusclient(c, 1); if (warpcursor) @@ -131,7 +147,7 @@ int focusdir(const Arg *arg) { return 0; } -int focuslast(const Arg *arg) { +int32_t focuslast(const Arg *arg) { Client *c = NULL; Client *tc = NULL; @@ -163,7 +179,7 @@ int focuslast(const Arg *arg) { if (!tc || !client_surface(tc)->mapped) return 0; - if ((int)tc->tags > 0) { + if ((int32_t)tc->tags > 0) { focusclient(tc, 1); target = get_tags_first_tag(tc->tags); view(&(Arg){.ui = target}, true); @@ -171,12 +187,12 @@ int focuslast(const Arg *arg) { return 0; } -int toggle_trackpad_enable(const Arg *arg) { +int32_t toggle_trackpad_enable(const Arg *arg) { disable_trackpad = !disable_trackpad; return 0; } -int focusmon(const Arg *arg) { +int32_t focusmon(const Arg *arg) { Client *c = NULL; Monitor *m = NULL; Monitor *tm = NULL; @@ -216,7 +232,7 @@ int focusmon(const Arg *arg) { return 0; } -int focusstack(const Arg *arg) { +int32_t focusstack(const Arg *arg) { /* Focus the next or previous client (in tiling order) on selmon */ Client *sel = focustop(selmon); Client *tc = NULL; @@ -239,58 +255,58 @@ int focusstack(const Arg *arg) { return 0; } -int incnmaster(const Arg *arg) { +int32_t incnmaster(const Arg *arg) { if (!arg || !selmon) return 0; selmon->pertag->nmasters[selmon->pertag->curtag] = MAX(selmon->pertag->nmasters[selmon->pertag->curtag] + arg->i, 0); - arrange(selmon, false); + arrange(selmon, false, false); return 0; } -int incgaps(const Arg *arg) { +int32_t incgaps(const Arg *arg) { setgaps(selmon->gappoh + arg->i, selmon->gappov + arg->i, selmon->gappih + arg->i, selmon->gappiv + arg->i); return 0; } -int incigaps(const Arg *arg) { +int32_t incigaps(const Arg *arg) { setgaps(selmon->gappoh, selmon->gappov, selmon->gappih + arg->i, selmon->gappiv + arg->i); return 0; } -int incogaps(const Arg *arg) { +int32_t incogaps(const Arg *arg) { setgaps(selmon->gappoh + arg->i, selmon->gappov + arg->i, selmon->gappih, selmon->gappiv); return 0; } -int incihgaps(const Arg *arg) { +int32_t incihgaps(const Arg *arg) { setgaps(selmon->gappoh, selmon->gappov, selmon->gappih + arg->i, selmon->gappiv); return 0; } -int incivgaps(const Arg *arg) { +int32_t incivgaps(const Arg *arg) { setgaps(selmon->gappoh, selmon->gappov, selmon->gappih, selmon->gappiv + arg->i); return 0; } -int incohgaps(const Arg *arg) { +int32_t incohgaps(const Arg *arg) { setgaps(selmon->gappoh + arg->i, selmon->gappov, selmon->gappih, selmon->gappiv); return 0; } -int incovgaps(const Arg *arg) { +int32_t incovgaps(const Arg *arg) { setgaps(selmon->gappoh, selmon->gappov + arg->i, selmon->gappih, selmon->gappiv); return 0; } -int setmfact(const Arg *arg) { +int32_t setmfact(const Arg *arg) { float f; Client *c = NULL; @@ -308,11 +324,11 @@ int setmfact(const Arg *arg) { c->master_mfact_per = f; } } - arrange(selmon, false); + arrange(selmon, false, false); return 0; } -int killclient(const Arg *arg) { +int32_t killclient(const Arg *arg) { Client *c = NULL; c = selmon->sel; if (c) { @@ -321,7 +337,10 @@ int killclient(const Arg *arg) { return 0; } -int moveresize(const Arg *arg) { +int32_t moveresize(const Arg *arg) { + const char *cursors[] = {"nw-resize", "ne-resize", "sw-resize", + "se-resize"}; + if (cursor_mode != CurNormal && cursor_mode != CurPressed) return 0; xytonode(cursor->x, cursor->y, NULL, &grabc, NULL, NULL, NULL); @@ -347,10 +366,29 @@ int moveresize(const Arg *arg) { /* Doesn't work for X11 output - the next absolute motion event * returns the cursor to where it started */ if (grabc->isfloating) { - wlr_cursor_warp_closest(cursor, NULL, - grabc->geom.x + grabc->geom.width, - grabc->geom.y + grabc->geom.height); - wlr_cursor_set_xcursor(cursor, cursor_mgr, "bottom_right_corner"); + rzcorner = drag_corner; + grabcx = (int)round(cursor->x); + grabcy = (int)round(cursor->y); + if (rzcorner == 4) + /* identify the closest corner index */ + rzcorner = (grabcx - grabc->geom.x < + grabc->geom.x + grabc->geom.width - grabcx + ? 0 + : 1) + + (grabcy - grabc->geom.y < + grabc->geom.y + grabc->geom.height - grabcy + ? 0 + : 2); + + if (drag_warp_cursor) { + grabcx = rzcorner & 1 ? grabc->geom.x + grabc->geom.width + : grabc->geom.x; + grabcy = rzcorner & 2 ? grabc->geom.y + grabc->geom.height + : grabc->geom.y; + wlr_cursor_warp_closest(cursor, NULL, grabcx, grabcy); + } + + wlr_cursor_set_xcursor(cursor, cursor_mgr, cursors[rzcorner]); } else { wlr_cursor_set_xcursor(cursor, cursor_mgr, "grab"); } @@ -359,7 +397,7 @@ int moveresize(const Arg *arg) { return 0; } -int movewin(const Arg *arg) { +int32_t movewin(const Arg *arg) { Client *c = NULL; c = selmon->sel; if (!c || c->isfullscreen) @@ -397,19 +435,23 @@ int movewin(const Arg *arg) { return 0; } -int quit(const Arg *arg) { +int32_t quit(const Arg *arg) { wl_display_terminate(dpy); return 0; } -int resizewin(const Arg *arg) { +int32_t resizewin(const Arg *arg) { Client *c = NULL; c = selmon->sel; - int offsetx = 0, offsety = 0; + int32_t offsetx = 0, offsety = 0; if (!c || c->isfullscreen || c->ismaximizescreen) return 0; + int32_t animations_state_backup = animations; + if (!c->isfloating) + animations = 0; + if (ISTILED(c)) { switch (arg->ui) { case NUM_TYPE_MINUS: @@ -435,6 +477,7 @@ int resizewin(const Arg *arg) { break; } resize_tile_client(c, false, offsetx, offsety, 0); + animations = animations_state_backup; return 0; } @@ -465,10 +508,11 @@ int resizewin(const Arg *arg) { c->iscustomsize = 1; c->float_geom = c->geom; resize(c, c->geom, 0); + animations = animations_state_backup; return 0; } -int restore_minimized(const Arg *arg) { +int32_t restore_minimized(const Arg *arg) { Client *c = NULL; if (selmon && selmon->isoverview) @@ -491,7 +535,7 @@ int restore_minimized(const Arg *arg) { c->isnamedscratchpad = 0; show_hide_client(c); setborder_color(c); - arrange(c->mon, false); + arrange(c->mon, false, false); focusclient(c, 0); warp_cursor(c); return 0; @@ -500,14 +544,14 @@ int restore_minimized(const Arg *arg) { return 0; } -int setlayout(const Arg *arg) { - int jk; +int32_t setlayout(const Arg *arg) { + int32_t jk; for (jk = 0; jk < LENGTH(layouts); jk++) { if (strcmp(layouts[jk].name, arg->v) == 0) { selmon->pertag->ltidxs[selmon->pertag->curtag] = &layouts[jk]; clear_fullscreen_and_maximized_state(selmon); - arrange(selmon, false); + arrange(selmon, false, false); printstatus(); return 0; } @@ -515,7 +559,7 @@ int setlayout(const Arg *arg) { return 0; } -int setkeymode(const Arg *arg) { +int32_t setkeymode(const Arg *arg) { snprintf(keymode.mode, sizeof(keymode.mode), "%.27s", arg->v); if (strcmp(keymode.mode, "default") == 0) { keymode.isdefault = true; @@ -526,7 +570,7 @@ int setkeymode(const Arg *arg) { return 1; } -int set_proportion(const Arg *arg) { +int32_t set_proportion(const Arg *arg) { if (selmon->isoverview || !is_scroller_layout(selmon)) return 0; @@ -535,21 +579,23 @@ int set_proportion(const Arg *arg) { !scroller_ignore_proportion_single) return 0; - if (selmon->sel) { + Client *tc = selmon->sel; + + if (tc) { + tc = get_scroll_stack_head(tc); uint32_t max_client_width = selmon->w.width - 2 * scroller_structs - gappih; - selmon->sel->scroller_proportion = arg->f; - selmon->sel->geom.width = max_client_width * arg->f; - // resize(selmon->sel, selmon->sel->geom, 0); - arrange(selmon, false); + tc->scroller_proportion = arg->f; + tc->geom.width = max_client_width * arg->f; + arrange(selmon, false, false); } return 0; } -int smartmovewin(const Arg *arg) { +int32_t smartmovewin(const Arg *arg) { Client *c = NULL, *tc = NULL; - int nx, ny; - int buttom, top, left, right, tar; + int32_t nx, ny; + int32_t buttom, top, left, right, tar; c = selmon->sel; if (!c || c->isfullscreen) return 0; @@ -647,10 +693,10 @@ int smartmovewin(const Arg *arg) { return 0; } -int smartresizewin(const Arg *arg) { +int32_t smartresizewin(const Arg *arg) { Client *c = NULL, *tc = NULL; - int nw, nh; - int buttom, top, left, right, tar; + int32_t nw, nh; + int32_t buttom, top, left, right, tar; c = selmon->sel; if (!c || c->isfullscreen) return 0; @@ -717,7 +763,7 @@ int smartresizewin(const Arg *arg) { return 0; } -int centerwin(const Arg *arg) { +int32_t centerwin(const Arg *arg) { Client *c = NULL; c = selmon->sel; @@ -725,7 +771,7 @@ int centerwin(const Arg *arg) { return 0; if (c->isfloating) { - c->float_geom = setclient_coordinate_center(c, c->geom, 0, 0); + c->float_geom = setclient_coordinate_center(c, c->mon, c->geom, 0, 0); c->iscustomsize = 1; resize(c, c->float_geom, 1); return 0; @@ -734,17 +780,20 @@ int centerwin(const Arg *arg) { if (!is_scroller_layout(selmon)) return 0; + Client *stack_head = get_scroll_stack_head(c); if (selmon->pertag->ltidxs[selmon->pertag->curtag]->id == SCROLLER) { - c->geom.x = selmon->w.x + (selmon->w.width - c->geom.width) / 2; + stack_head->geom.x = + selmon->w.x + (selmon->w.width - stack_head->geom.width) / 2; } else { - c->geom.y = selmon->w.y + (selmon->w.height - c->geom.height) / 2; + stack_head->geom.y = + selmon->w.y + (selmon->w.height - stack_head->geom.height) / 2; } - arrange(selmon, false); + arrange(selmon, false, false); return 0; } -int spawn_shell(const Arg *arg) { +int32_t spawn_shell(const Arg *arg) { if (!arg->v) return 0; @@ -771,7 +820,7 @@ int spawn_shell(const Arg *arg) { return 0; } -int spawn(const Arg *arg) { +int32_t spawn(const Arg *arg) { if (!arg->v) return 0; @@ -787,7 +836,7 @@ int spawn(const Arg *arg) { // 2. 解析参数 char *argv[64]; - int argc = 0; + int32_t argc = 0; char *token = strtok((char *)arg->v, " "); while (token != NULL && argc < 63) { wordexp_t p; @@ -811,7 +860,7 @@ int spawn(const Arg *arg) { return 0; } -int spawn_on_empty(const Arg *arg) { +int32_t spawn_on_empty(const Arg *arg) { bool is_empty = true; Client *c = NULL; @@ -831,7 +880,7 @@ int spawn_on_empty(const Arg *arg) { return 0; } -int switch_keyboard_layout(const Arg *arg) { +int32_t switch_keyboard_layout(const Arg *arg) { if (!kb_group || !kb_group->wlr_group || !seat) { wlr_log(WLR_ERROR, "Invalid keyboard group or seat"); return 0; @@ -846,7 +895,7 @@ int switch_keyboard_layout(const Arg *arg) { // 1. 获取当前布局和计算下一个布局 xkb_layout_index_t current = xkb_state_serialize_layout( keyboard->xkb_state, XKB_STATE_LAYOUT_EFFECTIVE); - const int num_layouts = xkb_keymap_num_layouts(keyboard->keymap); + const int32_t num_layouts = xkb_keymap_num_layouts(keyboard->keymap); if (num_layouts < 2) { wlr_log(WLR_INFO, "Only one layout available"); return 0; @@ -887,9 +936,9 @@ int switch_keyboard_layout(const Arg *arg) { return 0; } -int switch_layout(const Arg *arg) { +int32_t switch_layout(const Arg *arg) { - int jk, ji; + int32_t jk, ji; char *target_layout_name = NULL; uint32_t len; @@ -923,7 +972,7 @@ int switch_layout(const Arg *arg) { } } clear_fullscreen_and_maximized_state(selmon); - arrange(selmon, false); + arrange(selmon, false, false); printstatus(); return 0; } @@ -934,7 +983,7 @@ int switch_layout(const Arg *arg) { selmon->pertag->ltidxs[selmon->pertag->curtag] = jk == LENGTH(layouts) - 1 ? &layouts[0] : &layouts[jk + 1]; clear_fullscreen_and_maximized_state(selmon); - arrange(selmon, false); + arrange(selmon, false, false); printstatus(); return 0; } @@ -942,7 +991,7 @@ int switch_layout(const Arg *arg) { return 0; } -int switch_proportion_preset(const Arg *arg) { +int32_t switch_proportion_preset(const Arg *arg) { float target_proportion = 0; if (config.scroller_proportion_preset_count == 0) { @@ -956,11 +1005,13 @@ int switch_proportion_preset(const Arg *arg) { !scroller_ignore_proportion_single) return 0; - if (selmon->sel) { + Client *tc = selmon->sel; - for (int i = 0; i < config.scroller_proportion_preset_count; i++) { + if (tc) { + tc = get_scroll_stack_head(tc); + for (int32_t i = 0; i < config.scroller_proportion_preset_count; i++) { if (config.scroller_proportion_preset[i] == - selmon->sel->scroller_proportion) { + tc->scroller_proportion) { if (i == config.scroller_proportion_preset_count - 1) { target_proportion = config.scroller_proportion_preset[0]; break; @@ -978,21 +1029,20 @@ int switch_proportion_preset(const Arg *arg) { uint32_t max_client_width = selmon->w.width - 2 * scroller_structs - gappih; - selmon->sel->scroller_proportion = target_proportion; - selmon->sel->geom.width = max_client_width * target_proportion; - // resize(selmon->sel, selmon->sel->geom, 0); - arrange(selmon, false); + tc->scroller_proportion = target_proportion; + tc->geom.width = max_client_width * target_proportion; + arrange(selmon, false, false); } return 0; } -int tag(const Arg *arg) { +int32_t tag(const Arg *arg) { Client *target_client = selmon->sel; tag_client(arg, target_client); return 0; } -int tagmon(const Arg *arg) { +int32_t tagmon(const Arg *arg) { Monitor *m = NULL, *cm = NULL; Client *c = focustop(selmon); @@ -1036,11 +1086,11 @@ int tagmon(const Arg *arg) { reset_foreign_tolevel(c); c->float_geom.width = - (int)(c->float_geom.width * c->mon->w.width / selmon->w.width); + (int32_t)(c->float_geom.width * c->mon->w.width / selmon->w.width); c->float_geom.height = - (int)(c->float_geom.height * c->mon->w.height / selmon->w.height); + (int32_t)(c->float_geom.height * c->mon->w.height / selmon->w.height); selmon = c->mon; - c->float_geom = setclient_coordinate_center(c, c->float_geom, 0, 0); + c->float_geom = setclient_coordinate_center(c, c->mon, c->float_geom, 0, 0); // 重新计算居中的坐标 // 重新计算居中的坐标 @@ -1055,7 +1105,7 @@ int tagmon(const Arg *arg) { target = get_tags_first_tag(c->tags); view(&(Arg){.ui = target}, true); focusclient(c, 1); - arrange(selmon, false); + arrange(selmon, false, false); } if (warpcursor) { warp_cursor_to_selmon(c->mon); @@ -1063,7 +1113,7 @@ int tagmon(const Arg *arg) { return 0; } -int tagsilent(const Arg *arg) { +int32_t tagsilent(const Arg *arg) { Client *fc = NULL; Client *target_client = NULL; @@ -1078,12 +1128,13 @@ int tagsilent(const Arg *arg) { clear_fullscreen_flag(fc); } } + exit_scroller_stack(target_client); focusclient(focustop(selmon), 1); - arrange(target_client->mon, false); + arrange(target_client->mon, false, false); return 0; } -int tagtoleft(const Arg *arg) { +int32_t tagtoleft(const Arg *arg) { if (selmon->sel != NULL && __builtin_popcount(selmon->tagset[selmon->seltags] & TAGMASK) == 1 && selmon->tagset[selmon->seltags] > 1) { @@ -1092,7 +1143,7 @@ int tagtoleft(const Arg *arg) { return 0; } -int tagtoright(const Arg *arg) { +int32_t tagtoright(const Arg *arg) { if (selmon->sel != NULL && __builtin_popcount(selmon->tagset[selmon->seltags] & TAGMASK) == 1 && selmon->tagset[selmon->seltags] & (TAGMASK >> 1)) { @@ -1101,7 +1152,7 @@ int tagtoright(const Arg *arg) { return 0; } -int toggle_named_scratchpad(const Arg *arg) { +int32_t toggle_named_scratchpad(const Arg *arg) { Client *target_client = NULL; char *arg_id = arg->v; char *arg_title = arg->v2; @@ -1120,13 +1171,13 @@ int toggle_named_scratchpad(const Arg *arg) { return 0; } -int toggle_render_border(const Arg *arg) { +int32_t toggle_render_border(const Arg *arg) { render_border = !render_border; - arrange(selmon, false); + arrange(selmon, false, false); return 0; } -int toggle_scratchpad(const Arg *arg) { +int32_t toggle_scratchpad(const Arg *arg) { Client *c = NULL; bool hit = false; Client *tmp = NULL; @@ -1155,14 +1206,14 @@ int toggle_scratchpad(const Arg *arg) { return 0; } -int togglefakefullscreen(const Arg *arg) { +int32_t togglefakefullscreen(const Arg *arg) { Client *sel = focustop(selmon); if (sel) setfakefullscreen(sel, !sel->isfakefullscreen); return 0; } -int togglefloating(const Arg *arg) { +int32_t togglefloating(const Arg *arg) { Client *sel = focustop(selmon); if (selmon && selmon->isoverview) @@ -1181,7 +1232,7 @@ int togglefloating(const Arg *arg) { return 0; } -int togglefullscreen(const Arg *arg) { +int32_t togglefullscreen(const Arg *arg) { Client *sel = focustop(selmon); if (!sel) return 0; @@ -1197,7 +1248,7 @@ int togglefullscreen(const Arg *arg) { return 0; } -int toggleglobal(const Arg *arg) { +int32_t toggleglobal(const Arg *arg) { if (!selmon->sel) return 0; if (selmon->sel->is_in_scratchpad) { @@ -1206,20 +1257,22 @@ int toggleglobal(const Arg *arg) { selmon->sel->isnamedscratchpad = 0; } selmon->sel->isglobal ^= 1; - // selmon->sel->tags = - // selmon->sel->isglobal ? TAGMASK : selmon->tagset[selmon->seltags]; - // focustop(selmon); + if (selmon->sel->isglobal && + (selmon->sel->prev_in_stack || selmon->sel->next_in_stack)) { + exit_scroller_stack(selmon->sel); + arrange(selmon, false, false); + } setborder_color(selmon->sel); return 0; } -int togglegaps(const Arg *arg) { +int32_t togglegaps(const Arg *arg) { enablegaps ^= 1; - arrange(selmon, false); + arrange(selmon, false, false); return 0; } -int togglemaximizescreen(const Arg *arg) { +int32_t togglemaximizescreen(const Arg *arg) { Client *sel = focustop(selmon); if (!sel) return 0; @@ -1237,7 +1290,7 @@ int togglemaximizescreen(const Arg *arg) { return 0; } -int toggleoverlay(const Arg *arg) { +int32_t toggleoverlay(const Arg *arg) { if (!selmon->sel || !selmon->sel->mon || selmon->sel->isfullscreen) { return 0; } @@ -1258,15 +1311,15 @@ int toggleoverlay(const Arg *arg) { return 0; } -int toggletag(const Arg *arg) { +int32_t toggletag(const Arg *arg) { uint32_t newtags; Client *sel = focustop(selmon); if (!sel) return 0; - if ((int)arg->ui == INT_MIN && sel->tags != (~0 & TAGMASK)) { + if ((int32_t)arg->ui == INT_MIN && sel->tags != (~0 & TAGMASK)) { newtags = ~0 & TAGMASK; - } else if ((int)arg->ui == INT_MIN && sel->tags == (~0 & TAGMASK)) { + } else if ((int32_t)arg->ui == INT_MIN && sel->tags == (~0 & TAGMASK)) { newtags = 1 << (sel->mon->pertag->curtag - 1); } else { newtags = sel->tags ^ (arg->ui & TAGMASK); @@ -1275,13 +1328,13 @@ int toggletag(const Arg *arg) { if (newtags) { sel->tags = newtags; focusclient(focustop(selmon), 1); - arrange(selmon, false); + arrange(selmon, false, false); } printstatus(); return 0; } -int toggleview(const Arg *arg) { +int32_t toggleview(const Arg *arg) { uint32_t newtagset; uint32_t target; @@ -1293,13 +1346,13 @@ int toggleview(const Arg *arg) { if (newtagset) { selmon->tagset[selmon->seltags] = newtagset; focusclient(focustop(selmon), 1); - arrange(selmon, false); + arrange(selmon, false, false); } printstatus(); return 0; } -int viewtoleft(const Arg *arg) { +int32_t viewtoleft(const Arg *arg) { uint32_t target = selmon->tagset[selmon->seltags]; if (selmon->isoverview || selmon->pertag->curtag == 0) { @@ -1319,7 +1372,7 @@ int viewtoleft(const Arg *arg) { return 0; } -int viewtoright(const Arg *arg) { +int32_t viewtoright(const Arg *arg) { if (selmon->isoverview || selmon->pertag->curtag == 0) { return 0; } @@ -1336,7 +1389,7 @@ int viewtoright(const Arg *arg) { return 0; } -int viewtoleft_have_client(const Arg *arg) { +int32_t viewtoleft_have_client(const Arg *arg) { uint32_t n; uint32_t current = get_tags_first_tag_num(selmon->tagset[selmon->seltags]); bool found = false; @@ -1360,7 +1413,7 @@ int viewtoleft_have_client(const Arg *arg) { return 0; } -int viewtoright_have_client(const Arg *arg) { +int32_t viewtoright_have_client(const Arg *arg) { uint32_t n; uint32_t current = get_tags_first_tag_num(selmon->tagset[selmon->seltags]); bool found = false; @@ -1384,21 +1437,26 @@ int viewtoright_have_client(const Arg *arg) { return 0; } -int viewcrossmon(const Arg *arg) { +int32_t viewcrossmon(const Arg *arg) { focusmon(&(Arg){.v = arg->v, .i = UNDIR}); view_in_mon(arg, true, selmon, true); return 0; } -int tagcrossmon(const Arg *arg) { - if (!selmon->sel) +int32_t tagcrossmon(const Arg *arg) { + if (!selmon || !selmon->sel) return 0; + if (regex_match(selmon->wlr_output->name, arg->v)) { + tag_client(arg, selmon->sel); + return 0; + } + tagmon(&(Arg){.ui = arg->ui, .i = UNDIR, .v = arg->v}); return 0; } -int comboview(const Arg *arg) { +int32_t comboview(const Arg *arg) { uint32_t newtags = arg->ui & TAGMASK; if (!newtags || !selmon) @@ -1407,7 +1465,7 @@ int comboview(const Arg *arg) { if (tag_combo) { selmon->tagset[selmon->seltags] |= newtags; focusclient(focustop(selmon), 1); - arrange(selmon, false); + arrange(selmon, false, false); } else { tag_combo = true; view(&(Arg){.ui = newtags}, false); @@ -1417,7 +1475,7 @@ int comboview(const Arg *arg) { return 0; } -int zoom(const Arg *arg) { +int32_t zoom(const Arg *arg) { Client *c = NULL, *sel = focustop(selmon); if (!sel || !selmon || @@ -1446,18 +1504,18 @@ int zoom(const Arg *arg) { wl_list_insert(&clients, &sel->link); focusclient(sel, 1); - arrange(selmon, false); + arrange(selmon, false, false); return 0; } -int setoption(const Arg *arg) { +int32_t setoption(const Arg *arg) { parse_option(&config, arg->v, arg->v2); override_config(); reset_option(); return 0; } -int minimized(const Arg *arg) { +int32_t minimized(const Arg *arg) { if (selmon && selmon->isoverview) return 0; @@ -1468,7 +1526,7 @@ int minimized(const Arg *arg) { return 0; } -int toggleoverview(const Arg *arg) { +int32_t toggleoverview(const Arg *arg) { Client *c = NULL; if (selmon->isoverview && ov_tab_mode && arg->i != 1 && selmon->sel) { @@ -1526,7 +1584,7 @@ int toggleoverview(const Arg *arg) { return 0; } -int disable_monitor(const Arg *arg) { +int32_t disable_monitor(const Arg *arg) { Monitor *m = NULL; struct wlr_output_state state = {0}; wl_list_for_each(m, &mons, link) { @@ -1541,7 +1599,7 @@ int disable_monitor(const Arg *arg) { return 0; } -int enable_monitor(const Arg *arg) { +int32_t enable_monitor(const Arg *arg) { Monitor *m = NULL; struct wlr_output_state state = {0}; wl_list_for_each(m, &mons, link) { @@ -1556,7 +1614,7 @@ int enable_monitor(const Arg *arg) { return 0; } -int toggle_monitor(const Arg *arg) { +int32_t toggle_monitor(const Arg *arg) { Monitor *m = NULL; struct wlr_output_state state = {0}; wl_list_for_each(m, &mons, link) { @@ -1570,3 +1628,106 @@ int toggle_monitor(const Arg *arg) { } return 0; } + +int32_t scroller_stack(const Arg *arg) { + Client *c = selmon->sel; + Client *stack_head = NULL; + Client *source_stack_head = NULL; + if (!c || !c->mon || c->isfloating || !is_scroller_layout(selmon)) + return 0; + + if (c && (!client_only_in_one_tag(c) || c->isglobal || c->isunglobal)) + return 0; + + bool is_horizontal_layout = + c->mon->pertag->ltidxs[c->mon->pertag->curtag]->id == SCROLLER ? true + : false; + + Client *target_client = find_client_by_direction(c, arg, false, true); + + if (target_client && (!client_only_in_one_tag(target_client) || + target_client->isglobal || target_client->isunglobal)) + return 0; + + if (target_client) { + stack_head = get_scroll_stack_head(target_client); + } + + if (c) { + source_stack_head = get_scroll_stack_head(c); + } + + if (stack_head == source_stack_head) { + return 0; + } + + if (c->isfullscreen) { + setfullscreen(c, 0); + } + + if (c->ismaximizescreen) { + setmaximizescreen(c, 0); + } + + if (c->prev_in_stack) { + if ((is_horizontal_layout && arg->i == LEFT) || + (!is_horizontal_layout && arg->i == UP)) { + exit_scroller_stack(c); + wl_list_remove(&c->link); + wl_list_insert(source_stack_head->link.prev, &c->link); + arrange(selmon, false, false); + + } else if ((is_horizontal_layout && arg->i == RIGHT) || + (!is_horizontal_layout && arg->i == DOWN)) { + exit_scroller_stack(c); + wl_list_remove(&c->link); + wl_list_insert(&source_stack_head->link, &c->link); + arrange(selmon, false, false); + } + return 0; + } else if (c->next_in_stack) { + Client *next_in_stack = c->next_in_stack; + if ((is_horizontal_layout && arg->i == LEFT) || + (!is_horizontal_layout && arg->i == UP)) { + exit_scroller_stack(c); + wl_list_remove(&c->link); + wl_list_insert(next_in_stack->link.prev, &c->link); + arrange(selmon, false, false); + } else if ((is_horizontal_layout && arg->i == RIGHT) || + (!is_horizontal_layout && arg->i == DOWN)) { + exit_scroller_stack(c); + wl_list_remove(&c->link); + wl_list_insert(&next_in_stack->link, &c->link); + arrange(selmon, false, false); + } + return 0; + } + + if (!target_client || target_client->mon != c->mon) { + return 0; + } + + exit_scroller_stack(c); + + // Find the tail of target_client's stack + Client *stack_tail = target_client; + while (stack_tail->next_in_stack) { + stack_tail = stack_tail->next_in_stack; + } + + // Add c to the stack + stack_tail->next_in_stack = c; + c->prev_in_stack = stack_tail; + c->next_in_stack = NULL; + + if (stack_head->ismaximizescreen) { + setmaximizescreen(stack_head, 0); + } + + if (stack_head->isfullscreen) { + setfullscreen(stack_head, 0); + } + + arrange(selmon, false, false); + return 0; +} \ No newline at end of file diff --git a/src/ext-protocol/dwl-ipc.h b/src/ext-protocol/dwl-ipc.h index eda3f49..ab0bdb8 100644 --- a/src/ext-protocol/dwl-ipc.h +++ b/src/ext-protocol/dwl-ipc.h @@ -112,7 +112,7 @@ void dwl_ipc_output_printstatus_to(DwlIpcOutput *ipc_output) { Client *c = NULL, *focused = NULL; struct wlr_keyboard *keyboard; xkb_layout_index_t current; - int tagmask, state, numclients, focused_client, tag; + int32_t tagmask, state, numclients, focused_client, tag; const char *title, *appid, *symbol; char kb_layout[32]; focused = focustop(monitor); @@ -238,7 +238,7 @@ void dwl_ipc_output_set_client_tags(struct wl_client *client, selected_client->tags = newtags; if (selmon == monitor) focusclient(focustop(monitor), 1); - arrange(selmon, false); + arrange(selmon, false, false); printstatus(); } @@ -257,7 +257,7 @@ void dwl_ipc_output_set_layout(struct wl_client *client, monitor->pertag->ltidxs[monitor->pertag->curtag] = &layouts[index]; clear_fullscreen_and_maximized_state(monitor); - arrange(monitor, false); + arrange(monitor, false, false); printstatus(); } @@ -287,7 +287,7 @@ void dwl_ipc_output_dispatch(struct wl_client *client, const char *arg3, const char *arg4, const char *arg5) { - int (*func)(const Arg *); + int32_t (*func)(const Arg *); Arg arg; func = parse_func_name((char *)dispatch, &arg, (char *)arg1, (char *)arg2, (char *)arg3, (char *)arg4, (char *)arg5); diff --git a/src/ext-protocol/ext-workspace.h b/src/ext-protocol/ext-workspace.h index 8ff53cc..28aaeee 100644 --- a/src/ext-protocol/ext-workspace.h +++ b/src/ext-protocol/ext-workspace.h @@ -102,7 +102,7 @@ static void remove_workspace_by_tag(uint32_t tag, Monitor *m) { } } -static void add_workspace_by_tag(int tag, Monitor *m) { +static void add_workspace_by_tag(int32_t tag, Monitor *m) { const char *name = get_name_from_tag(tag); struct workspace *workspace = ecalloc(1, sizeof(*workspace)); @@ -162,7 +162,7 @@ void dwl_ext_workspace_printstatus(Monitor *m) { } void refresh_monitors_workspaces_status(Monitor *m) { - int i; + int32_t i; if (m->isoverview) { for (i = 1; i <= LENGTH(tags); i++) { diff --git a/src/ext-protocol/foreign-toplevel.h b/src/ext-protocol/foreign-toplevel.h index 01c384f..89f3839 100644 --- a/src/ext-protocol/foreign-toplevel.h +++ b/src/ext-protocol/foreign-toplevel.h @@ -15,7 +15,7 @@ void handle_foreign_activate_request(struct wl_listener *listener, void *data) { c->is_scratchpad_show = 0; setborder_color(c); show_hide_client(c); - arrange(c->mon, true); + arrange(c->mon, true, false); return; } @@ -60,7 +60,7 @@ void handle_foreign_minimize_request(struct wl_listener *listener, void *data) { c->is_scratchpad_show = 0; setborder_color(c); show_hide_client(c); - arrange(c->mon, true); + arrange(c->mon, true, false); return; } } diff --git a/src/ext-protocol/text-input.h b/src/ext-protocol/text-input.h index 4c922ac..dbd97e1 100644 --- a/src/ext-protocol/text-input.h +++ b/src/ext-protocol/text-input.h @@ -77,7 +77,7 @@ Monitor *output_from_wlr_output(struct wlr_output *wlr_output) { return NULL; } -Monitor *output_nearest_to(int lx, int ly) { +Monitor *output_nearest_to(int32_t lx, int32_t ly) { double closest_x, closest_y; wlr_output_layout_closest_point(output_layout, NULL, lx, ly, &closest_x, &closest_y); @@ -225,7 +225,7 @@ static void update_popup_position(struct dwl_input_method_popup *popup) { Monitor *output = NULL; struct wlr_xdg_positioner_rules pointer_rules; struct wlr_box output_box; - int lx, ly; + int32_t lx, ly; struct wlr_box popup_box; if (!text_input || !relay->focused_surface || diff --git a/src/fetch/client.h b/src/fetch/client.h index 56ca982..bf30e17 100644 --- a/src/fetch/client.h +++ b/src/fetch/client.h @@ -1,5 +1,5 @@ bool check_hit_no_border(Client *c) { - int i; + int32_t i; bool hit_no_border = false; if (!render_border) { hit_no_border = true; @@ -12,7 +12,9 @@ bool check_hit_no_border(Client *c) { } } - if (no_border_when_single && c && c->mon && c->mon->visible_clients == 1) { + if (no_border_when_single && c && c->mon && + ((ISSCROLLTILED(c) && c->mon->visible_scroll_tiling_clients == 1) || + c->mon->visible_clients == 1)) { hit_no_border = true; } return hit_no_border; @@ -74,16 +76,16 @@ Client *get_client_by_id_or_title(const char *arg_id, const char *arg_title) { return target_client; } struct wlr_box // 计算客户端居中坐标 -setclient_coordinate_center(Client *c, struct wlr_box geom, int offsetx, - int offsety) { +setclient_coordinate_center(Client *c, Monitor *tm, struct wlr_box geom, + int32_t offsetx, int32_t offsety) { struct wlr_box tempbox; - int offset = 0; - int len = 0; - Monitor *m = c->mon ? c->mon : selmon; + int32_t offset = 0; + int32_t len = 0; + Monitor *m = tm ? tm : selmon; uint32_t cbw = check_hit_no_border(c) ? c->bw : 0; - if (!c->no_force_center) { + if (!c->no_force_center && m) { tempbox.x = m->w.x + (m->w.width - geom.width) / 2; tempbox.y = m->w.y + (m->w.height - geom.height) / 2; } else { @@ -135,9 +137,9 @@ static bool is_window_rule_matches(const ConfigWinRule *r, const char *appid, Client *center_tiled_select(Monitor *m) { Client *c = NULL; Client *target_c = NULL; - long int mini_distance = -1; - int dirx, diry; - long int distance; + int64_t mini_distance = -1; + int32_t dirx, diry; + int64_t distance; wl_list_for_each(c, &clients, link) { if (c && VISIBLEON(c, m) && ISSCROLLTILED(c) && client_surface(c)->mapped && !c->isfloating && @@ -157,7 +159,7 @@ Client *find_client_by_direction(Client *tc, const Arg *arg, bool findfloating, bool ignore_align) { Client *c = NULL; Client **tempClients = NULL; // 初始化为 NULL - int last = -1; + int32_t last = -1; // 第一次遍历,计算客户端数量 wl_list_for_each(c, &clients, link) { @@ -190,23 +192,23 @@ Client *find_client_by_direction(Client *tc, const Arg *arg, bool findfloating, } } - int sel_x = tc->geom.x; - int sel_y = tc->geom.y; - long long int distance = LLONG_MAX; - long long int same_monitor_distance = LLONG_MAX; + int32_t sel_x = tc->geom.x; + int32_t sel_y = tc->geom.y; + int64_t distance = LLONG_MAX; + int64_t same_monitor_distance = LLONG_MAX; Client *tempFocusClients = NULL; Client *tempSameMonitorFocusClients = NULL; switch (arg->i) { case UP: if (!ignore_align) { - for (int _i = 0; _i <= last; _i++) { + for (int32_t _i = 0; _i <= last; _i++) { if (tempClients[_i]->geom.y < sel_y && tempClients[_i]->geom.x == sel_x && tempClients[_i]->mon == tc->mon) { - int dis_x = tempClients[_i]->geom.x - sel_x; - int dis_y = tempClients[_i]->geom.y - sel_y; - long long int tmp_distance = + int32_t dis_x = tempClients[_i]->geom.x - sel_x; + int32_t dis_y = tempClients[_i]->geom.y - sel_y; + int64_t tmp_distance = dis_x * dis_x + dis_y * dis_y; // 计算距离 if (tmp_distance < distance) { distance = tmp_distance; @@ -216,11 +218,32 @@ Client *find_client_by_direction(Client *tc, const Arg *arg, bool findfloating, } } if (!tempFocusClients) { - for (int _i = 0; _i <= last; _i++) { + for (int32_t _i = 0; _i <= last; _i++) { + if (tempClients[_i]->geom.y < sel_y && + tempClients[_i]->mon == tc->mon && + client_is_in_same_stack(tc, tempClients[_i], NULL)) { + int32_t dis_x = tempClients[_i]->geom.x - sel_x; + int32_t dis_y = tempClients[_i]->geom.y - sel_y; + int64_t tmp_distance = + dis_x * dis_x + dis_y * dis_y; // 计算距离 + if (tmp_distance < distance) { + distance = tmp_distance; + tempFocusClients = tempClients[_i]; + } + if (tempClients[_i]->mon == tc->mon && + tmp_distance < same_monitor_distance) { + same_monitor_distance = tmp_distance; + tempSameMonitorFocusClients = tempClients[_i]; + } + } + } + } + if (!tempFocusClients) { + for (int32_t _i = 0; _i <= last; _i++) { if (tempClients[_i]->geom.y < sel_y) { - int dis_x = tempClients[_i]->geom.x - sel_x; - int dis_y = tempClients[_i]->geom.y - sel_y; - long long int tmp_distance = + int32_t dis_x = tempClients[_i]->geom.x - sel_x; + int32_t dis_y = tempClients[_i]->geom.y - sel_y; + int64_t tmp_distance = dis_x * dis_x + dis_y * dis_y; // 计算距离 if (tmp_distance < distance) { distance = tmp_distance; @@ -237,13 +260,13 @@ Client *find_client_by_direction(Client *tc, const Arg *arg, bool findfloating, break; case DOWN: if (!ignore_align) { - for (int _i = 0; _i <= last; _i++) { + for (int32_t _i = 0; _i <= last; _i++) { if (tempClients[_i]->geom.y > sel_y && tempClients[_i]->geom.x == sel_x && tempClients[_i]->mon == tc->mon) { - int dis_x = tempClients[_i]->geom.x - sel_x; - int dis_y = tempClients[_i]->geom.y - sel_y; - long long int tmp_distance = + int32_t dis_x = tempClients[_i]->geom.x - sel_x; + int32_t dis_y = tempClients[_i]->geom.y - sel_y; + int64_t tmp_distance = dis_x * dis_x + dis_y * dis_y; // 计算距离 if (tmp_distance < distance) { distance = tmp_distance; @@ -253,11 +276,32 @@ Client *find_client_by_direction(Client *tc, const Arg *arg, bool findfloating, } } if (!tempFocusClients) { - for (int _i = 0; _i <= last; _i++) { + for (int32_t _i = 0; _i <= last; _i++) { + if (tempClients[_i]->geom.y > sel_y && + tempClients[_i]->mon == tc->mon && + client_is_in_same_stack(tc, tempClients[_i], NULL)) { + int32_t dis_x = tempClients[_i]->geom.x - sel_x; + int32_t dis_y = tempClients[_i]->geom.y - sel_y; + int64_t tmp_distance = + dis_x * dis_x + dis_y * dis_y; // 计算距离 + if (tmp_distance < distance) { + distance = tmp_distance; + tempFocusClients = tempClients[_i]; + } + if (tempClients[_i]->mon == tc->mon && + tmp_distance < same_monitor_distance) { + same_monitor_distance = tmp_distance; + tempSameMonitorFocusClients = tempClients[_i]; + } + } + } + } + if (!tempFocusClients) { + for (int32_t _i = 0; _i <= last; _i++) { if (tempClients[_i]->geom.y > sel_y) { - int dis_x = tempClients[_i]->geom.x - sel_x; - int dis_y = tempClients[_i]->geom.y - sel_y; - long long int tmp_distance = + int32_t dis_x = tempClients[_i]->geom.x - sel_x; + int32_t dis_y = tempClients[_i]->geom.y - sel_y; + int64_t tmp_distance = dis_x * dis_x + dis_y * dis_y; // 计算距离 if (tmp_distance < distance) { distance = tmp_distance; @@ -274,13 +318,13 @@ Client *find_client_by_direction(Client *tc, const Arg *arg, bool findfloating, break; case LEFT: if (!ignore_align) { - for (int _i = 0; _i <= last; _i++) { + for (int32_t _i = 0; _i <= last; _i++) { if (tempClients[_i]->geom.x < sel_x && tempClients[_i]->geom.y == sel_y && tempClients[_i]->mon == tc->mon) { - int dis_x = tempClients[_i]->geom.x - sel_x; - int dis_y = tempClients[_i]->geom.y - sel_y; - long long int tmp_distance = + int32_t dis_x = tempClients[_i]->geom.x - sel_x; + int32_t dis_y = tempClients[_i]->geom.y - sel_y; + int64_t tmp_distance = dis_x * dis_x + dis_y * dis_y; // 计算距离 if (tmp_distance < distance) { distance = tmp_distance; @@ -290,11 +334,32 @@ Client *find_client_by_direction(Client *tc, const Arg *arg, bool findfloating, } } if (!tempFocusClients) { - for (int _i = 0; _i <= last; _i++) { + for (int32_t _i = 0; _i <= last; _i++) { + if (tempClients[_i]->geom.x < sel_x && + tempClients[_i]->mon == tc->mon && + client_is_in_same_stack(tc, tempClients[_i], NULL)) { + int32_t dis_x = tempClients[_i]->geom.x - sel_x; + int32_t dis_y = tempClients[_i]->geom.y - sel_y; + int64_t tmp_distance = + dis_x * dis_x + dis_y * dis_y; // 计算距离 + if (tmp_distance < distance) { + distance = tmp_distance; + tempFocusClients = tempClients[_i]; + } + if (tempClients[_i]->mon == tc->mon && + tmp_distance < same_monitor_distance) { + same_monitor_distance = tmp_distance; + tempSameMonitorFocusClients = tempClients[_i]; + } + } + } + } + if (!tempFocusClients) { + for (int32_t _i = 0; _i <= last; _i++) { if (tempClients[_i]->geom.x < sel_x) { - int dis_x = tempClients[_i]->geom.x - sel_x; - int dis_y = tempClients[_i]->geom.y - sel_y; - long long int tmp_distance = + int32_t dis_x = tempClients[_i]->geom.x - sel_x; + int32_t dis_y = tempClients[_i]->geom.y - sel_y; + int64_t tmp_distance = dis_x * dis_x + dis_y * dis_y; // 计算距离 if (tmp_distance < distance) { distance = tmp_distance; @@ -311,13 +376,13 @@ Client *find_client_by_direction(Client *tc, const Arg *arg, bool findfloating, break; case RIGHT: if (!ignore_align) { - for (int _i = 0; _i <= last; _i++) { + for (int32_t _i = 0; _i <= last; _i++) { if (tempClients[_i]->geom.x > sel_x && tempClients[_i]->geom.y == sel_y && tempClients[_i]->mon == tc->mon) { - int dis_x = tempClients[_i]->geom.x - sel_x; - int dis_y = tempClients[_i]->geom.y - sel_y; - long long int tmp_distance = + int32_t dis_x = tempClients[_i]->geom.x - sel_x; + int32_t dis_y = tempClients[_i]->geom.y - sel_y; + int64_t tmp_distance = dis_x * dis_x + dis_y * dis_y; // 计算距离 if (tmp_distance < distance) { distance = tmp_distance; @@ -327,11 +392,32 @@ Client *find_client_by_direction(Client *tc, const Arg *arg, bool findfloating, } } if (!tempFocusClients) { - for (int _i = 0; _i <= last; _i++) { + for (int32_t _i = 0; _i <= last; _i++) { + if (tempClients[_i]->geom.x > sel_x && + tempClients[_i]->mon == tc->mon && + client_is_in_same_stack(tc, tempClients[_i], NULL)) { + int32_t dis_x = tempClients[_i]->geom.x - sel_x; + int32_t dis_y = tempClients[_i]->geom.y - sel_y; + int64_t tmp_distance = + dis_x * dis_x + dis_y * dis_y; // 计算距离 + if (tmp_distance < distance) { + distance = tmp_distance; + tempFocusClients = tempClients[_i]; + } + if (tempClients[_i]->mon == tc->mon && + tmp_distance < same_monitor_distance) { + same_monitor_distance = tmp_distance; + tempSameMonitorFocusClients = tempClients[_i]; + } + } + } + } + if (!tempFocusClients) { + for (int32_t _i = 0; _i <= last; _i++) { if (tempClients[_i]->geom.x > sel_x) { - int dis_x = tempClients[_i]->geom.x - sel_x; - int dis_y = tempClients[_i]->geom.y - sel_y; - long long int tmp_distance = + int32_t dis_x = tempClients[_i]->geom.x - sel_x; + int32_t dis_y = tempClients[_i]->geom.y - sel_y; + int64_t tmp_distance = dis_x * dis_x + dis_y * dis_y; // 计算距离 if (tmp_distance < distance) { distance = tmp_distance; @@ -369,7 +455,9 @@ Client *direction_select(const Arg *arg) { } return find_client_by_direction( - tc, arg, true, is_scroller_layout(selmon) && !selmon->isoverview); + tc, arg, true, + (is_scroller_layout(selmon) || is_centertile_layout(selmon)) && + !selmon->isoverview); } /* We probably should change the name of this, it sounds like @@ -396,6 +484,9 @@ Client *get_next_stack_client(Client *c, bool reverse) { if (&next->link == &clients) continue; /* wrap past the sentinel node */ + if (next->isunglobal) + continue; + if (next != c && next->mon && VISIBLEON(next, c->mon)) return next; } @@ -404,6 +495,9 @@ Client *get_next_stack_client(Client *c, bool reverse) { if (&next->link == &clients) continue; /* wrap past the sentinel node */ + if (next->isunglobal) + continue; + if (next != c && next->mon && VISIBLEON(next, c->mon)) return next; } @@ -432,7 +526,7 @@ float *get_border_color(Client *c) { } } -int is_single_bit_set(uint32_t x) { return x && !(x & (x - 1)); } +int32_t is_single_bit_set(uint32_t x) { return x && !(x & (x - 1)); } bool client_only_in_one_tag(Client *c) { uint32_t masked = c->tags & TAGMASK; @@ -441,4 +535,91 @@ bool client_only_in_one_tag(Client *c) { } else { return false; } -} \ No newline at end of file +} + +Client *get_scroll_stack_head(Client *c) { + Client *scroller_stack_head = c; + + if (!scroller_stack_head) + return NULL; + + while (scroller_stack_head->prev_in_stack) { + scroller_stack_head = scroller_stack_head->prev_in_stack; + } + return scroller_stack_head; +} + +bool client_is_in_same_stack(Client *sc, Client *tc, Client *fc) { + if (!sc || !tc) + return false; + + uint32_t id = sc->mon->pertag->ltidxs[sc->mon->pertag->curtag]->id; + + if (id != SCROLLER && id != VERTICAL_SCROLLER && id != TILE && + id != VERTICAL_TILE && id != DECK && id != VERTICAL_DECK && + id != CENTER_TILE && id != RIGHT_TILE && id != TGMIX) + return false; + + if (id == SCROLLER || id == VERTICAL_SCROLLER) { + Client *source_stack_head = get_scroll_stack_head(sc); + Client *target_stack_head = get_scroll_stack_head(tc); + Client *fc_head = fc ? get_scroll_stack_head(fc) : NULL; + if (fc && fc->prev_in_stack && fc_head == source_stack_head) + return false; + if (source_stack_head == target_stack_head) + return true; + else + return false; + } + + if (id == TILE || id == VERTICAL_TILE || id == DECK || + id == VERTICAL_DECK || id == RIGHT_TILE) { + if (fc && !fc->ismaster) + return false; + else if (!sc->ismaster) + return true; + } + + if (id == TGMIX) { + if (fc && !fc->ismaster) + return false; + if (!sc->ismaster && sc->mon->visible_tiling_clients <= 3) + return true; + } + + if (id == CENTER_TILE) { + if (fc && !fc->ismaster) + return false; + if (!sc->ismaster && sc->geom.x == tc->geom.x) + return true; + else + return false; + } + + return false; +} + +Client *get_focused_stack_client(Client *sc) { + if (!sc || sc->isfloating) + return sc; + + Client *tc = NULL; + Client *fc = focustop(sc->mon); + + if (fc->isfloating || sc->isfloating) + return sc; + + wl_list_for_each(tc, &fstack, flink) { + if (tc->iskilling || tc->isunglobal) + continue; + if (!VISIBLEON(tc, sc->mon)) + continue; + if (tc == fc) + continue; + + if (client_is_in_same_stack(sc, tc, fc)) { + return tc; + } + } + return sc; +} diff --git a/src/fetch/common.h b/src/fetch/common.h index 6840750..58e69dc 100644 --- a/src/fetch/common.h +++ b/src/fetch/common.h @@ -19,11 +19,11 @@ pid_t getparentprocess(pid_t p) { return (pid_t)v; } -int isdescprocess(pid_t p, pid_t c) { +int32_t isdescprocess(pid_t p, pid_t c) { while (p != c && c != 0) c = getparentprocess(c); - return (int)c; + return (int32_t)c; } void get_layout_abbr(char *abbr, const char *full_name) { @@ -31,7 +31,7 @@ void get_layout_abbr(char *abbr, const char *full_name) { abbr[0] = '\0'; // 1. 尝试在映射表中查找 - for (int i = 0; layout_mappings[i].full_name != NULL; i++) { + for (int32_t i = 0; layout_mappings[i].full_name != NULL; i++) { if (strcmp(full_name, layout_mappings[i].full_name) == 0) { strcpy(abbr, layout_mappings[i].abbr); return; @@ -83,7 +83,7 @@ void xytonode(double x, double y, struct wlr_surface **psurface, Client **pc, struct wlr_surface *surface = NULL; Client *c = NULL; LayerSurface *l = NULL; - int layer; + int32_t layer; for (layer = NUM_LAYERS - 1; !surface && layer >= 0; layer--) { diff --git a/src/fetch/monitor.h b/src/fetch/monitor.h index 47a5b82..7a1ca4d 100644 --- a/src/fetch/monitor.h +++ b/src/fetch/monitor.h @@ -26,6 +26,14 @@ bool is_scroller_layout(Monitor *m) { return false; } +bool is_centertile_layout(Monitor *m) { + + if (m->pertag->ltidxs[m->pertag->curtag]->id == CENTER_TILE) + return true; + + return false; +} + uint32_t get_tag_status(uint32_t tag, Monitor *m) { Client *c = NULL; uint32_t status = 0; diff --git a/src/layout/arrange.h b/src/layout/arrange.h index dc8b47e..3721364 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -1,6 +1,10 @@ void set_size_per(Monitor *m, Client *c) { Client *fc = NULL; bool found = false; + + if (!m || !c) + return; + wl_list_for_each(fc, &clients, link) { if (VISIBLEON(fc, m) && ISTILED(fc) && fc != c) { c->master_mfact_per = fc->master_mfact_per; @@ -18,8 +22,9 @@ void set_size_per(Monitor *m, Client *c) { } } -void resize_tile_master_horizontal(Client *grabc, bool isdrag, int offsetx, - int offsety, uint32_t time, int type) { +void resize_tile_master_horizontal(Client *grabc, bool isdrag, int32_t offsetx, + int32_t offsety, uint32_t time, + int32_t type) { Client *tc = NULL; float delta_x, delta_y; Client *next = NULL; @@ -200,20 +205,20 @@ void resize_tile_master_horizontal(Client *grabc, bool isdrag, int offsetx, grabc->stack_inner_per = new_stack_inner_per; if (!isdrag) { - arrange(grabc->mon, false); + arrange(grabc->mon, false, false); return; } if (last_apply_drap_time == 0 || - time - last_apply_drap_time > drag_refresh_interval) { - arrange(grabc->mon, false); + time - last_apply_drap_time > drag_tile_refresh_interval) { + arrange(grabc->mon, false, false); last_apply_drap_time = time; } } } -void resize_tile_master_vertical(Client *grabc, bool isdrag, int offsetx, - int offsety, uint32_t time, int type) { +void resize_tile_master_vertical(Client *grabc, bool isdrag, int32_t offsetx, + int32_t offsety, uint32_t time, int32_t type) { Client *tc = NULL; float delta_x, delta_y; Client *next = NULL; @@ -357,22 +362,24 @@ void resize_tile_master_vertical(Client *grabc, bool isdrag, int offsetx, grabc->stack_inner_per = new_stack_inner_per; if (!isdrag) { - arrange(grabc->mon, false); + arrange(grabc->mon, false, false); return; } if (last_apply_drap_time == 0 || - time - last_apply_drap_time > drag_refresh_interval) { - arrange(grabc->mon, false); + time - last_apply_drap_time > drag_tile_refresh_interval) { + arrange(grabc->mon, false, false); last_apply_drap_time = time; } } } -void resize_tile_scroller(Client *grabc, bool isdrag, int offsetx, int offsety, - uint32_t time, bool isvertical) { +void resize_tile_scroller(Client *grabc, bool isdrag, int32_t offsetx, + int32_t offsety, uint32_t time, bool isvertical) { float delta_x, delta_y; float new_scroller_proportion; + float new_stack_proportion; + Client *stack_head = get_scroll_stack_head(grabc); if (grabc && grabc->mon->visible_tiling_clients == 1 && !scroller_ignore_proportion_single) @@ -384,7 +391,8 @@ void resize_tile_scroller(Client *grabc, bool isdrag, int offsetx, int offsety, start_drag_window = true; // 记录初始状态 - grabc->old_scroller_pproportion = grabc->scroller_proportion; + stack_head->old_scroller_pproportion = stack_head->scroller_proportion; + grabc->old_stack_proportion = grabc->stack_proportion; grabc->cursor_in_left_half = cursor->x < grabc->geom.x + grabc->geom.width / 2; @@ -404,15 +412,26 @@ void resize_tile_scroller(Client *grabc, bool isdrag, int offsetx, int offsety, grabc->old_master_inner_per = grabc->master_inner_per; grabc->old_stack_inner_per = grabc->stack_inner_per; grabc->drag_begin_geom = grabc->geom; - grabc->old_scroller_pproportion = grabc->scroller_proportion; + stack_head->old_scroller_pproportion = + stack_head->scroller_proportion; + grabc->old_stack_proportion = grabc->stack_proportion; grabc->cursor_in_upper_half = false; grabc->cursor_in_left_half = false; } - delta_x = (float)(offsetx) * (grabc->old_scroller_pproportion) / - grabc->drag_begin_geom.width; - delta_y = (float)(offsety) * (grabc->old_scroller_pproportion) / - grabc->drag_begin_geom.height; + if (isvertical) { + delta_y = (float)(offsety) * + (stack_head->old_scroller_pproportion) / + grabc->drag_begin_geom.height; + delta_x = (float)(offsetx) * (grabc->old_stack_proportion) / + grabc->drag_begin_geom.width; + } else { + delta_x = (float)(offsetx) * + (stack_head->old_scroller_pproportion) / + grabc->drag_begin_geom.width; + delta_y = (float)(offsety) * (grabc->old_stack_proportion) / + grabc->drag_begin_geom.height; + } bool moving_up; bool moving_down; @@ -447,34 +466,97 @@ void resize_tile_scroller(Client *grabc, bool isdrag, int offsetx, int offsety, delta_x = -fabsf(delta_x); } + if (isvertical) { + if (!grabc->next_in_stack && grabc->prev_in_stack && !isdrag) { + delta_x = delta_x * -1.0f; + } + if (!grabc->next_in_stack && grabc->prev_in_stack && isdrag) { + if (moving_right) { + delta_x = -fabsf(delta_x); + } else { + delta_x = fabsf(delta_x); + } + } + if (!grabc->prev_in_stack && grabc->next_in_stack && isdrag) { + if (moving_left) { + delta_x = -fabsf(delta_x); + } else { + delta_x = fabsf(delta_x); + } + } + + if (isdrag) { + if (moving_up) { + delta_y = -fabsf(delta_y); + } else { + delta_y = fabsf(delta_y); + } + } + + } else { + if (!grabc->next_in_stack && grabc->prev_in_stack && !isdrag) { + delta_y = delta_y * -1.0f; + } + if (!grabc->next_in_stack && grabc->prev_in_stack && isdrag) { + if (moving_down) { + delta_y = -fabsf(delta_y); + } else { + delta_y = fabsf(delta_y); + } + } + if (!grabc->prev_in_stack && grabc->next_in_stack && isdrag) { + if (moving_up) { + delta_y = -fabsf(delta_y); + } else { + delta_y = fabsf(delta_y); + } + } + + if (isdrag) { + if (moving_left) { + delta_x = -fabsf(delta_x); + } else { + delta_x = fabsf(delta_x); + } + } + } + // 直接设置新的比例,基于初始值 + 变化量 if (isvertical) { - new_scroller_proportion = grabc->old_scroller_pproportion + delta_y; + new_scroller_proportion = + stack_head->old_scroller_pproportion + delta_y; + new_stack_proportion = grabc->old_stack_proportion + delta_x; + } else { - new_scroller_proportion = grabc->old_scroller_pproportion + delta_x; + new_scroller_proportion = + stack_head->old_scroller_pproportion + delta_x; + new_stack_proportion = grabc->old_stack_proportion + delta_y; } // 应用限制,确保比例在合理范围内 new_scroller_proportion = fmaxf(0.1f, fminf(1.0f, new_scroller_proportion)); + new_stack_proportion = fmaxf(0.1f, fminf(1.0f, new_stack_proportion)); - grabc->scroller_proportion = new_scroller_proportion; + grabc->stack_proportion = new_stack_proportion; + + stack_head->scroller_proportion = new_scroller_proportion; if (!isdrag) { - arrange(grabc->mon, false); + arrange(grabc->mon, false, false); return; } if (last_apply_drap_time == 0 || - time - last_apply_drap_time > drag_refresh_interval) { - arrange(grabc->mon, false); + time - last_apply_drap_time > drag_tile_refresh_interval) { + arrange(grabc->mon, false, false); last_apply_drap_time = time; } } } -void resize_tile_client(Client *grabc, bool isdrag, int offsetx, int offsety, - uint32_t time) { +void resize_tile_client(Client *grabc, bool isdrag, int32_t offsetx, + int32_t offsety, uint32_t time) { if (!grabc || grabc->isfullscreen || grabc->ismaximizescreen) return; @@ -502,14 +584,14 @@ void resize_tile_client(Client *grabc, bool isdrag, int offsetx, int offsety, } } -void reset_size_per_mon(Monitor *m, int tile_cilent_num, +void reset_size_per_mon(Monitor *m, int32_t tile_cilent_num, double total_left_stack_hight_percent, double total_right_stack_hight_percent, double total_stack_hight_percent, - double total_master_inner_percent, int master_num, - int stack_num) { + double total_master_inner_percent, int32_t master_num, + int32_t stack_num) { Client *c = NULL; - int i = 0; + int32_t i = 0; uint32_t stack_index = 0; uint32_t nmasters = m->pertag->nmasters[m->pertag->curtag]; @@ -576,35 +658,18 @@ void reset_size_per_mon(Monitor *m, int tile_cilent_num, } } -void reset_multi_tag_client_per(Monitor *m) { - Client *c = NULL; - wl_list_for_each(c, &clients, link) { - - if (c->isglobal || c->isunglobal) { - set_size_per(m, c); - } - - if (!VISIBLEON(c, m)) - continue; - - if (!client_only_in_one_tag(c)) { - set_size_per(m, c); - } - } -} - void // 17 -arrange(Monitor *m, bool want_animation) { +arrange(Monitor *m, bool want_animation, bool from_view) { Client *c = NULL; double total_stack_inner_percent = 0; double total_master_inner_percent = 0; double total_right_stack_hight_percent = 0; double total_left_stack_hight_percent = 0; - int i = 0; - int nmasters = 0; - int stack_index = 0; - int master_num = 0; - int stack_num = 0; + int32_t i = 0; + int32_t nmasters = 0; + int32_t stack_index = 0; + int32_t master_num = 0; + int32_t stack_num = 0; if (!m) return; @@ -617,13 +682,27 @@ arrange(Monitor *m, bool want_animation) { wl_list_for_each(c, &clients, link) { + if (!client_only_in_one_tag(c) || c->isglobal || c->isunglobal) { + exit_scroller_stack(c); + } + + if (from_view && (c->isglobal || c->isunglobal)) { + set_size_per(m, c); + } + if (c->mon == m && (c->isglobal || c->isunglobal)) { c->tags = m->tagset[m->seltags]; - if (c->mon->sel == NULL) - focusclient(c, 0); + } + + if (from_view && m->sel == NULL && c->isglobal && VISIBLEON(c, m)) { + focusclient(c, 1); } if (VISIBLEON(c, m)) { + if (from_view && !client_only_in_one_tag(c)) { + set_size_per(m, c); + } + if (!c->isunglobal) m->visible_clients++; @@ -631,7 +710,7 @@ arrange(Monitor *m, bool want_animation) { m->visible_tiling_clients++; } - if (ISSCROLLTILED(c)) { + if (ISSCROLLTILED(c) && !c->prev_in_stack) { m->visible_scroll_tiling_clients++; } } diff --git a/src/layout/horizontal.h b/src/layout/horizontal.h index a9d6248..e1a335d 100644 --- a/src/layout/horizontal.h +++ b/src/layout/horizontal.h @@ -1,13 +1,15 @@ // 网格布局窗口大小和位置计算 void grid(Monitor *m) { - uint32_t i, n; - uint32_t cx, cy, cw, ch; - uint32_t dx; - uint32_t cols, rows, overcols; + int32_t i, n; + int32_t cx, cy, cw, ch; + int32_t dx; + int32_t cols, rows, overcols; Client *c = NULL; n = 0; - int target_gappo = enablegaps ? m->isoverview ? overviewgappo : gappoh : 0; - int target_gappi = enablegaps ? m->isoverview ? overviewgappi : gappih : 0; + int32_t target_gappo = + enablegaps ? m->isoverview ? overviewgappo : gappoh : 0; + int32_t target_gappi = + enablegaps ? m->isoverview ? overviewgappi : gappih : 0; float single_width_ratio = m->isoverview ? 0.7 : 0.9; float single_height_ratio = m->isoverview ? 0.8 : 0.9; @@ -110,15 +112,16 @@ void grid(Monitor *m) { } void deck(Monitor *m) { - uint32_t mw, my; - int i, n = 0; + int32_t mw, my; + int32_t i, n = 0; Client *c = NULL; Client *fc = NULL; float mfact; + uint32_t nmasters = m->pertag->nmasters[m->pertag->curtag]; - uint32_t cur_gappih = enablegaps ? m->gappih : 0; - uint32_t cur_gappoh = enablegaps ? m->gappoh : 0; - uint32_t cur_gappov = enablegaps ? m->gappov : 0; + int32_t cur_gappih = enablegaps ? m->gappih : 0; + int32_t cur_gappoh = enablegaps ? m->gappoh : 0; + int32_t cur_gappov = enablegaps ? m->gappov : 0; cur_gappih = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappih; cur_gappoh = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappoh; @@ -140,8 +143,8 @@ void deck(Monitor *m) { : m->pertag->mfacts[m->pertag->curtag]; // Calculate master width including outer gaps - if (n > m->nmaster) - mw = m->nmaster ? round((m->w.width - 2 * cur_gappoh) * mfact) : 0; + if (n > nmasters) + mw = nmasters ? round((m->w.width - 2 * cur_gappoh) * mfact) : 0; else mw = m->w.width - 2 * cur_gappoh; @@ -149,7 +152,7 @@ void deck(Monitor *m) { wl_list_for_each(c, &clients, link) { if (!VISIBLEON(c, m) || !ISTILED(c)) continue; - if (i < m->nmaster) { + if (i < nmasters) { c->master_mfact_per = mfact; // Master area clients resize( @@ -158,7 +161,7 @@ void deck(Monitor *m) { .y = m->w.y + cur_gappov + my, .width = mw, .height = (m->w.height - 2 * cur_gappov - my) / - (MIN(n, m->nmaster) - i)}, + (MIN(n, nmasters) - i)}, 0); my += c->geom.height; } else { @@ -181,9 +184,9 @@ void deck(Monitor *m) { void horizontal_scroll_adjust_fullandmax(Client *c, struct wlr_box *target_geom) { Monitor *m = c->mon; - uint32_t cur_gappih = enablegaps ? m->gappih : 0; - uint32_t cur_gappoh = enablegaps ? m->gappoh : 0; - uint32_t cur_gappov = enablegaps ? m->gappov : 0; + int32_t cur_gappih = enablegaps ? m->gappih : 0; + int32_t cur_gappoh = enablegaps ? m->gappoh : 0; + int32_t cur_gappov = enablegaps ? m->gappov : 0; cur_gappih = smartgaps && m->visible_scroll_tiling_clients == 1 ? 0 : cur_gappih; @@ -210,19 +213,80 @@ void horizontal_scroll_adjust_fullandmax(Client *c, target_geom->y = m->w.y + (m->w.height - target_geom->height) / 2; } +void arrange_stack(Client *scroller_stack_head, struct wlr_box geometry, + int32_t gappiv) { + int32_t stack_size = 0; + Client *iter = scroller_stack_head; + + while (iter) { + stack_size++; + iter = iter->next_in_stack; + } + + if (stack_size == 0) + return; + + float total_proportion = 0.0f; + iter = scroller_stack_head; + while (iter) { + if (iter->stack_proportion <= 0.0f || iter->stack_proportion >= 1.0f) { + iter->stack_proportion = + stack_size == 1 ? 1.0f : 1.0f / (stack_size - 1); + } + total_proportion += iter->stack_proportion; + iter = iter->next_in_stack; + } + + iter = scroller_stack_head; + while (iter) { + iter->stack_proportion = iter->stack_proportion / total_proportion; + iter = iter->next_in_stack; + } + + int32_t client_height; + int32_t current_y = geometry.y; + int32_t remain_client_height = geometry.height - (stack_size - 1) * gappiv; + float remain_proportion = 1.0f; + + iter = scroller_stack_head; + while (iter) { + + client_height = + remain_client_height * (iter->stack_proportion / remain_proportion); + + struct wlr_box client_geom = {.x = geometry.x, + .y = current_y, + .width = geometry.width, + .height = client_height}; + resize(iter, client_geom, 0); + remain_proportion -= iter->stack_proportion; + remain_client_height -= client_height; + current_y += client_height + gappiv; + iter = iter->next_in_stack; + } +} + +void horizontal_check_scroller_root_inside_mon(Client *c, + struct wlr_box *geometry) { + if (!GEOMINSIDEMON(geometry, c->mon)) { + geometry->x = c->mon->w.x + (c->mon->w.width - geometry->width) / 2; + } +} + // 滚动布局 void scroller(Monitor *m) { - uint32_t i, n, j; + int32_t i, n, j; float single_proportion = 1.0; Client *c = NULL, *root_client = NULL; Client **tempClients = NULL; // 初始化为 NULL struct wlr_box target_geom; - int focus_client_index = 0; + int32_t focus_client_index = 0; bool need_scroller = false; - uint32_t cur_gappih = enablegaps ? m->gappih : 0; - uint32_t cur_gappoh = enablegaps ? m->gappoh : 0; - uint32_t cur_gappov = enablegaps ? m->gappov : 0; + int32_t cur_gappih = enablegaps ? m->gappih : 0; + int32_t cur_gappoh = enablegaps ? m->gappoh : 0; + int32_t cur_gappov = enablegaps ? m->gappov : 0; + int32_t cur_gappiv = enablegaps ? m->gappiv : 0; cur_gappih = smartgaps && m->visible_scroll_tiling_clients == 1 ? 0 : cur_gappih; @@ -231,7 +295,7 @@ void scroller(Monitor *m) { cur_gappov = smartgaps && m->visible_scroll_tiling_clients == 1 ? 0 : cur_gappov; - uint32_t max_client_width = m->w.width - 2 * scroller_structs - cur_gappih; + int32_t max_client_width = m->w.width - 2 * scroller_structs - cur_gappih; n = m->visible_scroll_tiling_clients; @@ -249,7 +313,7 @@ void scroller(Monitor *m) { // 第二次遍历,填充 tempClients j = 0; wl_list_for_each(c, &clients, link) { - if (VISIBLEON(c, m) && ISSCROLLTILED(c)) { + if (VISIBLEON(c, m) && ISSCROLLTILED(c) && !c->prev_in_stack) { tempClients[j] = c; j++; } @@ -267,7 +331,8 @@ void scroller(Monitor *m) { target_geom.width = (m->w.width - 2 * cur_gappoh) * single_proportion; target_geom.x = m->w.x + (m->w.width - target_geom.width) / 2; target_geom.y = m->w.y + (m->w.height - target_geom.height) / 2; - resize(c, target_geom, 0); + horizontal_check_scroller_root_inside_mon(c, &target_geom); + arrange_stack(c, target_geom, cur_gappiv); free(tempClients); // 释放内存 return; } @@ -281,6 +346,11 @@ void scroller(Monitor *m) { root_client = center_tiled_select(m); } + // root_client might be in a stack, find the stack head + if (root_client) { + root_client = get_scroll_stack_head(root_client); + } + if (!root_client) { free(tempClients); // 释放内存 return; @@ -315,10 +385,14 @@ void scroller(Monitor *m) { &target_geom); if (tempClients[focus_client_index]->isfullscreen) { target_geom.x = m->m.x; - resize(tempClients[focus_client_index], target_geom, 0); + horizontal_check_scroller_root_inside_mon( + tempClients[focus_client_index], &target_geom); + arrange_stack(tempClients[focus_client_index], target_geom, cur_gappiv); } else if (tempClients[focus_client_index]->ismaximizescreen) { target_geom.x = m->w.x + cur_gappoh; - resize(tempClients[focus_client_index], target_geom, 0); + horizontal_check_scroller_root_inside_mon( + tempClients[focus_client_index], &target_geom); + arrange_stack(tempClients[focus_client_index], target_geom, cur_gappiv); } else if (need_scroller) { if (scroller_focus_center || ((!m->prevsel || @@ -336,10 +410,14 @@ void scroller(Monitor *m) { scroller_structs) : m->w.x + scroller_structs; } - resize(tempClients[focus_client_index], target_geom, 0); + horizontal_check_scroller_root_inside_mon( + tempClients[focus_client_index], &target_geom); + arrange_stack(tempClients[focus_client_index], target_geom, cur_gappiv); } else { target_geom.x = c->geom.x; - resize(tempClients[focus_client_index], target_geom, 0); + horizontal_check_scroller_root_inside_mon( + tempClients[focus_client_index], &target_geom); + arrange_stack(tempClients[focus_client_index], target_geom, cur_gappiv); } for (i = 1; i <= focus_client_index; i++) { @@ -349,7 +427,7 @@ void scroller(Monitor *m) { target_geom.x = tempClients[focus_client_index - i + 1]->geom.x - cur_gappih - target_geom.width; - resize(c, target_geom, 0); + arrange_stack(c, target_geom, cur_gappiv); } for (i = 1; i < n - focus_client_index; i++) { @@ -359,19 +437,19 @@ void scroller(Monitor *m) { target_geom.x = tempClients[focus_client_index + i - 1]->geom.x + cur_gappih + tempClients[focus_client_index + i - 1]->geom.width; - resize(c, target_geom, 0); + arrange_stack(c, target_geom, cur_gappiv); } free(tempClients); // 最后释放内存 } void center_tile(Monitor *m) { - uint32_t i, n = 0, h, r, ie = enablegaps, mw, mx, my, oty, ety, tw; + int32_t i, n = 0, h, r, ie = enablegaps, mw, mx, my, oty, ety, tw; Client *c = NULL; Client *fc = NULL; double mfact = 0; - int master_num = 0; - int stack_num = 0; + int32_t master_num = 0; + int32_t stack_num = 0; n = m->visible_tiling_clients; master_num = m->pertag->nmasters[m->pertag->curtag]; @@ -389,10 +467,10 @@ void center_tile(Monitor *m) { } // 间隙参数处理 - uint32_t cur_gappiv = enablegaps ? m->gappiv : 0; // 内部垂直间隙 - uint32_t cur_gappih = enablegaps ? m->gappih : 0; // 内部水平间隙 - uint32_t cur_gappov = enablegaps ? m->gappov : 0; // 外部垂直间隙 - uint32_t cur_gappoh = enablegaps ? m->gappoh : 0; // 外部水平间隙 + int32_t cur_gappiv = enablegaps ? m->gappiv : 0; // 内部垂直间隙 + int32_t cur_gappih = enablegaps ? m->gappih : 0; // 内部水平间隙 + int32_t cur_gappov = enablegaps ? m->gappov : 0; // 外部垂直间隙 + int32_t cur_gappoh = enablegaps ? m->gappoh : 0; // 外部水平间隙 // 智能间隙处理 cur_gappiv = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappiv; @@ -400,7 +478,7 @@ void center_tile(Monitor *m) { cur_gappov = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappov; cur_gappoh = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappoh; - uint32_t nmasters = m->pertag->nmasters[m->pertag->curtag]; + int32_t nmasters = m->pertag->nmasters[m->pertag->curtag]; mfact = fc->master_mfact_per > 0.0f ? fc->master_mfact_per : m->pertag->mfacts[m->pertag->curtag]; @@ -411,17 +489,17 @@ void center_tile(Monitor *m) { tw = mw; // 判断是否需要主区域铺满 - int should_overspread = center_master_overspread && (n <= nmasters); + int32_t should_overspread = center_master_overspread && (n <= nmasters); - uint32_t master_surplus_height = + int32_t master_surplus_height = (m->w.height - 2 * cur_gappov - cur_gappiv * ie * (master_num - 1)); float master_surplus_ratio = 1.0; - uint32_t slave_left_surplus_height = + int32_t slave_left_surplus_height = (m->w.height - 2 * cur_gappov - cur_gappiv * ie * (stack_num / 2 - 1)); float slave_left_surplus_ratio = 1.0; - uint32_t slave_right_surplus_height = + int32_t slave_right_surplus_height = (m->w.height - 2 * cur_gappov - cur_gappiv * ie * ((stack_num + 1) / 2 - 1)); float slave_right_surplus_ratio = 1.0; @@ -494,7 +572,7 @@ void center_tile(Monitor *m) { my += c->geom.height + cur_gappiv * ie; } else { // 堆叠区域窗口 - uint32_t stack_index = i - nmasters; + int32_t stack_index = i - nmasters; if (n - nmasters == 1) { // 单个堆叠窗口 @@ -513,7 +591,7 @@ void center_tile(Monitor *m) { c->master_mfact_per = mfact; } - int stack_x; + int32_t stack_x; if (center_when_single_stack) { // 放在右侧(master居中时,stack在右边) stack_x = m->w.x + mx + mw + cur_gappih * ie; @@ -553,7 +631,7 @@ void center_tile(Monitor *m) { c->master_mfact_per = mfact; } - int stack_x = m->w.x + mx + mw + cur_gappih * ie; + int32_t stack_x = m->w.x + mx + mw + cur_gappih * ie; resize(c, (struct wlr_box){.x = stack_x, @@ -582,7 +660,7 @@ void center_tile(Monitor *m) { c->master_mfact_per = mfact; } - int stack_x = m->w.x + cur_gappoh; + int32_t stack_x = m->w.x + cur_gappoh; resize(c, (struct wlr_box){.x = stack_x, .y = m->w.y + oty, @@ -598,12 +676,12 @@ void center_tile(Monitor *m) { } void tile(Monitor *m) { - uint32_t i, n = 0, h, r, ie = enablegaps, mw, my, ty; + int32_t i, n = 0, h, r, ie = enablegaps, mw, my, ty; Client *c = NULL; Client *fc = NULL; double mfact = 0; - int master_num = 0; - int stack_num = 0; + int32_t master_num = 0; + int32_t stack_num = 0; n = m->visible_tiling_clients; master_num = m->pertag->nmasters[m->pertag->curtag]; @@ -613,10 +691,10 @@ void tile(Monitor *m) { if (n == 0) return; - uint32_t cur_gappiv = enablegaps ? m->gappiv : 0; - uint32_t cur_gappih = enablegaps ? m->gappih : 0; - uint32_t cur_gappov = enablegaps ? m->gappov : 0; - uint32_t cur_gappoh = enablegaps ? m->gappoh : 0; + int32_t cur_gappiv = enablegaps ? m->gappiv : 0; + int32_t cur_gappih = enablegaps ? m->gappih : 0; + int32_t cur_gappov = enablegaps ? m->gappov : 0; + int32_t cur_gappoh = enablegaps ? m->gappoh : 0; cur_gappiv = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappiv; cur_gappih = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappih; @@ -641,11 +719,11 @@ void tile(Monitor *m) { i = 0; my = ty = cur_gappov; - uint32_t master_surplus_height = + int32_t master_surplus_height = (m->w.height - 2 * cur_gappov - cur_gappiv * ie * (master_num - 1)); float master_surplus_ratio = 1.0; - uint32_t slave_surplus_height = + int32_t slave_surplus_height = (m->w.height - 2 * cur_gappov - cur_gappiv * ie * (stack_num - 1)); float slave_surplus_ratio = 1.0; @@ -708,12 +786,12 @@ void tile(Monitor *m) { } void right_tile(Monitor *m) { - uint32_t i, n = 0, h, r, ie = enablegaps, mw, my, ty; + int32_t i, n = 0, h, r, ie = enablegaps, mw, my, ty; Client *c = NULL; Client *fc = NULL; double mfact = 0; - int master_num = 0; - int stack_num = 0; + int32_t master_num = 0; + int32_t stack_num = 0; n = m->visible_tiling_clients; master_num = m->pertag->nmasters[m->pertag->curtag]; @@ -723,10 +801,10 @@ void right_tile(Monitor *m) { if (n == 0) return; - uint32_t cur_gappiv = enablegaps ? m->gappiv : 0; - uint32_t cur_gappih = enablegaps ? m->gappih : 0; - uint32_t cur_gappov = enablegaps ? m->gappov : 0; - uint32_t cur_gappoh = enablegaps ? m->gappoh : 0; + int32_t cur_gappiv = enablegaps ? m->gappiv : 0; + int32_t cur_gappih = enablegaps ? m->gappih : 0; + int32_t cur_gappov = enablegaps ? m->gappov : 0; + int32_t cur_gappoh = enablegaps ? m->gappoh : 0; cur_gappiv = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappiv; cur_gappih = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappih; @@ -751,11 +829,11 @@ void right_tile(Monitor *m) { i = 0; my = ty = cur_gappov; - uint32_t master_surplus_height = + int32_t master_surplus_height = (m->w.height - 2 * cur_gappov - cur_gappiv * ie * (master_num - 1)); float master_surplus_ratio = 1.0; - uint32_t slave_surplus_height = + int32_t slave_surplus_height = (m->w.height - 2 * cur_gappov - cur_gappiv * ie * (stack_num - 1)); float slave_surplus_ratio = 1.0; @@ -823,8 +901,8 @@ monocle(Monitor *m) { Client *c = NULL; struct wlr_box geom; - uint32_t cur_gappov = enablegaps ? m->gappov : 0; - uint32_t cur_gappoh = enablegaps ? m->gappoh : 0; + int32_t cur_gappov = enablegaps ? m->gappov : 0; + int32_t cur_gappoh = enablegaps ? m->gappoh : 0; cur_gappoh = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappoh; cur_gappov = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappov; @@ -843,7 +921,7 @@ monocle(Monitor *m) { } void tgmix(Monitor *m) { - uint32_t n = m->visible_tiling_clients; + int32_t n = m->visible_tiling_clients; if (n <= 3) { tile(m); return; @@ -851,4 +929,4 @@ void tgmix(Monitor *m) { grid(m); return; } -} \ No newline at end of file +} diff --git a/src/layout/layout.h b/src/layout/layout.h index 169ab11..f896ac2 100644 --- a/src/layout/layout.h +++ b/src/layout/layout.h @@ -17,8 +17,8 @@ static void tgmix(Monitor *m); Layout overviewlayout = {"󰃇", overview, "overview"}; enum { - SCROLLER, TILE, + SCROLLER, GRID, MONOCLE, DECK, @@ -34,8 +34,8 @@ enum { Layout layouts[] = { // 最少两个,不能删除少于两个 /* symbol arrange function name */ - {"S", scroller, "scroller", SCROLLER}, // 滚动布局 {"T", tile, "tile", TILE}, // 平铺布局 + {"S", scroller, "scroller", SCROLLER}, // 滚动布局 {"G", grid, "grid", GRID}, // 格子布局 {"M", monocle, "monocle", MONOCLE}, // 单屏布局 {"K", deck, "deck", DECK}, // 卡片布局 diff --git a/src/layout/vertical.h b/src/layout/vertical.h index da6a127..f7bd442 100644 --- a/src/layout/vertical.h +++ b/src/layout/vertical.h @@ -1,10 +1,10 @@ void vertical_tile(Monitor *m) { - uint32_t i, n = 0, w, r, ie = enablegaps, mh, mx, tx; + int32_t i, n = 0, w, r, ie = enablegaps, mh, mx, tx; Client *c = NULL; Client *fc = NULL; double mfact = 0; - int master_num = 0; - int stack_num = 0; + int32_t master_num = 0; + int32_t stack_num = 0; n = m->visible_tiling_clients; master_num = m->pertag->nmasters[m->pertag->curtag]; @@ -14,10 +14,10 @@ void vertical_tile(Monitor *m) { if (n == 0) return; - uint32_t cur_gapih = enablegaps ? m->gappih : 0; - uint32_t cur_gapiv = enablegaps ? m->gappiv : 0; - uint32_t cur_gapoh = enablegaps ? m->gappoh : 0; - uint32_t cur_gapov = enablegaps ? m->gappov : 0; + int32_t cur_gapih = enablegaps ? m->gappih : 0; + int32_t cur_gapiv = enablegaps ? m->gappiv : 0; + int32_t cur_gapoh = enablegaps ? m->gappoh : 0; + int32_t cur_gapov = enablegaps ? m->gappov : 0; cur_gapih = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gapih; cur_gapiv = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gapiv; @@ -42,11 +42,11 @@ void vertical_tile(Monitor *m) { i = 0; mx = tx = cur_gapoh; - uint32_t master_surplus_width = + int32_t master_surplus_width = (m->w.width - 2 * cur_gapoh - cur_gapih * ie * (master_num - 1)); float master_surplus_ratio = 1.0; - uint32_t slave_surplus_width = + int32_t slave_surplus_width = (m->w.width - 2 * cur_gapoh - cur_gapih * ie * (stack_num - 1)); float slave_surplus_ratio = 1.0; @@ -105,15 +105,16 @@ void vertical_tile(Monitor *m) { } void vertical_deck(Monitor *m) { - uint32_t mh, mx; - int i, n = 0; + int32_t mh, mx; + int32_t i, n = 0; Client *c = NULL; Client *fc = NULL; float mfact; + uint32_t nmasters = m->pertag->nmasters[m->pertag->curtag]; - uint32_t cur_gappiv = enablegaps ? m->gappiv : 0; - uint32_t cur_gappoh = enablegaps ? m->gappoh : 0; - uint32_t cur_gappov = enablegaps ? m->gappov : 0; + int32_t cur_gappiv = enablegaps ? m->gappiv : 0; + int32_t cur_gappoh = enablegaps ? m->gappoh : 0; + int32_t cur_gappov = enablegaps ? m->gappov : 0; cur_gappiv = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappiv; cur_gappoh = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappoh; @@ -134,8 +135,8 @@ void vertical_deck(Monitor *m) { mfact = fc->master_mfact_per > 0.0f ? fc->master_mfact_per : m->pertag->mfacts[m->pertag->curtag]; - if (n > m->nmaster) - mh = m->nmaster ? round((m->w.height - 2 * cur_gappov) * mfact) : 0; + if (n > nmasters) + mh = nmasters ? round((m->w.height - 2 * cur_gappov) * mfact) : 0; else mh = m->w.height - 2 * cur_gappov; @@ -143,13 +144,13 @@ void vertical_deck(Monitor *m) { wl_list_for_each(c, &clients, link) { if (!VISIBLEON(c, m) || !ISTILED(c)) continue; - if (i < m->nmaster) { + if (i < nmasters) { resize( c, (struct wlr_box){.x = m->w.x + cur_gappoh + mx, .y = m->w.y + cur_gappov, .width = (m->w.width - 2 * cur_gappoh - mx) / - (MIN(n, m->nmaster) - i), + (MIN(n, nmasters) - i), .height = mh}, 0); mx += c->geom.width; @@ -170,9 +171,9 @@ void vertical_deck(Monitor *m) { void vertical_scroll_adjust_fullandmax(Client *c, struct wlr_box *target_geom) { Monitor *m = c->mon; - uint32_t cur_gappiv = enablegaps ? m->gappiv : 0; - uint32_t cur_gappov = enablegaps ? m->gappov : 0; - uint32_t cur_gappoh = enablegaps ? m->gappoh : 0; + int32_t cur_gappiv = enablegaps ? m->gappiv : 0; + int32_t cur_gappov = enablegaps ? m->gappov : 0; + int32_t cur_gappoh = enablegaps ? m->gappoh : 0; cur_gappiv = smartgaps && m->visible_scroll_tiling_clients == 1 ? 0 : cur_gappiv; @@ -199,19 +200,80 @@ void vertical_scroll_adjust_fullandmax(Client *c, struct wlr_box *target_geom) { target_geom->x = m->w.x + (m->w.width - target_geom->width) / 2; } +void arrange_stack_vertical(Client *scroller_stack_head, + struct wlr_box geometry, int32_t gappih) { + int32_t stack_size = 0; + Client *iter = scroller_stack_head; + + while (iter) { + stack_size++; + iter = iter->next_in_stack; + } + + if (stack_size == 0) + return; + + float total_proportion = 0.0f; + iter = scroller_stack_head; + while (iter) { + if (iter->stack_proportion <= 0.0f || iter->stack_proportion >= 1.0f) { + iter->stack_proportion = + stack_size == 1 ? 1.0f : 1.0f / (stack_size - 1); + } + total_proportion += iter->stack_proportion; + iter = iter->next_in_stack; + } + + iter = scroller_stack_head; + while (iter) { + iter->stack_proportion = iter->stack_proportion / total_proportion; + iter = iter->next_in_stack; + } + + int32_t client_width; + int32_t current_x = geometry.x; + int32_t remain_client_width = geometry.width - (stack_size - 1) * gappih; + float remain_proportion = 1.0f; + + iter = scroller_stack_head; + while (iter) { + + client_width = + remain_client_width * (iter->stack_proportion / remain_proportion); + + struct wlr_box client_geom = {.y = geometry.y, + .x = current_x, + .height = geometry.height, + .width = client_width}; + resize(iter, client_geom, 0); + remain_proportion -= iter->stack_proportion; + remain_client_width -= client_width; + current_x += client_width + gappih; + iter = iter->next_in_stack; + } +} + +void vertical_check_scroller_root_inside_mon(Client *c, + struct wlr_box *geometry) { + if (!GEOMINSIDEMON(geometry, c->mon)) { + geometry->y = c->mon->w.y + (c->mon->w.height - geometry->height) / 2; + } +} + // 竖屏滚动布局 void vertical_scroller(Monitor *m) { - uint32_t i, n, j; + int32_t i, n, j; float single_proportion = 1.0; Client *c = NULL, *root_client = NULL; Client **tempClients = NULL; struct wlr_box target_geom; - int focus_client_index = 0; + int32_t focus_client_index = 0; bool need_scroller = false; - uint32_t cur_gappiv = enablegaps ? m->gappiv : 0; - uint32_t cur_gappov = enablegaps ? m->gappov : 0; - uint32_t cur_gappoh = enablegaps ? m->gappoh : 0; + int32_t cur_gappiv = enablegaps ? m->gappiv : 0; + int32_t cur_gappov = enablegaps ? m->gappov : 0; + int32_t cur_gappoh = enablegaps ? m->gappoh : 0; + int32_t cur_gappih = enablegaps ? m->gappih : 0; cur_gappiv = smartgaps && m->visible_scroll_tiling_clients == 1 ? 0 : cur_gappiv; @@ -220,8 +282,7 @@ void vertical_scroller(Monitor *m) { cur_gappoh = smartgaps && m->visible_scroll_tiling_clients == 1 ? 0 : cur_gappoh; - uint32_t max_client_height = - m->w.height - 2 * scroller_structs - cur_gappiv; + int32_t max_client_height = m->w.height - 2 * scroller_structs - cur_gappiv; n = m->visible_scroll_tiling_clients; @@ -236,7 +297,7 @@ void vertical_scroller(Monitor *m) { j = 0; wl_list_for_each(c, &clients, link) { - if (VISIBLEON(c, m) && ISSCROLLTILED(c)) { + if (VISIBLEON(c, m) && ISSCROLLTILED(c) && !c->prev_in_stack) { tempClients[j] = c; j++; } @@ -254,7 +315,8 @@ void vertical_scroller(Monitor *m) { target_geom.height = (m->w.height - 2 * cur_gappov) * single_proportion; target_geom.y = m->w.y + (m->w.height - target_geom.height) / 2; target_geom.x = m->w.x + (m->w.width - target_geom.width) / 2; - resize(c, target_geom, 0); + vertical_check_scroller_root_inside_mon(c, &target_geom); + arrange_stack_vertical(c, target_geom, cur_gappih); free(tempClients); return; } @@ -268,6 +330,11 @@ void vertical_scroller(Monitor *m) { root_client = center_tiled_select(m); } + // root_client might be in a stack, find the stack head + if (root_client) { + root_client = get_scroll_stack_head(root_client); + } + if (!root_client) { free(tempClients); return; @@ -303,10 +370,16 @@ void vertical_scroller(Monitor *m) { if (tempClients[focus_client_index]->isfullscreen) { target_geom.y = m->m.y; - resize(tempClients[focus_client_index], target_geom, 0); + vertical_check_scroller_root_inside_mon(tempClients[focus_client_index], + &target_geom); + arrange_stack_vertical(tempClients[focus_client_index], target_geom, + cur_gappih); } else if (tempClients[focus_client_index]->ismaximizescreen) { target_geom.y = m->w.y + cur_gappov; - resize(tempClients[focus_client_index], target_geom, 0); + vertical_check_scroller_root_inside_mon(tempClients[focus_client_index], + &target_geom); + arrange_stack_vertical(tempClients[focus_client_index], target_geom, + cur_gappih); } else if (need_scroller) { if (scroller_focus_center || ((!m->prevsel || @@ -324,10 +397,16 @@ void vertical_scroller(Monitor *m) { scroller_structs) : m->w.y + scroller_structs; } - resize(tempClients[focus_client_index], target_geom, 0); + vertical_check_scroller_root_inside_mon(tempClients[focus_client_index], + &target_geom); + arrange_stack_vertical(tempClients[focus_client_index], target_geom, + cur_gappih); } else { target_geom.y = c->geom.y; - resize(tempClients[focus_client_index], target_geom, 0); + vertical_check_scroller_root_inside_mon(tempClients[focus_client_index], + &target_geom); + arrange_stack_vertical(tempClients[focus_client_index], target_geom, + cur_gappih); } for (i = 1; i <= focus_client_index; i++) { @@ -337,7 +416,7 @@ void vertical_scroller(Monitor *m) { target_geom.y = tempClients[focus_client_index - i + 1]->geom.y - cur_gappiv - target_geom.height; - resize(c, target_geom, 0); + arrange_stack_vertical(c, target_geom, cur_gappih); } for (i = 1; i < n - focus_client_index; i++) { @@ -347,20 +426,22 @@ void vertical_scroller(Monitor *m) { target_geom.y = tempClients[focus_client_index + i - 1]->geom.y + cur_gappiv + tempClients[focus_client_index + i - 1]->geom.height; - resize(c, target_geom, 0); + arrange_stack_vertical(c, target_geom, cur_gappih); } free(tempClients); } void vertical_grid(Monitor *m) { - uint32_t i, n; - uint32_t cx, cy, cw, ch; - uint32_t dy; - uint32_t rows, cols, overrows; + int32_t i, n; + int32_t cx, cy, cw, ch; + int32_t dy; + int32_t rows, cols, overrows; Client *c = NULL; - int target_gappo = enablegaps ? m->isoverview ? overviewgappo : gappov : 0; - int target_gappi = enablegaps ? m->isoverview ? overviewgappi : gappiv : 0; + int32_t target_gappo = + enablegaps ? m->isoverview ? overviewgappo : gappov : 0; + int32_t target_gappi = + enablegaps ? m->isoverview ? overviewgappi : gappiv : 0; float single_width_ratio = m->isoverview ? 0.7 : 0.9; float single_height_ratio = m->isoverview ? 0.8 : 0.9; diff --git a/src/mango.c b/src/mango.c index 6726a6c..591d4f6 100644 --- a/src/mango.c +++ b/src/mango.c @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -101,6 +102,10 @@ (A->geom.x >= A->mon->m.x && A->geom.y >= A->mon->m.y && \ A->geom.x + A->geom.width <= A->mon->m.x + A->mon->m.width && \ A->geom.y + A->geom.height <= A->mon->m.y + A->mon->m.height) +#define GEOMINSIDEMON(A, M) \ + (A->x >= M->m.x && A->y >= M->m.y && \ + A->x + A->width <= M->m.x + M->m.width && \ + A->y + A->height <= M->m.y + M->m.height) #define ISTILED(A) \ (A && !(A)->isfloating && !(A)->isminimized && !(A)->iskilling && \ !(A)->ismaximizescreen && !(A)->isfullscreen && !(A)->isunglobal) @@ -138,6 +143,8 @@ #define BAKED_POINTS_COUNT 256 /* enums */ +enum { TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT }; + enum { VERTICAL, HORIZONTAL }; enum { SWIPE_UP, SWIPE_DOWN, SWIPE_LEFT, SWIPE_RIGHT }; enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */ @@ -212,12 +219,12 @@ struct dvec2 { }; struct ivec2 { - int x, y, width, height; + int32_t x, y, width, height; }; typedef struct { - int i; - int i2; + int32_t i; + int32_t i2; float f; float f2; char *v; @@ -230,7 +237,7 @@ typedef struct { typedef struct { uint32_t mod; uint32_t button; - int (*func)(const Arg *); + int32_t (*func)(const Arg *); const Arg arg; } Button; // 鼠标按键 @@ -242,7 +249,7 @@ typedef struct { typedef struct { uint32_t mod; uint32_t dir; - int (*func)(const Arg *); + int32_t (*func)(const Arg *); const Arg arg; } Axis; @@ -273,7 +280,7 @@ struct dwl_animation { uint32_t duration; struct wlr_box initial; struct wlr_box current; - int action; + int32_t action; }; struct dwl_opacity_animation { @@ -291,8 +298,8 @@ struct dwl_opacity_animation { typedef struct { float width_scale; float height_scale; - int width; - int height; + int32_t width; + int32_t height; enum corner_location corner_location; bool should_scale; } BufferData; @@ -336,14 +343,14 @@ struct Client { bool dirty; uint32_t configure_serial; struct wlr_foreign_toplevel_handle_v1 *foreign_toplevel; - int isfloating, isurgent, isfullscreen, isfakefullscreen, + int32_t isfloating, isurgent, isfullscreen, isfakefullscreen, need_float_size_reduce, isminimized, isoverlay, isnosizehint, ignore_maximize, ignore_minimize; - int ismaximizescreen; - int overview_backup_bw; - int fullscreen_backup_x, fullscreen_backup_y, fullscreen_backup_w, + int32_t ismaximizescreen; + int32_t overview_backup_bw; + int32_t fullscreen_backup_x, fullscreen_backup_y, fullscreen_backup_w, fullscreen_backup_h; - int overview_isfullscreenbak, overview_ismaximizescreenbak, + int32_t overview_isfullscreenbak, overview_ismaximizescreenbak, overview_isfloatingbak; struct wlr_xdg_toplevel_decoration_v1 *decoration; @@ -358,54 +365,59 @@ struct Client { const char *animation_type_open; const char *animation_type_close; - int is_in_scratchpad; - int iscustomsize; - int is_scratchpad_show; - int isglobal; - int isnoborder; - int isnoshadow; - int isnoradius; - int isnoanimation; - int isopensilent; - int istagsilent; - int iskilling; - int istagswitching; - int isnamedscratchpad; + int32_t is_in_scratchpad; + int32_t iscustomsize; + int32_t iscustompos; + int32_t is_scratchpad_show; + int32_t isglobal; + int32_t isnoborder; + int32_t isnoshadow; + int32_t isnoradius; + int32_t isnoanimation; + int32_t isopensilent; + int32_t istagsilent; + int32_t iskilling; + int32_t istagswitching; + int32_t isnamedscratchpad; bool is_pending_open_animation; bool is_restoring_from_ov; float scroller_proportion; + float stack_proportion; + float old_stack_proportion; bool need_output_flush; struct dwl_animation animation; struct dwl_opacity_animation opacity_animation; - int isterm, noswallow; - int allow_csd; - int force_maximize; + int32_t isterm, noswallow; + int32_t allow_csd; + int32_t force_maximize; pid_t pid; Client *swallowing, *swallowedby; bool is_clip_to_hide; bool drag_to_tile; bool scratchpad_switching_mon; bool fake_no_border; - int nofocus; - int nofadein; - int nofadeout; - int no_force_center; - int isunglobal; + int32_t nofocus; + int32_t nofadein; + int32_t nofadeout; + int32_t no_force_center; + int32_t isunglobal; float focused_opacity; float unfocused_opacity; char oldmonname[128]; - int noblur; + int32_t noblur; double master_mfact_per, master_inner_per, stack_inner_per; double old_master_mfact_per, old_master_inner_per, old_stack_inner_per; double old_scroller_pproportion; bool ismaster; bool cursor_in_upper_half, cursor_in_left_half; bool isleftstack; - int tearing_hint; - int force_tearing; - int allow_shortcuts_inhibit; + int32_t tearing_hint; + int32_t force_tearing; + int32_t allow_shortcuts_inhibit; float scroller_proportion_single; bool isfocusing; + struct Client *next_in_stack; + struct Client *prev_in_stack; }; typedef struct { @@ -417,14 +429,14 @@ typedef struct { typedef struct { uint32_t mod; xkb_keysym_t keysym; - int (*func)(const Arg *); + int32_t (*func)(const Arg *); const Arg arg; } Key; typedef struct { struct wlr_keyboard_group *wlr_group; - int nsyms; + int32_t nsyms; const xkb_keysym_t *keysyms; /* invalid if nsyms == 0 */ uint32_t mods; /* invalid if nsyms == 0 */ uint32_t keycode; @@ -452,7 +464,7 @@ typedef struct { struct wlr_scene_layer_surface_v1 *scene_layer; struct wl_list link; struct wl_list fadeout_link; - int mapped; + int32_t mapped; struct wlr_layer_surface_v1 *layer_surface; struct wl_listener destroy; @@ -462,12 +474,13 @@ typedef struct { struct dwl_animation animation; bool dirty; - int noblur; - int noanim; - int noshadow; + int32_t noblur; + int32_t noanim; + int32_t noshadow; char *animation_type_open; char *animation_type_close; bool need_output_flush; + bool being_unmapped; } LayerSurface; typedef struct { @@ -490,22 +503,19 @@ struct Monitor { struct wlr_box m; /* monitor area, layout-relative */ struct wlr_box w; /* window area, layout-relative */ struct wl_list layers[4]; /* LayerSurface::link */ - const Layout *lt; uint32_t seltags; uint32_t tagset[2]; - double mfact; - int nmaster; struct wl_list dwl_ipc_outputs; - int gappih; /* horizontal gap between windows */ - int gappiv; /* vertical gap between windows */ - int gappoh; /* horizontal outer gaps */ - int gappov; /* vertical outer gaps */ + int32_t gappih; /* horizontal gap between windows */ + int32_t gappiv; /* vertical gap between windows */ + int32_t gappoh; /* horizontal outer gaps */ + int32_t gappov; /* vertical outer gaps */ Pertag *pertag; Client *sel, *prevsel; - int isoverview; - int is_in_hotarea; - int asleep; + int32_t isoverview; + int32_t is_in_hotarea; + int32_t asleep; uint32_t visible_clients; uint32_t visible_tiling_clients; uint32_t visible_scroll_tiling_clients; @@ -533,18 +543,17 @@ static void applybounds( Client *c, struct wlr_box *bbox); // 设置边界规则,能让一些窗口拥有比较适合的大小 static void applyrules(Client *c); // 窗口规则应用,应用config.h中定义的窗口规则 -static void -arrange(Monitor *m, - bool want_animation); // 布局函数,让窗口俺平铺规则移动和重置大小 +static void arrange(Monitor *m, bool want_animation, + bool from_view); // 布局函数,让窗口俺平铺规则移动和重置大小 static void arrangelayer(Monitor *m, struct wl_list *list, - struct wlr_box *usable_area, int exclusive); + struct wlr_box *usable_area, int32_t exclusive); static void arrangelayers(Monitor *m); static void handle_print_status(struct wl_listener *listener, void *data); static void axisnotify(struct wl_listener *listener, void *data); // 滚轮事件处理 static void buttonpress(struct wl_listener *listener, void *data); // 鼠标按键事件处理 -static int ongesture(struct wlr_pointer_swipe_end_event *event); +static int32_t ongesture(struct wlr_pointer_swipe_end_event *event); static void swipe_begin(struct wl_listener *listener, void *data); static void swipe_update(struct wl_listener *listener, void *data); static void swipe_end(struct wl_listener *listener, void *data); @@ -558,7 +567,7 @@ static void cleanup(void); // 退出清理 static void cleanupmon(struct wl_listener *listener, void *data); // 退出清理 static void closemon(Monitor *m); static void cleanuplisteners(void); -static void toggle_hotarea(int x_root, int y_root); // 触发热区 +static void toggle_hotarea(int32_t x_root, int32_t y_root); // 触发热区 static void maplayersurfacenotify(struct wl_listener *listener, void *data); static void commitlayersurfacenotify(struct wl_listener *listener, void *data); static void commitnotify(struct wl_listener *listener, void *data); @@ -584,8 +593,8 @@ static void cursorwarptohint(void); static void destroydecoration(struct wl_listener *listener, void *data); static void destroydragicon(struct wl_listener *listener, void *data); static void destroyidleinhibitor(struct wl_listener *listener, void *data); -static void destroylayersurfacenotify(struct wl_listener *listener, void *data); -static void destroylock(SessionLock *lock, int unlocked); +static void destroylayernodenotify(struct wl_listener *listener, void *data); +static void destroylock(SessionLock *lock, int32_t unlocked); static void destroylocksurface(struct wl_listener *listener, void *data); static void destroynotify(struct wl_listener *listener, void *data); static void destroypointerconstraint(struct wl_listener *listener, void *data); @@ -594,18 +603,18 @@ static void destroykeyboardgroup(struct wl_listener *listener, void *data); static Monitor *dirtomon(enum wlr_direction dir); static void setcursorshape(struct wl_listener *listener, void *data); -static void focusclient(Client *c, int lift); +static void focusclient(Client *c, int32_t lift); static void setborder_color(Client *c); static Client *focustop(Monitor *m); static void fullscreennotify(struct wl_listener *listener, void *data); static void gpureset(struct wl_listener *listener, void *data); -static int keyrepeat(void *data); +static int32_t keyrepeat(void *data); static void inputdevice(struct wl_listener *listener, void *data); -static int keybinding(uint32_t state, bool locked, uint32_t mods, - xkb_keysym_t sym, uint32_t keycode); +static int32_t keybinding(uint32_t state, bool locked, uint32_t mods, + xkb_keysym_t sym, uint32_t keycode); static void keypress(struct wl_listener *listener, void *data); static void keypressmod(struct wl_listener *listener, void *data); static bool keypressglobal(struct wlr_surface *last_surface, @@ -628,26 +637,26 @@ static void add_foreign_topleve(Client *c); static void exchange_two_client(Client *c1, Client *c2); static void outputmgrapply(struct wl_listener *listener, void *data); static void outputmgrapplyortest(struct wlr_output_configuration_v1 *config, - int test); + int32_t test); static void outputmgrtest(struct wl_listener *listener, void *data); static void pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, uint32_t time); static void printstatus(void); -static void quitsignal(int signo); +static void quitsignal(int32_t signo); static void powermgrsetmode(struct wl_listener *listener, void *data); static void rendermon(struct wl_listener *listener, void *data); static void requestdecorationmode(struct wl_listener *listener, void *data); static void requestdrmlease(struct wl_listener *listener, void *data); static void requeststartdrag(struct wl_listener *listener, void *data); -static void resize(Client *c, struct wlr_box geo, int interact); +static void resize(Client *c, struct wlr_box geo, int32_t interact); static void run(char *startup_cmd); static void setcursor(struct wl_listener *listener, void *data); -static void setfloating(Client *c, int floating); -static void setfakefullscreen(Client *c, int fakefullscreen); -static void setfullscreen(Client *c, int fullscreen); -static void setmaximizescreen(Client *c, int maximizescreen); +static void setfloating(Client *c, int32_t floating); +static void setfakefullscreen(Client *c, int32_t fakefullscreen); +static void setfullscreen(Client *c, int32_t fullscreen); +static void setmaximizescreen(Client *c, int32_t maximizescreen); static void reset_maximizescreen_size(Client *c); -static void setgaps(int oh, int ov, int ih, int iv); +static void setgaps(int32_t oh, int32_t ov, int32_t ih, int32_t iv); static void setmon(Client *c, Monitor *m, uint32_t newtags, bool focus); static void setpsel(struct wl_listener *listener, void *data); @@ -663,7 +672,7 @@ static void updatetitle(struct wl_listener *listener, void *data); static void urgent(struct wl_listener *listener, void *data); static void view(const Arg *arg, bool want_animation); -static void handlesig(int signo); +static void handlesig(int32_t signo); static void handle_keyboard_shortcuts_inhibit_new_inhibitor(struct wl_listener *listener, void *data); @@ -675,7 +684,7 @@ static void xytonode(double x, double y, struct wlr_surface **psurface, Client **pc, LayerSurface **pl, double *nx, double *ny); static void clear_fullscreen_flag(Client *c); static pid_t getparentprocess(pid_t p); -static int isdescprocess(pid_t p, pid_t c); +static int32_t isdescprocess(pid_t p, pid_t c); static Client *termforwin(Client *w); static void swallow(Client *c, Client *w); @@ -683,29 +692,29 @@ static void warp_cursor_to_selmon(Monitor *m); uint32_t want_restore_fullscreen(Client *target_client); static void overview_restore(Client *c, const Arg *arg); static void overview_backup(Client *c); -static int applyrulesgeom(Client *c); static void set_minimized(Client *c); static void show_scratchpad(Client *c); static void show_hide_client(Client *c); static void tag_client(const Arg *arg, Client *target_client); -static struct wlr_box setclient_coordinate_center(Client *c, +static struct wlr_box setclient_coordinate_center(Client *c, Monitor *m, struct wlr_box geom, - int offsetx, int offsety); + int32_t offsetx, + int32_t offsety); static uint32_t get_tags_first_tag(uint32_t tags); static struct wlr_output_mode * -get_nearest_output_mode(struct wlr_output *output, int width, int height, - float refresh); +get_nearest_output_mode(struct wlr_output *output, int32_t width, + int32_t height, float refresh); static void client_commit(Client *c); static void layer_commit(LayerSurface *l); static void apply_border(Client *c); static void client_set_opacity(Client *c, double opacity); static void init_baked_points(void); -static void scene_buffer_apply_opacity(struct wlr_scene_buffer *buffer, int sx, - int sy, void *data); +static void scene_buffer_apply_opacity(struct wlr_scene_buffer *buffer, + int32_t sx, int32_t sy, void *data); static Client *direction_select(const Arg *arg); static void view_in_mon(const Arg *arg, bool want_animation, Monitor *m, @@ -713,13 +722,14 @@ static void view_in_mon(const Arg *arg, bool want_animation, Monitor *m, static void buffer_set_effect(Client *c, BufferData buffer_data); static void snap_scene_buffer_apply_effect(struct wlr_scene_buffer *buffer, - int sx, int sy, void *data); + int32_t sx, int32_t sy, void *data); static void client_set_pending_state(Client *c); static void layer_set_pending_state(LayerSurface *l); -static void set_rect_size(struct wlr_scene_rect *rect, int width, int height); +static void set_rect_size(struct wlr_scene_rect *rect, int32_t width, + int32_t height); static Client *center_tiled_select(Monitor *m); static void handlecursoractivity(void); -static int hidecursor(void *data); +static int32_t hidecursor(void *data); static bool check_hit_no_border(Client *c); static void reset_keyboard_layout(void); static void client_update_oldmonname_record(Client *c, Monitor *m); @@ -727,13 +737,12 @@ static void pending_kill_client(Client *c); static uint32_t get_tags_first_tag_num(uint32_t source_tags); static void set_layer_open_animaiton(LayerSurface *l, struct wlr_box geo); static void init_fadeout_layers(LayerSurface *l); -static void layer_actual_size(LayerSurface *l, uint32_t *width, - uint32_t *height); +static void layer_actual_size(LayerSurface *l, int32_t *width, int32_t *height); static void get_layer_target_geometry(LayerSurface *l, struct wlr_box *target_box); -static void scene_buffer_apply_effect(struct wlr_scene_buffer *buffer, int sx, - int sy, void *data); -static double find_animation_curve_at(double t, int type); +static void scene_buffer_apply_effect(struct wlr_scene_buffer *buffer, + int32_t sx, int32_t sy, void *data); +static double find_animation_curve_at(double t, int32_t type); static void apply_opacity_to_rect_nodes(Client *c, struct wlr_scene_node *node, double animation_passed); @@ -743,6 +752,7 @@ static struct wlr_scene_tree * wlr_scene_tree_snapshot(struct wlr_scene_node *node, struct wlr_scene_tree *parent); static bool is_scroller_layout(Monitor *m); +static bool is_centertile_layout(Monitor *m); static void create_output(struct wlr_backend *backend, void *data); static void get_layout_abbr(char *abbr, const char *full_name); static void apply_named_scratchpad(Client *target_client); @@ -755,12 +765,20 @@ static void enable_adaptive_sync(Monitor *m, struct wlr_output_state *state); static Client *get_next_stack_client(Client *c, bool reverse); static void set_float_malposition(Client *tc); static void set_size_per(Monitor *m, Client *c); -static void resize_tile_client(Client *grabc, bool isdrag, int offsetx, - int offsety, uint32_t time); +static void resize_tile_client(Client *grabc, bool isdrag, int32_t offsetx, + int32_t offsety, uint32_t time); static void refresh_monitors_workspaces_status(Monitor *m); static void init_client_properties(Client *c); static float *get_border_color(Client *c); static void clear_fullscreen_and_maximized_state(Monitor *m); +static void request_fresh_all_monitors(void); +static Client *find_client_by_direction(Client *tc, const Arg *arg, + bool findfloating, bool ignore_align); +static void exit_scroller_stack(Client *c); +static Client *get_scroll_stack_head(Client *c); +static bool client_only_in_one_tag(Client *c); +static Client *get_focused_stack_client(Client *sc); +static bool client_is_in_same_stack(Client *sc, Client *tc, Client *fc); #include "data/static_keymap.h" #include "dispatch/bind_declare.h" @@ -769,7 +787,7 @@ static void clear_fullscreen_and_maximized_state(Monitor *m); /* variables */ static const char broken[] = "broken"; static pid_t child_pid = -1; -static int locked; +static int32_t locked; static uint32_t locked_mods = 0; static void *exclusive_focus; static struct wl_display *dpy; @@ -810,7 +828,7 @@ static struct wlr_scene_rect *root_bg; static struct wlr_session_lock_manager_v1 *session_lock_mgr; static struct wlr_scene_rect *locked_bg; static struct wlr_session_lock_v1 *cur_lock; -static const int layermap[] = {LyrBg, LyrBottom, LyrTop, LyrOverlay}; +static const int32_t layermap[] = {LyrBg, LyrBottom, LyrTop, LyrOverlay}; static struct wlr_scene_tree *drag_icon; static struct wlr_cursor_shape_manager_v1 *cursor_shape_mgr; static struct wlr_pointer_constraints_v1 *pointer_constraints; @@ -823,20 +841,21 @@ static struct wl_list inputdevices; static struct wl_list keyboard_shortcut_inhibitors; static uint32_t cursor_mode; static Client *grabc; -static int grabcx, grabcy; /* client-relative */ -static int drag_begin_cursorx, drag_begin_cursory; /* client-relative */ +static int32_t rzcorner; +static int32_t grabcx, grabcy; /* client-relative */ +static int32_t drag_begin_cursorx, drag_begin_cursory; /* client-relative */ static bool start_drag_window = false; -static int last_apply_drap_time = 0; +static int32_t last_apply_drap_time = 0; static struct wlr_output_layout *output_layout; static struct wlr_box sgeom; static struct wl_list mons; static Monitor *selmon; -static int enablegaps = 1; /* enables gaps, used by togglegaps */ -static int axis_apply_time = 0; -static int axis_apply_dir = 0; -static int scroller_focus_lock = 0; +static int32_t enablegaps = 1; /* enables gaps, used by togglegaps */ +static int32_t axis_apply_time = 0; +static int32_t axis_apply_dir = 0; +static int32_t scroller_focus_lock = 0; static uint32_t swipe_fingers = 0; static double swipe_dx = 0; @@ -845,6 +864,7 @@ static double swipe_dy = 0; bool render_border = true; uint32_t chvt_backup_tag = 0; +bool allow_frame_scheduling = true; char chvt_backup_selmon[32] = {0}; struct dvec2 *baked_points_move; @@ -866,18 +886,19 @@ static KeyMode keymode = { static struct { enum wp_cursor_shape_device_v1_shape shape; struct wlr_surface *surface; - int hotspot_x; - int hotspot_y; + int32_t hotspot_x; + int32_t hotspot_y; } last_cursor; #include "client/client.h" #include "config/preset.h" struct Pertag { - uint32_t curtag, prevtag; /* current and previous tag */ - int nmasters[LENGTH(tags) + 1]; /* number of windows in master area */ - float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */ - bool no_hide[LENGTH(tags) + 1]; /* no_hide per tag */ + uint32_t curtag, prevtag; /* current and previous tag */ + int32_t nmasters[LENGTH(tags) + 1]; /* number of windows in master area */ + float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */ + bool no_hide[LENGTH(tags) + 1]; /* no_hide per tag */ + bool no_render_border[LENGTH(tags) + 1]; /* no_render_border per tag */ const Layout *ltidxs[LENGTH(tags) + 1]; /* matrix of tags and layouts indexes */ }; @@ -948,16 +969,16 @@ static struct wlr_xwayland *xwayland; void client_change_mon(Client *c, Monitor *m) { setmon(c, m, c->tags, true); - reset_foreign_tolevel(c); if (c->isfloating) { - c->float_geom = c->geom = setclient_coordinate_center(c, c->geom, 0, 0); + c->float_geom = c->geom = + setclient_coordinate_center(c, c->mon, c->geom, 0, 0); } } void applybounds(Client *c, struct wlr_box *bbox) { /* set minimum possible */ - c->geom.width = MAX(1 + 2 * (int)c->bw, c->geom.width); - c->geom.height = MAX(1 + 2 * (int)c->bw, c->geom.height); + c->geom.width = MAX(1 + 2 * (int32_t)c->bw, c->geom.width); + c->geom.height = MAX(1 + 2 * (int32_t)c->bw, c->geom.height); if (c->geom.x >= bbox->x + bbox->width) c->geom.x = bbox->x + bbox->width - c->geom.width; @@ -1017,7 +1038,7 @@ void show_scratchpad(Client *c) { : c->mon->w.height * scratchpad_height_ratio; // 重新计算居中的坐标 c->float_geom = c->geom = c->animainit_geom = c->animation.current = - setclient_coordinate_center(c, c->geom, 0, 0); + setclient_coordinate_center(c, c->mon, c->geom, 0, 0); c->iscustomsize = 1; resize(c, c->geom, 0); } @@ -1049,7 +1070,17 @@ void swallow(Client *c, Client *w) { c->tags = w->tags; c->geom = w->geom; c->float_geom = w->float_geom; + c->stack_inner_per = w->stack_inner_per; + c->master_inner_per = w->master_inner_per; + c->master_mfact_per = w->master_mfact_per; c->scroller_proportion = w->scroller_proportion; + c->next_in_stack = w->next_in_stack; + c->prev_in_stack = w->prev_in_stack; + if (w->next_in_stack) + w->next_in_stack->prev_in_stack = c; + if (w->prev_in_stack) + w->prev_in_stack->next_in_stack = c; + c->stack_proportion = w->stack_proportion; wl_list_insert(&w->link, &c->link); wl_list_insert(&w->flink, &c->flink); @@ -1083,17 +1114,18 @@ bool switch_scratchpad_client_state(Client *c) { // 根据新monitor调整窗口尺寸 c->float_geom.width = - (int)(c->float_geom.width * c->mon->w.width / oldmon->w.width); - c->float_geom.height = - (int)(c->float_geom.height * c->mon->w.height / oldmon->w.height); + (int32_t)(c->float_geom.width * c->mon->w.width / oldmon->w.width); + c->float_geom.height = (int32_t)(c->float_geom.height * + c->mon->w.height / oldmon->w.height); - c->float_geom = setclient_coordinate_center(c, c->float_geom, 0, 0); + c->float_geom = + setclient_coordinate_center(c, c->mon, c->float_geom, 0, 0); // 只有显示状态的scratchpad才需要聚焦和返回true if (c->is_scratchpad_show) { c->tags = get_tags_first_tag(selmon->tagset[selmon->seltags]); resize(c, c->float_geom, 0); - arrange(selmon, false); + arrange(selmon, false, false); focusclient(c, true); c->scratchpad_switching_mon = false; return true; @@ -1106,7 +1138,7 @@ bool switch_scratchpad_client_state(Client *c) { if (c->is_in_scratchpad && c->is_scratchpad_show && (c->mon->tagset[c->mon->seltags] & c->tags) == 0) { c->tags = c->mon->tagset[c->mon->seltags]; - arrange(c->mon, false); + arrange(c->mon, false, false); focusclient(c, true); return true; } else if (c->is_in_scratchpad && c->is_scratchpad_show && @@ -1168,7 +1200,7 @@ void gpureset(struct wl_listener *listener, void *data) { wlr_renderer_destroy(old_drw); } -void handlesig(int signo) { +void handlesig(int32_t signo) { if (signo == SIGCHLD) while (waitpid(-1, NULL, WNOHANG) > 0) ; @@ -1176,7 +1208,7 @@ void handlesig(int signo) { quit(NULL); } -void toggle_hotarea(int x_root, int y_root) { +void toggle_hotarea(int32_t x_root, int32_t y_root) { // 左下角热区坐标计算,兼容多显示屏 Arg arg = {0}; @@ -1188,17 +1220,59 @@ void toggle_hotarea(int x_root, int y_root) { if (grabc) return; - unsigned hx = selmon->m.x + hotarea_size; - unsigned hy = selmon->m.y + selmon->m.height - hotarea_size; + // 根据热角位置计算不同的热区坐标 + unsigned hx, hy; - if (enable_hotarea == 1 && selmon->is_in_hotarea == 0 && y_root > hy && - x_root < hx && x_root >= selmon->m.x && - y_root <= (selmon->m.y + selmon->m.height)) { + switch (hotarea_corner) { + case BOTTOM_RIGHT: // 右下角 + hx = selmon->m.x + selmon->m.width - hotarea_size; + hy = selmon->m.y + selmon->m.height - hotarea_size; + break; + case TOP_LEFT: // 左上角 + hx = selmon->m.x + hotarea_size; + hy = selmon->m.y + hotarea_size; + break; + case TOP_RIGHT: // 右上角 + hx = selmon->m.x + selmon->m.width - hotarea_size; + hy = selmon->m.y + hotarea_size; + break; + case BOTTOM_LEFT: // 左下角(默认) + default: + hx = selmon->m.x + hotarea_size; + hy = selmon->m.y + selmon->m.height - hotarea_size; + break; + } + + // 判断鼠标是否在热区内 + int in_hotarea = 0; + + switch (hotarea_corner) { + case BOTTOM_RIGHT: // 右下角 + in_hotarea = (y_root > hy && x_root > hx && + x_root <= (selmon->m.x + selmon->m.width) && + y_root <= (selmon->m.y + selmon->m.height)); + break; + case TOP_LEFT: // 左上角 + in_hotarea = (y_root < hy && x_root < hx && x_root >= selmon->m.x && + y_root >= selmon->m.y); + break; + case TOP_RIGHT: // 右上角 + in_hotarea = (y_root < hy && x_root > hx && + x_root <= (selmon->m.x + selmon->m.width) && + y_root >= selmon->m.y); + break; + case BOTTOM_LEFT: // 左下角(默认) + default: + in_hotarea = (y_root > hy && x_root < hx && x_root >= selmon->m.x && + y_root <= (selmon->m.y + selmon->m.height)); + break; + } + + if (enable_hotarea == 1 && selmon->is_in_hotarea == 0 && in_hotarea) { toggleoverview(&arg); selmon->is_in_hotarea = 1; } else if (enable_hotarea == 1 && selmon->is_in_hotarea == 1 && - (y_root <= hy || x_root >= hx || x_root < selmon->m.x || - y_root > (selmon->m.y + selmon->m.height))) { + !in_hotarea) { selmon->is_in_hotarea = 0; } } @@ -1240,49 +1314,9 @@ static void apply_rule_properties(Client *c, const ConfigWinRule *r) { APPLY_STRING_PROP(c, r, animation_type_close); } -int applyrulesgeom(Client *c) { - /* rule matching */ - const char *appid, *title; - ConfigWinRule *r; - int hit = 0; - int ji; - - if (!(appid = client_get_appid(c))) - appid = broken; - if (!(title = client_get_title(c))) - title = broken; - - for (ji = 0; ji < config.window_rules_count; ji++) { - if (config.window_rules_count < 1) - break; - r = &config.window_rules[ji]; - - if (!is_window_rule_matches(r, appid, title)) - continue; - - c->geom.width = r->width > 0 ? r->width : c->geom.width; - c->geom.height = r->height > 0 ? r->height : c->geom.height; - - if (!c->isnosizehint) - client_set_size_bound(c); - - // 重新计算居中的坐标 - if (r->offsetx != 0 || r->offsety != 0 || r->width > 0 || r->height > 0) - c->geom = - setclient_coordinate_center(c, c->geom, r->offsetx, r->offsety); - if (r->height > 0 || r->width > 0 || r->offsetx != 0 || - r->offsety != 0) { - hit = 1; - } else { - hit = 0; - } - } - return hit; -} - void set_float_malposition(Client *tc) { Client *c = NULL; - int x, y, offset, xreverse, yreverse; + int32_t x, y, offset, xreverse, yreverse; x = tc->geom.x; y = tc->geom.y; xreverse = 1; @@ -1328,7 +1362,6 @@ void applyrules(Client *c) { const ConfigWinRule *r; Monitor *m = NULL; Client *fc = NULL; - bool hit_rule_pos = false; Client *parent = NULL; parent = client_get_parent(c); @@ -1377,11 +1410,14 @@ void applyrules(Client *c) { if (r->height > 0) c->float_geom.height = r->height; - if (r->offsetx || r->offsety || r->width > 0 || r->height > 0) { - hit_rule_pos = r->offsetx || r->offsety ? true : false; + if (r->width > 0 || r->height > 0) { c->iscustomsize = 1; - c->float_geom = setclient_coordinate_center(c, c->float_geom, - r->offsetx, r->offsety); + } + + if (r->offsetx || r->offsety) { + c->iscustompos = 1; + c->float_geom = c->geom = setclient_coordinate_center( + c, mon, c->float_geom, r->offsetx, r->offsety); } if (c->isfloating) { c->geom = c->float_geom.width > 0 && c->float_geom.height > 0 @@ -1392,13 +1428,15 @@ void applyrules(Client *c) { } } - set_size_per(mon, c); + if (mon) + set_size_per(mon, c); // if no geom rule hit and is normal winodw, use the center pos and record // the hit size - if (!hit_rule_pos && + if (!c->iscustompos && (!client_is_x11(c) || (c->geom.x == 0 && c->geom.y == 0))) { - c->float_geom = c->geom = setclient_coordinate_center(c, c->geom, 0, 0); + c->float_geom = c->geom = + setclient_coordinate_center(c, mon, c->geom, 0, 0); } else { c->float_geom = c->geom; } @@ -1427,7 +1465,8 @@ void applyrules(Client *c) { } } - int fullscreen_state_backup = c->isfullscreen || client_wants_fullscreen(c); + int32_t fullscreen_state_backup = + c->isfullscreen || client_wants_fullscreen(c); setmon(c, mon, newtags, !c->isopensilent && !(client_is_x11_popup(c) && client_should_ignore_focus(c)) && @@ -1452,10 +1491,10 @@ void applyrules(Client *c) { VISIBLEON(fc, c->mon) && ISFULLSCREEN(fc) && !c->isfloating) { clear_fullscreen_flag(fc); - arrange(c->mon, false); + arrange(c->mon, false, false); } - if (c->isfloating && !hit_rule_pos && !c->isnamedscratchpad) { + if (c->isfloating && !c->iscustompos && !c->isnamedscratchpad) { wl_list_remove(&c->link); wl_list_insert(clients.prev, &c->link); set_float_malposition(c); @@ -1468,13 +1507,13 @@ void applyrules(Client *c) { // apply overlay rule if (c->isoverlay) { - wlr_scene_node_reparent(&selmon->sel->scene->node, layers[LyrOverlay]); - wlr_scene_node_raise_to_top(&selmon->sel->scene->node); + wlr_scene_node_reparent(&c->scene->node, layers[LyrOverlay]); + wlr_scene_node_raise_to_top(&c->scene->node); } } void arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, - int exclusive) { + int32_t exclusive) { LayerSurface *l = NULL; struct wlr_box full_area = m->m; @@ -1485,6 +1524,9 @@ void arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, !layer_surface->initialized) continue; + if (l->being_unmapped) + continue; + wlr_scene_layer_surface_v1_configure(l->scene_layer, &full_area, usable_area); wlr_scene_node_set_position(&l->popups->node, l->scene->node.x, @@ -1493,14 +1535,14 @@ void arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, } void apply_window_snap(Client *c) { - int snap_up = 99999, snap_down = 99999, snap_left = 99999, - snap_right = 99999; - int snap_up_temp = 0, snap_down_temp = 0, snap_left_temp = 0, - snap_right_temp = 0; - int snap_up_screen = 0, snap_down_screen = 0, snap_left_screen = 0, - snap_right_screen = 0; - int snap_up_mon = 0, snap_down_mon = 0, snap_left_mon = 0, - snap_right_mon = 0; + int32_t snap_up = 99999, snap_down = 99999, snap_left = 99999, + snap_right = 99999; + int32_t snap_up_temp = 0, snap_down_temp = 0, snap_left_temp = 0, + snap_right_temp = 0; + int32_t snap_up_screen = 0, snap_down_screen = 0, snap_left_screen = 0, + snap_right_screen = 0; + int32_t snap_up_mon = 0, snap_down_mon = 0, snap_left_mon = 0, + snap_right_mon = 0; uint32_t cbw = !render_border || c->fake_no_border ? borderpx : 0; uint32_t tcbw; @@ -1603,7 +1645,7 @@ void focuslayer(LayerSurface *l) { void reset_exclusive_layer(Monitor *m) { LayerSurface *l = NULL; - int i; + int32_t i; uint32_t layers_above_shell[] = { ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, ZWLR_LAYER_SHELL_V1_LAYER_TOP, @@ -1613,7 +1655,7 @@ void reset_exclusive_layer(Monitor *m) { if (!m) return; - for (i = 0; i < (int)LENGTH(layers_above_shell); i++) { + for (i = 0; i < (int32_t)LENGTH(layers_above_shell); i++) { wl_list_for_each_reverse(l, &m->layers[layers_above_shell[i]], link) { if (l == exclusive_focus && l->layer_surface->current.keyboard_interactive != @@ -1639,7 +1681,7 @@ void reset_exclusive_layer(Monitor *m) { } void arrangelayers(Monitor *m) { - int i; + int32_t i; struct wlr_box usable_area = m->m; if (!m->wlr_output->enabled) @@ -1651,7 +1693,7 @@ void arrangelayers(Monitor *m) { if (!wlr_box_equal(&usable_area, &m->w)) { m->w = usable_area; - arrange(m, false); + arrange(m, false, false); } /* Arrange non-exlusive surfaces from top->bottom */ @@ -1671,7 +1713,7 @@ axisnotify(struct wl_listener *listener, void *data) { struct wlr_keyboard *keyboard, *hard_keyboard; uint32_t mods, hard_mods; AxisBinding *a; - int ji; + int32_t ji; uint32_t adir; // IDLE_NOTIFY_ACTIVITY; handlecursoractivity(); @@ -1725,15 +1767,15 @@ axisnotify(struct wl_listener *listener, void *data) { event->relative_direction); } -int ongesture(struct wlr_pointer_swipe_end_event *event) { +int32_t ongesture(struct wlr_pointer_swipe_end_event *event) { struct wlr_keyboard *keyboard, *hard_keyboard; uint32_t mods, hard_mods; const GestureBinding *g; uint32_t motion; - uint32_t adx = (int)round(fabs(swipe_dx)); - uint32_t ady = (int)round(fabs(swipe_dy)); - int handled = 0; - int ji; + uint32_t adx = (int32_t)round(fabs(swipe_dx)); + uint32_t ady = (int32_t)round(fabs(swipe_dy)); + int32_t handled = 0; + int32_t ji; if (event->cancelled) { return handled; @@ -1849,12 +1891,12 @@ void place_drag_tile_client(Client *c) { Client *closest_client = NULL; long min_distant = LONG_MAX; long temp_distant; - int x, y; + int32_t x, y; wl_list_for_each(tc, &clients, link) { if (tc != c && ISTILED(tc) && VISIBLEON(tc, c->mon)) { - x = tc->geom.x + (int)(tc->geom.width / 2) - cursor->x; - y = tc->geom.y + (int)(tc->geom.height / 2) - cursor->y; + x = tc->geom.x + (int32_t)(tc->geom.width / 2) - cursor->x; + y = tc->geom.y + (int32_t)(tc->geom.height / 2) - cursor->y; temp_distant = x * x + y * y; if (temp_distant < min_distant) { min_distant = temp_distant; @@ -1901,7 +1943,7 @@ buttonpress(struct wl_listener *listener, void *data) { LayerSurface *l = NULL; struct wlr_surface *surface; Client *tmpc = NULL; - int ji; + int32_t ji; const MouseBinding *m; struct wlr_surface *old_pointer_focus_surface = seat->pointer_state.focused_surface; @@ -1983,7 +2025,6 @@ buttonpress(struct wl_listener *listener, void *data) { selmon = xytomon(cursor->x, cursor->y); client_update_oldmonname_record(grabc, selmon); setmon(grabc, selmon, 0, true); - reset_foreign_tolevel(grabc); selmon->prevsel = ISTILED(selmon->sel) ? selmon->sel : NULL; selmon->sel = grabc; tmpc = grabc; @@ -2009,7 +2050,7 @@ buttonpress(struct wl_listener *listener, void *data) { } void checkidleinhibitor(struct wlr_surface *exclude) { - int inhibited = 0; + int32_t inhibited = 0; Client *c = NULL; struct wlr_surface *surface = NULL; struct wlr_idle_inhibitor_v1 *inhibitor; @@ -2163,7 +2204,7 @@ void closemon(Monitor *m) { /* update selmon if needed and * move closed monitor's clients to the focused one */ Client *c = NULL; - int i = 0, nmons = wl_list_length(&mons); + int32_t i = 0, nmons = wl_list_length(&mons); if (!nmons) { selmon = NULL; } else if (m == selmon) { @@ -2196,8 +2237,8 @@ void closemon(Monitor *m) { } } -static void iter_layer_scene_buffers(struct wlr_scene_buffer *buffer, int sx, - int sy, void *user_data) { +static void iter_layer_scene_buffers(struct wlr_scene_buffer *buffer, + int32_t sx, int32_t sy, void *user_data) { struct wlr_scene_surface *scene_surface = wlr_scene_surface_try_from_buffer(buffer); if (!scene_surface) { @@ -2216,7 +2257,7 @@ static void iter_layer_scene_buffers(struct wlr_scene_buffer *buffer, int sx, void maplayersurfacenotify(struct wl_listener *listener, void *data) { LayerSurface *l = wl_container_of(listener, l, map); struct wlr_layer_surface_v1 *layer_surface = l->layer_surface; - int ji; + int32_t ji; ConfigLayerRule *r; l->mapped = 1; @@ -2301,6 +2342,15 @@ void commitlayersurfacenotify(struct wl_listener *listener, void *data) { return; } + // 检查surface是否有buffer + // 空buffer,只是隐藏,不改变mapped状态 + if (l->mapped && !layer_surface->surface->buffer) { + wlr_scene_node_set_enabled(&l->scene->node, false); + return; + } else { + wlr_scene_node_set_enabled(&l->scene->node, true); + } + get_layer_target_geometry(l, &box); if (animations && layer_animations && !l->noanim && l->mapped && @@ -2447,14 +2497,14 @@ void commitpopup(struct wl_listener *listener, void *data) { LayerSurface *l = NULL; Client *c = NULL; struct wlr_box box; - int type = -1; + int32_t type = -1; - if (!popup->base->initial_commit) - return; + if (!popup || !popup->base->initial_commit) + goto commitpopup_listen_free; type = toplevel_from_wlr_surface(popup->base->surface, &c, &l); - if (!popup->parent || type < 0) - return; + if (!popup->parent || !popup->parent->data || type < 0) + goto commitpopup_listen_free; wlr_scene_node_raise_to_top(popup->parent->data); @@ -2462,13 +2512,14 @@ void commitpopup(struct wl_listener *listener, void *data) { wlr_scene_xdg_surface_create(popup->parent->data, popup->base); if ((l && !l->mon) || (c && !c->mon)) { wlr_xdg_popup_destroy(popup); - return; + goto commitpopup_listen_free; } box = type == LayerShell ? l->mon->m : c->mon->w; box.x -= (type == LayerShell ? l->scene->node.x : c->geom.x); box.y -= (type == LayerShell ? l->scene->node.y : c->geom.y); wlr_xdg_popup_unconstrain_from_box(popup, &box); +commitpopup_listen_free: wl_list_remove(&listener->link); free(listener); } @@ -2596,8 +2647,6 @@ void createlayersurface(struct wl_listener *listener, void *data) { LISTEN(&surface->events.commit, &l->surface_commit, commitlayersurfacenotify); LISTEN(&surface->events.unmap, &l->unmap, unmaplayersurfacenotify); - LISTEN(&layer_surface->events.destroy, &l->destroy, - destroylayersurfacenotify); l->layer_surface = layer_surface; l->mon = layer_surface->output->data; @@ -2610,6 +2659,8 @@ void createlayersurface(struct wl_listener *listener, void *data) { : scene_layer); l->scene->node.data = l->popups->node.data = l; + LISTEN(&l->scene->node.events.destroy, &l->destroy, destroylayernodenotify); + wl_list_insert(&l->mon->layers[layer_surface->pending.layer], &l->link); wlr_surface_send_enter(surface, layer_surface->output); } @@ -2634,7 +2685,7 @@ void createlocksurface(struct wl_listener *listener, void *data) { } struct wlr_output_mode *get_nearest_output_mode(struct wlr_output *output, - int width, int height, + int32_t width, int32_t height, float refresh) { struct wlr_output_mode *mode, *nearest_mode = NULL; float min_diff = 99999.0f; @@ -2672,7 +2723,7 @@ void createmon(struct wl_listener *listener, void *data) { struct wlr_output *wlr_output = data; const ConfigMonitorRule *r; uint32_t i; - int ji, jk; + int32_t ji, vrr; struct wlr_output_state state; Monitor *m = NULL; struct wlr_output_mode *internal_mode = NULL; @@ -2708,30 +2759,19 @@ void createmon(struct wl_listener *listener, void *data) { m->sel = NULL; m->is_in_hotarea = 0; float scale = 1; - m->mfact = default_mfact; - m->nmaster = default_nmaster; enum wl_output_transform rr = WL_OUTPUT_TRANSFORM_NORMAL; wlr_output_state_set_scale(&state, scale); wlr_output_state_set_transform(&state, rr); - m->lt = &layouts[0]; for (ji = 0; ji < config.monitor_rules_count; ji++) { if (config.monitor_rules_count < 1) break; r = &config.monitor_rules[ji]; - if (!r->name || regex_match(r->name, wlr_output->name)) { - m->mfact = r->mfact; - m->nmaster = r->nmaster; - m->m.x = r->x; - m->m.y = r->y; - if (r->layout) { - for (jk = 0; jk < LENGTH(layouts); jk++) { - if (strcmp(layouts[jk].name, r->layout) == 0) { - m->lt = &layouts[jk]; - } - } - } + if (regex_match(r->name, wlr_output->name)) { + m->m.x = r->x == INT32_MAX ? INT32_MAX : r->x; + m->m.y = r->y == INT32_MAX ? INT32_MAX : r->y; + vrr = r->vrr >= 0 ? r->vrr : 0; scale = r->scale; rr = r->rr; @@ -2745,9 +2785,16 @@ void createmon(struct wl_listener *listener, void *data) { custom_monitor_mode = true; wlr_output_state_set_custom_mode( &state, r->width, r->height, - (int)roundf(r->refresh * 1000)); + (int32_t)roundf(r->refresh * 1000)); } } + + if (vrr) { + enable_adaptive_sync(m, &state); + } else { + wlr_output_state_set_adaptive_sync_enabled(&state, false); + } + wlr_output_state_set_scale(&state, r->scale); wlr_output_state_set_transform(&state, r->rr); break; @@ -2762,10 +2809,6 @@ void createmon(struct wl_listener *listener, void *data) { wlr_output_state_set_mode(&state, wlr_output_preferred_mode(wlr_output)); - if (adaptive_sync) { - enable_adaptive_sync(m, &state); - } - /* Set up event listeners */ LISTEN(&wlr_output->events.frame, &m->frame, rendermon); LISTEN(&wlr_output->events.destroy, &m->destroy, cleanupmon); @@ -2790,9 +2833,9 @@ void createmon(struct wl_listener *listener, void *data) { } for (i = 0; i <= LENGTH(tags); i++) { - m->pertag->nmasters[i] = m->nmaster; - m->pertag->mfacts[i] = m->mfact; - m->pertag->ltidxs[i] = m->lt; + m->pertag->nmasters[i] = default_nmaster; + m->pertag->mfacts[i] = default_mfact; + m->pertag->ltidxs[i] = &layouts[0]; } // apply tag rule @@ -2814,7 +2857,7 @@ void createmon(struct wl_listener *listener, void *data) { * output (such as DPI, scale factor, manufacturer, etc). */ m->scene_output = wlr_scene_output_create(scene, wlr_output); - if (m->m.x == -1 && m->m.y == -1) + if (m->m.x == INT32_MAX || m->m.y == INT32_MAX) wlr_output_layout_add_auto(output_layout, wlr_output); else wlr_output_layout_add(output_layout, wlr_output, m->m.x, m->m.y); @@ -2931,9 +2974,14 @@ void configure_pointer(struct libinput_device *device) { if (libinput_device_config_send_events_get_modes(device)) libinput_device_config_send_events_set_mode(device, send_events_mode); - if (libinput_device_config_accel_is_available(device)) { + if (accel_profile && libinput_device_config_accel_is_available(device)) { libinput_device_config_accel_set_profile(device, accel_profile); libinput_device_config_accel_set_speed(device, accel_speed); + } else { + // profile cannot be directly applied to 0, need to set to 1 first + libinput_device_config_accel_set_profile(device, 1); + libinput_device_config_accel_set_profile(device, 0); + libinput_device_config_accel_set_speed(device, 0); } } @@ -2966,7 +3014,7 @@ void switch_toggle(struct wl_listener *listener, void *data) { // 处理切换事件 struct wlr_switch_toggle_event *event = data; SwitchBinding *s; - int ji; + int32_t ji; for (ji = 0; ji < config.switch_bindings_count; ji++) { if (config.switch_bindings_count < 1) @@ -3078,7 +3126,7 @@ void destroyidleinhibitor(struct wl_listener *listener, void *data) { free(listener); } -void destroylayersurfacenotify(struct wl_listener *listener, void *data) { +void destroylayernodenotify(struct wl_listener *listener, void *data) { LayerSurface *l = wl_container_of(listener, l, destroy); wl_list_remove(&l->link); @@ -3086,12 +3134,11 @@ void destroylayersurfacenotify(struct wl_listener *listener, void *data) { wl_list_remove(&l->map.link); wl_list_remove(&l->unmap.link); wl_list_remove(&l->surface_commit.link); - wlr_scene_node_destroy(&l->scene->node); wlr_scene_node_destroy(&l->popups->node); free(l); } -void destroylock(SessionLock *lock, int unlock) { +void destroylock(SessionLock *lock, int32_t unlock) { wlr_seat_keyboard_notify_clear_focus(seat); if ((locked = !unlock)) goto destroy; @@ -3195,7 +3242,7 @@ void destroykeyboardgroup(struct wl_listener *listener, void *data) { free(group); } -void focusclient(Client *c, int lift) { +void focusclient(Client *c, int32_t lift) { Client *last_focus_client = NULL; Monitor *um = NULL; @@ -3254,7 +3301,7 @@ void focusclient(Client *c, int lift) { (selmon->prevsel->tags & selmon->tagset[selmon->seltags]) && (c->tags & selmon->tagset[selmon->seltags]) && !c->isfloating && is_scroller_layout(selmon)) { - arrange(selmon, false); + arrange(selmon, false, false); } // change focus link position @@ -3286,7 +3333,7 @@ void focusclient(Client *c, int lift) { * layer is closed. */ Client *w = NULL; LayerSurface *l = NULL; - int type = + int32_t type = toplevel_from_wlr_surface(old_keyboard_focus_surface, &w, &l); if (type == LayerShell && l->scene->node.enabled && l->layer_surface->current.layer >= ZWLR_LAYER_SHELL_V1_LAYER_TOP && @@ -3402,9 +3449,9 @@ void inputdevice(struct wl_listener *listener, void *data) { wlr_seat_set_capabilities(seat, caps); } -int keyrepeat(void *data) { +int32_t keyrepeat(void *data) { KeyboardGroup *group = data; - int i; + int32_t i; if (!group->nsyms || group->wlr_group->keyboard.repeat_info.rate <= 0) return 0; @@ -3430,7 +3477,7 @@ bool is_keyboard_shortcut_inhibitor(struct wlr_surface *surface) { return false; } -int // 17 +int32_t // 17 keybinding(uint32_t state, bool locked, uint32_t mods, xkb_keysym_t sym, uint32_t keycode) { /* @@ -3438,10 +3485,10 @@ keybinding(uint32_t state, bool locked, uint32_t mods, xkb_keysym_t sym, * processing keys, rather than passing them on to the client for its * own processing. */ - int handled = 0; + int32_t handled = 0; const KeyBinding *k; - int ji; - int isbreak = 0; + int32_t ji; + int32_t isbreak = 0; // not allow modifier keys to be used as a keybinding if (keycode == 50 || keycode == 37 || keycode == 133 || keycode == 64 || @@ -3504,10 +3551,10 @@ bool keypressglobal(struct wlr_surface *last_surface, xkb_keysym_t keysym, uint32_t keycode) { Client *c = NULL, *lastc = focustop(selmon); uint32_t keycodes[32] = {0}; - int reset = false; + int32_t reset = false; const char *appid = NULL; const char *title = NULL; - int ji; + int32_t ji; const ConfigWinRule *r; for (ji = 0; ji < config.window_rules_count; ji++) { @@ -3561,7 +3608,7 @@ done: } void keypress(struct wl_listener *listener, void *data) { - int i; + int32_t i; /* This event is raised when a key is pressed or released. */ KeyboardGroup *group = wl_container_of(listener, group, key); struct wlr_keyboard_key_event *event = data; @@ -3570,7 +3617,7 @@ void keypress(struct wl_listener *listener, void *data) { struct wlr_xdg_surface *xdg_surface = last_surface ? wlr_xdg_surface_try_from_wlr_surface(last_surface) : NULL; - int pass = 0; + int32_t pass = 0; bool hit_global = false; #ifdef XWAYLAND struct wlr_xwayland_surface *xsurface = @@ -3582,10 +3629,10 @@ void keypress(struct wl_listener *listener, void *data) { uint32_t keycode = event->keycode + 8; /* Get a list of keysyms based on the keymap for this keyboard */ const xkb_keysym_t *syms; - int nsyms = xkb_state_key_get_syms(group->wlr_group->keyboard.xkb_state, - keycode, &syms); + int32_t nsyms = xkb_state_key_get_syms(group->wlr_group->keyboard.xkb_state, + keycode, &syms); - int handled = 0; + int32_t handled = 0; uint32_t mods = wlr_keyboard_get_modifiers(&group->wlr_group->keyboard); wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); @@ -3667,7 +3714,8 @@ void keypressmod(struct wl_listener *listener, void *data) { } void pending_kill_client(Client *c) { - // c->iskilling = 1; //不可以提前标记已经杀掉,因为有些客户端可能拒绝 + if (!c || c->iskilling) + return; client_send_close(c); } @@ -3696,8 +3744,8 @@ void locksession(struct wl_listener *listener, void *data) { wlr_session_lock_v1_send_locked(session_lock); } -static void iter_xdg_scene_buffers(struct wlr_scene_buffer *buffer, int sx, - int sy, void *user_data) { +static void iter_xdg_scene_buffers(struct wlr_scene_buffer *buffer, int32_t sx, + int32_t sy, void *user_data) { Client *c = user_data; struct wlr_scene_surface *scene_surface = @@ -3761,6 +3809,7 @@ void init_client_properties(Client *c) { c->ignore_maximize = 1; c->ignore_minimize = 1; c->iscustomsize = 0; + c->iscustompos = 0; c->master_mfact_per = 0.0f; c->master_inner_per = 0.0f; c->stack_inner_per = 0.0f; @@ -3774,6 +3823,15 @@ void init_client_properties(Client *c) { c->float_geom.height = 0; c->float_geom.x = 0; c->float_geom.y = 0; + c->stack_proportion = 0.0f; + c->next_in_stack = NULL; + c->prev_in_stack = NULL; + memcpy(c->opacity_animation.initial_border_color, bordercolor, + sizeof(c->opacity_animation.initial_border_color)); + memcpy(c->opacity_animation.current_border_color, bordercolor, + sizeof(c->opacity_animation.current_border_color)); + c->opacity_animation.initial_opacity = c->unfocused_opacity; + c->opacity_animation.current_opacity = c->unfocused_opacity; } void // old fix to 0.5 @@ -3853,7 +3911,7 @@ mapnotify(struct wl_listener *listener, void *data) { if (selmon->sel && ISSCROLLTILED(selmon->sel) && VISIBLEON(selmon->sel, selmon)) { - at_client = selmon->sel; + at_client = get_scroll_stack_head(selmon->sel); } else { at_client = center_tiled_select(selmon); } @@ -3922,7 +3980,7 @@ void unminimize(Client *c) { c->is_in_scratchpad = 0; c->isnamedscratchpad = 0; setborder_color(c); - arrange(c->mon, false); + arrange(c->mon, false, false); return; } } @@ -3940,7 +3998,7 @@ void set_minimized(Client *c) { c->is_in_scratchpad = 1; c->is_scratchpad_show = 0; focusclient(focustop(selmon), 1); - arrange(c->mon, false); + arrange(c->mon, false, false); wlr_foreign_toplevel_handle_v1_set_activated(c->foreign_toplevel, false); wlr_foreign_toplevel_handle_v1_set_minimized(c->foreign_toplevel, true); wl_list_remove(&c->link); // 从原来位置移除 @@ -3990,6 +4048,30 @@ void motionabsolute(struct wl_listener *listener, void *data) { motionnotify(event->time_msec, &event->pointer->base, dx, dy, dx, dy); } +void resize_floating_window(Client *grabc) { + int cdx = (int)round(cursor->x) - grabcx; + int cdy = (int)round(cursor->y) - grabcy; + + cdx = !(rzcorner & 1) && grabc->geom.width - 2 * (int)grabc->bw - cdx < 1 + ? 0 + : cdx; + cdy = !(rzcorner & 2) && grabc->geom.height - 2 * (int)grabc->bw - cdy < 1 + ? 0 + : cdy; + + const struct wlr_box box = { + .x = grabc->geom.x + (rzcorner & 1 ? 0 : cdx), + .y = grabc->geom.y + (rzcorner & 2 ? 0 : cdy), + .width = grabc->geom.width + (rzcorner & 1 ? cdx : -cdx), + .height = grabc->geom.height + (rzcorner & 2 ? cdy : -cdy)}; + + grabc->float_geom = box; + + resize(grabc, box, 1); + grabcx += cdx; + grabcy += cdy; +} + void motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double dy, double dx_unaccel, double dy_unaccel) { double sx = 0, sy = 0, sx_confined, sy_confined; @@ -4050,16 +4132,16 @@ void motionnotify(uint32_t time, struct wlr_input_device *device, double dx, } /* Update drag icon's position */ - wlr_scene_node_set_position(&drag_icon->node, (int)round(cursor->x), - (int)round(cursor->y)); + wlr_scene_node_set_position(&drag_icon->node, (int32_t)round(cursor->x), + (int32_t)round(cursor->y)); /* If we are currently grabbing the mouse, handle and return */ if (cursor_mode == CurMove) { /* Move the grabbed client to the new position. */ grabc->iscustomsize = 1; grabc->float_geom = - (struct wlr_box){.x = (int)round(cursor->x) - grabcx, - .y = (int)round(cursor->y) - grabcy, + (struct wlr_box){.x = (int32_t)round(cursor->x) - grabcx, + .y = (int32_t)round(cursor->y) - grabcy, .width = grabc->geom.width, .height = grabc->geom.height}; resize(grabc, grabc->float_geom, 1); @@ -4067,14 +4149,9 @@ void motionnotify(uint32_t time, struct wlr_input_device *device, double dx, } else if (cursor_mode == CurResize) { if (grabc->isfloating) { grabc->iscustomsize = 1; - grabc->float_geom = (struct wlr_box){ - .x = grabc->geom.x, - .y = grabc->geom.y, - .width = (int)round(cursor->x) - grabc->geom.x, - .height = (int)round(cursor->y) - grabc->geom.y}; if (last_apply_drap_time == 0 || - time - last_apply_drap_time > drag_refresh_interval) { - resize(grabc, grabc->float_geom, 1); + time - last_apply_drap_time > drag_floating_refresh_interval) { + resize_floating_window(grabc); last_apply_drap_time = time; } return; @@ -4134,7 +4211,7 @@ void outputmgrapply(struct wl_listener *listener, void *data) { } void // 0.7 custom -outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test) { +outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int32_t test) { /* * Called when a client such as wlr-randr requests a change in output * configuration. This is only one way that the layout can be changed, @@ -4142,7 +4219,7 @@ outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int test) { * output_layout.change event, not here. */ struct wlr_output_configuration_head_v1 *config_head; - int ok = 1; + int32_t ok = 1; wl_list_for_each(config_head, &config->heads, link) { struct wlr_output *wlr_output = config_head->state.output; @@ -4205,8 +4282,10 @@ void pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, uint32_t time) { struct timespec now; - if (surface != seat->pointer_state.focused_surface && sloppyfocus && time && - c && c->scene->node.enabled && !client_is_unmanaged(c)) + if (sloppyfocus && !start_drag_window && c && time && + c->scene->node.enabled && !c->animation.tagining && + (surface != seat->pointer_state.focused_surface) && + !client_is_unmanaged(c) && VISIBLEON(c, c->mon)) focusclient(c, 0); /* If surface is NULL, clear pointer focus */ @@ -4245,10 +4324,10 @@ void powermgrsetmode(struct wl_listener *listener, void *data) { updatemons(NULL, NULL); } -void quitsignal(int signo) { quit(NULL); } +void quitsignal(int32_t signo) { quit(NULL); } -void scene_buffer_apply_opacity(struct wlr_scene_buffer *buffer, int sx, int sy, - void *data) { +void scene_buffer_apply_opacity(struct wlr_scene_buffer *buffer, int32_t sx, + int32_t sy, void *data) { wlr_scene_buffer_set_opacity(buffer, *(double *)data); } @@ -4262,7 +4341,7 @@ void rendermon(struct wl_listener *listener, void *data) { Client *c = NULL, *tmp = NULL; struct wlr_output_state pending = {0}; LayerSurface *l = NULL, *tmpl = NULL; - int i; + int32_t i; struct wl_list *layer_list; bool frame_allow_tearing = false; struct timespec now; @@ -4272,7 +4351,7 @@ void rendermon(struct wl_listener *listener, void *data) { return; } - if (!m->wlr_output->enabled) + if (!m->wlr_output->enabled || !allow_frame_scheduling) return; frame_allow_tearing = check_tearing_frame_allow(m); @@ -4293,11 +4372,6 @@ void rendermon(struct wl_listener *listener, void *data) { need_more_frames = layer_draw_fadeout_frame(l) || need_more_frames; } - // 如果需要更多帧,确保安排下一帧 - if (need_more_frames) { - wlr_output_schedule_frame(m->wlr_output); - } - // 绘制客户端 wl_list_for_each(c, &clients, link) { need_more_frames = client_draw_frame(c) || need_more_frames; @@ -4324,6 +4398,11 @@ skip: wlr_scene_output_send_frame_done(m->scene_output, &now); wlr_output_state_finish(&pending); } + + // 如果需要更多帧,确保安排下一帧 + if (need_more_frames && allow_frame_scheduling) { + request_fresh_all_monitors(); + } } void requestdecorationmode(struct wl_listener *listener, void *data) { @@ -4381,12 +4460,32 @@ void exchange_two_client(Client *c1, Client *c2) { double master_inner_per = 0.0f; double master_mfact_per = 0.0f; double stack_inner_per = 0.0f; + float scroller_proportion = 0.0f; + float stack_proportion = 0.0f; if (c1 == NULL || c2 == NULL || (!exchange_cross_monitor && c1->mon != c2->mon)) { return; } + if (c1->mon != c2->mon && (c1->prev_in_stack || c2->prev_in_stack || + c1->next_in_stack || c2->next_in_stack)) + return; + + Client *c1head = get_scroll_stack_head(c1); + Client *c2head = get_scroll_stack_head(c2); + + // 交换布局参数 + if (c1head == c2head) { + scroller_proportion = c1->scroller_proportion; + stack_proportion = c1->stack_proportion; + + c1->scroller_proportion = c2->scroller_proportion; + c1->stack_proportion = c2->stack_proportion; + c2->scroller_proportion = scroller_proportion; + c2->stack_proportion = stack_proportion; + } + master_inner_per = c1->master_inner_per; master_mfact_per = c1->master_mfact_per; stack_inner_per = c1->stack_inner_per; @@ -4399,17 +4498,47 @@ void exchange_two_client(Client *c1, Client *c2) { c2->master_mfact_per = master_mfact_per; c2->stack_inner_per = stack_inner_per; + // 交换栈链表连接 + Client *tmp1_next_in_stack = c1->next_in_stack; + Client *tmp1_prev_in_stack = c1->prev_in_stack; + Client *tmp2_next_in_stack = c2->next_in_stack; + Client *tmp2_prev_in_stack = c2->prev_in_stack; + + // 处理相邻节点的情况 + if (c1->next_in_stack == c2) { + c1->next_in_stack = tmp2_next_in_stack; + c2->next_in_stack = c1; + c1->prev_in_stack = c2; + c2->prev_in_stack = tmp1_prev_in_stack; + if (tmp1_prev_in_stack) + tmp1_prev_in_stack->next_in_stack = c2; + if (tmp2_next_in_stack) + tmp2_next_in_stack->prev_in_stack = c1; + } else if (c2->next_in_stack == c1) { + c2->next_in_stack = tmp1_next_in_stack; + c1->next_in_stack = c2; + c2->prev_in_stack = c1; + c1->prev_in_stack = tmp2_prev_in_stack; + if (tmp2_prev_in_stack) + tmp2_prev_in_stack->next_in_stack = c1; + if (tmp1_next_in_stack) + tmp1_next_in_stack->prev_in_stack = c2; + } else if (is_scroller_layout(c1->mon) && + (c1->prev_in_stack || c2->prev_in_stack)) { + Client *c1head = get_scroll_stack_head(c1); + Client *c2head = get_scroll_stack_head(c2); + exchange_two_client(c1head, c2head); + focusclient(c1, 0); + return; + } + + // 交换全局链表连接 struct wl_list *tmp1_prev = c1->link.prev; struct wl_list *tmp2_prev = c2->link.prev; struct wl_list *tmp1_next = c1->link.next; struct wl_list *tmp2_next = c2->link.next; - // wl_list - // 是双向链表,其中clients是头部节点,它的下一个节点是第一个客户端的链表节点 - // 最后一个客户端的链表节点的下一个节点也指向clients,但clients本身不是客户端的链表节点 - // 客户端遍历从clients的下一个节点开始,到检测到客户端节点的下一个是clients结束 - - // 当c1和c2为相邻节点时 + // 处理相邻节点的情况 if (c1->link.next == &c2->link) { c1->link.next = c2->link.next; c1->link.prev = &c2->link; @@ -4436,17 +4565,17 @@ void exchange_two_client(Client *c1, Client *c2) { tmp2_next->prev = &c1->link; } + // 处理跨监视器交换 if (exchange_cross_monitor) { tmp_mon = c2->mon; tmp_tags = c2->tags; setmon(c2, c1->mon, c1->tags, false); setmon(c1, tmp_mon, tmp_tags, false); - arrange(c1->mon, false); - arrange(c2->mon, false); + arrange(c1->mon, false, false); + arrange(c2->mon, false, false); focusclient(c1, 0); } else { - arrange(c1->mon, false); - focusclient(c1, 0); + arrange(c1->mon, false, false); } } @@ -4470,7 +4599,7 @@ run(char *startup_cmd) { * startup command */ if (startup_cmd) { - int piperw[2]; + int32_t piperw[2]; if (pipe(piperw) < 0) die("startup: pipe:"); if ((child_pid = fork()) < 0) @@ -4546,11 +4675,11 @@ void setcursor(struct wl_listener *listener, void *data) { } void // 0.5 -setfloating(Client *c, int floating) { +setfloating(Client *c, int32_t floating) { Client *fc = NULL; - int hit; - struct wlr_box target_box, backup_box; + struct wlr_box target_box; + int32_t old_floating_state = c->isfloating; c->isfloating = floating; bool window_size_outofrange = false; @@ -4567,13 +4696,14 @@ setfloating(Client *c, int floating) { c->bw = c->isnoborder ? 0 : borderpx; } + exit_scroller_stack(c); + // 重新计算居中的坐标 - if (!client_is_x11(c) || (c->geom.x == 0 && c->geom.y == 0)) - target_box = setclient_coordinate_center(c, target_box, 0, 0); - backup_box = c->geom; - hit = applyrulesgeom(c); - target_box = hit == 1 ? c->geom : target_box; - c->geom = backup_box; + if (!client_is_x11(c) && !c->iscustompos) + target_box = + setclient_coordinate_center(c, c->mon, target_box, 0, 0); + else + target_box = c->geom; // restore to the memeroy geom if (c->float_geom.width > 0 && c->float_geom.height > 0) { @@ -4587,7 +4717,7 @@ setfloating(Client *c, int floating) { } if (window_size_outofrange) { c->float_geom = - setclient_coordinate_center(c, c->float_geom, 0, 0); + setclient_coordinate_center(c, c->mon, c->float_geom, 0, 0); } resize(c, c->float_geom, 0); } else { @@ -4619,14 +4749,14 @@ setfloating(Client *c, int floating) { layers[c->isfloating ? LyrTop : LyrTile]); } - if (!c->isfloating) { + if (!c->isfloating && old_floating_state) { set_size_per(c->mon, c); } if (!c->force_maximize) client_set_maximized(c, false); - arrange(c->mon, false); + arrange(c->mon, false, false); setborder_color(c); printstatus(); } @@ -4639,7 +4769,28 @@ void reset_maximizescreen_size(Client *c) { resize(c, c->geom, 0); } -void setmaximizescreen(Client *c, int maximizescreen) { +void exit_scroller_stack(Client *c) { + // If c is already in a stack, remove it. + if (c->prev_in_stack) { + c->prev_in_stack->next_in_stack = c->next_in_stack; + } + + if (!c->prev_in_stack && c->next_in_stack) { + c->next_in_stack->scroller_proportion = c->scroller_proportion; + wl_list_remove(&c->next_in_stack->link); + wl_list_insert(&c->link, &c->next_in_stack->link); + } + + if (c->next_in_stack) { + c->next_in_stack->prev_in_stack = c->prev_in_stack; + } + + c->prev_in_stack = NULL; + c->next_in_stack = NULL; + c->stack_proportion = 0.0f; +} + +void setmaximizescreen(Client *c, int32_t maximizescreen) { struct wlr_box maximizescreen_box; if (!c || !c->mon || !client_surface(c)->mapped || c->iskilling) return; @@ -4647,6 +4798,7 @@ void setmaximizescreen(Client *c, int maximizescreen) { if (c->mon->isoverview) return; + int32_t old_maximizescreen_state = c->ismaximizescreen; c->ismaximizescreen = maximizescreen; if (maximizescreen) { @@ -4654,6 +4806,8 @@ void setmaximizescreen(Client *c, int maximizescreen) { if (c->isfullscreen) setfullscreen(c, 0); + exit_scroller_stack(c); + if (c->isfloating) c->float_geom = c->geom; @@ -4674,7 +4828,7 @@ void setmaximizescreen(Client *c, int maximizescreen) { wlr_scene_node_reparent(&c->scene->node, layers[c->isfloating ? LyrTop : LyrTile]); - if (!c->ismaximizescreen) { + if (!c->ismaximizescreen && old_maximizescreen_state) { set_size_per(c->mon, c); } @@ -4684,20 +4838,21 @@ void setmaximizescreen(Client *c, int maximizescreen) { client_set_maximized(c, true); } - arrange(c->mon, false); + arrange(c->mon, false, false); } -void setfakefullscreen(Client *c, int fakefullscreen) { +void setfakefullscreen(Client *c, int32_t fakefullscreen) { c->isfakefullscreen = fakefullscreen; if (!c->mon) return; + if (c->isfullscreen) setfullscreen(c, 0); - else - client_set_fullscreen(c, fakefullscreen); + + client_set_fullscreen(c, fakefullscreen); } -void setfullscreen(Client *c, int fullscreen) // 用自定义全屏代理自带全屏 +void setfullscreen(Client *c, int32_t fullscreen) // 用自定义全屏代理自带全屏 { if (!c || !c->mon || !client_surface(c)->mapped || c->iskilling) @@ -4706,6 +4861,7 @@ void setfullscreen(Client *c, int fullscreen) // 用自定义全屏代理自带 if (c->mon->isoverview) return; + int32_t old_fullscreen_state = c->isfullscreen; c->isfullscreen = fullscreen; client_set_fullscreen(c, fullscreen); @@ -4714,9 +4870,13 @@ void setfullscreen(Client *c, int fullscreen) // 用自定义全屏代理自带 if (c->ismaximizescreen) setmaximizescreen(c, 0); + exit_scroller_stack(c); + if (c->isfloating) c->float_geom = c->geom; + c->isfakefullscreen = 0; + c->bw = 0; wlr_scene_node_raise_to_top(&c->scene->node); // 将视图提升到顶层 if (!is_scroller_layout(c->mon) || c->isfloating) @@ -4725,7 +4885,6 @@ void setfullscreen(Client *c, int fullscreen) // 用自定义全屏代理自带 } else { c->bw = c->isnoborder ? 0 : borderpx; c->isfullscreen = 0; - c->isfakefullscreen = 0; if (c->isfloating) setfloating(c, 1); } @@ -4740,19 +4899,19 @@ void setfullscreen(Client *c, int fullscreen) // 用自定义全屏代理自带 layers[fullscreen || c->isfloating ? LyrTop : LyrTile]); } - if (!c->isfullscreen) { + if (!c->isfullscreen && old_fullscreen_state) { set_size_per(c->mon, c); } - arrange(c->mon, false); + arrange(c->mon, false, false); } -void setgaps(int oh, int ov, int ih, int iv) { +void setgaps(int32_t oh, int32_t ov, int32_t ih, int32_t iv) { selmon->gappoh = MAX(oh, 0); selmon->gappov = MAX(ov, 0); selmon->gappih = MAX(ih, 0); selmon->gappiv = MAX(iv, 0); - arrange(selmon, false); + arrange(selmon, false, false); } void reset_keyboard_layout(void) { @@ -4770,7 +4929,7 @@ void reset_keyboard_layout(void) { // Get current layout xkb_layout_index_t current = xkb_state_serialize_layout( keyboard->xkb_state, XKB_STATE_LAYOUT_EFFECTIVE); - const int num_layouts = xkb_keymap_num_layouts(keyboard->keymap); + const int32_t num_layouts = xkb_keymap_num_layouts(keyboard->keymap); if (num_layouts < 1) { wlr_log(WLR_INFO, "No layouts available"); return; @@ -4794,7 +4953,7 @@ void reset_keyboard_layout(void) { } // 验证新keymap是否有布局 - const int new_num_layouts = xkb_keymap_num_layouts(new_keymap); + const int32_t new_num_layouts = xkb_keymap_num_layouts(new_keymap); if (new_num_layouts < 1) { wlr_log(WLR_ERROR, "New keymap has no layouts"); xkb_keymap_unref(new_keymap); @@ -4866,9 +5025,10 @@ void setmon(Client *c, Monitor *m, uint32_t newtags, bool focus) { /* Scene graph sends surface leave/enter events on move and resize */ if (oldmon) - arrange(oldmon, false); + arrange(oldmon, false, false); if (m) { /* Make sure window actually overlaps with the monitor */ + reset_foreign_tolevel(c); resize(c, c->geom, 0); c->tags = newtags ? newtags @@ -4880,21 +5040,6 @@ void setmon(Client *c, Monitor *m, uint32_t newtags, bool focus) { if (focus && !client_is_x11_popup(c)) { focusclient(focustop(selmon), 1); } - - if (m) { - - if (c->foreign_toplevel) { - remove_foreign_topleve(c); - } - - add_foreign_toplevel(c); - if (m->sel && m->sel->foreign_toplevel) - wlr_foreign_toplevel_handle_v1_set_activated( - m->sel->foreign_toplevel, false); - if (c->foreign_toplevel) - wlr_foreign_toplevel_handle_v1_set_activated(c->foreign_toplevel, - true); - } } void setpsel(struct wl_listener *listener, void *data) { @@ -4927,7 +5072,7 @@ void show_hide_client(Client *c) { tag_client(&(Arg){.ui = target}, c); } else { c->tags = c->oldtags; - arrange(c->mon, false); + arrange(c->mon, false, false); } c->isminimized = 0; wlr_foreign_toplevel_handle_v1_set_minimized(c->foreign_toplevel, false); @@ -4977,7 +5122,7 @@ void setup(void) { parse_config(); init_baked_points(); - int drm_fd, i, sig[] = {SIGCHLD, SIGINT, SIGTERM, SIGPIPE}; + int32_t drm_fd, i, sig[] = {SIGCHLD, SIGINT, SIGTERM, SIGPIPE}; struct sigaction sa = {.sa_flags = SA_RESTART, .sa_handler = handlesig}; sigemptyset(&sa.sa_mask); @@ -5287,6 +5432,7 @@ void tag_client(const Arg *arg, Client *target_client) { Client *fc = NULL; if (target_client && arg->ui & TAGMASK) { + exit_scroller_stack(target_client); target_client->tags = arg->ui & TAGMASK; target_client->istagswitching = 1; @@ -5401,7 +5547,7 @@ void handlecursoractivity(void) { last_cursor.hotspot_x, last_cursor.hotspot_y); } -int hidecursor(void *data) { +int32_t hidecursor(void *data) { wlr_cursor_unset_image(cursor); cursor_hidden = true; return 1; @@ -5416,6 +5562,7 @@ void unmaplayersurfacenotify(struct wl_listener *listener, void *data) { LayerSurface *l = wl_container_of(listener, l, unmap); l->mapped = 0; + l->being_unmapped = true; init_fadeout_layers(l); @@ -5427,6 +5574,9 @@ void unmaplayersurfacenotify(struct wl_listener *listener, void *data) { if (l->layer_surface->surface == seat->keyboard_state.focused_surface) focusclient(focustop(selmon), 1); motionnotify(0, NULL, 0, 0, 0, 0); + l->being_unmapped = false; + wlr_scene_node_destroy(&l->shadow->node); + l->shadow = NULL; } void unmapnotify(struct wl_listener *listener, void *data) { @@ -5434,15 +5584,22 @@ void unmapnotify(struct wl_listener *listener, void *data) { */ Client *c = wl_container_of(listener, c, unmap); Monitor *m = NULL; + Client *nextfocus = NULL; + Client *next_in_stack = c->next_in_stack; + Client *prev_in_stack = c->prev_in_stack; c->iskilling = 1; if (animations && !c->is_clip_to_hide && !c->isminimized && (!c->mon || VISIBLEON(c, c->mon))) init_fadeout_client(c); + // If the client is in a stack, remove it from the stack + if (c->swallowedby) { c->swallowedby->mon = c->mon; swallow(c->swallowedby, c); + } else { + exit_scroller_stack(c); } if (c == grabc) { @@ -5463,7 +5620,13 @@ void unmapnotify(struct wl_listener *listener, void *data) { } if (c->mon && c->mon == selmon) { - Client *nextfocus = focustop(selmon); + if (next_in_stack && !c->swallowedby) { + nextfocus = next_in_stack; + } else if (prev_in_stack && !c->swallowedby) { + nextfocus = prev_in_stack; + } else { + nextfocus = focustop(selmon); + } if (nextfocus) { focusclient(nextfocus, 0); @@ -5510,6 +5673,10 @@ void unmapnotify(struct wl_listener *listener, void *data) { c->swallowing = NULL; } + c->stack_proportion = 0.0f; + c->next_in_stack = NULL; + c->prev_in_stack = NULL; + wlr_scene_node_destroy(&c->scene->node); printstatus(); motionnotify(0, NULL, 0, 0, 0, 0); @@ -5528,7 +5695,7 @@ void updatemons(struct wl_listener *listener, void *data) { Client *c = NULL; struct wlr_output_configuration_head_v1 *config_head; Monitor *m = NULL; - int mon_pos_offsetx, mon_pos_offsety, oldx, oldy; + int32_t mon_pos_offsetx, mon_pos_offsety, oldx, oldy; /* First remove from the layout the disabled monitors */ wl_list_for_each(m, &mons, link) { @@ -5612,7 +5779,7 @@ void updatemons(struct wl_listener *listener, void *data) { /* Calculate the effective monitor geometry to use for clients */ arrangelayers(m); /* Don't move clients to the left output when plugging monitors */ - arrange(m, false); + arrange(m, false, false); /* make sure fullscreen clients have the right size */ if ((c = focustop(m)) && c->isfullscreen) resize(c, m->m, 0); @@ -5627,7 +5794,8 @@ void updatemons(struct wl_listener *listener, void *data) { if (selmon && selmon->wlr_output->enabled) { wl_list_for_each(c, &clients, link) { if (!c->mon && client_surface(c)->mapped) { - client_change_mon(c, selmon); + c->mon = selmon; + reset_foreign_tolevel(c); } } focusclient(focustop(selmon), 1); @@ -5733,8 +5901,7 @@ toggleseltags: if (changefocus) focusclient(focustop(m), 1); - reset_multi_tag_client_per(m); - arrange(m, want_animation); + arrange(m, want_animation, true); printstatus(); } @@ -5779,7 +5946,7 @@ void handle_keyboard_shortcuts_inhibit_new_inhibitor( Client *c = NULL; LayerSurface *l = NULL; - int type = toplevel_from_wlr_surface(inhibitor->surface, &c, &l); + int32_t type = toplevel_from_wlr_surface(inhibitor->surface, &c, &l); if (type < 0) return; @@ -5882,7 +6049,7 @@ void activatex11(struct wl_listener *listener, void *data) { } if (need_arrange) { - arrange(c->mon, false); + arrange(c->mon, false, false); } printstatus(); @@ -5911,7 +6078,7 @@ void configurex11(struct wl_listener *listener, void *data) { .height = event->height + c->bw * 2}, 0); } else { - arrange(c->mon, false); + arrange(c->mon, false, false); } } @@ -5986,21 +6153,26 @@ static void setgeometrynotify(struct wl_listener *listener, void *data) { } #endif -int main(int argc, char *argv[]) { +int32_t main(int32_t argc, char *argv[]) { char *startup_cmd = NULL; - int c; + int32_t c; - while ((c = getopt(argc, argv, "s:c:hdv")) != -1) { - if (c == 's') + while ((c = getopt(argc, argv, "s:c:hdvp")) != -1) { + if (c == 's') { startup_cmd = optarg; - else if (c == 'd') + } else if (c == 'd') { log_level = WLR_DEBUG; - else if (c == 'v') - die("mango " VERSION); - else if (c == 'c') + } else if (c == 'v') { + printf("mango " VERSION "\n"); + return EXIT_SUCCESS; + } else if (c == 'c') { cli_config_path = optarg; - else + } else if (c == 'p') { + parse_config(); + return EXIT_SUCCESS; + } else { goto usage; + } } if (optind < argc) goto usage; @@ -6014,7 +6186,14 @@ int main(int argc, char *argv[]) { run(startup_cmd); cleanup(); return EXIT_SUCCESS; - usage: - die("Usage: %s [-v] [-d] [-c config file] [-s startup command]", argv[0]); + printf("Usage: mango [OPTIONS]\n" + "\n" + "Options:\n" + " -v Show mango version\n" + " -d Enable debug log\n" + " -c Use custom configuration file\n" + " -s Execute startup command\n" + " -p Check configuration file error\n"); + return EXIT_SUCCESS; }