mirror of
https://github.com/DreamMaoMao/maomaowm.git
synced 2026-02-04 04:06:21 -05:00
feat: add scroller stack support
This commit is contained in:
parent
48737bb58c
commit
e0d69ece59
8 changed files with 466 additions and 52 deletions
|
|
@ -1080,6 +1080,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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,4 +68,5 @@ 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 toggle_monitor(const Arg *arg);
|
||||
int32_t scroller_stack(const Arg *arg);
|
||||
|
|
@ -550,12 +550,14 @@ int32_t 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);
|
||||
tc->scroller_proportion = arg->f;
|
||||
tc->geom.width = max_client_width * arg->f;
|
||||
arrange(selmon, false, false);
|
||||
}
|
||||
return 0;
|
||||
|
|
@ -971,11 +973,13 @@ int32_t switch_proportion_preset(const Arg *arg) {
|
|||
!scroller_ignore_proportion_single)
|
||||
return 0;
|
||||
|
||||
if (selmon->sel) {
|
||||
Client *tc = selmon->sel;
|
||||
|
||||
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;
|
||||
|
|
@ -993,9 +997,8 @@ int32_t 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);
|
||||
tc->scroller_proportion = target_proportion;
|
||||
tc->geom.width = max_client_width * target_proportion;
|
||||
arrange(selmon, false, false);
|
||||
}
|
||||
return 0;
|
||||
|
|
@ -1093,6 +1096,7 @@ int32_t tagsilent(const Arg *arg) {
|
|||
clear_fullscreen_flag(fc);
|
||||
}
|
||||
}
|
||||
exit_scroller_stack(target_client);
|
||||
focusclient(focustop(selmon), 1);
|
||||
arrange(target_client->mon, false, false);
|
||||
return 0;
|
||||
|
|
@ -1221,9 +1225,11 @@ int32_t 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;
|
||||
}
|
||||
|
|
@ -1585,3 +1591,85 @@ int32_t 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->isfloating || !is_scroller_layout(selmon))
|
||||
return 0;
|
||||
|
||||
if (c && (!client_only_in_one_tag(c) || c->isglobal || c->isunglobal))
|
||||
return 0;
|
||||
|
||||
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) {
|
||||
exit_scroller_stack(c);
|
||||
if (arg->i == LEFT || arg->i == UP) {
|
||||
wl_list_remove(&c->link);
|
||||
wl_list_insert(source_stack_head->link.prev, &c->link);
|
||||
} else {
|
||||
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;
|
||||
exit_scroller_stack(c);
|
||||
if (arg->i == LEFT || arg->i == UP) {
|
||||
wl_list_remove(&c->link);
|
||||
wl_list_insert(next_in_stack->link.prev, &c->link);
|
||||
} else {
|
||||
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;
|
||||
|
||||
arrange(selmon, false, false);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -378,6 +378,8 @@ 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)
|
||||
|
|
@ -389,7 +391,8 @@ void resize_tile_scroller(Client *grabc, bool isdrag, int32_t offsetx,
|
|||
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;
|
||||
|
|
@ -409,15 +412,26 @@ void resize_tile_scroller(Client *grabc, bool isdrag, int32_t offsetx,
|
|||
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;
|
||||
|
|
@ -452,18 +466,36 @@ void resize_tile_scroller(Client *grabc, bool isdrag, int32_t offsetx,
|
|||
delta_x = -fabsf(delta_x);
|
||||
}
|
||||
|
||||
if (isvertical) {
|
||||
if (!grabc->next_in_stack && grabc->prev_in_stack && !isdrag) {
|
||||
delta_x = delta_x * -1.0f;
|
||||
}
|
||||
} else {
|
||||
if (!grabc->next_in_stack && grabc->prev_in_stack && !isdrag) {
|
||||
delta_y = delta_y * -1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
// 直接设置新的比例,基于初始值 + 变化量
|
||||
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, false);
|
||||
|
|
@ -487,6 +519,9 @@ void resize_tile_client(Client *grabc, bool isdrag, int32_t offsetx,
|
|||
if (grabc->mon->isoverview)
|
||||
return;
|
||||
|
||||
int32_t animations_state_backup = animations;
|
||||
animations = 0;
|
||||
|
||||
const Layout *current_layout =
|
||||
grabc->mon->pertag->ltidxs[grabc->mon->pertag->curtag];
|
||||
if (current_layout->id == TILE || current_layout->id == DECK ||
|
||||
|
|
@ -505,6 +540,8 @@ void resize_tile_client(Client *grabc, bool isdrag, int32_t offsetx,
|
|||
} else if (current_layout->id == VERTICAL_SCROLLER) {
|
||||
resize_tile_scroller(grabc, isdrag, offsetx, offsety, time, true);
|
||||
}
|
||||
|
||||
animations = animations_state_backup;
|
||||
}
|
||||
|
||||
void reset_size_per_mon(Monitor *m, int32_t tile_cilent_num,
|
||||
|
|
@ -605,6 +642,10 @@ arrange(Monitor *m, bool want_animation, bool from_view) {
|
|||
|
||||
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);
|
||||
}
|
||||
|
|
@ -627,7 +668,7 @@ arrange(Monitor *m, bool want_animation, bool from_view) {
|
|||
m->visible_tiling_clients++;
|
||||
}
|
||||
|
||||
if (ISSCROLLTILED(c)) {
|
||||
if (ISSCROLLTILED(c) && !c->prev_in_stack) {
|
||||
m->visible_scroll_tiling_clients++;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -212,6 +212,66 @@ 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) {
|
||||
int32_t i, n, j;
|
||||
|
|
@ -225,6 +285,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;
|
||||
|
||||
cur_gappih =
|
||||
smartgaps && m->visible_scroll_tiling_clients == 1 ? 0 : cur_gappih;
|
||||
|
|
@ -251,7 +312,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++;
|
||||
}
|
||||
|
|
@ -269,7 +330,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;
|
||||
}
|
||||
|
|
@ -283,6 +345,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;
|
||||
|
|
@ -317,10 +384,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 ||
|
||||
|
|
@ -338,10 +409,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++) {
|
||||
|
|
@ -351,7 +426,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++) {
|
||||
|
|
@ -361,7 +436,7 @@ 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); // 最后释放内存
|
||||
|
|
@ -853,4 +928,4 @@ void tgmix(Monitor *m) {
|
|||
grid(m);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -199,6 +199,66 @@ 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) {
|
||||
int32_t i, n, j;
|
||||
|
|
@ -212,6 +272,7 @@ void vertical_scroller(Monitor *m) {
|
|||
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;
|
||||
|
|
@ -235,7 +296,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++;
|
||||
}
|
||||
|
|
@ -253,7 +314,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;
|
||||
}
|
||||
|
|
@ -267,6 +329,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;
|
||||
|
|
@ -302,10 +369,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 ||
|
||||
|
|
@ -323,10 +396,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++) {
|
||||
|
|
@ -336,7 +415,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++) {
|
||||
|
|
@ -346,7 +425,7 @@ 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);
|
||||
|
|
|
|||
143
src/mango.c
143
src/mango.c
|
|
@ -21,6 +21,7 @@
|
|||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <wayland-server-core.h>
|
||||
#include <wayland-util.h>
|
||||
#include <wlr/backend.h>
|
||||
#include <wlr/backend/headless.h>
|
||||
#include <wlr/backend/libinput.h>
|
||||
|
|
@ -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)
|
||||
|
|
@ -375,6 +380,8 @@ struct Client {
|
|||
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;
|
||||
|
|
@ -407,6 +414,8 @@ struct Client {
|
|||
int32_t allow_shortcuts_inhibit;
|
||||
float scroller_proportion_single;
|
||||
bool isfocusing;
|
||||
struct Client *next_in_stack;
|
||||
struct Client *prev_in_stack;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -762,6 +771,11 @@ 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);
|
||||
|
||||
#include "data/static_keymap.h"
|
||||
#include "dispatch/bind_declare.h"
|
||||
|
|
@ -1053,6 +1067,13 @@ void swallow(Client *c, Client *w) {
|
|||
c->geom = w->geom;
|
||||
c->float_geom = w->float_geom;
|
||||
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);
|
||||
|
||||
|
|
@ -3636,7 +3657,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);
|
||||
}
|
||||
|
||||
|
|
@ -3744,6 +3766,9 @@ 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;
|
||||
}
|
||||
|
||||
void // old fix to 0.5
|
||||
|
|
@ -3823,7 +3848,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);
|
||||
}
|
||||
|
|
@ -4175,8 +4200,8 @@ void pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy,
|
|||
uint32_t time) {
|
||||
struct timespec now;
|
||||
|
||||
if (sloppyfocus && c && time && c->scene->node.enabled &&
|
||||
!c->animation.tagining &&
|
||||
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);
|
||||
|
|
@ -4353,12 +4378,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;
|
||||
|
|
@ -4371,17 +4416,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);
|
||||
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;
|
||||
|
|
@ -4408,6 +4482,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;
|
||||
|
|
@ -4418,7 +4493,6 @@ void exchange_two_client(Client *c1, Client *c2) {
|
|||
focusclient(c1, 0);
|
||||
} else {
|
||||
arrange(c1->mon, false, false);
|
||||
focusclient(c1, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4538,6 +4612,8 @@ setfloating(Client *c, int32_t floating) {
|
|||
c->bw = c->isnoborder ? 0 : borderpx;
|
||||
}
|
||||
|
||||
exit_scroller_stack(c);
|
||||
|
||||
// 重新计算居中的坐标
|
||||
if (!client_is_x11(c) && !c->iscustompos)
|
||||
target_box =
|
||||
|
|
@ -4609,6 +4685,27 @@ 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->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)
|
||||
|
|
@ -4624,6 +4721,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;
|
||||
|
||||
|
|
@ -4685,6 +4784,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;
|
||||
|
||||
|
|
@ -5259,6 +5360,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;
|
||||
|
||||
|
|
@ -5406,15 +5508,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) {
|
||||
|
|
@ -5435,7 +5544,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);
|
||||
|
|
@ -5482,6 +5597,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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue