feat: support resize tile window

This commit is contained in:
DreamMaoMao 2025-10-09 13:09:40 +08:00
parent aec8c29210
commit ca48f95997
13 changed files with 1060 additions and 677 deletions

View file

@ -16,7 +16,7 @@ This project's development is based on [dwl](https://codeberg.org/dwl/dwl/).
- Base tags not workspaces (supports separate window layouts for each tag) - Base tags not workspaces (supports separate window layouts for each tag)
- Smooth and customizable complete animations (window open/move/close, tag enter/leave,layer open/close/move) - Smooth and customizable complete animations (window open/move/close, tag enter/leave,layer open/close/move)
- Excellent input method support (text input v2/v3) - Excellent input method support (text input v2/v3)
- Flexible window layouts with easy switching (scroller, master, monocle, spiral, etc.) - Flexible window layouts with easy switching (scroller, master-stack, monocle,center-master, etc.)
- Rich window states (swallow, minimize, maximize, unglobal, global, fakefullscreen, overlay, etc.) - Rich window states (swallow, minimize, maximize, unglobal, global, fakefullscreen, overlay, etc.)
- Simple yet powerful external configuration(support shortcuts hot-reload) - Simple yet powerful external configuration(support shortcuts hot-reload)
- Sway-like scratchpad and named scratchpad - Sway-like scratchpad and named scratchpad
@ -24,10 +24,6 @@ This project's development is based on [dwl](https://codeberg.org/dwl/dwl/).
- Hycov-like overview - Hycov-like overview
- Window effects from scenefx (blur, shadow, corner radius, opacity) - Window effects from scenefx (blur, shadow, corner radius, opacity)
3. **Some disadvantages**
- Since it uses the fully automatic layout like dwm style, it does not allow you to manually adjust the window size when the window is in tiled state. It only allows you to use dispatch like `setmfact` or `increase_proportion` bind to adjust the tiled window ratio.
Master-Stack Layout Master-Stack Layout
https://github.com/user-attachments/assets/a9d4776e-b50b-48fb-94ce-651d8a749b8a https://github.com/user-attachments/assets/a9d4776e-b50b-48fb-94ce-651d8a749b8a
@ -43,23 +39,14 @@ https://github.com/user-attachments/assets/014c893f-115c-4ae9-8342-f9ae3e9a0df0
# Supported layouts # Supported layouts
## Horizontal Layouts
- tile - tile
- scroller - scroller
- monocle - monocle
- grid - grid
- dwindle
- spiral
- deck - deck
- center_tile - center_tile
## Vertical Layouts
- vertical_tile - vertical_tile
- vertical_scroller - vertical_scroller
- vertical_monocle
- vertical_grid
- vertical_dwindle
- vertical_spiral
# Installation # Installation

View file

@ -56,7 +56,7 @@ edge_scroller_pointer_focus=1
scroller_default_proportion_single=1.0 scroller_default_proportion_single=1.0
scroller_proportion_preset=0.5,0.8,1.0 scroller_proportion_preset=0.5,0.8,1.0
# Master-Stack Layout Setting (tile,spiral,dwindle) # Master-Stack Layout Setting
new_is_master=1 new_is_master=1
default_mfact=0.55 default_mfact=0.55
default_nmaster=1 default_nmaster=1
@ -123,8 +123,7 @@ globalcolor=0xb153a7ff
overlaycolor=0x14a57cff overlaycolor=0x14a57cff
# layout support: # layout support:
# horizontal:tile,scroller,grid,monocle,spiral,dwindle,center_tile # tile,scroller,grid,deck,monocle,center_tile,vertical_tile,vertical_scroller
# vertical:vertical_tile,vertical_scroller,vertical_grid,vertical_spiral,vertical_dwindle
tagrule=id:1,layout_name:tile tagrule=id:1,layout_name:tile
tagrule=id:2,layout_name:tile tagrule=id:2,layout_name:tile
tagrule=id:3,layout_name:tile tagrule=id:3,layout_name:tile
@ -224,17 +223,6 @@ bind=ALT+SHIFT,X,incgaps,1
bind=ALT+SHIFT,Z,incgaps,-1 bind=ALT+SHIFT,Z,incgaps,-1
bind=ALT+SHIFT,R,togglegaps bind=ALT+SHIFT,R,togglegaps
# adjust tile window size
# change master fact for tile,spiral,deck,dwindle
bind=ALT+SUPER,h,setmfact,-0.05
bind=ALT+SUPER,l,setmfact,+0.05
# change sub master fact for dwindle,spiral
bind=ALT+SUPER,k,setsmfact,-0.05
bind=ALT+SUPER,j,setsmfact,+0.05
# change scroller proportion
bind=ctrl+super,j,increase_proportion,0.1
bind=ctrl+super,k,increase_proportion,-0.1
# movewin # movewin
bind=CTRL+SHIFT,Up,movewin,+0,-50 bind=CTRL+SHIFT,Up,movewin,+0,-50
bind=CTRL+SHIFT,Down,movewin,+0,+50 bind=CTRL+SHIFT,Down,movewin,+0,+50

View file

@ -31,10 +31,8 @@ enum corner_location set_client_corner_location(Client *c) {
bool is_horizontal_stack_layout(Monitor *m) { bool is_horizontal_stack_layout(Monitor *m) {
if (m->pertag->curtag && if (m->pertag->curtag &&
(strcmp(m->pertag->ltidxs[m->pertag->curtag]->name, "tile") == 0 || (m->pertag->ltidxs[m->pertag->curtag]->id == TILE ||
strcmp(m->pertag->ltidxs[m->pertag->curtag]->name, "spiral") == 0 || m->pertag->ltidxs[m->pertag->curtag]->id == DECK))
strcmp(m->pertag->ltidxs[m->pertag->curtag]->name, "dwindle") == 0 ||
strcmp(m->pertag->ltidxs[m->pertag->curtag]->name, "deck") == 0))
return true; return true;
return false; return false;
@ -897,6 +895,11 @@ void client_set_pending_state(Client *c) {
c->istagswitching = 0; c->istagswitching = 0;
} }
if (start_drag_window) {
c->animation.should_animate = false;
c->animation.duration = 0;
}
// 开始动画 // 开始动画
client_commit(c); client_commit(c);
c->dirty = true; c->dirty = true;

View file

@ -202,10 +202,9 @@ typedef struct {
unsigned int new_is_master; unsigned int new_is_master;
float default_mfact; float default_mfact;
float default_smfact;
unsigned int default_nmaster; unsigned int default_nmaster;
int center_master_overspread; int center_master_overspread;
int center_when_single_slave; int center_when_single_stack;
unsigned int hotarea_size; unsigned int hotarea_size;
unsigned int enable_hotarea; unsigned int enable_hotarea;
@ -727,9 +726,6 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value,
} else if (strcmp(func_name, "setmfact") == 0) { } else if (strcmp(func_name, "setmfact") == 0) {
func = setmfact; func = setmfact;
(*arg).f = atof(arg_value); (*arg).f = atof(arg_value);
} else if (strcmp(func_name, "setsmfact") == 0) {
func = setsmfact;
(*arg).f = atof(arg_value);
} else if (strcmp(func_name, "zoom") == 0) { } else if (strcmp(func_name, "zoom") == 0) {
func = zoom; func = zoom;
} else if (strcmp(func_name, "exchange_client") == 0) { } else if (strcmp(func_name, "exchange_client") == 0) {
@ -1262,14 +1258,12 @@ void parse_option(Config *config, char *key, char *value) {
config->new_is_master = atoi(value); config->new_is_master = atoi(value);
} else if (strcmp(key, "default_mfact") == 0) { } else if (strcmp(key, "default_mfact") == 0) {
config->default_mfact = atof(value); config->default_mfact = atof(value);
} else if (strcmp(key, "default_smfact") == 0) {
config->default_smfact = atof(value);
} else if (strcmp(key, "default_nmaster") == 0) { } else if (strcmp(key, "default_nmaster") == 0) {
config->default_nmaster = atoi(value); config->default_nmaster = atoi(value);
} else if (strcmp(key, "center_master_overspread") == 0) { } else if (strcmp(key, "center_master_overspread") == 0) {
config->center_master_overspread = atoi(value); config->center_master_overspread = atoi(value);
} else if (strcmp(key, "center_when_single_slave") == 0) { } else if (strcmp(key, "center_when_single_stack") == 0) {
config->center_when_single_slave = atoi(value); config->center_when_single_stack = atoi(value);
} else if (strcmp(key, "hotarea_size") == 0) { } else if (strcmp(key, "hotarea_size") == 0) {
config->hotarea_size = atoi(value); config->hotarea_size = atoi(value);
} else if (strcmp(key, "enable_hotarea") == 0) { } else if (strcmp(key, "enable_hotarea") == 0) {
@ -2478,10 +2472,9 @@ void override_config(void) {
// 主从布局设置 // 主从布局设置
default_mfact = CLAMP_FLOAT(config.default_mfact, 0.1f, 0.9f); default_mfact = CLAMP_FLOAT(config.default_mfact, 0.1f, 0.9f);
default_smfact = CLAMP_FLOAT(config.default_smfact, 0.1f, 0.9f);
default_nmaster = CLAMP_INT(config.default_nmaster, 1, 1000); default_nmaster = CLAMP_INT(config.default_nmaster, 1, 1000);
center_master_overspread = CLAMP_INT(config.center_master_overspread, 0, 1); center_master_overspread = CLAMP_INT(config.center_master_overspread, 0, 1);
center_when_single_slave = CLAMP_INT(config.center_when_single_slave, 0, 1); center_when_single_stack = CLAMP_INT(config.center_when_single_stack, 0, 1);
new_is_master = CLAMP_INT(config.new_is_master, 0, 1); new_is_master = CLAMP_INT(config.new_is_master, 0, 1);
// 概述模式设置 // 概述模式设置
@ -2624,15 +2617,14 @@ void set_value_default() {
config.axis_bind_apply_timeout = config.axis_bind_apply_timeout =
axis_bind_apply_timeout; // 滚轮绑定动作的触发的时间间隔 axis_bind_apply_timeout; // 滚轮绑定动作的触发的时间间隔
config.focus_on_activate = config.focus_on_activate =
focus_on_activate; // 收到窗口激活请求是否自动跳转聚焦 focus_on_activate; // 收到窗口激活请求是否自动跳转聚焦
config.new_is_master = new_is_master; // 新窗口是否插在头部 config.new_is_master = new_is_master; // 新窗口是否插在头部
config.default_mfact = default_mfact; // master 窗口比例 config.default_mfact = default_mfact; // master 窗口比例
config.default_smfact = default_smfact; // 第一个stack比例
config.default_nmaster = default_nmaster; // 默认master数量 config.default_nmaster = default_nmaster; // 默认master数量
config.center_master_overspread = config.center_master_overspread =
center_master_overspread; // 中心master时是否铺满 center_master_overspread; // 中心master时是否铺满
config.center_when_single_slave = config.center_when_single_stack =
center_when_single_slave; // 单个slave时是否居中 center_when_single_stack; // 单个stack时是否居中
config.numlockon = numlockon; // 是否打开右边小键盘 config.numlockon = numlockon; // 是否打开右边小键盘
@ -2983,7 +2975,6 @@ void reapply_master(void) {
} }
m->pertag->nmasters[i] = default_nmaster; m->pertag->nmasters[i] = default_nmaster;
m->pertag->mfacts[i] = default_mfact; m->pertag->mfacts[i] = default_mfact;
m->pertag->smfacts[i] = default_smfact;
m->gappih = gappih; m->gappih = gappih;
m->gappiv = gappiv; m->gappiv = gappiv;
m->gappoh = gappoh; m->gappoh = gappoh;

View file

@ -35,10 +35,9 @@ unsigned int axis_bind_apply_timeout = 100; // 滚轮绑定动作的触发的时
unsigned int focus_on_activate = 1; // 收到窗口激活请求是否自动跳转聚焦 unsigned int focus_on_activate = 1; // 收到窗口激活请求是否自动跳转聚焦
unsigned int new_is_master = 1; // 新窗口是否插在头部 unsigned int new_is_master = 1; // 新窗口是否插在头部
double default_mfact = 0.55f; // master 窗口比例 double default_mfact = 0.55f; // master 窗口比例
double default_smfact = 0.5f; // 第一个stack窗口比例
unsigned int default_nmaster = 1; // 默认master数量 unsigned int default_nmaster = 1; // 默认master数量
int center_master_overspread = 0; // 中心master时是否铺满 int center_master_overspread = 0; // 中心master时是否铺满
int center_when_single_slave = 1; // 单个slave时是否居中 int center_when_single_stack = 1; // 单个stack时是否居中
/* logging */ /* logging */
int log_level = WLR_ERROR; int log_level = WLR_ERROR;
unsigned int numlockon = 1; // 是否打开右边小键盘 unsigned int numlockon = 1; // 是否打开右边小键盘

View file

@ -27,7 +27,6 @@ void setlayout(const Arg *arg);
void switch_layout(const Arg *arg); void switch_layout(const Arg *arg);
void switch_keyboard_layout(const Arg *arg); void switch_keyboard_layout(const Arg *arg);
void setmfact(const Arg *arg); void setmfact(const Arg *arg);
void setsmfact(const Arg *arg);
void quit(const Arg *arg); void quit(const Arg *arg);
void moveresize(const Arg *arg); void moveresize(const Arg *arg);
void exchange_client(const Arg *arg); void exchange_client(const Arg *arg);

View file

@ -263,20 +263,6 @@ void increase_proportion(const Arg *arg) {
} }
} }
void setsmfact(const Arg *arg) {
float f;
if (!arg || !selmon ||
!selmon->pertag->ltidxs[selmon->pertag->curtag]->arrange)
return;
f = arg->f < 1.0 ? arg->f + selmon->pertag->smfacts[selmon->pertag->curtag]
: arg->f - 1.0;
if (f < 0.1 || f > 0.9)
return;
// selmon->mfact = f;
selmon->pertag->smfacts[selmon->pertag->curtag] = f;
arrange(selmon, false);
}
/* arg > 1.0 will set mfact absolutely */ /* arg > 1.0 will set mfact absolutely */
void // 17 void // 17
setmfact(const Arg *arg) { setmfact(const Arg *arg) {
@ -309,15 +295,15 @@ moveresize(const Arg *arg) {
xytonode(cursor->x, cursor->y, NULL, &grabc, NULL, NULL, NULL); xytonode(cursor->x, cursor->y, NULL, &grabc, NULL, NULL, NULL);
if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen) if (!grabc || client_is_unmanaged(grabc) || grabc->isfullscreen)
return; return;
/* Float the window and tell motionnotify to grab it */ /* Float the window and tell motionnotify to grab it */
if (grabc->isfloating == 0) { if (grabc->isfloating == 0 && arg->ui == CurMove) {
grabc->drag_to_tile = true; grabc->drag_to_tile = true;
setfloating(grabc, 1); setfloating(grabc, 1);
} }
switch (cursor_mode = arg->ui) { switch (cursor_mode = arg->ui) {
case CurMove: case CurMove:
grabcx = cursor->x - grabc->geom.x; grabcx = cursor->x - grabc->geom.x;
grabcy = cursor->y - grabc->geom.y; grabcy = cursor->y - grabc->geom.y;
wlr_cursor_set_xcursor(cursor, cursor_mgr, "grab"); wlr_cursor_set_xcursor(cursor, cursor_mgr, "grab");
@ -325,9 +311,14 @@ moveresize(const Arg *arg) {
case CurResize: case CurResize:
/* Doesn't work for X11 output - the next absolute motion event /* Doesn't work for X11 output - the next absolute motion event
* returns the cursor to where it started */ * returns the cursor to where it started */
wlr_cursor_warp_closest(cursor, NULL, grabc->geom.x + grabc->geom.width, if (grabc->isfloating) {
grabc->geom.y + grabc->geom.height); wlr_cursor_warp_closest(cursor, NULL,
wlr_cursor_set_xcursor(cursor, cursor_mgr, "bottom_right_corner"); grabc->geom.x + grabc->geom.width,
grabc->geom.y + grabc->geom.height);
wlr_cursor_set_xcursor(cursor, cursor_mgr, "bottom_right_corner");
} else {
wlr_cursor_set_xcursor(cursor, cursor_mgr, "grab");
}
break; break;
} }
} }
@ -377,10 +368,38 @@ quit(const Arg *arg) {
void resizewin(const Arg *arg) { void resizewin(const Arg *arg) {
Client *c = NULL; Client *c = NULL;
c = selmon->sel; c = selmon->sel;
if (!c || c->isfullscreen) int offsetx = 0, offsety = 0;
if (!c || c->isfullscreen || c->ismaxmizescreen)
return; return;
if (!c->isfloating)
togglefloating(NULL); if (ISTILED(c)) {
switch (arg->ui) {
case NUM_TYPE_MINUS:
offsetx = -arg->i;
break;
case NUM_TYPE_PLUS:
offsetx = arg->i;
break;
default:
offsetx = arg->i;
break;
}
switch (arg->ui2) {
case NUM_TYPE_MINUS:
offsety = -arg->i2;
break;
case NUM_TYPE_PLUS:
offsety = arg->i2;
break;
default:
offsety = arg->i2;
break;
}
resize_tile_client(c, false, offsetx, offsety, 0);
return;
}
switch (arg->ui) { switch (arg->ui) {
case NUM_TYPE_MINUS: case NUM_TYPE_MINUS:

View file

@ -17,11 +17,10 @@ Monitor *dirtomon(enum wlr_direction dir) {
bool is_scroller_layout(Monitor *m) { bool is_scroller_layout(Monitor *m) {
if (strcmp(m->pertag->ltidxs[m->pertag->curtag]->name, "scroller") == 0) if (m->pertag->ltidxs[m->pertag->curtag]->id == SCROLLER)
return true; return true;
if (strcmp(m->pertag->ltidxs[m->pertag->curtag]->name, if (m->pertag->ltidxs[m->pertag->curtag]->id == VERTICAL_SCROLLER)
"vertical_scroller") == 0)
return true; return true;
return false; return false;

657
src/layout/arrange.h Normal file
View file

@ -0,0 +1,657 @@
void set_size_per(Monitor *m, Client *c) {
Client *fc = NULL;
bool found = false;
wl_list_for_each(fc, &clients, link) {
if (VISIBLEON(fc, m) && ISTILED(fc) && fc != c) {
c->master_mfact_per = fc->master_mfact_per;
c->master_inner_per = fc->master_inner_per;
c->stack_innder_per = fc->stack_innder_per;
found = true;
break;
}
}
if (!found) {
c->master_mfact_per = default_mfact;
c->master_inner_per = 1.0f;
c->stack_innder_per = 1.0f;
}
}
void resize_tile_master_horizontal(Client *grabc, bool isdrag, int offsetx,
int offsety, unsigned int time, int type) {
Client *tc = NULL;
float delta_x, delta_y;
Client *next = NULL;
Client *prev = NULL;
Client *nextnext = NULL;
Client *prevprev = NULL;
double refresh_interval = 1000000.0 / grabc->mon->wlr_output->refresh;
struct wl_list *node;
bool begin_find_nextnext = false;
bool begin_find_prevprev = false;
// 从当前节点的下一个开始遍历
for (node = grabc->link.next; node != &clients; node = node->next) {
tc = wl_container_of(node, tc, link);
if (begin_find_nextnext && VISIBLEON(tc, grabc->mon) && ISTILED(tc)) {
nextnext = tc;
break;
}
if (!begin_find_nextnext && VISIBLEON(tc, grabc->mon) &&
ISTILED(tc)) { // 根据你的实际字段名调整
next = tc;
begin_find_nextnext = true;
continue;
}
}
// 从当前节点的上一个开始遍历
for (node = grabc->link.prev; node != &clients; node = node->prev) {
tc = wl_container_of(node, tc, link);
if (begin_find_prevprev && VISIBLEON(tc, grabc->mon) && ISTILED(tc)) {
prevprev = tc;
break;
}
if (!begin_find_prevprev && VISIBLEON(tc, grabc->mon) &&
ISTILED(tc)) { // 根据你的实际字段名调整
prev = tc;
begin_find_prevprev = true;
continue;
}
}
if (!start_drag_window && isdrag) {
drag_begin_cursorx = cursor->x;
drag_begin_cursory = cursor->y;
start_drag_window = true;
// 记录初始状态
grabc->old_master_mfact_per = grabc->master_mfact_per;
grabc->old_master_inner_per = grabc->master_inner_per;
grabc->old_stack_innder_per = grabc->stack_innder_per;
grabc->cursor_in_upper_half =
cursor->y < grabc->geom.y + grabc->geom.height / 2;
grabc->cursor_in_left_half =
cursor->x < grabc->geom.x + grabc->geom.width / 2;
// 记录初始几何信息
grabc->drag_begin_geom = grabc->geom;
} else {
// 计算相对于屏幕尺寸的比例变化
if (isdrag) {
offsetx = cursor->x - drag_begin_cursorx;
offsety = cursor->y - drag_begin_cursory;
} else {
grabc->old_master_mfact_per = grabc->master_mfact_per;
grabc->old_master_inner_per = grabc->master_inner_per;
grabc->old_stack_innder_per = grabc->stack_innder_per;
grabc->drag_begin_geom = grabc->geom;
grabc->cursor_in_upper_half = true;
grabc->cursor_in_left_half = false;
}
if (grabc->ismaster) {
delta_x = (float)(offsetx) * (grabc->old_master_mfact_per) /
grabc->drag_begin_geom.width;
delta_y = (float)(offsety) * (grabc->old_master_inner_per) /
grabc->drag_begin_geom.height;
} else {
delta_x = (float)(offsetx) * (1 - grabc->old_master_mfact_per) /
grabc->drag_begin_geom.width;
delta_y = (float)(offsety) * (grabc->old_stack_innder_per) /
grabc->drag_begin_geom.height;
}
bool moving_up;
bool moving_down;
if (!isdrag) {
moving_up = offsety < 0 ? true : false;
moving_down = offsety > 0 ? true : false;
} else {
moving_up = cursor->y < drag_begin_cursory;
moving_down = cursor->y > drag_begin_cursory;
}
if (grabc->ismaster && !prev) {
if (moving_up) {
delta_y = -fabsf(delta_y);
} else {
delta_y = fabsf(delta_y);
}
} else if (grabc->ismaster && next && !next->ismaster) {
if (moving_up) {
delta_y = fabsf(delta_y);
} else {
delta_y = -fabsf(delta_y);
}
} else if (!grabc->ismaster && prev && prev->ismaster) {
if (moving_up) {
delta_y = -fabsf(delta_y);
} else {
delta_y = fabsf(delta_y);
}
} else if (!grabc->ismaster && !next) {
if (moving_up) {
delta_y = fabsf(delta_y);
} else {
delta_y = -fabsf(delta_y);
}
} else if (type == CENTER_TILE && !grabc->ismaster && !nextnext) {
if (moving_up) {
delta_y = fabsf(delta_y);
} else {
delta_y = -fabsf(delta_y);
}
} else if (type == CENTER_TILE && !grabc->ismaster && prevprev &&
prevprev->ismaster) {
if (moving_up) {
delta_y = -fabsf(delta_y);
} else {
delta_y = fabsf(delta_y);
}
} else if ((grabc->cursor_in_upper_half && moving_up) ||
(!grabc->cursor_in_upper_half && moving_down)) {
// 光标在窗口上方且向上移动,或在窗口下方且向下移动 → 增加高度
delta_y = fabsf(delta_y);
delta_y = delta_y * 2;
} else {
// 其他情况 → 减小高度
delta_y = -fabsf(delta_y);
delta_y = delta_y * 2;
}
if (!grabc->ismaster && grabc->isleftstack && type == CENTER_TILE) {
delta_x = delta_x * -1.0f;
}
if (grabc->ismaster && type == CENTER_TILE &&
grabc->cursor_in_left_half) {
delta_x = delta_x * -1.0f;
}
if (grabc->ismaster && type == CENTER_TILE) {
delta_x = delta_x * 2;
}
// 直接设置新的比例,基于初始值 + 变化量
float new_master_mfact_per = grabc->old_master_mfact_per + delta_x;
float new_master_inner_per = grabc->old_master_inner_per + delta_y;
float new_stack_innder_per = grabc->old_stack_innder_per + delta_y;
// 应用限制,确保比例在合理范围内
new_master_mfact_per = fmaxf(0.1f, fminf(0.9f, new_master_mfact_per));
new_master_inner_per = fmaxf(0.1f, fminf(0.9f, new_master_inner_per));
new_stack_innder_per = fmaxf(0.1f, fminf(0.9f, new_stack_innder_per));
// 应用到所有平铺窗口
wl_list_for_each(tc, &clients, link) {
if (VISIBLEON(tc, grabc->mon) && ISTILED(tc)) {
tc->master_mfact_per = new_master_mfact_per;
}
}
grabc->master_inner_per = new_master_inner_per;
grabc->stack_innder_per = new_stack_innder_per;
if (!isdrag) {
arrange(grabc->mon, false);
return;
}
if (last_apply_drap_time == 0 ||
time - last_apply_drap_time > refresh_interval) {
arrange(grabc->mon, false);
last_apply_drap_time = time;
}
}
}
void resize_tile_master_vertical(Client *grabc, bool isdrag, int offsetx,
int offsety, unsigned int time, int type) {
Client *tc = NULL;
float delta_x, delta_y;
Client *next = NULL;
Client *prev = NULL;
double refresh_interval = 1000000.0 / grabc->mon->wlr_output->refresh;
struct wl_list *node;
// 从当前节点的下一个开始遍历
for (node = grabc->link.next; node != &clients; node = node->next) {
tc = wl_container_of(node, tc, link);
if (VISIBLEON(tc, grabc->mon) &&
ISTILED(tc)) { // 根据你的实际字段名调整
next = tc;
break;
}
}
// 从当前节点的上一个开始遍历
for (node = grabc->link.prev; node != &clients; node = node->prev) {
tc = wl_container_of(node, tc, link);
if (VISIBLEON(tc, grabc->mon) &&
ISTILED(tc)) { // 根据你的实际字段名调整
prev = tc;
break;
}
}
if (!start_drag_window && isdrag) {
drag_begin_cursorx = cursor->x;
drag_begin_cursory = cursor->y;
start_drag_window = true;
// 记录初始状态
grabc->old_master_mfact_per = grabc->master_mfact_per;
grabc->old_master_inner_per = grabc->master_inner_per;
grabc->old_stack_innder_per = grabc->stack_innder_per;
grabc->cursor_in_upper_half =
cursor->y < grabc->geom.y + grabc->geom.height / 2;
grabc->cursor_in_left_half =
cursor->x < grabc->geom.x + grabc->geom.width / 2;
// 记录初始几何信息
grabc->drag_begin_geom = grabc->geom;
} else {
// 计算相对于屏幕尺寸的比例变化
// 计算相对于屏幕尺寸的比例变化
if (isdrag) {
offsetx = cursor->x - drag_begin_cursorx;
offsety = cursor->y - drag_begin_cursory;
} else {
grabc->old_master_mfact_per = grabc->master_mfact_per;
grabc->old_master_inner_per = grabc->master_inner_per;
grabc->old_stack_innder_per = grabc->stack_innder_per;
grabc->drag_begin_geom = grabc->geom;
grabc->cursor_in_upper_half = true;
grabc->cursor_in_left_half = false;
}
if (grabc->ismaster) {
// 垂直版本:左右移动调整高度比例,上下移动调整宽度比例
delta_x = (float)(offsetx) * (grabc->old_master_inner_per) /
grabc->drag_begin_geom.width;
delta_y = (float)(offsety) * (grabc->old_master_mfact_per) /
grabc->drag_begin_geom.height;
} else {
delta_x = (float)(offsetx) * (grabc->old_stack_innder_per) /
grabc->drag_begin_geom.width;
delta_y = (float)(offsety) * (1 - grabc->old_master_mfact_per) /
grabc->drag_begin_geom.height;
}
bool moving_left;
bool moving_right;
if (!isdrag) {
moving_left = offsetx < 0 ? true : false;
moving_right = offsetx > 0 ? true : false;
} else {
moving_left = cursor->x < drag_begin_cursorx;
moving_right = cursor->x > drag_begin_cursorx;
}
// 调整主区域和栈区域的高度比例(垂直分割)
if (grabc->ismaster && !prev) {
if (moving_left) {
delta_x = -fabsf(delta_x); // 向上移动减少主区域高度
} else {
delta_x = fabsf(delta_x); // 向下移动增加主区域高度
}
} else if (grabc->ismaster && next && !next->ismaster) {
if (moving_left) {
delta_x = fabsf(delta_x); // 向上移动增加主区域高度
} else {
delta_x = -fabsf(delta_x); // 向下移动减少主区域高度
}
} else if (!grabc->ismaster && prev && prev->ismaster) {
if (moving_left) {
delta_x = -fabsf(delta_x); // 向上移动减少栈区域高度
} else {
delta_x = fabsf(delta_x); // 向下移动增加栈区域高度
}
} else if (!grabc->ismaster && !next) {
if (moving_left) {
delta_x = fabsf(delta_x); // 向上移动增加栈区域高度
} else {
delta_x = -fabsf(delta_x); // 向下移动减少栈区域高度
}
} else if ((grabc->cursor_in_left_half && moving_left) ||
(!grabc->cursor_in_left_half && moving_right)) {
// 光标在窗口左侧且向左移动,或在窗口右侧且向右移动 → 增加宽度
delta_x = fabsf(delta_x);
delta_x = delta_x * 2;
} else {
// 其他情况 → 减小宽度
delta_x = -fabsf(delta_x);
delta_x = delta_x * 2;
}
// 直接设置新的比例,基于初始值 + 变化量
float new_master_mfact_per = grabc->old_master_mfact_per +
delta_y; // 垂直delta_y调整主区域高度
float new_master_inner_per = grabc->old_master_inner_per +
delta_x; // 垂直delta_x调整主区域内部宽度
float new_stack_innder_per = grabc->old_stack_innder_per +
delta_x; // 垂直delta_x调整栈区域内部宽度
// 应用限制,确保比例在合理范围内
new_master_mfact_per = fmaxf(0.1f, fminf(0.9f, new_master_mfact_per));
new_master_inner_per = fmaxf(0.1f, fminf(0.9f, new_master_inner_per));
new_stack_innder_per = fmaxf(0.1f, fminf(0.9f, new_stack_innder_per));
// 应用到所有平铺窗口
wl_list_for_each(tc, &clients, link) {
if (VISIBLEON(tc, grabc->mon) && ISTILED(tc)) {
tc->master_mfact_per = new_master_mfact_per;
}
}
grabc->master_inner_per = new_master_inner_per;
grabc->stack_innder_per = new_stack_innder_per;
if (!isdrag) {
arrange(grabc->mon, false);
return;
}
if (last_apply_drap_time == 0 ||
time - last_apply_drap_time > refresh_interval) {
arrange(grabc->mon, false);
last_apply_drap_time = time;
}
}
}
void resize_tile_scroller(Client *grabc, bool isdrag, int offsetx, int offsety,
unsigned int time, bool isvertical) {
float delta_x, delta_y;
float new_scroller_proportion;
double refresh_interval = 1000000.0 / grabc->mon->wlr_output->refresh;
if (!start_drag_window && isdrag) {
drag_begin_cursorx = cursor->x;
drag_begin_cursory = cursor->y;
start_drag_window = true;
// 记录初始状态
grabc->old_scroller_pproportion = grabc->scroller_proportion;
grabc->cursor_in_left_half =
cursor->x < grabc->geom.x + grabc->geom.width / 2;
grabc->cursor_in_upper_half =
cursor->y < grabc->geom.y + grabc->geom.height / 2;
// 记录初始几何信息
grabc->drag_begin_geom = grabc->geom;
} else {
// 计算相对于屏幕尺寸的比例变化
// 计算相对于屏幕尺寸的比例变化
if (isdrag) {
offsetx = cursor->x - drag_begin_cursorx;
offsety = cursor->y - drag_begin_cursory;
} else {
grabc->old_master_mfact_per = grabc->master_mfact_per;
grabc->old_master_inner_per = grabc->master_inner_per;
grabc->old_stack_innder_per = grabc->stack_innder_per;
grabc->drag_begin_geom = grabc->geom;
grabc->old_scroller_pproportion = grabc->scroller_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;
bool moving_up;
bool moving_down;
bool moving_left;
bool moving_right;
if (!isdrag) {
moving_up = offsety < 0 ? true : false;
moving_down = offsety > 0 ? true : false;
moving_left = offsetx < 0 ? true : false;
moving_right = offsetx > 0 ? true : false;
} else {
moving_up = cursor->y < drag_begin_cursory;
moving_down = cursor->y > drag_begin_cursory;
moving_left = cursor->x < drag_begin_cursorx;
moving_right = cursor->x > drag_begin_cursorx;
}
if ((grabc->cursor_in_upper_half && moving_up) ||
(!grabc->cursor_in_upper_half && moving_down)) {
// 光标在窗口上方且向上移动,或在窗口下方且向下移动 → 增加高度
delta_y = fabsf(delta_y);
} else {
// 其他情况 → 减小高度
delta_y = -fabsf(delta_y);
}
if ((grabc->cursor_in_left_half && moving_left) ||
(!grabc->cursor_in_left_half && moving_right)) {
delta_x = fabsf(delta_x);
} else {
delta_x = -fabsf(delta_x);
}
// 直接设置新的比例,基于初始值 + 变化量
if (isvertical) {
new_scroller_proportion = grabc->old_scroller_pproportion + delta_y;
} else {
new_scroller_proportion = grabc->old_scroller_pproportion + delta_x;
}
// 应用限制,确保比例在合理范围内
new_scroller_proportion =
fmaxf(0.1f, fminf(0.9f, new_scroller_proportion));
grabc->scroller_proportion = new_scroller_proportion;
if (!isdrag) {
arrange(grabc->mon, false);
return;
}
if (last_apply_drap_time == 0 ||
time - last_apply_drap_time > refresh_interval) {
arrange(grabc->mon, false);
last_apply_drap_time = time;
}
}
}
void resize_tile_client(Client *grabc, bool isdrag, int offsetx, int offsety,
unsigned int time) {
const Layout *current_layout =
grabc->mon->pertag->ltidxs[grabc->mon->pertag->curtag];
if (current_layout->id == TILE || current_layout->id == DECK ||
current_layout->id == CENTER_TILE
) {
resize_tile_master_horizontal(grabc, isdrag, offsetx, offsety, time,
current_layout->id);
} else if (current_layout->id == VERTICAL_TILE) {
resize_tile_master_vertical(grabc, isdrag, offsetx, offsety, time,
current_layout->id);
} else if (current_layout->id == SCROLLER) {
resize_tile_scroller(grabc, isdrag, offsetx, offsety, time, false);
} else if (current_layout->id == VERTICAL_SCROLLER) {
resize_tile_scroller(grabc, isdrag, offsetx, offsety, time, true);
}
}
void reset_size_per_mon(Monitor *m, int 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) {
Client *c = NULL;
int i = 0;
unsigned int stack_index;
unsigned int nmasters = m->pertag->nmasters[m->pertag->curtag];
if (m->pertag->ltidxs[m->pertag->curtag]->id != CENTER_TILE) {
wl_list_for_each(c, &clients, link) {
if (VISIBLEON(c, m) && ISTILED(c)) {
if (total_master_inner_percent <= 0.0)
return;
if (i < m->pertag->nmasters[m->pertag->curtag]) {
c->ismaster = true;
c->stack_innder_per = stack_num ? 1.0f / stack_num : 1.0f;
c->master_inner_per =
c->master_inner_per / total_master_inner_percent;
} else {
c->ismaster = false;
c->master_inner_per = 1.0f / master_num;
c->stack_innder_per =
total_stack_hight_percent
? c->stack_innder_per / total_stack_hight_percent
: 1.0f;
}
i++;
}
}
} else {
wl_list_for_each(c, &clients, link) {
if (VISIBLEON(c, m) && ISTILED(c)) {
if (total_master_inner_percent <= 0.0)
return;
if (i < m->pertag->nmasters[m->pertag->curtag]) {
c->ismaster = true;
c->stack_innder_per =
stack_num > 1 ? 2.0f / stack_num : 1.0f;
c->master_inner_per =
c->master_inner_per / total_master_inner_percent;
} else {
stack_index = i - nmasters;
c->ismaster = false;
c->master_inner_per = 1.0f / master_num;
if ((stack_index % 2) ^ (tile_cilent_num % 2 == 0)) {
c->stack_innder_per =
total_right_stack_hight_percent
? c->stack_innder_per /
total_right_stack_hight_percent
: 1.0f;
} else {
c->stack_innder_per =
total_left_stack_hight_percent
? c->stack_innder_per /
total_left_stack_hight_percent
: 1.0f;
}
}
i++;
}
}
}
}
void // 17
arrange(Monitor *m, bool want_animation) {
Client *c = NULL;
double total_stack_innder_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;
if (!m)
return;
if (!m->wlr_output->enabled)
return;
m->visible_clients = 0;
m->visible_tiling_clients = 0;
wl_list_for_each(c, &clients, link) {
if (VISIBLEON(c, m)) {
m->visible_clients++;
if (ISTILED(c)) {
m->visible_tiling_clients++;
}
}
}
nmasters = m->pertag->nmasters[m->pertag->curtag];
wl_list_for_each(c, &clients, link) {
if (c->iskilling)
continue;
if (c->mon == m && (c->isglobal || c->isunglobal)) {
c->tags = m->tagset[m->seltags];
if (c->mon->sel == NULL)
focusclient(c, 0);
}
if (c->mon == m) {
if (VISIBLEON(c, m)) {
if (ISTILED(c)) {
if (i < m->pertag->nmasters[m->pertag->curtag]) {
master_num++;
total_master_inner_percent += c->master_inner_per;
} else {
stack_num++;
total_stack_innder_percent += c->stack_innder_per;
stack_index = i - nmasters;
if ((stack_index % 2) ^
(m->visible_tiling_clients % 2 == 0)) {
c->isleftstack = false;
total_right_stack_hight_percent +=
c->stack_innder_per;
} else {
c->isleftstack = true;
total_left_stack_hight_percent +=
c->stack_innder_per;
}
}
i++;
}
set_arrange_visible(m, c, want_animation);
} else {
set_arrange_hidden(m, c, want_animation);
}
}
if (c->mon == m && c->ismaxmizescreen && !c->animation.tagouted &&
!c->animation.tagouting && VISIBLEON(c, m)) {
reset_maxmizescreen_size(c);
}
}
reset_size_per_mon(
m, m->visible_tiling_clients, total_left_stack_hight_percent,
total_right_stack_hight_percent, total_stack_innder_percent,
total_master_inner_percent, master_num, stack_num);
if (m->isoverview) {
overviewlayout.arrange(m);
} else {
m->pertag->ltidxs[m->pertag->curtag]->arrange(m);
}
if (!start_drag_window) {
motionnotify(0, NULL, 0, 0, 0, 0);
checkidleinhibitor(NULL);
}
}

View file

@ -1,128 +1,3 @@
void fibonacci(Monitor *mon, int s) {
unsigned int i = 0, n = 0, nx, ny, nw, nh;
Client *c = NULL;
unsigned int cur_gappih = enablegaps ? mon->gappih : 0;
unsigned int cur_gappiv = enablegaps ? mon->gappiv : 0;
unsigned int cur_gappoh = enablegaps ? mon->gappoh : 0;
unsigned int cur_gappov = enablegaps ? mon->gappov : 0;
cur_gappih = smartgaps && mon->visible_tiling_clients == 1 ? 0 : cur_gappih;
cur_gappiv = smartgaps && mon->visible_tiling_clients == 1 ? 0 : cur_gappiv;
cur_gappoh = smartgaps && mon->visible_tiling_clients == 1 ? 0 : cur_gappoh;
cur_gappov = smartgaps && mon->visible_tiling_clients == 1 ? 0 : cur_gappov;
// Count visible clients
n = mon->visible_tiling_clients;
if (n == 0)
return;
// Initial dimensions including outer gaps
nx = mon->w.x + cur_gappoh;
ny = mon->w.y + cur_gappov;
nw = mon->w.width - 2 * cur_gappoh;
nh = mon->w.height - 2 * cur_gappov;
// First pass: calculate client geometries
wl_list_for_each(c, &clients, link) {
if (!VISIBLEON(c, mon) || !ISTILED(c))
continue;
c->bw = mon->visible_tiling_clients == 1 && no_border_when_single &&
smartgaps
? 0
: borderpx;
if ((i % 2 && nh / 2 > 2 * c->bw) || (!(i % 2) && nw / 2 > 2 * c->bw)) {
if (i < n - 1) {
if (i % 2) {
if (i == 1) {
nh = nh * mon->pertag->smfacts[mon->pertag->curtag];
} else {
nh = (nh - cur_gappiv) / 2;
}
} else {
nw = (nw - cur_gappih) / 2;
}
if ((i % 4) == 2 && !s)
nx += nw + cur_gappih;
else if ((i % 4) == 3 && !s)
ny += nh + cur_gappiv;
}
if ((i % 4) == 0) {
if (s)
ny += nh + cur_gappiv;
else
ny -= nh + cur_gappiv;
} else if ((i % 4) == 1)
nx += nw + cur_gappih;
else if ((i % 4) == 2)
ny += nh + cur_gappiv;
else if ((i % 4) == 3) {
if (s)
nx += nw + cur_gappih;
else
nx -= nw + cur_gappih;
}
if (i == 0) {
if (n != 1)
nw = (mon->w.width - 2 * cur_gappoh) *
mon->pertag->mfacts[mon->pertag->curtag];
ny = mon->w.y + cur_gappov;
} else if (i == 1) {
nw = mon->w.width - 2 * cur_gappoh - nw - cur_gappih;
} else if (i == 2) {
nh = mon->w.height - 2 * cur_gappov - nh - cur_gappiv;
}
i++;
}
c->geom = (struct wlr_box){.x = nx, .y = ny, .width = nw, .height = nh};
}
// Second pass: apply gaps between clients
wl_list_for_each(c, &clients, link) {
if (!VISIBLEON(c, mon) || !ISTILED(c))
continue;
unsigned int right_gap = 0;
unsigned int bottom_gap = 0;
Client *nc = NULL;
wl_list_for_each(nc, &clients, link) {
if (!VISIBLEON(nc, mon) || !ISTILED(nc))
continue;
if (c == nc)
continue;
// Check for right neighbor
if (c->geom.y == nc->geom.y &&
c->geom.x + c->geom.width == nc->geom.x) {
right_gap = cur_gappih;
}
// Check for bottom neighbor
if (c->geom.x == nc->geom.x &&
c->geom.y + c->geom.height == nc->geom.y) {
bottom_gap = cur_gappiv;
}
}
resize(c,
(struct wlr_box){.x = c->geom.x,
.y = c->geom.y,
.width = c->geom.width - right_gap,
.height = c->geom.height - bottom_gap},
0);
}
}
void dwindle(Monitor *mon) { fibonacci(mon, 1); }
void spiral(Monitor *mon) { fibonacci(mon, 0); }
// 网格布局窗口大小和位置计算 // 网格布局窗口大小和位置计算
void grid(Monitor *m) { void grid(Monitor *m) {
unsigned int i, n; unsigned int i, n;
@ -247,6 +122,9 @@ void deck(Monitor *m) {
unsigned int mw, my; unsigned int mw, my;
int i, n = 0; int i, n = 0;
Client *c = NULL; Client *c = NULL;
Client *fc = NULL;
float mfact;
unsigned int cur_gappih = enablegaps ? m->gappih : 0; unsigned int cur_gappih = enablegaps ? m->gappih : 0;
unsigned int cur_gappoh = enablegaps ? m->gappoh : 0; unsigned int cur_gappoh = enablegaps ? m->gappoh : 0;
unsigned int cur_gappov = enablegaps ? m->gappov : 0; unsigned int cur_gappov = enablegaps ? m->gappov : 0;
@ -260,8 +138,15 @@ void deck(Monitor *m) {
if (n == 0) if (n == 0)
return; return;
wl_list_for_each(fc, &clients, link) {
if (VISIBLEON(fc, m) && ISTILED(fc))
break;
}
// Calculate master width using mfact from pertag // Calculate master width using mfact from pertag
float mfact = m->pertag ? m->pertag->mfacts[m->pertag->curtag] : m->mfact; mfact = fc->master_mfact_per > 0.0f ? fc->master_mfact_per
: m->pertag->mfacts[m->pertag->curtag];
// Calculate master width including outer gaps // Calculate master width including outer gaps
if (n > m->nmaster) if (n > m->nmaster)
@ -274,6 +159,7 @@ void deck(Monitor *m) {
if (!VISIBLEON(c, m) || !ISTILED(c)) if (!VISIBLEON(c, m) || !ISTILED(c))
continue; continue;
if (i < m->nmaster) { if (i < m->nmaster) {
c->master_mfact_per = mfact;
// Master area clients // Master area clients
resize( resize(
c, c,
@ -286,6 +172,7 @@ void deck(Monitor *m) {
my += c->geom.height; my += c->geom.height;
} else { } else {
// Stack area clients // Stack area clients
c->master_mfact_per = mfact;
resize(c, resize(c,
(struct wlr_box){.x = m->w.x + mw + cur_gappoh + cur_gappih, (struct wlr_box){.x = m->w.x + mw + cur_gappoh + cur_gappih,
.y = m->w.y + cur_gappov, .y = m->w.y + cur_gappov,
@ -385,6 +272,9 @@ void scroller(Monitor *m) {
} }
} }
if (start_drag_window)
need_scroller = false;
target_geom.height = m->w.height - 2 * cur_gappov; target_geom.height = m->w.height - 2 * cur_gappov;
target_geom.width = max_client_width * c->scroller_proportion; target_geom.width = max_client_width * c->scroller_proportion;
target_geom.y = m->w.y + (m->w.height - target_geom.height) / 2; target_geom.y = m->w.y + (m->w.height - target_geom.height) / 2;
@ -433,31 +323,46 @@ void scroller(Monitor *m) {
} }
void center_tile(Monitor *m) { void center_tile(Monitor *m) {
unsigned int i, n = 0, h, mw, mx, my, oty, ety, tw; unsigned int i, n = 0, h, r, ie = enablegaps, mw, mx, my, oty, ety, tw;
Client *c = NULL; Client *c = NULL;
Client *fc = NULL;
double mfact = 0;
int master_num = 0;
int stack_num = 0;
n = m->visible_tiling_clients; n = m->visible_tiling_clients;
master_num = m->pertag->nmasters[m->pertag->curtag];
stack_num = n - master_num;
if (n == 0) if (n == 0)
return; return;
// 间隙参数处理 // 获取第一个可见的平铺客户端用于主区域宽度百分比
unsigned int gappiv = enablegaps ? m->gappiv : 0; // 内部垂直间隙 wl_list_for_each(fc, &clients, link) {
unsigned int gappih = enablegaps ? m->gappih : 0; // 内部水平间隙 if (VISIBLEON(fc, m) && ISTILED(fc))
unsigned int gappov = enablegaps ? m->gappov : 0; // 外部垂直间隙 break;
unsigned int gappoh = enablegaps ? m->gappoh : 0; // 外部水平间隙
// 智能间隙处理
if (smartgaps && n == 1) {
gappiv = gappih = gappov = gappoh = 0;
} }
// 间隙参数处理
unsigned int cur_gappiv = enablegaps ? m->gappiv : 0; // 内部垂直间隙
unsigned int cur_gappih = enablegaps ? m->gappih : 0; // 内部水平间隙
unsigned int cur_gappov = enablegaps ? m->gappov : 0; // 外部垂直间隙
unsigned int 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;
cur_gappov = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappov;
cur_gappoh = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappoh;
unsigned int nmasters = m->pertag->nmasters[m->pertag->curtag]; unsigned int nmasters = m->pertag->nmasters[m->pertag->curtag];
float mfact = m->pertag->mfacts[m->pertag->curtag]; mfact = fc->master_mfact_per > 0.0f ? fc->master_mfact_per
: m->pertag->mfacts[m->pertag->curtag];
// 初始化区域 // 初始化区域
mw = m->w.width; mw = m->w.width;
mx = gappoh; mx = cur_gappoh;
my = gappov; my = cur_gappov;
tw = mw; tw = mw;
// 判断是否需要主区域铺满 // 判断是否需要主区域铺满
@ -465,37 +370,38 @@ void center_tile(Monitor *m) {
if (n > nmasters || !should_overspread) { if (n > nmasters || !should_overspread) {
// 计算主区域宽度(居中模式) // 计算主区域宽度(居中模式)
mw = nmasters ? (m->w.width - 2 * gappoh - gappih) * mfact : 0; mw = nmasters ? (m->w.width - 2 * cur_gappoh - cur_gappih * ie) * mfact
: 0;
if (n - nmasters > 1) { if (n - nmasters > 1) {
// 多个堆叠窗口:主区域居中,左右两侧各有一个堆叠区域 // 多个堆叠窗口:主区域居中,左右两侧各有一个堆叠区域
tw = (m->w.width - mw) / 2 - gappoh - gappih; tw = (m->w.width - mw) / 2 - cur_gappoh - cur_gappih * ie;
mx = gappoh + tw + gappih; mx = cur_gappoh + tw + cur_gappih * ie;
} else if (n - nmasters == 1) { } else if (n - nmasters == 1) {
// 单个堆叠窗口的处理 // 单个堆叠窗口的处理
if (center_when_single_slave) { if (center_when_single_stack) {
// 修改slave在右边master居中左边空着 // stack在右边master居中左边空着
tw = (m->w.width - mw) / 2 - gappoh - gappih; tw = (m->w.width - mw) / 2 - cur_gappoh - cur_gappih * ie;
mx = gappoh + tw + gappih; // master居中 mx = cur_gappoh + tw + cur_gappih * ie; // master居中
} else { } else {
// slave在右边master在左边 // stack在右边master在左边
tw = m->w.width - mw - 2 * gappoh - gappih; tw = m->w.width - mw - 2 * cur_gappoh - cur_gappih * ie;
mx = gappoh; // master在左边 mx = cur_gappoh; // master在左边
} }
} else { } else {
// 只有主区域窗口:居中显示 // 只有主区域窗口:居中显示
tw = (m->w.width - mw) / 2 - gappoh - gappih; tw = (m->w.width - mw) / 2 - cur_gappoh - cur_gappih * ie;
mx = gappoh + tw + gappih; mx = cur_gappoh + tw + cur_gappih * ie;
} }
} else { } else {
// 主区域铺满模式(只有主区域窗口时) // 主区域铺满模式(只有主区域窗口时)
mw = m->w.width - 2 * gappoh; mw = m->w.width - 2 * cur_gappoh;
mx = gappoh; mx = cur_gappoh;
tw = 0; // 堆叠区域宽度为0 tw = 0; // 堆叠区域宽度为0
} }
oty = gappov; oty = cur_gappov;
ety = gappov; ety = cur_gappov;
i = 0; i = 0;
wl_list_for_each(c, &clients, link) { wl_list_for_each(c, &clients, link) {
@ -504,68 +410,119 @@ void center_tile(Monitor *m) {
if (i < nmasters) { if (i < nmasters) {
// 主区域窗口 // 主区域窗口
unsigned int r = MIN(n, nmasters) - i; r = MIN(n, nmasters) - i;
h = (m->w.height - my - gappov - gappiv * (r - 1)) / r; if (c->master_inner_per > 0.0f) {
h = (m->w.height - 2 * cur_gappov -
cur_gappiv * ie * (master_num - 1)) *
c->master_inner_per;
c->master_mfact_per = mfact;
} else {
h = (m->w.height - my - cur_gappov -
cur_gappiv * ie * (r - 1)) /
r;
c->master_inner_per = h / (m->w.height - my - cur_gappov -
cur_gappiv * ie * (r - 1));
c->master_mfact_per = mfact;
}
resize(c, resize(c,
(struct wlr_box){.x = m->w.x + mx, (struct wlr_box){.x = m->w.x + mx,
.y = m->w.y + my, .y = m->w.y + my,
.width = mw, .width = mw - cur_gappih * ie,
.height = h}, .height = h},
0); 0);
my += c->geom.height + gappiv; my += c->geom.height + cur_gappiv * ie;
} else { } else {
// 堆叠区域窗口 // 堆叠区域窗口
unsigned int stack_index = i - nmasters; unsigned int stack_index = i - nmasters;
if (n - nmasters == 1) { if (n - nmasters == 1) {
// 单个堆叠窗口 // 单个堆叠窗口
unsigned int r = n - i; r = n - i;
h = (m->w.height - ety - gappov - gappiv * (r - 1)) / r; if (c->stack_innder_per > 0.0f) {
h = (m->w.height - 2 * cur_gappov -
cur_gappiv * ie * (stack_num - 1)) *
c->stack_innder_per;
c->master_mfact_per = mfact;
} else {
h = (m->w.height - ety - cur_gappov -
cur_gappiv * ie * (r - 1)) /
r;
c->stack_innder_per = h / (m->w.height - ety - cur_gappov -
cur_gappiv * ie * (r - 1));
c->master_mfact_per = mfact;
}
int stack_x; int stack_x;
if (center_when_single_slave) { if (center_when_single_stack) {
// 修改放在右侧master居中时slave在右边 // 放在右侧master居中时stack在右边)
stack_x = m->w.x + mx + mw + gappih; stack_x = m->w.x + mx + mw + cur_gappih * ie;
} else { } else {
// 放在右侧master在左边时slave在右边 // 放在右侧master在左边时stack在右边)
stack_x = m->w.x + mx + mw + gappih; stack_x = m->w.x + mx + mw + cur_gappih * ie;
} }
resize(c, resize(c,
(struct wlr_box){.x = stack_x, (struct wlr_box){.x = stack_x,
.y = m->w.y + ety, .y = m->w.y + ety,
.width = tw, .width = tw - cur_gappih * ie,
.height = h}, .height = h},
0); 0);
ety += c->geom.height + gappiv; ety += c->geom.height + cur_gappiv * ie;
} else { } else {
// 多个堆叠窗口:交替放在左右两侧 // 多个堆叠窗口:交替放在左右两侧
unsigned int r = (n - i + 1) / 2; r = (n - i + 1) / 2;
// 当n为偶数时翻转判断逻辑
if ((stack_index % 2) ^ (n % 2 == 0)) { if ((stack_index % 2) ^ (n % 2 == 0)) {
// 右侧堆叠窗口 // 右侧堆叠窗口
h = (m->w.height - ety - gappov - gappiv * (r - 1)) / r; if (c->stack_innder_per > 0.0f) {
int stack_x = m->w.x + mx + mw + gappih; h = (m->w.height - 2 * cur_gappov -
cur_gappiv * ie * (stack_num / 2 - 1)) *
c->stack_innder_per;
c->master_mfact_per = mfact;
} else {
h = (m->w.height - ety - cur_gappov -
cur_gappiv * ie * (r - 1)) /
r;
c->stack_innder_per =
h / (m->w.height - ety - cur_gappov -
cur_gappiv * ie * (r - 1));
c->master_mfact_per = mfact;
}
int stack_x = m->w.x + mx + mw + cur_gappih * ie;
resize(c, resize(c,
(struct wlr_box){.x = stack_x, (struct wlr_box){.x = stack_x,
.y = m->w.y + ety, .y = m->w.y + ety,
.width = tw, .width = tw - cur_gappih * ie,
.height = h}, .height = h},
0); 0);
ety += c->geom.height + gappiv; ety += c->geom.height + cur_gappiv * ie;
} else { } else {
// 左侧堆叠窗口 // 左侧堆叠窗口
h = (m->w.height - oty - gappov - gappiv * (r - 1)) / r; if (c->stack_innder_per > 0.0f) {
int stack_x = m->w.x + gappoh; h = (m->w.height - 2 * cur_gappov -
cur_gappiv * ie * (stack_num / 2 - 1)) *
c->stack_innder_per;
c->master_mfact_per = mfact;
} else {
h = (m->w.height - oty - cur_gappov -
cur_gappiv * ie * (r - 1)) /
r;
c->stack_innder_per =
h / (m->w.height - oty - cur_gappov -
cur_gappiv * ie * (r - 1));
c->master_mfact_per = mfact;
}
int stack_x = m->w.x + cur_gappoh;
resize(c, resize(c,
(struct wlr_box){.x = stack_x, (struct wlr_box){.x = stack_x,
.y = m->w.y + oty, .y = m->w.y + oty,
.width = tw, .width = tw - cur_gappih * ie,
.height = h}, .height = h},
0); 0);
oty += c->geom.height + gappiv; oty += c->geom.height + cur_gappiv * ie;
} }
} }
} }
@ -576,8 +533,14 @@ void center_tile(Monitor *m) {
void tile(Monitor *m) { void tile(Monitor *m) {
unsigned int i, n = 0, h, r, ie = enablegaps, mw, my, ty; unsigned int i, n = 0, h, r, ie = enablegaps, mw, my, ty;
Client *c = NULL; Client *c = NULL;
Client *fc = NULL;
double mfact = 0;
int master_num = 0;
int stack_num = 0;
n = m->visible_tiling_clients; n = m->visible_tiling_clients;
master_num = m->pertag->nmasters[m->pertag->curtag];
stack_num = n - master_num;
if (n == 0) if (n == 0)
return; return;
@ -592,10 +555,18 @@ void tile(Monitor *m) {
cur_gappov = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappov; cur_gappov = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappov;
cur_gappoh = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappoh; cur_gappoh = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappoh;
wl_list_for_each(fc, &clients, link) {
if (VISIBLEON(fc, m) && ISTILED(fc))
break;
}
mfact = fc->master_mfact_per > 0.0f ? fc->master_mfact_per
: m->pertag->mfacts[m->pertag->curtag];
if (n > m->pertag->nmasters[m->pertag->curtag]) if (n > m->pertag->nmasters[m->pertag->curtag])
mw = m->pertag->nmasters[m->pertag->curtag] mw = m->pertag->nmasters[m->pertag->curtag]
? (m->w.width + cur_gappih * ie) * ? (m->w.width + cur_gappih * ie) * mfact
m->pertag->mfacts[m->pertag->curtag]
: 0; : 0;
else else
mw = m->w.width - 2 * cur_gappoh + cur_gappih * ie; mw = m->w.width - 2 * cur_gappoh + cur_gappih * ie;
@ -606,7 +577,19 @@ void tile(Monitor *m) {
continue; continue;
if (i < m->pertag->nmasters[m->pertag->curtag]) { if (i < m->pertag->nmasters[m->pertag->curtag]) {
r = MIN(n, m->pertag->nmasters[m->pertag->curtag]) - i; r = MIN(n, m->pertag->nmasters[m->pertag->curtag]) - i;
h = (m->w.height - my - cur_gappov - cur_gappiv * ie * (r - 1)) / r; if (c->master_inner_per > 0.0f) {
h = (m->w.height - 2 * cur_gappov -
cur_gappiv * ie * (master_num - 1)) *
c->master_inner_per;
c->master_mfact_per = mfact;
} else {
h = (m->w.height - my - cur_gappov -
cur_gappiv * ie * (r - 1)) /
r;
c->master_inner_per = h / (m->w.height - my - cur_gappov -
cur_gappiv * ie * (r - 1));
c->master_mfact_per = mfact;
}
resize(c, resize(c,
(struct wlr_box){.x = m->w.x + cur_gappoh, (struct wlr_box){.x = m->w.x + cur_gappoh,
.y = m->w.y + my, .y = m->w.y + my,
@ -616,7 +599,22 @@ void tile(Monitor *m) {
my += c->geom.height + cur_gappiv * ie; my += c->geom.height + cur_gappiv * ie;
} else { } else {
r = n - i; r = n - i;
h = (m->w.height - ty - cur_gappov - cur_gappiv * ie * (r - 1)) / r; if (c->stack_innder_per > 0.0f) {
h = (m->w.height - 2 * cur_gappov -
cur_gappiv * ie * (stack_num - 1)) *
c->stack_innder_per;
c->master_mfact_per = mfact;
} else {
h = (m->w.height - ty - cur_gappov -
cur_gappiv * ie * (r - 1)) /
r;
c->stack_innder_per = h / (m->w.height - ty - cur_gappov -
cur_gappiv * ie * (r - 1));
c->master_mfact_per = mfact;
}
// wlr_log(WLR_ERROR, "stack_innder_per: %f", c->stack_innder_per);
resize(c, resize(c,
(struct wlr_box){.x = m->w.x + mw + cur_gappoh, (struct wlr_box){.x = m->w.x + mw + cur_gappoh,
.y = m->w.y + ty, .y = m->w.y + ty,

View file

@ -4,35 +4,37 @@ static void overview(Monitor *m);
static void grid(Monitor *m); static void grid(Monitor *m);
static void scroller(Monitor *m); static void scroller(Monitor *m);
static void deck(Monitor *mon); static void deck(Monitor *mon);
static void dwindle(Monitor *mon);
static void spiral(Monitor *mon);
static void monocle(Monitor *m); static void monocle(Monitor *m);
static void vertical_tile(Monitor *m); static void vertical_tile(Monitor *m);
static void vertical_overview(Monitor *m); static void vertical_overview(Monitor *m);
static void vertical_grid(Monitor *m); static void vertical_grid(Monitor *m);
static void vertical_scroller(Monitor *m); static void vertical_scroller(Monitor *m);
static void vertical_deck(Monitor *mon); static void vertical_deck(Monitor *mon);
static void vertical_dwindle(Monitor *mon);
static void vertical_spiral(Monitor *mon);
/* layout(s) */ /* layout(s) */
Layout overviewlayout = {"󰃇", overview, "overview"}; Layout overviewlayout = {"󰃇", overview, "overview"};
enum {
SCROLLER,
TILE,
GRID,
MONOCLE,
DECK,
CENTER_TILE,
VERTICAL_SCROLLER,
VERTICAL_TILE,
};
Layout layouts[] = { Layout layouts[] = {
// 最少两个,不能删除少于两个 // 最少两个,不能删除少于两个
/* symbol arrange function name */ /* symbol arrange function name */
{"S", scroller, "scroller"}, // 滚动布局 {"S", scroller, "scroller", SCROLLER}, // 滚动布局
{"T", tile, "tile"}, // 堆栈布局 {"T", tile, "tile", TILE}, // 平铺布局
{"G", grid, "grid"}, {"G", grid, "grid", GRID}, // 格子布局
{"M", monocle, "monocle"}, {"M", monocle, "monocle", MONOCLE}, // 单屏布局
{"D", dwindle, "dwindle"}, {"K", deck, "deck", DECK}, // 卡片布局
{"P", spiral, "spiral"}, {"CT", center_tile, "center_tile", CENTER_TILE}, // 居中布局
{"K", deck, "deck"}, {"VS", vertical_scroller, "vertical_scroller",
{"CT", center_tile, "center_tile"}, VERTICAL_SCROLLER}, // 垂直滚动布局
{"VS", vertical_scroller, "vertical_scroller"}, {"VT", vertical_tile, "vertical_tile", VERTICAL_TILE}, // 垂直平铺布局
{"VT", vertical_tile, "vertical_tile"},
{"VD", vertical_dwindle, "vertical_dwindle"},
{"VP", vertical_spiral, "vertical_spiral"},
{"VG", vertical_grid, "vertical_grid"},
{"VK", vertical_deck, "vertical_deck"},
}; };

View file

@ -1,292 +1,91 @@
void vertical_fibonacci(Monitor *mon, int s) { void vertical_tile(Monitor *m) {
unsigned int i = 0, n = 0, nx, ny, nw, nh; unsigned int i, n = 0, w, r, ie = enablegaps, mh, mx, tx;
Client *c = NULL; Client *c = NULL;
unsigned int cur_gappih = enablegaps ? mon->gappih : 0; Client *fc = NULL;
unsigned int cur_gappiv = enablegaps ? mon->gappiv : 0; double mfact = 0;
unsigned int cur_gappoh = enablegaps ? mon->gappoh : 0; int master_num = 0;
unsigned int cur_gappov = enablegaps ? mon->gappov : 0; int stack_num = 0;
cur_gappih = smartgaps && mon->visible_tiling_clients == 1 ? 0 : cur_gappih;
cur_gappiv = smartgaps && mon->visible_tiling_clients == 1 ? 0 : cur_gappiv;
cur_gappoh = smartgaps && mon->visible_tiling_clients == 1 ? 0 : cur_gappoh;
cur_gappov = smartgaps && mon->visible_tiling_clients == 1 ? 0 : cur_gappov;
n = mon->visible_tiling_clients;
if (n == 0)
return;
// Initial dimensions including outer gaps
nx = mon->w.x + cur_gappoh;
ny = mon->w.y + cur_gappov;
nw = mon->w.width - 2 * cur_gappoh;
nh = mon->w.height - 2 * cur_gappov;
// First pass: calculate client geometries
wl_list_for_each(c, &clients, link) {
if (!VISIBLEON(c, mon) || !ISTILED(c))
continue;
c->bw = mon->visible_tiling_clients == 1 && no_border_when_single &&
smartgaps
? 0
: borderpx;
if ((i % 2 && nw / 2 > 2 * c->bw) || (!(i % 2) && nh / 2 > 2 * c->bw)) {
if (i < n - 1) {
if (i % 2) {
if (i == 1) {
nw = nw * mon->pertag->smfacts[mon->pertag->curtag];
} else {
nw = (nw - cur_gappih) / 2;
}
} else {
nh = (nh - cur_gappiv) / 2;
}
if ((i % 4) == 2 && !s)
ny += nh + cur_gappiv;
else if ((i % 4) == 3 && !s)
nx += nw + cur_gappih;
}
if ((i % 4) == 0) {
if (s)
nx += nw + cur_gappih;
else
nx -= nw + cur_gappih;
} else if ((i % 4) == 1)
ny += nh + cur_gappiv;
else if ((i % 4) == 2)
nx += nw + cur_gappih;
else if ((i % 4) == 3) {
if (s)
ny += nh + cur_gappiv;
else
ny -= nh + cur_gappiv;
}
if (i == 0) {
if (n != 1)
nh = (mon->w.height - 2 * cur_gappov) *
mon->pertag->mfacts[mon->pertag->curtag];
nx = mon->w.x + cur_gappoh;
} else if (i == 1) {
nh = mon->w.height - 2 * cur_gappov - nh - cur_gappiv;
} else if (i == 2) {
nw = mon->w.width - 2 * cur_gappoh - nw - cur_gappih;
}
i++;
}
c->geom = (struct wlr_box){.x = nx, .y = ny, .width = nw, .height = nh};
}
// Second pass: apply gaps between clients
wl_list_for_each(c, &clients, link) {
if (!VISIBLEON(c, mon) || !ISTILED(c))
continue;
unsigned int right_gap = 0;
unsigned int bottom_gap = 0;
Client *nc = NULL;
wl_list_for_each(nc, &clients, link) {
if (!VISIBLEON(nc, mon) || !ISTILED(nc))
continue;
if (c == nc)
continue;
// Check for right neighbor
if (c->geom.y == nc->geom.y &&
c->geom.x + c->geom.width == nc->geom.x) {
right_gap = cur_gappih;
}
// Check for bottom neighbor
if (c->geom.x == nc->geom.x &&
c->geom.y + c->geom.height == nc->geom.y) {
bottom_gap = cur_gappiv;
}
}
resize(c,
(struct wlr_box){.x = c->geom.x,
.y = c->geom.y,
.width = c->geom.width - right_gap,
.height = c->geom.height - bottom_gap},
0);
}
}
void vertical_dwindle(Monitor *mon) { vertical_fibonacci(mon, 1); }
void vertical_spiral(Monitor *mon) { vertical_fibonacci(mon, 0); }
void vertical_grid(Monitor *m) {
unsigned int i, n;
unsigned int cx, cy, cw, ch;
unsigned int dy;
unsigned int rows, cols, overrows;
Client *c = NULL;
n = m->isoverview ? m->visible_clients : m->visible_tiling_clients;
if (n == 0) {
return;
}
if (n == 1) {
wl_list_for_each(c, &clients, link) {
if (c->mon != m)
continue;
c->bw = m->visible_tiling_clients == 1 && no_border_when_single &&
smartgaps
? 0
: borderpx;
if (VISIBLEON(c, m) && !c->isunglobal &&
((m->isoverview && !client_should_ignore_focus(c)) ||
ISTILED(c))) {
ch = (m->w.height - 2 * overviewgappo) * 0.7;
cw = (m->w.width - 2 * overviewgappo) * 0.8;
c->geom.x = m->w.x + (m->w.width - cw) / 2;
c->geom.y = m->w.y + (m->w.height - ch) / 2;
c->geom.width = cw - 2 * c->bw;
c->geom.height = ch - 2 * c->bw;
resize(c, c->geom, 0);
return;
}
}
}
if (n == 2) {
ch = (m->w.height - 2 * overviewgappo - overviewgappi) / 2;
cw = (m->w.width - 2 * overviewgappo) * 0.65;
i = 0;
wl_list_for_each(c, &clients, link) {
if (c->mon != m)
continue;
c->bw = m->visible_tiling_clients == 1 && no_border_when_single &&
smartgaps
? 0
: borderpx;
if (VISIBLEON(c, m) && !c->isunglobal &&
((m->isoverview && !client_should_ignore_focus(c)) ||
ISTILED(c))) {
if (i == 0) {
c->geom.x = m->w.x + (m->w.width - cw) / 2 + overviewgappo;
c->geom.y = m->w.y + overviewgappo;
c->geom.width = cw - 2 * c->bw;
c->geom.height = ch - 2 * c->bw;
resize(c, c->geom, 0);
} else if (i == 1) {
c->geom.x = m->w.x + (m->w.width - cw) / 2 + overviewgappo;
c->geom.y = m->w.y + ch + overviewgappo + overviewgappi;
c->geom.width = cw - 2 * c->bw;
c->geom.height = ch - 2 * c->bw;
resize(c, c->geom, 0);
}
i++;
}
}
return;
}
for (rows = 0; rows <= n / 2; rows++) {
if (rows * rows >= n) {
break;
}
}
cols = (rows && (rows - 1) * rows >= n) ? rows - 1 : rows;
cw = (m->w.width - 2 * overviewgappo - (cols - 1) * overviewgappi) / cols;
ch = (m->w.height - 2 * overviewgappo - (rows - 1) * overviewgappi) / rows;
overrows = n % rows;
if (overrows) {
dy =
(m->w.height - overrows * ch - (overrows - 1) * overviewgappi) / 2 -
overviewgappo;
}
i = 0;
wl_list_for_each(c, &clients, link) {
if (c->mon != m)
continue;
c->bw =
m->visible_tiling_clients == 1 && no_border_when_single && smartgaps
? 0
: borderpx;
if (VISIBLEON(c, m) && !c->isunglobal &&
((m->isoverview && !client_should_ignore_focus(c)) || ISTILED(c))) {
cx = m->w.x + (i / rows) * (cw + overviewgappi);
cy = m->w.y + (i % rows) * (ch + overviewgappi);
if (overrows && i >= n - overrows) {
cy += dy;
}
c->geom.x = cx + overviewgappo;
c->geom.y = cy + overviewgappo;
c->geom.width = cw - 2 * c->bw;
c->geom.height = ch - 2 * c->bw;
resize(c, c->geom, 0);
i++;
}
}
}
void vertical_deck(Monitor *m) {
unsigned int mh, mx;
int i, n = 0;
Client *c = NULL;
unsigned int cur_gappiv = enablegaps ? m->gappiv : 0;
unsigned int cur_gappoh = enablegaps ? m->gappoh : 0;
unsigned int 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;
cur_gappov = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappov;
n = m->visible_tiling_clients; n = m->visible_tiling_clients;
master_num = m->pertag->nmasters[m->pertag->curtag];
stack_num = n - master_num;
if (n == 0) if (n == 0)
return; return;
float mfact = m->pertag ? m->pertag->mfacts[m->pertag->curtag] : m->mfact; unsigned int cur_gapih = enablegaps ? m->gappih : 0;
unsigned int cur_gapiv = enablegaps ? m->gappiv : 0;
unsigned int cur_gapoh = enablegaps ? m->gappoh : 0;
unsigned int cur_gapov = enablegaps ? m->gappov : 0;
if (n > m->nmaster) cur_gapih = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gapih;
mh = m->nmaster ? round((m->w.height - 2 * cur_gappov) * mfact) : 0; cur_gapiv = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gapiv;
cur_gapoh = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gapoh;
cur_gapov = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gapov;
wl_list_for_each(fc, &clients, link) {
if (VISIBLEON(fc, m) && ISTILED(fc))
break;
}
mfact = fc->master_mfact_per > 0.0f ? fc->master_mfact_per
: m->pertag->mfacts[m->pertag->curtag];
if (n > m->pertag->nmasters[m->pertag->curtag])
mh = m->pertag->nmasters[m->pertag->curtag]
? (m->w.height + cur_gapiv * ie) * mfact
: 0;
else else
mh = m->w.height - 2 * cur_gappov; mh = m->w.height - 2 * cur_gapov + cur_gapiv * ie;
i = mx = 0; i = 0;
mx = tx = cur_gapih;
wl_list_for_each(c, &clients, link) { wl_list_for_each(c, &clients, link) {
if (!VISIBLEON(c, m) || !ISTILED(c)) if (!VISIBLEON(c, m) || !ISTILED(c))
continue; continue;
if (i < m->nmaster) { if (i < m->pertag->nmasters[m->pertag->curtag]) {
resize( r = MIN(n, m->pertag->nmasters[m->pertag->curtag]) - i;
c, if (c->master_inner_per > 0.0f) {
(struct wlr_box){.x = m->w.x + cur_gappoh + mx, w = (m->w.width - 2 * cur_gapih -
.y = m->w.y + cur_gappov, cur_gapih * ie * (master_num - 1)) *
.width = (m->w.width - 2 * cur_gappoh - mx) / c->master_inner_per;
(MIN(n, m->nmaster) - i), c->master_mfact_per = mfact;
.height = mh}, } else {
0); w = (m->w.width - mx - cur_gapih - cur_gapih * ie * (r - 1)) /
mx += c->geom.width; r;
} else { c->master_inner_per = w / (m->w.width - mx - cur_gapih -
cur_gapih * ie * (r - 1));
c->master_mfact_per = mfact;
}
resize(c, resize(c,
(struct wlr_box){.x = m->w.x + cur_gappoh, (struct wlr_box){.x = m->w.x + mx,
.y = m->w.y + mh + cur_gappov + cur_gappiv, .y = m->w.y + cur_gapov,
.width = m->w.width - 2 * cur_gappoh, .width = w,
.height = m->w.height - mh - .height = mh - cur_gapiv * ie},
2 * cur_gappov - cur_gappiv},
0); 0);
if (c == focustop(m)) mx += c->geom.width + cur_gapih * ie;
wlr_scene_node_raise_to_top(&c->scene->node); } else {
r = n - i;
if (c->stack_innder_per > 0.0f) {
w = (m->w.width - 2 * cur_gapih -
cur_gapih * ie * (stack_num - 1)) *
c->stack_innder_per;
c->master_mfact_per = mfact;
} else {
w = (m->w.width - tx - cur_gapih - cur_gapih * ie * (r - 1)) /
r;
c->stack_innder_per = w / (m->w.width - tx - cur_gapih -
cur_gapih * ie * (r - 1));
c->master_mfact_per = mfact;
}
resize(c,
(struct wlr_box){.x = m->w.x + tx,
.y = m->w.y + mh + cur_gapov,
.width = w,
.height = m->w.height - mh - 2 * cur_gapov},
0);
tx += c->geom.width + cur_gapih * ie;
} }
i++; i++;
} }
@ -418,60 +217,3 @@ void vertical_scroller(Monitor *m) {
free(tempClients); free(tempClients);
} }
void vertical_tile(Monitor *m) {
unsigned int i, n = 0, w, r, ie = enablegaps, mh, mx, tx;
Client *c = NULL;
n = m->visible_tiling_clients;
if (n == 0)
return;
unsigned int cur_gappiv = enablegaps ? m->gappiv : 0;
unsigned int cur_gappih = enablegaps ? m->gappih : 0;
unsigned int cur_gappov = enablegaps ? m->gappov : 0;
unsigned int 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;
cur_gappov = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappov;
cur_gappoh = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappoh;
if (n > m->pertag->nmasters[m->pertag->curtag])
mh = m->pertag->nmasters[m->pertag->curtag]
? (m->w.height + cur_gappiv * ie) *
m->pertag->mfacts[m->pertag->curtag]
: 0;
else
mh = m->w.height - 2 * cur_gappoh + cur_gappiv * ie;
i = 0;
mx = tx = cur_gappov;
wl_list_for_each(c, &clients, link) {
if (!VISIBLEON(c, m) || !ISTILED(c))
continue;
if (i < m->pertag->nmasters[m->pertag->curtag]) {
r = MIN(n, m->pertag->nmasters[m->pertag->curtag]) - i;
w = (m->w.width - mx - cur_gappov - cur_gappiv * ie * (r - 1)) / r;
resize(c,
(struct wlr_box){.x = m->w.x + mx,
.y = m->w.y + cur_gappoh,
.width = w,
.height = mh - cur_gappih * ie},
0);
mx += c->geom.width + cur_gappiv * ie;
} else {
r = n - i;
w = (m->w.width - tx - cur_gappov - cur_gappiv * ie * (r - 1)) / r;
resize(
c,
(struct wlr_box){.x = m->w.x + tx,
.y = m->w.y + mh + cur_gappoh,
.width = w,
.height = m->w.height - mh - 2 * cur_gappoh},
0);
tx += c->geom.width + cur_gappiv * ie;
}
i++;
}
}

View file

@ -253,7 +253,8 @@ struct Client {
/* Must keep these three elements in this order */ /* Must keep these three elements in this order */
unsigned int type; /* XDGShell or X11* */ unsigned int type; /* XDGShell or X11* */
struct wlr_box geom, pending, float_geom, animainit_geom, struct wlr_box geom, pending, float_geom, animainit_geom,
overview_backup_geom, current; /* layout-relative, includes border */ overview_backup_geom, current,
drag_begin_geom; /* layout-relative, includes border */
Monitor *mon; Monitor *mon;
struct wlr_scene_tree *scene; struct wlr_scene_tree *scene;
struct wlr_scene_rect *border; /* top, bottom, left, right */ struct wlr_scene_rect *border; /* top, bottom, left, right */
@ -337,6 +338,12 @@ struct Client {
float unfocused_opacity; float unfocused_opacity;
char oldmonname[128]; char oldmonname[128];
int noblur; int noblur;
double master_mfact_per, master_inner_per, stack_innder_per;
double old_master_mfact_per, old_master_inner_per, old_stack_innder_per;
double old_scroller_pproportion;
bool ismaster;
bool cursor_in_upper_half, cursor_in_left_half;
bool isleftstack;
}; };
typedef struct { typedef struct {
@ -413,6 +420,7 @@ typedef struct {
const char *symbol; const char *symbol;
void (*arrange)(Monitor *); void (*arrange)(Monitor *);
const char *name; const char *name;
unsigned int id;
} Layout; } Layout;
struct Monitor { struct Monitor {
@ -706,6 +714,9 @@ static unsigned int get_tag_status(unsigned int tag, Monitor *m);
static void enable_adaptive_sync(Monitor *m, struct wlr_output_state *state); static void enable_adaptive_sync(Monitor *m, struct wlr_output_state *state);
static Client *get_next_stack_client(Client *c, bool reverse); static Client *get_next_stack_client(Client *c, bool reverse);
static void set_float_malposition(Client *tc); 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, unsigned int time);
#include "data/static_keymap.h" #include "data/static_keymap.h"
#include "dispatch/bind_declare.h" #include "dispatch/bind_declare.h"
@ -765,7 +776,10 @@ static struct wl_list keyboards;
static struct wl_list inputdevices; static struct wl_list inputdevices;
static unsigned int cursor_mode; static unsigned int cursor_mode;
static Client *grabc; static Client *grabc;
static int grabcx, grabcy; /* client-relative */ static int grabcx, grabcy; /* client-relative */
static int drag_begin_cursorx, drag_begin_cursory; /* client-relative */
static bool start_drag_window = false;
static int last_apply_drap_time = 0;
static struct wlr_output_layout *output_layout; static struct wlr_output_layout *output_layout;
static struct wlr_box sgeom; static struct wlr_box sgeom;
@ -806,11 +820,10 @@ static struct {
#include "config/preset.h" #include "config/preset.h"
struct Pertag { struct Pertag {
unsigned int curtag, prevtag; /* current and previous tag */ unsigned int curtag, prevtag; /* current and previous tag */
int nmasters[LENGTH(tags) + 1]; /* number of windows in master area */ int nmasters[LENGTH(tags) + 1]; /* number of windows in master area */
float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */ float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */
float smfacts[LENGTH(tags) + 1]; /* smfacts per tag */ bool no_hide[LENGTH(tags) + 1]; /* no_hide per tag */
bool no_hide[LENGTH(tags) + 1]; /* no_hide per tag */
const Layout const Layout
*ltidxs[LENGTH(tags) + 1]; /* matrix of tags and layouts indexes */ *ltidxs[LENGTH(tags) + 1]; /* matrix of tags and layouts indexes */
}; };
@ -868,6 +881,7 @@ static struct wlr_xwayland *xwayland;
#include "dispatch/bind_define.h" #include "dispatch/bind_define.h"
#include "ext-protocol/all.h" #include "ext-protocol/all.h"
#include "fetch/fetch.h" #include "fetch/fetch.h"
#include "layout/arrange.h"
#include "layout/horizontal.h" #include "layout/horizontal.h"
#include "layout/vertical.h" #include "layout/vertical.h"
@ -1291,6 +1305,8 @@ void applyrules(Client *c) {
} }
} }
set_size_per(mon, c);
// if no geom rule hit and is normal winodw, use the center pos and record // if no geom rule hit and is normal winodw, use the center pos and record
// the hit size // the hit size
if (!hit_rule_pos && if (!hit_rule_pos &&
@ -1366,57 +1382,6 @@ void applyrules(Client *c) {
} }
} }
void // 17
arrange(Monitor *m, bool want_animation) {
Client *c = NULL;
if (!m)
return;
if (!m->wlr_output->enabled)
return;
m->visible_clients = 0;
m->visible_tiling_clients = 0;
wl_list_for_each(c, &clients, link) {
if (c->iskilling)
continue;
if (c->mon == m && (c->isglobal || c->isunglobal)) {
c->tags = m->tagset[m->seltags];
if (c->mon->sel == NULL)
focusclient(c, 0);
}
if (c->mon == m) {
if (VISIBLEON(c, m)) {
m->visible_clients++;
if (ISTILED(c))
m->visible_tiling_clients++;
set_arrange_visible(m, c, want_animation);
} else {
set_arrange_hidden(m, c, want_animation);
}
}
if (c->mon == m && c->ismaxmizescreen && !c->animation.tagouted &&
!c->animation.tagouting && VISIBLEON(c, m)) {
reset_maxmizescreen_size(c);
}
}
if (m->isoverview) {
overviewlayout.arrange(m);
} else {
m->pertag->ltidxs[m->pertag->curtag]->arrange(m);
}
motionnotify(0, NULL, 0, 0, 0, 0);
checkidleinhibitor(NULL);
}
void arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, void arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area,
int exclusive) { int exclusive) {
LayerSurface *l = NULL; LayerSurface *l = NULL;
@ -1917,6 +1882,8 @@ buttonpress(struct wl_listener *listener, void *data) {
selmon->sel = grabc; selmon->sel = grabc;
tmpc = grabc; tmpc = grabc;
grabc = NULL; grabc = NULL;
start_drag_window = false;
last_apply_drap_time = 0;
if (tmpc->drag_to_tile && drag_tile_to_tile) { if (tmpc->drag_to_tile && drag_tile_to_tile) {
place_drag_tile_client(tmpc); place_drag_tile_client(tmpc);
} else { } else {
@ -2667,7 +2634,6 @@ void createmon(struct wl_listener *listener, void *data) {
for (i = 0; i <= LENGTH(tags); i++) { for (i = 0; i <= LENGTH(tags); i++) {
m->pertag->nmasters[i] = m->nmaster; m->pertag->nmasters[i] = m->nmaster;
m->pertag->mfacts[i] = m->mfact; m->pertag->mfacts[i] = m->mfact;
m->pertag->smfacts[i] = default_smfact;
m->pertag->ltidxs[i] = m->lt; m->pertag->ltidxs[i] = m->lt;
} }
@ -3542,6 +3508,9 @@ void init_client_properties(Client *c) {
c->ignore_maximize = 0; c->ignore_maximize = 0;
c->ignore_minimize = 1; c->ignore_minimize = 1;
c->iscustomsize = 0; c->iscustomsize = 0;
c->master_mfact_per = 0.0f;
c->master_inner_per = 0.0f;
c->stack_innder_per = 0.0f;
} }
void // old fix to 0.5 void // old fix to 0.5
@ -3866,14 +3835,18 @@ void motionnotify(unsigned int time, struct wlr_input_device *device, double dx,
resize(grabc, grabc->float_geom, 1); resize(grabc, grabc->float_geom, 1);
return; return;
} else if (cursor_mode == CurResize) { } else if (cursor_mode == CurResize) {
grabc->iscustomsize = 1; if (grabc->isfloating) {
grabc->float_geom = grabc->iscustomsize = 1;
(struct wlr_box){.x = grabc->geom.x, grabc->float_geom = (struct wlr_box){
.y = grabc->geom.y, .x = grabc->geom.x,
.width = (int)round(cursor->x) - grabc->geom.x, .y = grabc->geom.y,
.height = (int)round(cursor->y) - grabc->geom.y}; .width = (int)round(cursor->x) - grabc->geom.x,
resize(grabc, grabc->float_geom, 1); .height = (int)round(cursor->y) - grabc->geom.y};
return; resize(grabc, grabc->float_geom, 1);
return;
} else {
resize_tile_client(grabc, true, 0, 0, time);
}
} }
/* If there's no client surface under the cursor, set the cursor image /* If there's no client surface under the cursor, set the cursor image
@ -4174,12 +4147,27 @@ void exchange_two_client(Client *c1, Client *c2) {
Monitor *tmp_mon = NULL; Monitor *tmp_mon = NULL;
unsigned int tmp_tags; unsigned int tmp_tags;
double master_inner_per = 0.0f;
double master_mfact_per = 0.0f;
double stack_innder_per = 0.0f;
if (c1 == NULL || c2 == NULL || if (c1 == NULL || c2 == NULL ||
(!exchange_cross_monitor && c1->mon != c2->mon)) { (!exchange_cross_monitor && c1->mon != c2->mon)) {
return; return;
} }
master_inner_per = c1->master_inner_per;
master_mfact_per = c1->master_mfact_per;
stack_innder_per = c1->stack_innder_per;
c1->master_inner_per = c2->master_inner_per;
c1->master_mfact_per = c2->master_mfact_per;
c1->stack_innder_per = c2->stack_innder_per;
c2->master_inner_per = master_inner_per;
c2->master_mfact_per = master_mfact_per;
c2->stack_innder_per = stack_innder_per;
struct wl_list *tmp1_prev = c1->link.prev; struct wl_list *tmp1_prev = c1->link.prev;
struct wl_list *tmp2_prev = c2->link.prev; struct wl_list *tmp2_prev = c2->link.prev;
struct wl_list *tmp1_next = c1->link.next; struct wl_list *tmp1_next = c1->link.next;
@ -4403,6 +4391,10 @@ setfloating(Client *c, int floating) {
layers[c->isfloating ? LyrTop : LyrTile]); layers[c->isfloating ? LyrTop : LyrTile]);
} }
if (!c->isfloating) {
set_size_per(c->mon, c);
}
arrange(c->mon, false); arrange(c->mon, false);
setborder_color(c); setborder_color(c);
printstatus(); printstatus();
@ -4447,12 +4439,15 @@ void setmaxmizescreen(Client *c, int maxmizescreen) {
c->ismaxmizescreen = 0; c->ismaxmizescreen = 0;
if (c->isfloating) if (c->isfloating)
setfloating(c, 1); setfloating(c, 1);
arrange(c->mon, false);
} }
wlr_scene_node_reparent(&c->scene->node, layers[maxmizescreen ? LyrTile wlr_scene_node_reparent(&c->scene->node, layers[maxmizescreen ? LyrTile
: c->isfloating ? LyrTop : c->isfloating ? LyrTop
: LyrTile]); : LyrTile]);
if (!c->ismaxmizescreen) {
set_size_per(c->mon, c);
}
arrange(c->mon, false);
} }
void setfakefullscreen(Client *c, int fakefullscreen) { void setfakefullscreen(Client *c, int fakefullscreen) {
@ -4508,6 +4503,10 @@ void setfullscreen(Client *c, int fullscreen) // 用自定义全屏代理自带
layers[fullscreen || c->isfloating ? LyrTop : LyrTile]); layers[fullscreen || c->isfloating ? LyrTop : LyrTile]);
} }
if (!c->isfullscreen) {
set_size_per(c->mon, c);
}
arrange(c->mon, false); arrange(c->mon, false);
} }