diff --git a/meson.build b/meson.build index cde6c600..82670f0a 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('mango', ['c'], - version : '0.14.2', + version : '0.14.3', ) subdir('protocols') diff --git a/src/action/client.h b/src/action/client.h index 1b3c9335..11602e70 100644 --- a/src/action/client.h +++ b/src/action/client.h @@ -48,6 +48,9 @@ static void finish_exchange_arrange_and_focus(Client *c1, Client *c2, } wl_list_remove(&c2->flink); wl_list_insert(&c1->flink, &c2->flink); + + if (config.warpcursor) + warp_cursor(c1); } void client_tile_resize(Client *c, struct wlr_box geo, int32_t interact) { diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 1e39386c..de51c0a0 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -131,9 +131,14 @@ int32_t exchange_stack_client(const Arg *arg) { } int32_t focusdir(const Arg *arg) { + + if (!selmon) + return 0; + Client *c = NULL; c = direction_select(arg); - c = get_focused_stack_client(c, arg->tc); + if (!selmon->isoverview) + c = get_focused_stack_client(c, arg->tc); if (c) { focusclient(c, 1); if (config.warpcursor) @@ -1919,7 +1924,7 @@ int32_t scroller_stack(const Arg *arg) { if (!c || !c->mon || c->isfloating || !is_scroller_layout(selmon)) return 0; - Client *target_client = find_client_by_direction(c, arg, false, true); + Client *target_client = find_client_by_direction(c, arg, false); return scroller_apply_stack(c, target_client, arg->i); } diff --git a/src/fetch/client.h b/src/fetch/client.h index 77b2d865..fb50c798 100644 --- a/src/fetch/client.h +++ b/src/fetch/client.h @@ -163,291 +163,130 @@ Client *center_tiled_select(Monitor *m) { } return target_c; } -Client *find_client_by_direction(Client *tc, const Arg *arg, bool findfloating, - bool ignore_align) { + +Client *find_client_by_direction(Client *tc, const Arg *arg, + bool findfloating) { Client *c = NULL; - Client **tempClients = NULL; // 初始化为 NULL - int32_t last = -1; - - // 第一次遍历,计算客户端数量 - wl_list_for_each(c, &clients, link) { - if (c && (findfloating || !c->isfloating) && !c->isunglobal && - (config.focus_cross_monitor || c->mon == tc->mon) && - (c->tags & c->mon->tagset[c->mon->seltags])) { - last++; - } - } - - if (last < 0) { - return NULL; // 没有符合条件的客户端 - } - - // 动态分配内存 - tempClients = malloc((last + 1) * sizeof(Client *)); - if (!tempClients) { - // 处理内存分配失败的情况 - return NULL; - } - - // 第二次遍历,填充 tempClients - last = -1; - wl_list_for_each(c, &clients, link) { - if (c && (findfloating || !c->isfloating) && !c->isunglobal && - (config.focus_cross_monitor || c->mon == tc->mon) && - (c->tags & c->mon->tagset[c->mon->seltags])) { - last++; - tempClients[last] = c; - } - } - - 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; + int64_t distance = LLONG_MAX; + int64_t same_monitor_distance = LLONG_MAX; - switch (arg->i) { - case UP: - if (!ignore_align) { - 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) { - 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]; - } + int32_t tc_l = tc->geom.x; + int32_t tc_r = tc->geom.x + tc->geom.width; + int32_t tc_t = tc->geom.y; + int32_t tc_b = tc->geom.y + tc->geom.height; + int32_t tc_cx = tc_l + tc->geom.width / 2; + int32_t tc_cy = tc_t + tc->geom.height / 2; + + for (int32_t step = 0; step < 2; step++) { + if (step == 1 && tempFocusClients) + break; + + wl_list_for_each(c, &clients, link) { + if (!c || c == tc) + continue; + if (!findfloating && c->isfloating) + continue; + if (c->isunglobal) + continue; + if (!config.focus_cross_monitor && c->mon != tc->mon) + continue; + if (!(c->tags & c->mon->tagset[c->mon->seltags])) + continue; + + if (step == 0 && ((!tc->mon->isoverview && + !client_is_in_same_stack(tc, c, NULL)) || + c->mon != tc->mon)) + continue; + + int32_t c_l = c->geom.x; + int32_t c_r = c->geom.x + c->geom.width; + int32_t c_t = c->geom.y; + int32_t c_b = c->geom.y + c->geom.height; + int32_t c_cx = c_l + c->geom.width / 2; + int32_t c_cy = c_t + c->geom.height / 2; + + int64_t main_dist = 0; + int64_t orth_dist = 0; + bool match_dir = false; + + switch (arg->i) { + case LEFT: + if (c_cx < tc_cx || (c_cx == tc_cx && c_l < tc_l)) { + match_dir = true; + main_dist = tc_l - c_r; + orth_dist = (c_b < tc_t) + ? (tc_t - c_b) + : ((c_t > tc_b) ? (c_t - tc_b) : 0); } + break; + case RIGHT: + if (c_cx > tc_cx || (c_cx == tc_cx && c_l > tc_l)) { + match_dir = true; + main_dist = c_l - tc_r; + orth_dist = (c_b < tc_t) + ? (tc_t - c_b) + : ((c_t > tc_b) ? (c_t - tc_b) : 0); + } + break; + case UP: + if (c_cy < tc_cy || (c_cy == tc_cy && c_t < tc_t)) { + match_dir = true; + main_dist = tc_t - c_b; + orth_dist = (c_r < tc_l) + ? (tc_l - c_r) + : ((c_l > tc_r) ? (c_l - tc_r) : 0); + } + break; + case DOWN: + if (c_cy > tc_cy || (c_cy == tc_cy && c_t > tc_t)) { + match_dir = true; + main_dist = c_t - tc_b; + orth_dist = (c_r < tc_l) + ? (tc_l - c_r) + : ((c_l > tc_r) ? (c_l - tc_r) : 0); + } + break; + default: + continue; + } + + if (!match_dir) + continue; + + int64_t penalty = 0; + if (main_dist < 0) { + penalty = 10000000000LL; // 主方向重叠(反方向)的极大惩罚 + main_dist = -main_dist; + } + + // 正交方向无重叠惩罚,优先选择在同一行/列的窗口 + int64_t no_overlap_penalty = 0; + if (orth_dist > 0) { + // LEFT/RIGHT 时 orth_dist 是垂直间距,>0 表示垂直无重叠 + // UP/DOWN 时 orth_dist 是水平间距,>0 表示水平无重叠 + no_overlap_penalty = 10000000LL; + } + + int64_t tmp_distance = penalty + no_overlap_penalty + + (main_dist * main_dist) + + (orth_dist * orth_dist); + + if (tmp_distance < distance) { + distance = tmp_distance; + tempFocusClients = c; + } + if (c->mon == tc->mon && tmp_distance < same_monitor_distance) { + same_monitor_distance = tmp_distance; + tempSameMonitorFocusClients = c; } } - if (!tempFocusClients) { - 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) { - 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]; - } - } - } - } - break; - case DOWN: - if (!ignore_align) { - 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) { - 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 (!tempFocusClients) { - 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) { - 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]; - } - } - } - } - break; - case LEFT: - if (!ignore_align) { - 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) { - 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 (!tempFocusClients) { - 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) { - 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]; - } - } - } - } - break; - case RIGHT: - if (!ignore_align) { - 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) { - 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 (!tempFocusClients) { - 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) { - 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]; - } - } - } - } - break; } - free(tempClients); // 释放内存 - if (tempSameMonitorFocusClients) { + if (tempSameMonitorFocusClients) return tempSameMonitorFocusClients; - } else { - return tempFocusClients; - } + return tempFocusClients; } Client *direction_select(const Arg *arg) { @@ -462,10 +301,7 @@ Client *direction_select(const Arg *arg) { return NULL; } - return find_client_by_direction( - tc, arg, true, - (is_scroller_layout(selmon) || is_centertile_layout(selmon)) && - !selmon->isoverview); + return find_client_by_direction(tc, arg, true); } /* We probably should change the name of this, it sounds like diff --git a/src/layout/arrange.h b/src/layout/arrange.h index 0a39b248..23b9d080 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -26,8 +26,15 @@ void set_size_per(Monitor *m, Client *c) { c->stack_inner_per = 1.0f; } - c->scroller_proportion = - m->pertag->scroller_default_proportion[m->pertag->curtag]; + if (!c->iscustom_scroller_proportion) { + c->scroller_proportion = + m->pertag->scroller_default_proportion[m->pertag->curtag]; + } + + if (!c->iscustom_scroller_proportion_single) { + c->scroller_proportion_single = + m->pertag->scroller_default_proportion_single[m->pertag->curtag]; + } } void resize_tile_master_horizontal(Client *grabc, bool isdrag, int32_t offsetx, diff --git a/src/mango.c b/src/mango.c index 0e274caf..295c6465 100644 --- a/src/mango.c +++ b/src/mango.c @@ -383,6 +383,8 @@ struct Client { int32_t is_in_scratchpad; int32_t iscustomsize; int32_t iscustompos; + int32_t iscustom_scroller_proportion; + int32_t iscustom_scroller_proportion_single; int32_t is_scratchpad_show; int32_t isglobal; int32_t isnoborder; @@ -866,7 +868,7 @@ 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); + bool findfloating); static void exit_scroller_stack(Client *c); static Client *scroll_get_stack_head_client(Client *c); static bool client_only_in_one_tag(Client *c); @@ -1677,6 +1679,14 @@ void applyrules(Client *c) { c->isfloating = 1; } + if (r->scroller_proportion > 0.0f) { + c->iscustom_scroller_proportion = 1; + } + + if (r->scroller_proportion_single > 0.0f) { + c->iscustom_scroller_proportion_single = 1; + } + // set geometry of floating client if (r->width > 1) @@ -4333,6 +4343,8 @@ void init_client_properties(Client *c) { c->ignore_minimize = 1; c->iscustomsize = 0; c->iscustompos = 0; + c->iscustom_scroller_proportion = 0; + c->iscustom_scroller_proportion_single = 0; c->master_mfact_per = 0.0f; c->master_inner_per = 0.0f; c->stack_inner_per = 0.0f;