diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 3020485..b13e7d9 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -205,7 +205,6 @@ typedef struct { int32_t scroller_ignore_proportion_single; int32_t scroller_focus_center; int32_t scroller_prefer_center; - int32_t stacker_loop; int32_t edge_scroller_pointer_focus; int32_t focus_cross_monitor; int32_t exchange_cross_monitor; @@ -1081,26 +1080,11 @@ 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, "expand_client_left") == 0) { - func = expand_client_left; - if (arg_value && *arg_value) { - (*arg).f = atof(arg_value); - } else { - (*arg).f = 0.05; - } - } else if (strcmp(func_name, "collapse_client_right") == 0) { - func = collapse_client_right; - if (arg_value && *arg_value) { - (*arg).f = atof(arg_value); - } else { - (*arg).f = -0.05; - } - } else if (strcmp(func_name, "stack_with_left") == 0) { - func = stack_with_left; - } else if (strcmp(func_name, "unstack") == 0) { - func = unstack; - } else if (strcmp(func_name, "revert_size") == 0) { - func = revert_size; + } else if (strcmp(func_name, "scroller_stack") == 0) { + func = scroller_stack; + (*arg).i = parse_direction(arg_value); + } else if (strcmp(func_name, "scroller_unstack") == 0) { + func = scroller_unstack; } else { return NULL; } @@ -1242,8 +1226,6 @@ void parse_option(Config *config, char *key, char *value) { config->scroller_focus_center = atoi(value); } else if (strcmp(key, "scroller_prefer_center") == 0) { config->scroller_prefer_center = atoi(value); - } else if (strcmp(key, "stacker_loop") == 0) { - config->stacker_loop = atoi(value); } else if (strcmp(key, "edge_scroller_pointer_focus") == 0) { config->edge_scroller_pointer_focus = atoi(value); } else if (strcmp(key, "focus_cross_monitor") == 0) { diff --git a/src/config/preset.h b/src/config/preset.h index 2955eba..6f3cd89 100644 --- a/src/config/preset.h +++ b/src/config/preset.h @@ -65,7 +65,6 @@ float scroller_default_proportion_single = 1.0; int32_t scroller_ignore_proportion_single = 0; int32_t scroller_focus_center = 0; int32_t scroller_prefer_center = 0; -int32_t stacker_loop = 1; int32_t focus_cross_monitor = 0; int32_t focus_cross_tag = 0; int32_t exchange_cross_monitor = 0; diff --git a/src/dispatch/bind_declare.h b/src/dispatch/bind_declare.h index 1e6f3d3..0984e7d 100644 --- a/src/dispatch/bind_declare.h +++ b/src/dispatch/bind_declare.h @@ -69,8 +69,5 @@ 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 expand_client_left(const Arg *arg); -int32_t collapse_client_right(const Arg *arg); -int32_t stack_with_left(const Arg *arg); -int32_t unstack(const Arg *arg); -int32_t revert_size(const Arg *arg); +int32_t scroller_stack(const Arg *arg); +int32_t scroller_unstack(const Arg *arg); \ No newline at end of file diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 694d610..2c542be 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -107,7 +107,7 @@ int32_t exchange_client(const Arg *arg) { if ((c->isfullscreen || c->ismaximizescreen) && !is_scroller_layout(c->mon)) return 0; - exchange_two_client(c, direction_select(arg)); + exchange_two_client(c, direction_select(arg), false); return 0; } @@ -122,7 +122,7 @@ int32_t exchange_stack_client(const Arg *arg) { tc = get_next_stack_client(c, true); } if (tc) - exchange_two_client(c, tc); + exchange_two_client(c, tc, false); return 0; } @@ -427,7 +427,8 @@ int32_t resizewin(const Arg *arg) { if (ISTILED(c)) { Client *target_client = c; - if (is_scroller_layout(c->mon) && (c->prev_in_stack || c->next_in_stack)) { + if (is_scroller_layout(c->mon) && + (c->prev_in_stack || c->next_in_stack)) { while (target_client->prev_in_stack) { target_client = target_client->prev_in_stack; } @@ -1592,143 +1593,69 @@ int32_t toggle_monitor(const Arg *arg) { return 0; } -int32_t expand_client_left(const Arg *arg) { +int32_t scroller_stack(const Arg *arg) { Client *c = selmon->sel; - if (selmon && c && is_scroller_layout(selmon)) { - c->scroller_proportion += arg->f; - if (c->scroller_proportion > 1.0) - c->scroller_proportion = 1.0; - arrange(selmon, false, false); - } else { - setmfact(arg); + if (!c || c->isfloating || !is_scroller_layout(selmon)) + return 0; + + Client *left_c = find_client_by_direction(c, arg, false, true); + + if (!left_c) + return 0; + + if (c->isfullscreen) { + setfullscreen(c, 0); } + + if (c->ismaximizescreen) { + setmaximizescreen(c, 0); + } + + exit_scroller_stack(c); + + // Find the tail of left_c's stack + Client *stack_tail = left_c; + 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; + + arrange(selmon, false, false); return 0; } -int32_t collapse_client_right(const Arg *arg) { +int32_t scroller_unstack(const Arg *arg) { Client *c = selmon->sel; - if (selmon && c && is_scroller_layout(selmon)) { - c->scroller_proportion += arg->f; - if (c->scroller_proportion < 0.1) - c->scroller_proportion = 0.1; - arrange(selmon, false, false); - } else { - setmfact(arg); + if (!c || !c->prev_in_stack) { + // Not in a stack or is the head of a stack, do nothing. + return 0; } + + Client *scroller_stack_head = c; + while (scroller_stack_head->prev_in_stack) { + scroller_stack_head = scroller_stack_head->prev_in_stack; + } + + // Remove c from its current stack + if (c->prev_in_stack) { + c->prev_in_stack->next_in_stack = c->next_in_stack; + } + if (c->next_in_stack) { + c->next_in_stack->prev_in_stack = c->prev_in_stack; + } + + c->next_in_stack = NULL; + c->prev_in_stack = NULL; + + // Insert c after the stack it was in + wl_list_remove(&c->link); + wl_list_insert(&scroller_stack_head->link, &c->link); + + focusclient(c, 1); + arrange(selmon, false, false); return 0; -} - -int32_t stack_with_left(const Arg *arg) { - Client *c = selmon->sel; - if (!c || c->isfloating || !is_scroller_layout(selmon)) - return 0; - - if (!config.stacker_loop) { - Client *first_tiled = NULL; - Client *iter_c = NULL; - wl_list_for_each(iter_c, &clients, link) { - if (ISTILED(iter_c) && VISIBLEON(iter_c, selmon)) { - first_tiled = iter_c; - break; - } - } - if (c == first_tiled) { - return 0; // It's the first client and loop is disabled, so do nothing. - } - } - - Client *left_c = get_next_stack_client(c, true); - if (!left_c) - return 0; - - // 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->next_in_stack) { - c->next_in_stack->prev_in_stack = c->prev_in_stack; - } - // If c was a stack head, its next client becomes the new head. - if (c->next_in_stack) { - c->next_in_stack->prev_in_stack = NULL; - } - - - // Find the tail of left_c's stack - Client *stack_tail = left_c; - 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; - - arrange(selmon, false, false); - return 0; -} - -int32_t unstack(const Arg *arg) { - Client *c = selmon->sel; - if (!c || !c->prev_in_stack) { - // Not in a stack or is the head of a stack, do nothing. - return 0; - } - - Client *stack_head = c; - while(stack_head->prev_in_stack) { - stack_head = stack_head->prev_in_stack; - } - - // Remove c from its current stack - if (c->prev_in_stack) { - c->prev_in_stack->next_in_stack = c->next_in_stack; - } - if (c->next_in_stack) { - c->next_in_stack->prev_in_stack = c->prev_in_stack; - } - - c->next_in_stack = NULL; - c->prev_in_stack = NULL; - - // Insert c after the stack it was in - wl_list_remove(&c->link); - wl_list_insert(&stack_head->link, &c->link); - - focusclient(c, 1); - arrange(selmon, false, false); - return 0; -} - -int32_t revert_size(const Arg *arg) { - Client *c = selmon->sel; - if (!c) { - return 0; - } - - // Ensure the client is not floating and its size is managed by the layout - if (c->isfloating) { - setfloating(c, false); - } - c->iscustomsize = 0; // Let the layout manage its size - - // Explicitly remove the client from any stack it might be in - if (c->prev_in_stack) { - c->prev_in_stack->next_in_stack = c->next_in_stack; - } - 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; - - // Explicitly reset float_geom to ensure arrange recalculates geometry - c->float_geom = (struct wlr_box){0}; - - // The arrange function will now correctly size and position the window - // within the scroller layout, giving it full vertical size and preventing overlaps. - arrange(selmon, false, false); - - return 0; -} +} \ No newline at end of file diff --git a/src/fetch/client.h b/src/fetch/client.h index 0af1723..4cd0364 100644 --- a/src/fetch/client.h +++ b/src/fetch/client.h @@ -447,4 +447,12 @@ bool client_only_in_one_tag(Client *c) { } else { return false; } +} + +Client *get_scroll_stack_head(Client *c) { + Client *scroller_stack_head = c; + while (scroller_stack_head->prev_in_stack) { + scroller_stack_head = scroller_stack_head->prev_in_stack; + } + return scroller_stack_head; } \ No newline at end of file diff --git a/src/layout/horizontal.h b/src/layout/horizontal.h index 15f8f7a..c17484e 100644 --- a/src/layout/horizontal.h +++ b/src/layout/horizontal.h @@ -212,31 +212,32 @@ void horizontal_scroll_adjust_fullandmax(Client *c, target_geom->y = m->w.y + (m->w.height - target_geom->height) / 2; } -void arrange_stack(Client *stack_head, struct wlr_box geometry, int32_t gappiv) { - int32_t stack_size = 0; - Client *iter = stack_head; - while (iter) { - stack_size++; - iter = iter->next_in_stack; - } +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; + if (stack_size == 0) + return; - int32_t client_height = (geometry.height - (stack_size - 1) * gappiv) / stack_size; - int32_t current_y = geometry.y; + int32_t client_height = + (geometry.height - (stack_size - 1) * gappiv) / stack_size; + int32_t current_y = geometry.y; - iter = stack_head; - while (iter) { - struct wlr_box client_geom = { - .x = geometry.x, - .y = current_y, - .width = geometry.width, - .height = client_height - }; - resize(iter, client_geom, 0); - current_y += client_height + gappiv; - iter = iter->next_in_stack; - } + iter = scroller_stack_head; + while (iter) { + struct wlr_box client_geom = {.x = geometry.x, + .y = current_y, + .width = geometry.width, + .height = client_height}; + resize(iter, client_geom, 0); + current_y += client_height + gappiv; + iter = iter->next_in_stack; + } } // 滚动布局 @@ -252,7 +253,7 @@ void scroller(Monitor *m) { 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; + int32_t cur_gappiv = enablegaps ? m->gappiv : 0; cur_gappih = smartgaps && m->visible_scroll_tiling_clients == 1 ? 0 : cur_gappih; @@ -311,13 +312,12 @@ void scroller(Monitor *m) { root_client = center_tiled_select(m); } - // root_client might be in a stack, find the stack head - if (root_client) { - while(root_client->prev_in_stack) { - root_client = root_client->prev_in_stack; - } - } - + // root_client might be in a stack, find the stack head + if (root_client) { + while (root_client->prev_in_stack) { + root_client = root_client->prev_in_stack; + } + } if (!root_client) { free(tempClients); // 释放内存 diff --git a/src/mango.c b/src/mango.c index 5a06e3a..6da5fd2 100644 --- a/src/mango.c +++ b/src/mango.c @@ -627,7 +627,7 @@ static void motionrelative(struct wl_listener *listener, void *data); static void reset_foreign_tolevel(Client *c); static void remove_foreign_topleve(Client *c); static void add_foreign_topleve(Client *c); -static void exchange_two_client(Client *c1, Client *c2); +static void exchange_two_client(Client *c1, Client *c2, bool samemon); static void outputmgrapply(struct wl_listener *listener, void *data); static void outputmgrapplyortest(struct wlr_output_configuration_v1 *config, int32_t test); @@ -764,6 +764,9 @@ 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); #include "data/static_keymap.h" #include "dispatch/bind_declare.h" @@ -1840,7 +1843,7 @@ void place_drag_tile_client(Client *c) { closest_client->link.prev->next = &c->link; closest_client->link.prev = &c->link; } else if (closest_client) { - exchange_two_client(c, closest_client); + exchange_two_client(c, closest_client, false); } setfloating(c, 0); } @@ -3640,25 +3643,6 @@ void keypressmod(struct wl_listener *listener, void *data) { void pending_kill_client(Client *c) { if (!c || c->iskilling) return; - - // If the client is in a stack, remove it from the stack - if (c->prev_in_stack || c->next_in_stack) { - if (c->prev_in_stack) { - c->prev_in_stack->next_in_stack = c->next_in_stack; - } - if (c->next_in_stack) { - c->next_in_stack->prev_in_stack = c->prev_in_stack; - if (!c->prev_in_stack) { // c was the head of the stack - // The next client becomes the new head, so we need to ensure it's treated as such. - // This is implicitly handled by setting its prev_in_stack to NULL. - } - } - c->prev_in_stack = NULL; - c->next_in_stack = NULL; - arrange(c->mon, false, false); - } - - c->iskilling = 1; client_send_close(c); } @@ -3845,7 +3829,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); } @@ -4368,7 +4352,7 @@ void setborder_color(Client *c) { client_set_border_color(c, border_color); } -void exchange_two_client(Client *c1, Client *c2) { +void exchange_two_client(Client *c1, Client *c2, bool samemon) { Monitor *tmp_mon = NULL; uint32_t tmp_tags; @@ -4381,6 +4365,10 @@ void exchange_two_client(Client *c1, Client *c2) { return; } + if (samemon && c1->mon != c2->mon) + return; + + // 交换布局参数 master_inner_per = c1->master_inner_per; master_mfact_per = c1->master_mfact_per; stack_inner_per = c1->stack_inner_per; @@ -4393,17 +4381,46 @@ 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 (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, true); + 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; @@ -4430,6 +4447,7 @@ 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; @@ -4440,7 +4458,6 @@ void exchange_two_client(Client *c1, Client *c2) { focusclient(c1, 0); } else { arrange(c1->mon, false, false); - focusclient(c1, 0); } } @@ -4631,6 +4648,19 @@ void reset_maximizescreen_size(Client *c) { resize(c, c->geom, 0); } +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->next_in_stack) { + c->next_in_stack->prev_in_stack = c->prev_in_stack; + } + + c->prev_in_stack = NULL; + c->next_in_stack = NULL; +} + void setmaximizescreen(Client *c, int32_t maximizescreen) { struct wlr_box maximizescreen_box; if (!c || !c->mon || !client_surface(c)->mapped || c->iskilling) @@ -4646,6 +4676,8 @@ void setmaximizescreen(Client *c, int32_t maximizescreen) { if (c->isfullscreen) setfullscreen(c, 0); + exit_scroller_stack(c); + if (c->isfloating) c->float_geom = c->geom; @@ -4706,6 +4738,8 @@ void setfullscreen(Client *c, int32_t fullscreen) // 用自定义全屏代理自 if (c->ismaximizescreen) setmaximizescreen(c, 0); + exit_scroller_stack(c); + if (c->isfloating) c->float_geom = c->geom; @@ -5426,12 +5460,27 @@ 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->prev_in_stack || c->next_in_stack) { + if (c->prev_in_stack) { + c->prev_in_stack->next_in_stack = c->next_in_stack; + } + 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; + } + if (c->swallowedby) { c->swallowedby->mon = c->mon; swallow(c->swallowedby, c); @@ -5455,7 +5504,13 @@ void unmapnotify(struct wl_listener *listener, void *data) { } if (c->mon && c->mon == selmon) { - Client *nextfocus = focustop(selmon); + if (next_in_stack) { + nextfocus = next_in_stack; + } else if (prev_in_stack) { + nextfocus = prev_in_stack; + } else { + nextfocus = focustop(selmon); + } if (nextfocus) { focusclient(nextfocus, 0);