Compare commits

..

No commits in common. "main" and "0.14.0" have entirely different histories.
main ... 0.14.0

26 changed files with 518 additions and 781 deletions

View file

@ -88,7 +88,7 @@ bindr=Super,Super_L,spawn,rofi -show run
| Command | Param | Description |
| :--- | :--- | :--- |
| `killclient` | `force` | Close the focused window. If `force` is specified, sends `SIGKILL`. |
| `killclient` | - | Close the focused window. |
| `togglefloating` | - | Toggle floating state. |
| `toggle_all_floating` | - | Toggle all visible clients floating state. |
| `togglefullscreen` | - | Toggle fullscreen. |

View file

@ -21,7 +21,6 @@ description: Advanced settings for XWayland, focus behavior, and system integrat
| `sloppyfocus` | `1` | Focus follows the mouse cursor. |
| `warpcursor` | `1` | Warp the cursor to the center of the window when focus changes via keyboard. |
| `cursor_hide_timeout` | `0` | Hide the cursor after `N` seconds of inactivity (`0` to disable). |
| `cursor_hide_on_keypress` | `0` | Hide the cursor on keypress. |
| `drag_tile_to_tile` | `0` | Allow dragging a tiled window onto another to swap their positions. |
| `drag_tile_small` | `1` | Allow dragging a tiled window temporarily to small size.|
| `drag_corner` | `3` | Corner for drag-to-tile detection (0: none, 13: corners, 4: auto-detect). |

View file

@ -163,8 +163,6 @@ Some GPUs have compatibility issues with `syncobj_enable=1` — it may crash app
## Power Management
You can control monitor power using the `mmsg` IPC tool.
> Notice: This command does not remove the monitor, it only turns it off.
> if you want completely remove monitor, just use `wlr-randr`
```bash
# Turn off
@ -180,13 +178,13 @@ mmsg dispatch toggle_monitor,eDP-1
You can also use `wlr-randr` for monitor management:
```bash
# remove a monitor
# Turn off monitor
wlr-randr --output eDP-1 --off
# add a monitor
# Turn on monitor
wlr-randr --output eDP-1 --on
# Show all monitors spec
# Show all monitors
wlr-randr
```

View file

@ -18,7 +18,6 @@ You can install it using the `moss` package manager:
```bash
sudo moss install mangowm
```
* The Default config will be located at `/usr/share/defaults/mango`.
---

View file

@ -14,7 +14,7 @@ Instead, compose your own workflow from small Wayland utilities and bind them to
| [`slurp`](https://github.com/emersion/slurp) | Interactively select a region for `grim` |
| [`wl-copy`](https://github.com/bugaevc/wl-clipboard) | Copy screenshots directly to the clipboard |
| [`satty`](https://github.com/gabm/Satty) | Annotate screenshots before saving |
| [`wayfreeze`](https://github.com/Jappie3/wayfreeze) | Freeze the screen before capture |
| [`wayfreeze`](https://github.com/nicbk/wayfreeze) | Freeze the screen before capture |
Install the required with your package manager or from source.

View file

@ -115,7 +115,7 @@ windowrule=width:1000,height:900,appid:yesplaymusic,title:Demons
# Global keybindings for OBS Studio
windowrule=globalkeybinding:ctrl+alt-o,appid:com.obsproject.Studio
windowrule=globalkeybinding:ctrl+alt-n,appid:com.obsproject.Studio
windowrule=globalkeybinding:ctrl+alt+n,appid:com.obsproject.Studio
windowrule=isopensilent:1,appid:com.obsproject.Studio
# Force tearing for games
@ -183,9 +183,6 @@ tagrule=id:Values,monitor_make:xxx,monitor_model:xxx,Parameter:Values
| `no_hide` | integer | `0` / `1` | Not hide even if the tag is empty |
| `nmaster` | integer | 0, 99 | Number of master windows |
| `mfact` | float | 0.10.9 | Master area factor |
| `scroller_default_proportion` | float | 0.1-1.0 | Set scroller default proportion. |
| `scroller_default_proportion_single` | float | 0.1-1.0 | Set scroller auto adjust proportion when it is single window(only apply when set `scroller_ignore_proportion_single` to `0`) |
| `scroller_ignore_proportion_single` | integer | `0` / `1` | Ignore scroller single proportion setting. |
### Examples
@ -207,10 +204,6 @@ tagrule=id:4,monitor_name:eDP-1,no_hide:1,layout_name:scroller
# Advanced tag configuration with master layout settings
tagrule=id:5,layout_name:tile,nmaster:2,mfact:0.6
tagrule=id:6,monitor_name:HDMI-A-1,layout_name:monocle,no_render_border:1
# set scroller proportion for specific tag
tagrule=id:1,layout_name:scroller,scroller_default_proportion_single:0.5,scroller_ignore_proportion_single:0,scroller_default_proportion:0.9,monitor_name:HDMI-A-1
```
> **Tip:** For Waybar configuration with persistent tags, see [Status Bar](/docs/visuals/status-bar) documentation.

View file

@ -10,7 +10,7 @@
#:use-module (gnu packages pciutils)
#:use-module (gnu packages admin)
#:use-module (gnu packages pcre)
#:use-module (gnu packages javascript)
#:use-module (gnu packages cjson)
#:use-module (gnu packages xorg)
#:use-module (gnu packages build-tools)
#:use-module (gnu packages ninja)

View file

@ -1,5 +1,5 @@
project('mango', ['c'],
version : '0.14.3',
project('mango', ['c', 'cpp'],
version : '0.14.0',
)
subdir('protocols')
@ -24,6 +24,10 @@ if sysconfdir.startswith(prefix) and not is_nixos
endif
endif
# 打印调试信息,确认 sysconfdir 的值
# message('prefix: ' + prefix)
# message('sysconfdir: ' + sysconfdir)
cc = meson.get_compiler('c')
libm = cc.find_library('m')
xcb = dependency('xcb', required : get_option('xwayland'))
@ -38,11 +42,12 @@ libscenefx_dep = dependency('scenefx-0.4',version: '>=0.4.1')
pixman_dep = dependency('pixman-1')
cjson_dep = dependency('libcjson')
# version info
# 获取版本信息
git = find_program('git', required : false)
is_git_repo = false
# check if current directory is a git repo
# 检查当前目录是否是 Git 仓库
if git.found()
git_status = run_command(git, 'rev-parse', '--is-inside-work-tree', check : false)
if git_status.returncode() == 0 and git_status.stdout().strip() == 'true'
@ -51,18 +56,18 @@ if git.found()
endif
if is_git_repo
# if current directory is a git repo, get commit hash and latest tag
# 如果是 Git 目录,获取 Commit Hash 和最新的 tag
commit_hash = run_command(git, 'rev-parse', '--short', 'HEAD', check : false).stdout().strip()
latest_tag = meson.project_version()
version_with_hash = '@0@(@1@)'.format(latest_tag, commit_hash)
else
# if not a git repo, use project version and "release" string
# 如果不是 Git 目录,使用项目版本号和 "release" 字符串
commit_hash = 'release'
latest_tag = meson.project_version()
version_with_hash = '@0@(@1@)'.format(latest_tag, commit_hash)
endif
# define compilation args
# 定义编译参数
c_args = [
'-g',
'-Wno-unused-function',
@ -72,7 +77,7 @@ c_args = [
'-DSYSCONFDIR="@0@"'.format('/etc'),
]
# add debug args only when debug option is enabled
# 仅在 debug 选项启用时添加调试参数
if get_option('asan')
c_args += [
'-fsanitize=address',
@ -85,7 +90,7 @@ if xcb.found() and xlibs.found()
c_args += '-DXWAYLAND'
endif
# define link args
# 链接参数(根据 debug 状态添加 ASAN
link_args = []
if get_option('asan')
link_args += '-fsanitize=address'
@ -130,7 +135,7 @@ wayland_scanner_private_code = generator(
arguments: ['private-code', '@INPUT@', '@OUTPUT@']
)
# use generator in mmsg target
# 在 mmsg 目标中使用生成器
executable('mmsg',
'mmsg/mmsg.c',
wayland_scanner_private_code.process(dwl_ipc_protocol),
@ -145,10 +150,8 @@ executable('mmsg',
],
)
mandir = get_option('mandir')
desktop_install_dir = join_paths(prefix, 'share/wayland-sessions')
portal_install_dir = join_paths(prefix, 'share/xdg-desktop-portal')
install_data('assets/mango.desktop', install_dir : desktop_install_dir)
install_data('assets/mango-portals.conf', install_dir : portal_install_dir)
install_data('assets/config.conf', install_dir : join_paths(sysconfdir, 'mango'))
install_data('mmsg/mmsg.1', install_dir : join_paths(mandir, 'man1'))

View file

@ -1,122 +0,0 @@
.TH "mmsg" "1" "2026-05-31" "mmsg 0.14.0" "mmsg manual"
.SH NAME
mmsg \- send commands to the mango Wayland compositor and receive JSON responses
.SH SYNOPSIS
\fBmmsg\fR <command> [\fIargs\fR...]
.br
\fBmmsg\fR \-\-help | \-h | help
.SH DESCRIPTION
\fBmmsg\fR connects to a running \fBmango\fR(1) compositor via the UNIX domain socket
specified by the \fIMANGO_INSTANCE_SIGNATURE\fR environment variable. It sends
the given command and prints the JSON reply to standard output. In \fBwatch\fR
mode it keeps the connection open and prints a stream of updates as they
occur.
.PP
If \fB\-\-help\fR, \fB\-h\fR or \fBhelp\fR is given, a complete usage summary is printed and
the program exits with success.
.SH COMMANDS
.SS "One\-shot queries (get)"
All \fBget\fR commands print a single JSON object and then close the connection.
.TP
\fBget version\fR
Return compositor version.
.TP
\fBget keymode\fR
Return current keymode.
.TP
\fBget keyboardlayout\fR
Return current keyboard layout.
.TP
\fBget last_open_surface\fR [\fImonitor\fR]
Return the last open surface (application) for the given monitor.
If \fImonitor\fR is omitted the focused monitor is used.
.TP
\fBget monitor\fR <name>
Return details of the named monitor.
.TP
\fBget focusing\-client\fR
Return details of the currently focused client.
.TP
\fBget client\fR <id>
Return details of the client with the given numeric ID.
.TP
\fBget tag\fR <monitor> <index>
Return details of a specific tag (1\-based index) on the named monitor.
.TP
\fBget all\-clients\fR
List all clients.
.TP
\fBget all\-monitors\fR
List all monitors.
.TP
\fBget all\-tags\fR
List tags for all monitors.
.TP
\fBget tags\fR <monitor>
List tags for a specific monitor.
.TP
\fBdispatch\fR <func>[,arg...] [client,<id>]
Invoke an internal compositor function.
The function name and its arguments are separated by commas.
Optionally add \fBclient,<id>\fR (before or after the function) to target a
specific client.
.br
Examples:
.RS
.IP \(bu 2
\fBmmsg dispatch togglefloating\fR
.IP \(bu 2
\fBmmsg dispatch movewin,10,100\fR
.IP \(bu 2
\fBmmsg dispatch movewin,10,100 client,4\fR
.RE
.SS "Persistent streams (watch)"
\fBWatch\fR commands keep the connection open and continuously output JSON
updates. The initial state is sent immediately, followed by updates whenever
relevant changes occur.
.TP
\fBwatch monitor\fR <name>
Stream updates for the named monitor.
.TP
\fBwatch focusing\-client\fR
Stream updates for the focused client.
.TP
\fBwatch client\fR <id>
Stream updates for the client with the given ID.
.TP
\fBwatch tags\fR <monitor>
Stream tag updates for the named monitor.
.TP
\fBwatch all\-monitors\fR
Stream updates for all monitors.
.TP
\fBwatch all\-tags\fR
Stream updates for all tags.
.TP
\fBwatch all\-clients\fR
Stream updates for all clients.
.TP
\fBwatch keymode\fR
Stream keymode changes.
.TP
\fBwatch keyboardlayout\fR
Stream keyboard layout changes.
.TP
\fBwatch last_open_surface\fR [\fImonitor\fR]
Stream last open surface changes for a specific monitor (or the focused one).
.SH ENVIRONMENT
.TP
\fIMANGO_INSTANCE_SIGNATURE\fR
Path to the compositor's IPC socket. Set automatically by \fBmango\fR(1).
If unset, \fBmmsg\fR prints an error and exits.
.SH EXIT STATUS
.TP
\fB0\fR
Success (or help message printed).
.TP
\fBEXIT_FAILURE\fR
An error occurred (connection refused, send/receive error, etc.).
.SH SEE ALSO
\fBmango\fR(1)
.SH BUGS
Report issues at the project's issue tracker.

View file

@ -7,73 +7,7 @@
#include <sys/un.h>
#include <unistd.h>
static void usage(void) {
printf("Usage: mmsg <command> [args...]\n\n");
printf("One-shot queries (get):\n");
printf(
" get version Show compositor version\n");
printf(" get keymode Show current keymode\n");
printf(" get keyboardlayout Show current keyboard "
"layout\n");
printf(" get last_open_surface [monitor] Show last open surface "
"(default focused monitor)\n");
printf(" get monitor <name> Show monitor details\n");
printf(" get focusing-client Show focused client "
"details\n");
printf(" get client <id> Show client details by "
"ID\n");
printf(" get tag <monitor> <index> Show tag details "
"(1based index)\n");
printf(" get all-clients List all clients\n");
printf(" get all-monitors List all monitors\n");
printf(" get all-tags List all tags (all "
"monitors)\n");
printf(
" get tags <monitor> List tags for a monitor\n");
printf(" dispatch <func>[,arg...] [client,<id>] Call a compositor "
"function\n");
printf(" <func> and arguments are separated by commas.\n");
printf(" Add 'client,<id>' at the beginning or end to target a "
"specific client.\n");
printf(" Examples:\n");
printf(" dispatch togglefloating\n");
printf(" dispatch movewin,10,100\n");
printf(" dispatch movewin,10,100 client,4\n");
printf("Persistent streams (watch):\n");
printf(
" watch monitor <name> Stream monitor changes\n");
printf(" watch focusing-client Stream focused client "
"changes\n");
printf(
" watch client <id> Stream client changes\n");
printf(" watch tags <monitor> Stream tag changes for "
"a monitor\n");
printf(" watch all-monitors Stream all monitors "
"changes\n");
printf(
" watch all-tags Stream all tags changes\n");
printf(" watch all-clients Stream all clients "
"changes\n");
printf(
" watch keymode Stream keymode changes\n");
printf(" watch keyboardlayout Stream keyboard layout "
"changes\n");
printf(" watch last_open_surface [monitor] Stream last open "
"surface changes\n\n");
printf("Environment:\n");
printf(" MANGO_INSTANCE_SIGNATURE IPC socket path (set by the "
"compositor)\n\n");
printf("Run 'mmsg --help', '-h' or 'help' to see this message.\n");
}
int main(int argc, char *argv[]) {
if (argc >= 2 &&
(strcmp(argv[1], "--help") == 0 || strcmp(argv[1], "-h") == 0 ||
strcmp(argv[1], "help") == 0)) {
usage();
return EXIT_SUCCESS;
}
if (argc < 2) {
fprintf(stderr, "Usage: mmsg <command> [args...]\n");
fprintf(stderr, " get <type> ... one-shot request\n");
@ -103,6 +37,7 @@ int main(int argc, char *argv[]) {
return EXIT_FAILURE;
}
// 拼接命令,缓冲区大小 4096 以容纳较长参数
char cmd[4096] = {0};
int offset = 0;
for (int i = 1; i < argc; i++) {
@ -116,6 +51,7 @@ int main(int argc, char *argv[]) {
offset += n;
}
// 添加换行符
int n = snprintf(cmd + offset, sizeof(cmd) - offset, "\n");
if (n < 0 || n >= (int)(sizeof(cmd) - offset)) {
fprintf(stderr, "Error: command too long to append newline.\n");
@ -123,12 +59,14 @@ int main(int argc, char *argv[]) {
return EXIT_FAILURE;
}
// 发送命令,使用 MSG_NOSIGNAL 避免 SIGPIPE
if (send(sock, cmd, strlen(cmd), MSG_NOSIGNAL) < 0) {
perror("send");
close(sock);
return EXIT_FAILURE;
}
// 将 socket 封装为行缓冲文件流,自动处理 TCP 拆包,按完整行读取
FILE *stream = fdopen(sock, "r");
if (!stream) {
perror("fdopen");
@ -136,6 +74,7 @@ int main(int argc, char *argv[]) {
return EXIT_FAILURE;
}
// 按行读取并输出直到连接关闭get 模式服务端主动 close或出错
char *line = NULL;
size_t len = 0;
while (getline(&line, &len, stream) != -1) {
@ -143,10 +82,11 @@ int main(int argc, char *argv[]) {
fflush(stdout);
}
// 检查是否因读取错误退出(而非正常 EOF
if (ferror(stream)) {
perror("recv");
free(line);
fclose(stream);
fclose(stream); // 关闭 stream 同时关闭 socket
return EXIT_FAILURE;
}

View file

@ -51,7 +51,7 @@ static void finish_exchange_arrange_and_focus(Client *c1, Client *c2,
}
void client_tile_resize(Client *c, struct wlr_box geo, int32_t interact) {
if (!ISFAKETILED(c))
if (!ISSCROLLTILED(c))
return;
if (!c->isfullscreen && !c->ismaximizescreen) {
@ -87,9 +87,3 @@ void client_active(Client *c) {
view_in_mon(&(Arg){.ui = target}, true, c->mon, true);
focusclient(c, 1);
}
void client_pending_force_kill(Client *c) {
if (!c)
return;
kill(c->pid, SIGKILL);
}

View file

@ -305,8 +305,7 @@ void client_draw_shadow(Client *c) {
if (c->iskilling || !client_surface(c)->mapped || c->isnoshadow)
return;
if (!config.shadows || c->isfullscreen ||
(!c->isfloating && config.shadow_only_floating)) {
if (!config.shadows || (!c->isfloating && config.shadow_only_floating)) {
if (c->shadow->node.enabled)
wlr_scene_node_set_enabled(&c->shadow->node, false);
return;
@ -406,7 +405,7 @@ void apply_split_border(Client *c, bool hit_no_border) {
const Layout *layout = c->mon->pertag->ltidxs[c->mon->pertag->curtag];
if (hit_no_border || !ISTILED(c) || layout->id != DWINDLE ||
!config.dwindle_manual_split || c->isfullscreen) {
!config.dwindle_manual_split) {
if (c->splitindicator[0]->node.enabled) {
wlr_scene_node_set_enabled(&c->splitindicator[0]->node, false);
}
@ -493,18 +492,6 @@ void apply_border(Client *c) {
if (!c || c->iskilling || !client_surface(c)->mapped)
return;
if (c->isfullscreen) {
if (c->border->node.enabled) {
wlr_scene_node_set_position(&c->scene_surface->node, 0, 0);
wlr_scene_node_set_enabled(&c->border->node, false);
}
return;
} else {
if (!c->border->node.enabled) {
wlr_scene_node_set_enabled(&c->border->node, true);
}
}
bool hit_no_border = check_hit_no_border(c);
apply_split_border(c, hit_no_border);
@ -699,6 +686,17 @@ void client_set_drop_area(Client *c) {
bool dwindle_familiar =
cur_layout->id == DWINDLE && config.dwindle_drop_simple_split;
uint32_t nmaster = c->mon->pertag->nmasters[c->mon->pertag->curtag];
bool should_swap =
(cur_layout->id == DECK || cur_layout->id == VERTICAL_DECK ||
cur_layout->id == MONOCLE || cur_layout->id == GRID ||
cur_layout->id == FAIR || cur_layout->id == VERTICAL_FAIR ||
cur_layout->id == VERTICAL_GRID) ||
((cur_layout->id == TILE || cur_layout->id == VERTICAL_TILE ||
cur_layout->id == CENTER_TILE || cur_layout->id == RIGHT_TILE) &&
nmaster == 1 && c->ismaster);
if (dwindle_familiar) {
bool split_h = c->geom.width >= c->geom.height;
float ratio = config.dwindle_split_ratio;
@ -732,87 +730,42 @@ void client_set_drop_area(Client *c) {
client_height - (int32_t)(client_height * ratio);
}
}
} else if (should_swap) {
drop_box.x = bw;
drop_box.y = bw;
drop_box.width = client_width;
drop_box.height = client_height;
drop_direction = UNDIR;
} else if (cur_layout->id == TILE || cur_layout->id == DECK ||
cur_layout->id == CENTER_TILE || cur_layout->id == RIGHT_TILE) {
if (c->ismaster) {
if (c->mon->visible_tiling_clients == 1) {
if (rel_x < client_width * 0.5) {
drop_direction = LEFT;
drop_box.x = bw;
drop_box.y = bw;
drop_box.width = client_width / 2;
drop_box.height = client_height;
} else {
drop_direction = RIGHT;
drop_box.x = bw + client_width / 2;
drop_box.y = bw;
drop_box.width = client_width / 2;
drop_box.height = client_height;
}
} else {
drop_box.x = bw;
drop_box.y = bw;
drop_box.width = client_width;
drop_box.height = client_height;
drop_direction = UNDIR;
}
if (rel_y < client_height * 0.5) {
drop_direction = UP;
drop_box.x = bw;
drop_box.y = bw;
drop_box.width = client_width;
drop_box.height = client_height / 2;
} else {
if (rel_y < client_height * 0.5) {
drop_direction = UP;
drop_box.x = bw;
drop_box.y = bw;
drop_box.width = client_width;
drop_box.height = client_height / 2;
} else {
drop_direction = DOWN;
drop_box.x = bw;
drop_box.y = bw + client_height / 2;
drop_box.width = client_width;
drop_box.height = client_height / 2;
}
drop_direction = DOWN;
drop_box.x = bw;
drop_box.y = bw + client_height / 2;
drop_box.width = client_width;
drop_box.height = client_height / 2;
}
} else if (cur_layout->id == VERTICAL_TILE ||
cur_layout->id == VERTICAL_DECK) {
if (c->ismaster) {
if (c->mon->visible_tiling_clients == 1) {
if (rel_y < client_height * 0.5) {
drop_direction = UP;
drop_box.x = bw;
drop_box.y = bw;
drop_box.width = client_width;
drop_box.height = client_height / 2;
} else {
drop_direction = DOWN;
drop_box.x = bw;
drop_box.y = bw + client_height / 2;
drop_box.width = client_width;
drop_box.height = client_height / 2;
}
} else {
drop_box.x = bw;
drop_box.y = bw;
drop_box.width = client_width;
drop_box.height = client_height;
drop_direction = UNDIR;
}
if (rel_x < client_width * 0.5) {
drop_direction = LEFT;
drop_box.x = bw;
drop_box.y = bw;
drop_box.width = client_width / 2;
drop_box.height = client_height;
} else {
if (rel_x < client_width * 0.5) {
drop_direction = LEFT;
drop_box.x = bw;
drop_box.y = bw;
drop_box.width = client_width / 2;
drop_box.height = client_height;
} else {
drop_direction = RIGHT;
drop_box.x = bw + client_width / 2;
drop_box.y = bw;
drop_box.width = client_width / 2;
drop_box.height = client_height;
}
drop_direction = RIGHT;
drop_box.x = bw + client_width / 2;
drop_box.y = bw;
drop_box.width = client_width / 2;
drop_box.height = client_height;
}
} else {
double dist_left = rel_x;
double dist_right = client_width - rel_x;

View file

@ -117,9 +117,6 @@ void set_arrange_hidden(Monitor *m, Client *c, bool want_animation) {
c->animation.tagining = false;
set_tagout_animation(m, c);
} else {
c->animation.running = false;
wlr_scene_node_set_enabled(&c->scene->node, false);
c->animainit_geom = c->current = c->pending = c->animation.current =
c->geom;
}
}

View file

@ -167,9 +167,6 @@ typedef struct {
char *monitor_serial;
float mfact;
int32_t nmaster;
float scroller_default_proportion;
float scroller_default_proportion_single;
int32_t scroller_ignore_proportion_single;
int32_t no_render_border;
int32_t open_as_floating;
int32_t no_hide;
@ -264,7 +261,6 @@ typedef struct {
int32_t overviewgappi;
int32_t overviewgappo;
uint32_t cursor_hide_timeout;
uint32_t cursor_hide_on_keypress;
uint32_t axis_bind_apply_timeout;
uint32_t focus_on_activate;
@ -563,26 +559,6 @@ int32_t parse_direction(const char *str) {
}
}
int32_t parse_force(const char *str) {
// 将输入字符串转换为小写
char lowerStr[10];
int32_t i = 0;
while (str[i] && i < 9) {
lowerStr[i] = tolower(str[i]);
i++;
}
lowerStr[i] = '\0';
// 根据转换后的小写字符串返回对应的枚举值
if (strcmp(lowerStr, "unforce") == 0) {
return UNFORCE;
} else if (strcmp(lowerStr, "force") == 0) {
return FORCE;
} else {
return UNFORCE;
}
}
int32_t parse_fold_state(const char *str) {
// 将输入字符串转换为小写
char lowerStr[10];
@ -1053,7 +1029,6 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value,
(*arg).i = atoi(arg_value);
} else if (strcmp(func_name, "killclient") == 0) {
func = killclient;
(*arg).i = parse_force(arg_value);
} else if (strcmp(func_name, "centerwin") == 0) {
func = centerwin;
} else if (strcmp(func_name, "focuslast") == 0) {
@ -1718,8 +1693,6 @@ bool parse_option(Config *config, char *key, char *value) {
config->overviewgappo = atoi(value);
} else if (strcmp(key, "cursor_hide_timeout") == 0) {
config->cursor_hide_timeout = atoi(value);
} else if (strcmp(key, "cursor_hide_on_keypress") == 0) {
config->cursor_hide_on_keypress = atoi(value);
} else if (strcmp(key, "axis_bind_apply_timeout") == 0) {
config->axis_bind_apply_timeout = atoi(value);
} else if (strcmp(key, "focus_on_activate") == 0) {
@ -2044,9 +2017,6 @@ bool parse_option(Config *config, char *key, char *value) {
rule->no_render_border = 0;
rule->open_as_floating = 0;
rule->no_hide = 0;
rule->scroller_default_proportion = 0.0f;
rule->scroller_default_proportion_single = 0.0f;
rule->scroller_ignore_proportion_single = -1;
bool parse_error = false;
char *token = strtok(value, ",");
@ -2082,17 +2052,6 @@ bool parse_option(Config *config, char *key, char *value) {
rule->nmaster = CLAMP_INT(atoi(val), 1, 99);
} else if (strcmp(key, "mfact") == 0) {
rule->mfact = CLAMP_FLOAT(atof(val), 0.1f, 0.9f);
} else if (strcmp(key, "scroller_default_proportion") == 0) {
rule->scroller_default_proportion =
CLAMP_FLOAT(atof(val), 0.0f, 1.0f);
} else if (strcmp(key, "scroller_default_proportion_single") ==
0) {
rule->scroller_default_proportion_single =
CLAMP_FLOAT(atof(val), 0.0f, 1.0f);
} else if (strcmp(key, "scroller_ignore_proportion_single") ==
0) {
rule->scroller_ignore_proportion_single =
CLAMP_INT(atoi(val), 0, 1);
} else {
fprintf(stderr,
"\033[1m\033[31m[ERROR]:\033[33m Unknown "
@ -3366,8 +3325,6 @@ void override_config(void) {
CLAMP_INT(config.no_radius_when_single, 0, 1);
config.cursor_hide_timeout =
CLAMP_INT(config.cursor_hide_timeout, 0, 36000);
config.cursor_hide_on_keypress =
CLAMP_INT(config.cursor_hide_on_keypress, 0, 1);
config.single_scratchpad = CLAMP_INT(config.single_scratchpad, 0, 1);
config.repeat_rate = CLAMP_INT(config.repeat_rate, 1, 1000);
config.repeat_delay = CLAMP_INT(config.repeat_delay, 1, 20000);
@ -3529,7 +3486,6 @@ void set_value_default() {
config.overviewgappi = 5;
config.overviewgappo = 30;
config.cursor_hide_timeout = 0;
config.cursor_hide_on_keypress = 0;
config.warpcursor = 1;
config.drag_corner = 3;
@ -3951,12 +3907,6 @@ void parse_tagrule(Monitor *m) {
for (i = 0; i <= LENGTH(tags); i++) {
m->pertag->nmasters[i] = config.default_nmaster;
m->pertag->mfacts[i] = config.default_mfact;
m->pertag->scroller_default_proportion[i] =
config.scroller_default_proportion;
m->pertag->scroller_default_proportion_single[i] =
config.scroller_default_proportion_single;
m->pertag->scroller_ignore_proportion_single[i] =
config.scroller_ignore_proportion_single;
}
for (i = 0; i < config.tag_rules_count; i++) {
@ -4011,15 +3961,6 @@ void parse_tagrule(Monitor *m) {
m->pertag->no_render_border[tr.id] = tr.no_render_border;
if (tr.open_as_floating >= 0)
m->pertag->open_as_floating[tr.id] = tr.open_as_floating;
if (tr.scroller_default_proportion > 0.0f)
m->pertag->scroller_default_proportion[tr.id] =
tr.scroller_default_proportion;
if (tr.scroller_default_proportion_single > 0.0f)
m->pertag->scroller_default_proportion_single[tr.id] =
tr.scroller_default_proportion_single;
if (tr.scroller_ignore_proportion_single >= 0)
m->pertag->scroller_ignore_proportion_single[tr.id] =
tr.scroller_ignore_proportion_single;
}
}

View file

@ -345,11 +345,7 @@ int32_t setmfact(const Arg *arg) {
int32_t killclient(const Arg *arg) {
Client *c = arg->tc ? arg->tc : (selmon ? selmon->sel : NULL);
if (c) {
if (arg->i == FORCE) {
client_pending_force_kill(c);
} else {
pending_kill_client(c);
}
pending_kill_client(c);
}
return 0;
}
@ -1355,9 +1351,9 @@ int32_t togglefullscreen(const Arg *arg) {
sel->isnamedscratchpad = 0;
if (sel->isfullscreen)
setfullscreen(sel, 0, true);
setfullscreen(sel, 0);
else
setfullscreen(sel, 1, true);
setfullscreen(sel, 1);
return 0;
}
@ -1401,9 +1397,9 @@ int32_t togglemaximizescreen(const Arg *arg) {
sel->isnamedscratchpad = 0;
if (sel->ismaximizescreen)
setmaximizescreen(sel, 0, true);
setmaximizescreen(sel, 0);
else
setmaximizescreen(sel, 1, true);
setmaximizescreen(sel, 1);
setborder_color(sel);
return 0;
@ -1760,12 +1756,7 @@ int32_t toggleoverview(const Arg *arg) {
if (selmon->isoverview) {
wlr_seat_pointer_clear_focus(seat);
if (cursor_hidden) {
handlecursoractivity();
} else {
wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
}
wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
wl_list_for_each(c, &clients, link) {
if (c && c->mon == selmon && !client_is_unmanaged(c) &&
@ -1918,7 +1909,7 @@ int32_t scroller_stack(const Arg *arg) {
if (!c || !c->mon || c->isfloating || !is_scroller_layout(selmon))
return 0;
Client *target_client = find_client_by_direction(c, arg, false);
Client *target_client = find_client_by_direction(c, arg, false, true);
return scroller_apply_stack(c, target_client, arg->i);
}

View file

@ -188,10 +188,10 @@ void refresh_monitors_workspaces_status(Monitor *m) {
int32_t i;
if (m->isoverview) {
add_workspace_by_tag(0, m);
for (i = 1; i <= LENGTH(tags); i++) {
remove_workspace_by_tag(i, m);
}
add_workspace_by_tag(0, m);
} else {
remove_workspace_by_tag(0, m);
for (i = 1; i <= LENGTH(tags); i++) {

View file

@ -16,12 +16,12 @@ void handle_foreign_maximize_request(struct wl_listener *listener, void *data) {
return;
if (c->ismaximizescreen && !event->maximized) {
setmaximizescreen(c, 0, true);
setmaximizescreen(c, 0);
return;
}
if (!c->ismaximizescreen && event->maximized) {
setmaximizescreen(c, 1, true);
setmaximizescreen(c, 1);
return;
}
}
@ -59,12 +59,12 @@ void handle_foreign_fullscreen_request(struct wl_listener *listener,
return;
if (c->isfullscreen && !event->fullscreen) {
setfullscreen(c, 0, true);
setfullscreen(c, 0);
return;
}
if (!c->isfullscreen && event->fullscreen) {
setfullscreen(c, 1, true);
setfullscreen(c, 1);
return;
}
}

View file

@ -22,7 +22,6 @@ static struct wlr_tablet_manager_v2 *tablet_mgr;
struct Tablet {
struct wlr_tablet_v2_tablet *tablet_v2;
struct wl_listener destroy;
struct wlr_input_device *device;
struct wl_list link;
};
static struct wl_list tablets;
@ -39,7 +38,6 @@ struct TabletTool {
struct TabletPad {
struct wlr_tablet_v2_tablet_pad *pad_v2;
struct wlr_input_device *device;
struct Tablet *tablet;
struct wl_listener tablet_destroy;
struct wl_listener attach;
@ -74,18 +72,11 @@ void createtablet(struct wlr_input_device *device) {
return;
}
tablet->device = device;
tablet->tablet_v2 = wlr_tablet_create(tablet_mgr, seat, device);
if (!tablet->tablet_v2) {
free(tablet);
return;
}
tablet->tablet_v2->wlr_tablet->data = tablet;
tablet->destroy.notify = destroytablet;
wl_signal_add(&tablet->device->events.destroy, &tablet->destroy);
wl_signal_add(&tablet->tablet_v2->wlr_device->events.destroy,
&tablet->destroy);
if (libinput_device_config_send_events_get_modes(device_handle)) {
libinput_device_config_send_events_set_mode(device_handle,
config.send_events_mode);
@ -99,7 +90,7 @@ void createtablet(struct wlr_input_device *device) {
wlr_libinput_get_device_handle(device));
struct TabletPad *tablet_pad;
wl_list_for_each(tablet_pad, &tablet_pads, link) {
struct wlr_input_device *pad_device = tablet_pad->device;
struct wlr_input_device *pad_device = tablet_pad->pad_v2->wlr_device;
if (!wlr_input_device_is_libinput(pad_device)) {
continue;
}
@ -138,7 +129,8 @@ void attach_tablet_pad(struct TabletPad *tablet_pad, struct Tablet *tablet) {
wl_list_remove(&tablet_pad->tablet_destroy.link);
tablet_pad->tablet_destroy.notify = tabletpadtabletdestroy;
wl_signal_add(&tablet->device->events.destroy, &tablet_pad->tablet_destroy);
wl_signal_add(&tablet->tablet_v2->wlr_device->events.destroy,
&tablet_pad->tablet_destroy);
}
void tabletpadattach(struct wl_listener *listener, void *data) {
@ -160,38 +152,27 @@ void createtabletpad(struct wlr_input_device *device) {
wlr_log(WLR_ERROR, "could not allocate tablet_pad");
return;
}
tablet_pad->device = device;
tablet_pad->pad_v2 = wlr_tablet_pad_create(tablet_mgr, seat, device);
if (!tablet_pad->pad_v2) {
wlr_log(WLR_ERROR, "could not create tablet_pad_v2 wrapper");
free(tablet_pad);
return;
}
tablet_pad->destroy.notify = destroytabletpad;
tablet_pad->attach.notify = tabletpadattach;
wl_list_init(&tablet_pad->tablet_destroy.link);
wl_signal_add(&device->events.destroy, &tablet_pad->destroy);
wl_signal_add(&tablet_pad->pad_v2->wlr_device->events.destroy,
&tablet_pad->destroy);
wl_signal_add(&tablet_pad->pad_v2->wlr_pad->events.attach_tablet,
&tablet_pad->attach);
wl_list_insert(&tablet_pads, &tablet_pad->link);
/* Search for a sibling tablet */
if (!wlr_input_device_is_libinput(device)) {
if (!wlr_input_device_is_libinput(tablet_pad->pad_v2->wlr_device)) {
/* We can only do this on libinput devices */
return;
}
struct libinput_device_group *group = libinput_device_get_device_group(
wlr_libinput_get_device_handle(device));
wlr_libinput_get_device_handle(tablet_pad->pad_v2->wlr_device));
struct Tablet *tablet;
wl_list_for_each(tablet, &tablets, link) {
struct wlr_input_device *tablet_device = tablet->device;
struct wlr_input_device *tablet_device = tablet->tablet_v2->wlr_device;
if (!wlr_input_device_is_libinput(tablet_device)) {
continue;
}
@ -268,11 +249,11 @@ void tablettoolmotion(struct TabletTool *tool, bool change_x, bool change_y,
switch (tool->tool_v2->wlr_tool->type) {
case WLR_TABLET_TOOL_TYPE_LENS:
case WLR_TABLET_TOOL_TYPE_MOUSE:
wlr_cursor_move(cursor, tablet->device, dx, dy);
wlr_cursor_move(cursor, tablet->tablet_v2->wlr_device, dx, dy);
break;
default:
wlr_cursor_warp_absolute(cursor, tablet->device, change_x ? x : NAN,
change_y ? y : NAN);
wlr_cursor_warp_absolute(cursor, tablet->tablet_v2->wlr_device,
change_x ? x : NAN, change_y ? y : NAN);
break;
}

View file

@ -91,9 +91,9 @@ setclient_coordinate_center(Client *c, Monitor *tm, struct wlr_box geom,
if (!m)
return geom;
uint32_t cbw = c && check_hit_no_border(c) ? c->bw : 0;
uint32_t cbw = check_hit_no_border(c) ? c->bw : 0;
if ((!c || !c->no_force_center) && m) {
if (!c->no_force_center && m) {
tempbox.x = m->w.x + (m->w.width - geom.width) / 2;
tempbox.y = m->w.y + (m->w.height - geom.height) / 2;
} else {
@ -163,11 +163,10 @@ Client *center_tiled_select(Monitor *m) {
}
return target_c;
}
Client *find_client_by_direction(Client *tc, const Arg *arg,
bool findfloating) {
Client *find_client_by_direction(Client *tc, const Arg *arg, bool findfloating,
bool ignore_align) {
Client *c = NULL;
Client **tempClients = NULL;
Client **tempClients = NULL; // 初始化为 NULL
int32_t last = -1;
// 第一次遍历,计算客户端数量
@ -180,12 +179,13 @@ Client *find_client_by_direction(Client *tc, const Arg *arg,
}
if (last < 0) {
return NULL;
return NULL; // 没有符合条件的客户端
}
// 动态分配内存
tempClients = malloc((last + 1) * sizeof(Client *));
if (!tempClients) {
// 处理内存分配失败的情况
return NULL;
}
@ -200,102 +200,249 @@ Client *find_client_by_direction(Client *tc, const Arg *arg,
}
}
// 获取当前窗口的四个边界及中心点
int32_t tc_l = tc->geom.x;
int32_t tc_r = tc->geom.x + tc->geom.width;
int32_t tc_t = tc->geom.y;
int32_t tc_b = tc->geom.y + tc->geom.height;
int32_t tc_cx = tc_l + tc->geom.width / 2;
int32_t tc_cy = tc_t + tc->geom.height / 2;
int32_t sel_x = tc->geom.x;
int32_t sel_y = tc->geom.y;
int64_t distance = LLONG_MAX;
int64_t same_monitor_distance = LLONG_MAX;
Client *tempFocusClients = NULL;
Client *tempSameMonitorFocusClients = NULL;
for (int32_t step = 0; step < 2; step++) {
if (step == 1 && tempFocusClients)
break;
for (int32_t _i = 0; _i <= last; _i++) {
c = tempClients[_i];
if (c == tc)
continue;
if (step == 0 &&
(!client_is_in_same_stack(tc, c, NULL) || c->mon != tc->mon)) {
continue;
}
// 获取目标窗口的四个边界及中心点
int32_t c_l = c->geom.x;
int32_t c_r = c->geom.x + c->geom.width;
int32_t c_t = c->geom.y;
int32_t c_b = c->geom.y + c->geom.height;
int32_t c_cx = c_l + c->geom.width / 2;
int32_t c_cy = c_t + c->geom.height / 2;
int64_t main_dist = 0;
int64_t orth_dist = 0;
bool match_dir = false;
switch (arg->i) {
case LEFT:
match_dir = (c_cx < tc_cx && c_l < tc_l);
if (match_dir) {
main_dist = tc_l - c_r;
orth_dist = (c_b < tc_t)
? (tc_t - c_b)
: ((c_t > tc_b) ? (c_t - tc_b) : 0);
}
break;
case RIGHT:
match_dir = (c_cx > tc_cx && c_r > tc_r);
if (match_dir) {
main_dist = c_l - tc_r;
orth_dist = (c_b < tc_t)
? (tc_t - c_b)
: ((c_t > tc_b) ? (c_t - tc_b) : 0);
}
break;
case UP:
match_dir = (c_cy < tc_cy && c_t < tc_t);
if (match_dir) {
main_dist = tc_t - c_b;
orth_dist = (c_r < tc_l)
? (tc_l - c_r)
: ((c_l > tc_r) ? (c_l - tc_r) : 0);
}
break;
case DOWN:
match_dir = (c_cy > tc_cy && c_b > tc_b);
if (match_dir) {
main_dist = c_t - tc_b;
orth_dist = (c_r < tc_l)
? (tc_l - c_r)
: ((c_l > tc_r) ? (c_l - tc_r) : 0);
}
break;
}
if (match_dir) {
int64_t tmp_distance =
main_dist * main_dist + 2 * orth_dist * orth_dist;
if (tmp_distance < distance) {
distance = tmp_distance;
tempFocusClients = c;
}
if (c->mon == tc->mon && tmp_distance < same_monitor_distance) {
same_monitor_distance = tmp_distance;
tempSameMonitorFocusClients = c;
switch (arg->i) {
case UP:
if (!ignore_align) {
for (int32_t _i = 0; _i <= last; _i++) {
if (tempClients[_i]->geom.y < sel_y &&
tempClients[_i]->geom.x == sel_x &&
tempClients[_i]->mon == tc->mon) {
int32_t dis_x = tempClients[_i]->geom.x - sel_x;
int32_t dis_y = tempClients[_i]->geom.y - sel_y;
int64_t tmp_distance =
dis_x * dis_x + dis_y * dis_y; // 计算距离
if (tmp_distance < distance) {
distance = tmp_distance;
tempFocusClients = tempClients[_i];
}
}
}
}
if (!tempFocusClients) {
for (int32_t _i = 0; _i <= last; _i++) {
if (tempClients[_i]->geom.y < sel_y &&
tempClients[_i]->mon == tc->mon &&
client_is_in_same_stack(tc, tempClients[_i], NULL)) {
int32_t dis_x = tempClients[_i]->geom.x - sel_x;
int32_t dis_y = tempClients[_i]->geom.y - sel_y;
int64_t tmp_distance =
dis_x * dis_x + dis_y * dis_y; // 计算距离
if (tmp_distance < distance) {
distance = tmp_distance;
tempFocusClients = tempClients[_i];
}
if (tempClients[_i]->mon == tc->mon &&
tmp_distance < same_monitor_distance) {
same_monitor_distance = tmp_distance;
tempSameMonitorFocusClients = tempClients[_i];
}
}
}
}
if (!tempFocusClients) {
for (int32_t _i = 0; _i <= last; _i++) {
if (tempClients[_i]->geom.y < sel_y) {
int32_t dis_x = tempClients[_i]->geom.x - sel_x;
int32_t dis_y = tempClients[_i]->geom.y - sel_y;
int64_t tmp_distance =
dis_x * dis_x + dis_y * dis_y; // 计算距离
if (tmp_distance < distance) {
distance = tmp_distance;
tempFocusClients = tempClients[_i];
}
if (tempClients[_i]->mon == tc->mon &&
tmp_distance < same_monitor_distance) {
same_monitor_distance = tmp_distance;
tempSameMonitorFocusClients = tempClients[_i];
}
}
}
}
break;
case DOWN:
if (!ignore_align) {
for (int32_t _i = 0; _i <= last; _i++) {
if (tempClients[_i]->geom.y > sel_y &&
tempClients[_i]->geom.x == sel_x &&
tempClients[_i]->mon == tc->mon) {
int32_t dis_x = tempClients[_i]->geom.x - sel_x;
int32_t dis_y = tempClients[_i]->geom.y - sel_y;
int64_t tmp_distance =
dis_x * dis_x + dis_y * dis_y; // 计算距离
if (tmp_distance < distance) {
distance = tmp_distance;
tempFocusClients = tempClients[_i];
}
}
}
}
if (!tempFocusClients) {
for (int32_t _i = 0; _i <= last; _i++) {
if (tempClients[_i]->geom.y > sel_y &&
tempClients[_i]->mon == tc->mon &&
client_is_in_same_stack(tc, tempClients[_i], NULL)) {
int32_t dis_x = tempClients[_i]->geom.x - sel_x;
int32_t dis_y = tempClients[_i]->geom.y - sel_y;
int64_t tmp_distance =
dis_x * dis_x + dis_y * dis_y; // 计算距离
if (tmp_distance < distance) {
distance = tmp_distance;
tempFocusClients = tempClients[_i];
}
if (tempClients[_i]->mon == tc->mon &&
tmp_distance < same_monitor_distance) {
same_monitor_distance = tmp_distance;
tempSameMonitorFocusClients = tempClients[_i];
}
}
}
}
if (!tempFocusClients) {
for (int32_t _i = 0; _i <= last; _i++) {
if (tempClients[_i]->geom.y > sel_y) {
int32_t dis_x = tempClients[_i]->geom.x - sel_x;
int32_t dis_y = tempClients[_i]->geom.y - sel_y;
int64_t tmp_distance =
dis_x * dis_x + dis_y * dis_y; // 计算距离
if (tmp_distance < distance) {
distance = tmp_distance;
tempFocusClients = tempClients[_i];
}
if (tempClients[_i]->mon == tc->mon &&
tmp_distance < same_monitor_distance) {
same_monitor_distance = tmp_distance;
tempSameMonitorFocusClients = tempClients[_i];
}
}
}
}
break;
case LEFT:
if (!ignore_align) {
for (int32_t _i = 0; _i <= last; _i++) {
if (tempClients[_i]->geom.x < sel_x &&
tempClients[_i]->geom.y == sel_y &&
tempClients[_i]->mon == tc->mon) {
int32_t dis_x = tempClients[_i]->geom.x - sel_x;
int32_t dis_y = tempClients[_i]->geom.y - sel_y;
int64_t tmp_distance =
dis_x * dis_x + dis_y * dis_y; // 计算距离
if (tmp_distance < distance) {
distance = tmp_distance;
tempFocusClients = tempClients[_i];
}
}
}
}
if (!tempFocusClients) {
for (int32_t _i = 0; _i <= last; _i++) {
if (tempClients[_i]->geom.x < sel_x &&
tempClients[_i]->mon == tc->mon &&
client_is_in_same_stack(tc, tempClients[_i], NULL)) {
int32_t dis_x = tempClients[_i]->geom.x - sel_x;
int32_t dis_y = tempClients[_i]->geom.y - sel_y;
int64_t tmp_distance =
dis_x * dis_x + dis_y * dis_y; // 计算距离
if (tmp_distance < distance) {
distance = tmp_distance;
tempFocusClients = tempClients[_i];
}
if (tempClients[_i]->mon == tc->mon &&
tmp_distance < same_monitor_distance) {
same_monitor_distance = tmp_distance;
tempSameMonitorFocusClients = tempClients[_i];
}
}
}
}
if (!tempFocusClients) {
for (int32_t _i = 0; _i <= last; _i++) {
if (tempClients[_i]->geom.x < sel_x) {
int32_t dis_x = tempClients[_i]->geom.x - sel_x;
int32_t dis_y = tempClients[_i]->geom.y - sel_y;
int64_t tmp_distance =
dis_x * dis_x + dis_y * dis_y; // 计算距离
if (tmp_distance < distance) {
distance = tmp_distance;
tempFocusClients = tempClients[_i];
}
if (tempClients[_i]->mon == tc->mon &&
tmp_distance < same_monitor_distance) {
same_monitor_distance = tmp_distance;
tempSameMonitorFocusClients = tempClients[_i];
}
}
}
}
break;
case RIGHT:
if (!ignore_align) {
for (int32_t _i = 0; _i <= last; _i++) {
if (tempClients[_i]->geom.x > sel_x &&
tempClients[_i]->geom.y == sel_y &&
tempClients[_i]->mon == tc->mon) {
int32_t dis_x = tempClients[_i]->geom.x - sel_x;
int32_t dis_y = tempClients[_i]->geom.y - sel_y;
int64_t tmp_distance =
dis_x * dis_x + dis_y * dis_y; // 计算距离
if (tmp_distance < distance) {
distance = tmp_distance;
tempFocusClients = tempClients[_i];
}
}
}
}
if (!tempFocusClients) {
for (int32_t _i = 0; _i <= last; _i++) {
if (tempClients[_i]->geom.x > sel_x &&
tempClients[_i]->mon == tc->mon &&
client_is_in_same_stack(tc, tempClients[_i], NULL)) {
int32_t dis_x = tempClients[_i]->geom.x - sel_x;
int32_t dis_y = tempClients[_i]->geom.y - sel_y;
int64_t tmp_distance =
dis_x * dis_x + dis_y * dis_y; // 计算距离
if (tmp_distance < distance) {
distance = tmp_distance;
tempFocusClients = tempClients[_i];
}
if (tempClients[_i]->mon == tc->mon &&
tmp_distance < same_monitor_distance) {
same_monitor_distance = tmp_distance;
tempSameMonitorFocusClients = tempClients[_i];
}
}
}
}
if (!tempFocusClients) {
for (int32_t _i = 0; _i <= last; _i++) {
if (tempClients[_i]->geom.x > sel_x) {
int32_t dis_x = tempClients[_i]->geom.x - sel_x;
int32_t dis_y = tempClients[_i]->geom.y - sel_y;
int64_t tmp_distance =
dis_x * dis_x + dis_y * dis_y; // 计算距离
if (tmp_distance < distance) {
distance = tmp_distance;
tempFocusClients = tempClients[_i];
}
if (tempClients[_i]->mon == tc->mon &&
tmp_distance < same_monitor_distance) {
same_monitor_distance = tmp_distance;
tempSameMonitorFocusClients = tempClients[_i];
}
}
}
}
break;
}
free(tempClients);
free(tempClients); // 释放内存
if (tempSameMonitorFocusClients) {
return tempSameMonitorFocusClients;
} else {
@ -315,7 +462,10 @@ Client *direction_select(const Arg *arg) {
return NULL;
}
return find_client_by_direction(tc, arg, true);
return find_client_by_direction(
tc, arg, true,
(is_scroller_layout(selmon) || is_centertile_layout(selmon)) &&
!selmon->isoverview);
}
/* We probably should change the name of this, it sounds like

View file

@ -160,26 +160,11 @@ void xytonode(double x, double y, struct wlr_surface **psurface, Client **pc,
if (pl)
*pl = l;
if (selmon && selmon->isoverview && config.ov_no_resize) {
if (selmon && selmon->isoverview && (!l || layer_ignores_focus(l))) {
ovc = xytoclient(x, y);
bool is_below = false;
if (l && l->layer_surface) {
is_below = (l->layer_surface->current.layer ==
ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND ||
l->layer_surface->current.layer ==
ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM);
}
if (ovc && (!l || layer_ignores_focus(l) || is_below)) {
if (pc)
*pc = ovc;
if (psurface)
*psurface = ovc ? client_surface(ovc) : NULL;
if (pl && ovc)
*pl = NULL;
}
if (pc)
*pc = ovc;
if (psurface && ovc)
*psurface = client_surface(ovc);
}
}

View file

@ -217,7 +217,7 @@ static cJSON *build_monitor_tags_response(Monitor *m) {
static void send_static_json(int fd, const char *json_str) {
size_t len = strlen(json_str);
send(fd, json_str, len, 0);
send(fd, json_str, len, MSG_NOSIGNAL);
}
/* ---------- 一次性命令处理 ---------- */
@ -413,7 +413,7 @@ static void handle_command(int client_fd, const char *cmd_raw) {
char *msg = malloc(len + 2);
if (msg) {
snprintf(msg, len + 2, "%s\n", json_str);
send(client_fd, msg, len + 1, 0);
send(client_fd, msg, len + 1, MSG_NOSIGNAL);
free(msg);
}
free(json_str);
@ -434,7 +434,7 @@ static void ipc_notify_json_to_fd(int fd, cJSON *json) {
return;
}
snprintf(msg, len + 2, "%s\n", str);
if (send(fd, msg, len + 1, 0) < 0) {
if (send(fd, msg, len + 1, MSG_NOSIGNAL) < 0) {
struct ipc_watch_client *wc, *tmp;
wl_list_for_each_safe(wc, tmp, &watch_clients, link) {
if (wc->fd == fd) {
@ -462,7 +462,7 @@ static int ipc_watch_data_handler(int fd, uint32_t mask, void *data) {
}
if (mask & WL_EVENT_READABLE) {
char buf[64];
ssize_t n = recv(fd, buf, sizeof(buf), 0);
ssize_t n = recv(fd, buf, sizeof(buf), MSG_DONTWAIT);
if (n == 0 || (n < 0 && errno != EAGAIN && errno != EWOULDBLOCK)) {
ipc_remove_watch_client(wc);
}
@ -643,7 +643,8 @@ static int ipc_handle_client_data(int fd, uint32_t mask, void *data) {
available = client->buf_cap - client->buf_len;
}
ssize_t n = recv(fd, client->buf + client->buf_len, available - 1, 0);
ssize_t n = recv(fd, client->buf + client->buf_len, available - 1,
MSG_DONTWAIT);
if (n <= 0)
goto cleanup;
@ -682,12 +683,8 @@ static int ipc_handle_connection(int fd, uint32_t mask, void *data) {
if (client_fd < 0)
return 0;
// 设置 O_NONBLOCK
int flags = fcntl(client_fd, F_GETFL, 0);
fcntl(client_fd, F_SETFL, flags | O_NONBLOCK);
// 设置 FD_CLOEXEC
flags = fcntl(client_fd, F_GETFD, 0);
fcntl(client_fd, F_SETFD, flags | FD_CLOEXEC);
struct ipc_client_state *client = calloc(1, sizeof(*client));
client->fd = client_fd;
@ -718,7 +715,7 @@ void ipc_notify_monitor(Monitor *m) {
snprintf(json_str, len + 2, "%s\n", raw);
free(raw);
}
if (send(wc->fd, json_str, len + 1, 0) < 0)
if (send(wc->fd, json_str, len + 1, MSG_NOSIGNAL) < 0)
ipc_remove_watch_client(wc);
}
}
@ -734,8 +731,10 @@ void ipc_notify_last_surface_ws_name(Monitor *m) {
if (wc->type != IPC_WATCH_LAST_OPEN_SURFACE)
continue;
/* 匹配具体 monitor 名称,或空名称表示默认 selmon */
bool match = false;
if (wc->target.monitor.name[0] == '\0') {
/* 订阅的是 selmon */
if (m == selmon)
match = true;
} else {
@ -760,7 +759,7 @@ void ipc_notify_last_surface_ws_name(Monitor *m) {
snprintf(json_str, len + 2, "%s\n", raw);
free(raw);
}
if (send(wc->fd, json_str, len + 1, 0) < 0)
if (send(wc->fd, json_str, len + 1, MSG_NOSIGNAL) < 0)
ipc_remove_watch_client(wc);
}
free(json_str);
@ -791,7 +790,7 @@ void ipc_notify_focusing_client(void) {
snprintf(json_str, len + 2, "%s\n", raw);
free(raw);
}
if (send(wc->fd, json_str, len + 1, 0) < 0)
if (send(wc->fd, json_str, len + 1, MSG_NOSIGNAL) < 0)
ipc_remove_watch_client(wc);
}
}
@ -815,7 +814,7 @@ void ipc_notify_client(Client *c) {
snprintf(json_str, len + 2, "%s\n", raw);
free(raw);
}
if (send(wc->fd, json_str, len + 1, 0) < 0)
if (send(wc->fd, json_str, len + 1, MSG_NOSIGNAL) < 0)
ipc_remove_watch_client(wc);
}
}
@ -841,7 +840,7 @@ void ipc_notify_tags(Monitor *m) {
snprintf(json_str, len + 2, "%s\n", raw);
free(raw);
}
if (send(wc->fd, json_str, len + 1, 0) < 0)
if (send(wc->fd, json_str, len + 1, MSG_NOSIGNAL) < 0)
ipc_remove_watch_client(wc);
}
}
@ -871,7 +870,7 @@ void ipc_notify_all_monitors(void) {
snprintf(json_str, len + 2, "%s\n", raw);
free(raw);
}
if (send(wc->fd, json_str, len + 1, 0) < 0)
if (send(wc->fd, json_str, len + 1, MSG_NOSIGNAL) < 0)
ipc_remove_watch_client(wc);
}
}
@ -901,7 +900,7 @@ void ipc_notify_all_clients(void) {
snprintf(json_str, len + 2, "%s\n", raw);
free(raw);
}
if (send(wc->fd, json_str, len + 1, 0) < 0)
if (send(wc->fd, json_str, len + 1, MSG_NOSIGNAL) < 0)
ipc_remove_watch_client(wc);
}
}
@ -926,7 +925,7 @@ void ipc_notify_all_tags(void) {
snprintf(json_str, len + 2, "%s\n", raw);
free(raw);
}
if (send(wc->fd, json_str, len + 1, 0) < 0)
if (send(wc->fd, json_str, len + 1, MSG_NOSIGNAL) < 0)
ipc_remove_watch_client(wc);
}
}
@ -952,7 +951,7 @@ void ipc_notify_keymode(void) {
snprintf(json_str, len + 2, "%s\n", raw);
free(raw);
}
if (send(wc->fd, json_str, len + 1, 0) < 0)
if (send(wc->fd, json_str, len + 1, MSG_NOSIGNAL) < 0)
ipc_remove_watch_client(wc);
}
}
@ -978,7 +977,7 @@ void ipc_notify_kb_layout(void) {
snprintf(json_str, len + 2, "%s\n", raw);
free(raw);
}
if (send(wc->fd, json_str, len + 1, 0) < 0)
if (send(wc->fd, json_str, len + 1, MSG_NOSIGNAL) < 0)
ipc_remove_watch_client(wc);
}
}
@ -1001,25 +1000,11 @@ void ipc_init(struct wl_event_loop *event_loop) {
snprintf(ipc_socket_path, sizeof(ipc_socket_path), "%s/mango-%d.sock",
xdg_runtime, getpid());
ipc_sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);
ipc_sock_fd =
socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
if (ipc_sock_fd < 0)
return;
// 设置 FD_CLOEXEC
int flags = fcntl(ipc_sock_fd, F_GETFD, 0);
if (flags == -1 || fcntl(ipc_sock_fd, F_SETFD, flags | FD_CLOEXEC) == -1) {
wlr_log(WLR_ERROR, "failed to set FD_CLOEXEC on IPC socket");
close(ipc_sock_fd);
return;
}
// 设置 O_NONBLOCK
flags = fcntl(ipc_sock_fd, F_GETFL, 0);
if (flags == -1 || fcntl(ipc_sock_fd, F_SETFL, flags | O_NONBLOCK) == -1) {
wlr_log(WLR_ERROR, "failed to set O_NONBLOCK on IPC socket");
close(ipc_sock_fd);
return;
}
struct sockaddr_un addr = {.sun_family = AF_UNIX};
strncpy(addr.sun_path, ipc_socket_path, sizeof(addr.sun_path) - 1);

View file

@ -25,9 +25,6 @@ void set_size_per(Monitor *m, Client *c) {
c->master_inner_per = 1.0f;
c->stack_inner_per = 1.0f;
}
c->scroller_proportion =
m->pertag->scroller_default_proportion[m->pertag->curtag];
}
void resize_tile_master_horizontal(Client *grabc, bool isdrag, int32_t offsetx,
@ -754,7 +751,6 @@ void resize_tile_grid_fair(Client *grabc, bool isdrag, int32_t offsetx,
void resize_tile_scroller(Client *grabc, bool isdrag, int32_t offsetx,
int32_t offsety, uint32_t time, bool isvertical) {
if (!grabc || grabc->isfullscreen || grabc->ismaximizescreen)
return;
if (grabc->mon->isoverview)
@ -776,7 +772,7 @@ void resize_tile_scroller(Client *grabc, bool isdrag, int32_t offsetx,
Client *stack_head_client = headnode->client;
if (m->visible_scroll_tiling_clients == 1 &&
if (m->visible_tiling_clients == 1 &&
!config.scroller_ignore_proportion_single)
return;

View file

@ -500,13 +500,16 @@ void deck(Monitor *m) {
return;
wl_list_for_each(fc, &clients, link) {
if (VISIBLEON(fc, m) && ISFAKETILED(fc))
break;
}
// Calculate master width using mfact from pertag
mfact = fc->master_mfact_per > 0.0f ? fc->master_mfact_per
: m->pertag->mfacts[m->pertag->curtag];
// Calculate master width including outer gaps
if (n > nmasters)
mw = nmasters ? round((m->w.width - 2 * cur_gappoh) * mfact) : 0;
else
@ -518,15 +521,16 @@ void deck(Monitor *m) {
continue;
if (i < nmasters) {
c->master_mfact_per = mfact;
int32_t h =
(m->w.height - 2 * cur_gappov - my) / (MIN(n, nmasters) - i);
client_tile_resize(c,
(struct wlr_box){.x = m->w.x + cur_gappoh,
.y = m->w.y + cur_gappov + my,
.width = mw,
.height = h},
0);
my += h;
// Master area clients
client_tile_resize(
c,
(struct wlr_box){.x = m->w.x + cur_gappoh,
.y = m->w.y + cur_gappov + my,
.width = mw,
.height = (m->w.height - 2 * cur_gappov - my) /
(MIN(n, nmasters) - i)},
0);
my += c->geom.height;
} else {
// Stack area clients
c->master_mfact_per = mfact;
@ -584,7 +588,6 @@ void grid(Monitor *m) {
int32_t target_gappi = enablegaps ? config.gappih : 0;
float single_width_ratio = 0.9;
float single_height_ratio = 0.9;
struct wlr_box target_geom;
n = m->visible_fake_tiling_clients;
@ -600,11 +603,11 @@ void grid(Monitor *m) {
ISFAKETILED(c))) {
cw = (m->w.width - 2 * target_gappo) * single_width_ratio;
ch = (m->w.height - 2 * target_gappo) * single_height_ratio;
target_geom.x = m->w.x + (m->w.width - cw) / 2;
target_geom.y = m->w.y + (m->w.height - ch) / 2;
target_geom.width = cw;
target_geom.height = ch;
client_tile_resize(c, target_geom, 0);
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;
c->geom.height = ch;
client_tile_resize(c, c->geom, 0);
return;
}
}
@ -648,16 +651,16 @@ void grid(Monitor *m) {
cw = avail_w * (col_pers[i] / sum_col);
if (i == 0) {
target_geom.x = m->w.x + target_gappo;
c->geom.x = m->w.x + target_gappo;
} else if (i == 1) {
// 第二个窗口的 X 坐标紧跟第一个窗口后面
float cw0 = avail_w * (col_pers[0] / sum_col);
target_geom.x = m->w.x + target_gappo + cw0 + target_gappi;
c->geom.x = m->w.x + target_gappo + cw0 + target_gappi;
}
target_geom.y = m->w.y + (m->w.height - ch) / 2 + target_gappo;
target_geom.width = cw;
target_geom.height = ch;
client_tile_resize(c, target_geom, 0);
c->geom.y = m->w.y + (m->w.height - ch) / 2 + target_gappo;
c->geom.width = cw;
c->geom.height = ch;
client_tile_resize(c, c->geom, 0);
i++;
}
}
@ -754,11 +757,11 @@ void grid(Monitor *m) {
? (m->w.y + m->w.height - target_gappo - fl_cy)
: avail_h * (row_pers[r_idx] / sum_row);
target_geom.x = (int32_t)fl_cx;
target_geom.y = (int32_t)fl_cy;
target_geom.width = (int32_t)fl_cw;
target_geom.height = (int32_t)fl_ch;
client_tile_resize(c, target_geom, 0);
c->geom.x = (int32_t)fl_cx;
c->geom.y = (int32_t)fl_cy;
c->geom.width = (int32_t)fl_cw;
c->geom.height = (int32_t)fl_ch;
client_tile_resize(c, c->geom, 0);
i++;
}
}

View file

@ -284,10 +284,6 @@ void scroller(Monitor *m) {
uint32_t tag = m->pertag->curtag;
struct TagScrollerState *st = ensure_scroller_state(m, tag);
Client *c = NULL;
float scroller_default_proportion_single =
m->pertag->scroller_default_proportion_single[tag];
int32_t scroller_ignore_proportion_single =
m->pertag->scroller_ignore_proportion_single[tag];
/* 按全局客户端链表顺序收集所有堆叠头,确保视觉顺序正确 */
struct ScrollerStackNode *heads[64];
@ -327,13 +323,14 @@ void scroller(Monitor *m) {
m->w.width - 2 * config.scroller_structs - cur_gappih;
/* 单客户端特例 */
if (n_heads == 1 && !scroller_ignore_proportion_single &&
if (n_heads == 1 && !config.scroller_ignore_proportion_single &&
!heads[0]->client->isfullscreen &&
!heads[0]->client->ismaximizescreen) {
struct ScrollerStackNode *head = heads[0];
float single_proportion = head->scroller_proportion_single > 0.0f
? head->scroller_proportion_single
: scroller_default_proportion_single;
float single_proportion =
head->scroller_proportion_single > 0.0f
? head->scroller_proportion_single
: config.scroller_default_proportion_single;
struct wlr_box target_geom;
target_geom.height = m->w.height - 2 * cur_gappov;
target_geom.width = (m->w.width - 2 * cur_gappoh) * single_proportion;
@ -423,7 +420,7 @@ void scroller(Monitor *m) {
max_client_width) >
m->w.width - 2 * config.scroller_structs - cur_gappih)));
if (n_heads == 1 && scroller_ignore_proportion_single) {
if (n_heads == 1 && config.scroller_ignore_proportion_single) {
need_scroller = true;
}
if (start_drag_window)
@ -510,10 +507,6 @@ void vertical_scroller(Monitor *m) {
uint32_t tag = m->pertag->curtag;
struct TagScrollerState *st = ensure_scroller_state(m, tag);
Client *c = NULL;
float scroller_default_proportion_single =
m->pertag->scroller_default_proportion_single[tag];
int32_t scroller_ignore_proportion_single =
m->pertag->scroller_ignore_proportion_single[tag];
/* 按全局顺序收集堆叠头 */
struct ScrollerStackNode *heads[64];
@ -549,13 +542,14 @@ void vertical_scroller(Monitor *m) {
int32_t max_client_height =
m->w.height - 2 * config.scroller_structs - cur_gappiv;
if (n_heads == 1 && !scroller_ignore_proportion_single &&
if (n_heads == 1 && !config.scroller_ignore_proportion_single &&
!heads[0]->client->isfullscreen &&
!heads[0]->client->ismaximizescreen) {
struct ScrollerStackNode *head = heads[0];
float single_proportion = head->scroller_proportion_single > 0.0f
? head->scroller_proportion_single
: scroller_default_proportion_single;
float single_proportion =
head->scroller_proportion_single > 0.0f
? head->scroller_proportion_single
: config.scroller_default_proportion_single;
struct wlr_box target_geom;
target_geom.width = m->w.width - 2 * cur_gappoh;
target_geom.height = (m->w.height - 2 * cur_gappov) * single_proportion;
@ -644,7 +638,7 @@ void vertical_scroller(Monitor *m) {
max_client_height) >
m->w.height - 2 * config.scroller_structs - cur_gappiv)));
if (n_heads == 1 && scroller_ignore_proportion_single) {
if (n_heads == 1 && config.scroller_ignore_proportion_single) {
need_scroller = true;
}
if (start_drag_window)
@ -749,9 +743,9 @@ void scroller_insert_stack(Client *c, Client *target_client,
return;
if (c->isfullscreen)
setfullscreen(c, 0, true);
setfullscreen(c, 0);
if (c->ismaximizescreen)
setmaximizescreen(c, 0, true);
setmaximizescreen(c, 0);
Monitor *m = c->mon;
uint32_t tag = m->pertag->curtag;
@ -791,9 +785,9 @@ void scroller_insert_stack(Client *c, Client *target_client,
head = head->prev_in_stack;
Client *stack_head = head->client;
if (stack_head->ismaximizescreen)
setmaximizescreen(stack_head, 0, true);
setmaximizescreen(stack_head, 0);
if (stack_head->isfullscreen)
setfullscreen(stack_head, 0, true);
setfullscreen(stack_head, 0);
/* 同步到 Client 字段 */
sync_scroller_state_to_clients(m, tag);

View file

@ -137,10 +137,12 @@ void vertical_deck(Monitor *m) {
return;
wl_list_for_each(fc, &clients, link) {
if (VISIBLEON(fc, m) && ISFAKETILED(fc))
break;
}
// Calculate master width using mfact from pertag
mfact = fc->master_mfact_per > 0.0f ? fc->master_mfact_per
: m->pertag->mfacts[m->pertag->curtag];
@ -154,18 +156,16 @@ void vertical_deck(Monitor *m) {
if (!VISIBLEON(c, m) || !ISFAKETILED(c))
continue;
if (i < nmasters) {
c->master_mfact_per = mfact;
int32_t w =
(m->w.width - 2 * cur_gappoh - mx) / (MIN(n, nmasters) - i);
client_tile_resize(c,
(struct wlr_box){.x = m->w.x + cur_gappoh + mx,
.y = m->w.y + cur_gappov,
.width = w,
.height = mh},
0);
mx += w;
client_tile_resize(
c,
(struct wlr_box){.x = m->w.x + cur_gappoh + mx,
.y = m->w.y + cur_gappov,
.width = (m->w.width - 2 * cur_gappoh - mx) /
(MIN(n, nmasters) - i),
.height = mh},
0);
mx += c->geom.width;
} else {
c->master_mfact_per = mfact;
client_tile_resize(
c,
(struct wlr_box){.x = m->w.x + cur_gappoh,
@ -186,13 +186,14 @@ void vertical_grid(Monitor *m) {
int32_t cw, ch;
int32_t rows, cols, overrows;
Client *c = NULL;
int32_t target_gappo = enablegaps ? config.gappov : 0;
int32_t target_gappi = enablegaps ? config.gappiv : 0;
float single_width_ratio = 0.9;
float single_height_ratio = 0.9;
struct wlr_box target_geom;
int32_t target_gappo =
enablegaps ? m->isoverview ? config.overviewgappo : config.gappov : 0;
int32_t target_gappi =
enablegaps ? m->isoverview ? config.overviewgappi : config.gappiv : 0;
float single_width_ratio = m->isoverview ? 0.7 : 0.9;
float single_height_ratio = m->isoverview ? 0.8 : 0.9;
n = m->visible_fake_tiling_clients;
n = m->isoverview ? m->visible_clients : m->visible_fake_tiling_clients;
if (n == 0)
return;
@ -201,14 +202,15 @@ void vertical_grid(Monitor *m) {
if (c->mon != m)
continue;
if (VISIBLEON(c, m) && !c->isunglobal &&
(!client_is_x11_popup(c) || ISFAKETILED(c))) {
((m->isoverview && !client_is_x11_popup(c)) ||
ISFAKETILED(c))) {
ch = (m->w.height - 2 * target_gappo) * single_height_ratio;
cw = (m->w.width - 2 * target_gappo) * single_width_ratio;
target_geom.x = m->w.x + (m->w.width - cw) / 2;
target_geom.y = m->w.y + (m->w.height - ch) / 2;
target_geom.width = cw;
target_geom.height = ch;
client_tile_resize(c, target_geom, 0);
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;
c->geom.height = ch;
client_tile_resize(c, c->geom, 0);
return;
}
}
@ -222,7 +224,8 @@ void vertical_grid(Monitor *m) {
if (c->mon != m)
continue;
if (VISIBLEON(c, m) && !c->isunglobal &&
(!client_is_x11_popup(c) || ISFAKETILED(c))) {
((m->isoverview && !client_is_x11_popup(c)) ||
ISFAKETILED(c))) {
if (i < 2)
row_pers[i] =
(c->grid_row_per > 0.0f) ? c->grid_row_per : 1.0f;
@ -239,7 +242,8 @@ void vertical_grid(Monitor *m) {
if (c->mon != m)
continue;
if (VISIBLEON(c, m) && !c->isunglobal &&
(!client_is_x11_popup(c) || ISFAKETILED(c))) {
((m->isoverview && !client_is_x11_popup(c)) ||
ISFAKETILED(c))) {
c->grid_col_idx = 0;
c->grid_row_idx = i;
c->grid_col_per = 1.0f;
@ -248,17 +252,17 @@ void vertical_grid(Monitor *m) {
// 根据分配的权重动态计算当前窗口的高度
ch = avail_h * (row_pers[i] / sum_row);
target_geom.x = m->w.x + (m->w.width - cw) / 2 + target_gappo;
c->geom.x = m->w.x + (m->w.width - cw) / 2 + target_gappo;
if (i == 0) {
target_geom.y = m->w.y + target_gappo;
c->geom.y = m->w.y + target_gappo;
} else if (i == 1) {
// 第二个窗口的 Y 坐标紧跟第一个窗口下面
float ch0 = avail_h * (row_pers[0] / sum_row);
target_geom.y = m->w.y + target_gappo + ch0 + target_gappi;
c->geom.y = m->w.y + target_gappo + ch0 + target_gappi;
}
target_geom.width = cw;
target_geom.height = ch;
client_tile_resize(c, target_geom, 0);
c->geom.width = cw;
c->geom.height = ch;
client_tile_resize(c, c->geom, 0);
i++;
}
}
@ -283,7 +287,7 @@ void vertical_grid(Monitor *m) {
if (c->mon != m)
continue;
if (VISIBLEON(c, m) && !c->isunglobal &&
(!client_is_x11_popup(c) || ISFAKETILED(c))) {
((m->isoverview && !client_is_x11_popup(c)) || ISFAKETILED(c))) {
int32_t c_idx = i / rows;
int32_t r_idx = i % rows;
if (r_idx == 0)
@ -310,7 +314,7 @@ void vertical_grid(Monitor *m) {
if (c->mon != m)
continue;
if (VISIBLEON(c, m) && !c->isunglobal &&
(!client_is_x11_popup(c) || ISFAKETILED(c))) {
((m->isoverview && !client_is_x11_popup(c)) || ISFAKETILED(c))) {
int32_t c_idx = i / rows;
int32_t r_idx = i % rows;
@ -348,11 +352,11 @@ void vertical_grid(Monitor *m) {
? (m->w.x + m->w.width - target_gappo - fl_cx)
: avail_w * (col_pers[c_idx] / sum_col);
target_geom.x = (int32_t)fl_cx;
target_geom.y = (int32_t)fl_cy;
target_geom.width = (int32_t)fl_cw;
target_geom.height = (int32_t)fl_ch;
client_tile_resize(c, target_geom, 0);
c->geom.x = (int32_t)fl_cx;
c->geom.y = (int32_t)fl_cy;
c->geom.width = (int32_t)fl_cw;
c->geom.height = (int32_t)fl_ch;
client_tile_resize(c, c->geom, 0);
i++;
}
}

View file

@ -190,7 +190,6 @@ enum { NONE, OPEN, MOVE, CLOSE, TAG, FOCUS, OPAFADEIN, OPAFADEOUT, OVERVIEW };
enum { UNFOLD, FOLD, INVALIDFOLD };
enum { PREV, NEXT };
enum { STATE_UNSPECIFIED = 0, STATE_ENABLED, STATE_DISABLED };
enum { FORCE, UNFORCE };
enum tearing_mode {
TEARING_DISABLED = 0,
@ -735,9 +734,8 @@ static void run(char *startup_cmd);
static void setcursor(struct wl_listener *listener, void *data);
static void setfloating(Client *c, int32_t floating);
static void setfakefullscreen(Client *c, int32_t fakefullscreen);
static void setfullscreen(Client *c, int32_t fullscreen, bool rearrange);
static void setmaximizescreen(Client *c, int32_t maximizescreen,
bool rearrange);
static void setfullscreen(Client *c, int32_t fullscreen);
static void setmaximizescreen(Client *c, int32_t maximizescreen);
static void reset_maximizescreen_size(Client *c);
static void setgaps(int32_t oh, int32_t ov, int32_t ih, int32_t iv);
@ -856,7 +854,7 @@ static float *get_border_color(Client *c);
static void clear_fullscreen_and_maximized_state(Monitor *m);
static void request_fresh_all_monitors(void);
static Client *find_client_by_direction(Client *tc, const Arg *arg,
bool findfloating);
bool findfloating, bool ignore_align);
static void exit_scroller_stack(Client *c);
static Client *scroll_get_stack_head_client(Client *c);
static bool client_only_in_one_tag(Client *c);
@ -1027,9 +1025,6 @@ struct Pertag {
int32_t no_hide[LENGTH(tags) + 1];
int32_t no_render_border[LENGTH(tags) + 1];
int32_t open_as_floating[LENGTH(tags) + 1];
float scroller_default_proportion[LENGTH(tags) + 1];
float scroller_default_proportion_single[LENGTH(tags) + 1];
int32_t scroller_ignore_proportion_single[LENGTH(tags) + 1];
struct DwindleNode *dwindle_root[LENGTH(tags) + 1];
const Layout *ltidxs[LENGTH(tags) + 1];
struct TagScrollerState *scroller_state[LENGTH(tags) + 1];
@ -1077,7 +1072,7 @@ static struct wl_listener last_cursor_surface_destroy_listener = {
.notify = last_cursor_surface_destroy};
#ifdef XWAYLAND
static void fix_xwayland_coordinate(struct wlr_box *geom);
static void fix_xwayland_unmanaged_coordinate(Client *c);
static int32_t synckeymap(void *data);
static void activatex11(struct wl_listener *listener, void *data);
static void configurex11(struct wl_listener *listener, void *data);
@ -1154,11 +1149,11 @@ void clear_fullscreen_flag(Client *c) {
}
if (c->isfullscreen) {
setfullscreen(c, false, true);
setfullscreen(c, false);
}
if (c->ismaximizescreen) {
setmaximizescreen(c, 0, true);
setmaximizescreen(c, 0);
}
}
@ -1619,7 +1614,7 @@ void applyrules(Client *c) {
#ifdef XWAYLAND
if (c->isfloating && client_is_x11(c)) {
fix_xwayland_coordinate(&c->geom);
fix_xwayland_unmanaged_coordinate(c);
c->float_geom = c->geom;
}
#endif
@ -1752,7 +1747,7 @@ void applyrules(Client *c) {
view_in_mon(&(Arg){.ui = c->tags}, true, c->mon, true);
}
setfullscreen(c, fullscreen_state_backup, true);
setfullscreen(c, fullscreen_state_backup);
if (c->isfakefullscreen) {
setfakefullscreen(c, 1);
@ -2206,10 +2201,9 @@ void hold_end(struct wl_listener *listener, void *data) {
Client *find_closest_tiled_client(Client *c) {
Client *tc, *closest = NULL;
long min_dist = LONG_MAX;
Monitor *cursor_mon = xytomon(cursor->x, cursor->y);
wl_list_for_each(tc, &clients, link) {
if (tc == c || !ISTILED(tc) || !VISIBLEON(tc, cursor_mon))
if (tc == c || !ISTILED(tc) || !VISIBLEON(tc, c->mon))
continue;
if (cursor->x >= tc->geom.x &&
@ -2241,9 +2235,7 @@ void place_drag_tile_client(Client *c) {
if (closest->drop_direction == UNDIR) {
setfloating(c, 0);
wl_list_remove(&c->link);
wl_list_insert(closest->link.prev, &c->link);
arrange(closest->mon, false, false);
exchange_two_client(c, closest);
return;
}
@ -2342,17 +2334,6 @@ bool handle_buttonpress(struct wlr_pointer_button_event *event) {
}
}
// overview模式下鼠标左键跳转右键关闭窗口
if (selmon && selmon->isoverview && event->button == BTN_LEFT && c) {
toggleoverview(&(Arg){.i = 1});
return true;
}
if (selmon && selmon->isoverview && event->button == BTN_RIGHT && c) {
pending_kill_client(c);
return true;
}
// 当鼠标焦点在layer上的时候不检测虚拟键盘的mod状态
// 避免layer虚拟键盘锁死mod按键状态
hard_keyboard = &kb_group->wlr_group->keyboard;
@ -2369,6 +2350,16 @@ bool handle_buttonpress(struct wlr_pointer_button_event *event) {
break;
m = &config.mouse_bindings[ji];
if (selmon->isoverview && event->button == BTN_LEFT && c) {
toggleoverview(&(Arg){.i = 1});
return true;
}
if (selmon->isoverview && event->button == BTN_RIGHT && c) {
pending_kill_client(c);
return true;
}
if (CLEANMASK(mods) == CLEANMASK(m->mod) &&
event->button == m->button && m->func &&
(CLEANMASK(m->mod) != 0 ||
@ -3148,6 +3139,7 @@ void createlayersurface(struct wl_listener *listener, void *data) {
LISTEN(&l->scene->node.events.destroy, &l->destroy, destroylayernodenotify);
wl_list_insert(&l->mon->layers[layer_surface->pending.layer], &l->link);
wlr_surface_send_enter(surface, layer_surface->output);
}
void createlocksurface(struct wl_listener *listener, void *data) {
@ -3947,7 +3939,7 @@ fullscreennotify(struct wl_listener *listener, void *data) {
if (!c || c->iskilling)
return;
setfullscreen(c, client_wants_fullscreen(c), true);
setfullscreen(c, client_wants_fullscreen(c));
}
void requestmonstate(struct wl_listener *listener, void *data) {
@ -4213,11 +4205,6 @@ void keypress(struct wl_listener *listener, void *data) {
}
}
if (config.cursor_hide_on_keypress && !cursor_hidden &&
event->state == WL_KEYBOARD_KEY_STATE_PRESSED) {
hidecursor(NULL);
}
/* On _press_ if there is no active screen locker,
* attempt to process a compositor keybinding. */
for (i = 0; i < nsyms; i++)
@ -4481,24 +4468,24 @@ mapnotify(struct wl_listener *listener, void *data) {
/* Handle unmanaged clients first so we can return prior create borders
*/
#ifdef XWAYLAND
if (client_is_unmanaged(c)) {
/* Unmanaged clients always are floating */
fix_xwayland_coordinate(&c->geom);
wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y);
wlr_xwayland_surface_configure(c->surface.xwayland, c->geom.x,
c->geom.y, c->geom.width,
c->geom.height);
LISTEN(&c->surface.xwayland->events.set_geometry, &c->set_geometry,
setgeometrynotify);
#ifdef XWAYLAND
if (client_is_x11(c)) {
fix_xwayland_unmanaged_coordinate(c);
LISTEN(&c->surface.xwayland->events.set_geometry, &c->set_geometry,
setgeometrynotify);
}
#endif
wlr_scene_node_reparent(&c->scene->node, layers[LyrOverlay]);
wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y);
if (client_wants_focus(c)) {
focusclient(c, 1);
exclusive_focus = c;
}
return;
}
#endif
// extra node
for (i = 0; i < 2; i++) {
@ -4590,9 +4577,9 @@ void maximizenotify(struct wl_listener *listener, void *data) {
}
if (client_request_maximize(c, data)) {
setmaximizescreen(c, 1, true);
setmaximizescreen(c, 1);
} else {
setmaximizescreen(c, 0, true);
setmaximizescreen(c, 0);
}
}
@ -4820,8 +4807,7 @@ void motionnotify(uint32_t time, struct wlr_input_device *device, double dx,
if (!surface && !seat->drag && !cursor_hidden)
wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
if (c && c->mon && !c->animation.running &&
(INSIDEMON(c) || !ISSCROLLTILED(c))) {
if (c && c->mon && !c->animation.running && (INSIDEMON(c) || !ISTILED(c))) {
scroller_focus_lock = 0;
}
@ -4833,15 +4819,13 @@ void motionnotify(uint32_t time, struct wlr_input_device *device, double dx,
}
if (!scroller_focus_lock || !(c && c->mon && !INSIDEMON(c))) {
if (c && c->mon && ISSCROLLTILED(c) && is_scroller_layout(c->mon) &&
!INSIDEMON(c)) {
if (c && c->mon && is_scroller_layout(c->mon) && !INSIDEMON(c)) {
should_lock = true;
}
if (!((!config.edge_scroller_pointer_focus ||
speed < config.edge_scroller_focus_allow_speed) &&
c && c->mon && ISSCROLLTILED(c) && is_scroller_layout(c->mon) &&
!INSIDEMON(c))) {
c && c->mon && is_scroller_layout(c->mon) && !INSIDEMON(c))) {
pointerfocus(c, surface, sx, sy, time);
}
@ -5170,8 +5154,7 @@ void exchange_two_client(Client *c1, Client *c2) {
const Layout *layout1 = m1->pertag->ltidxs[m1->pertag->curtag];
const Layout *layout2 = m2->pertag->ltidxs[m2->pertag->curtag];
if (layout1->id == SCROLLER || layout2->id == SCROLLER ||
layout1->id == VERTICAL_SCROLLER || layout2->id == VERTICAL_SCROLLER) {
if (layout1->id == SCROLLER || layout2->id == SCROLLER) {
exchange_two_scroller_clients(c1, c2);
return;
}
@ -5457,7 +5440,7 @@ void exit_scroller_stack(Client *c) {
}
}
void setmaximizescreen(Client *c, int32_t maximizescreen, bool rearrange) {
void setmaximizescreen(Client *c, int32_t maximizescreen) {
struct wlr_box maximizescreen_box;
if (!c || !c->mon || !client_surface(c)->mapped || c->iskilling)
return;
@ -5498,8 +5481,7 @@ void setmaximizescreen(Client *c, int32_t maximizescreen, bool rearrange) {
client_set_maximized(c, true);
}
if (rearrange)
arrange(c->mon, false, false);
arrange(c->mon, false, false);
}
void setfakefullscreen(Client *c, int32_t fakefullscreen) {
@ -5508,13 +5490,12 @@ void setfakefullscreen(Client *c, int32_t fakefullscreen) {
return;
if (c->isfullscreen)
setfullscreen(c, 0, true);
setfullscreen(c, 0);
client_set_fullscreen(c, fakefullscreen);
}
void setfullscreen(Client *c, int32_t fullscreen,
bool rearrange) // 用自定义全屏代理自带全屏
void setfullscreen(Client *c, int32_t fullscreen) // 用自定义全屏代理自带全屏
{
if (!c || !c->mon || !client_surface(c)->mapped || c->iskilling)
@ -5543,7 +5524,6 @@ void setfullscreen(Client *c, int32_t fullscreen,
wlr_scene_node_raise_to_top(&c->scene->node); // 将视图提升到顶层
if (!is_scroller_layout(c->mon) || c->isfloating)
resize(c, c->mon->m, 1);
} else {
c->bw = c->isnoborder ? 0 : config.borderpx;
if (c->isfloating)
@ -5560,8 +5540,7 @@ void setfullscreen(Client *c, int32_t fullscreen,
layers[fullscreen || c->isfloating ? LyrTop : LyrTile]);
}
if (rearrange)
arrange(c->mon, false, false);
arrange(c->mon, false, false);
}
void setgaps(int32_t oh, int32_t ov, int32_t ih, int32_t iv) {
@ -5690,8 +5669,7 @@ void setmon(Client *c, Monitor *m, uint32_t newtags, bool focus) {
client_reset_mon_tags(c, m, newtags);
check_match_tag_floating_rule(c, m);
setfloating(c, c->isfloating);
setfullscreen(c, c->isfullscreen,
true); /* This will call arrange(c->mon) */
setfullscreen(c, c->isfullscreen); /* This will call arrange(c->mon) */
}
if (focus && !client_is_x11_popup(c)) {
@ -5827,20 +5805,13 @@ void setup(void) {
}
init_baked_points();
int32_t drm_fd, i;
int32_t sig[] = {SIGCHLD, SIGINT,
SIGTERM}; // 不设置SIGPIPE,因为ipc发送失败不应该影响主程序
int32_t drm_fd, i, sig[] = {SIGCHLD, SIGINT, SIGTERM, SIGPIPE};
struct sigaction sa = {.sa_flags = SA_RESTART, .sa_handler = handlesig};
sigemptyset(&sa.sa_mask);
for (i = 0; i < LENGTH(sig); i++)
sigaction(sig[i], &sa, NULL);
// 单独为 SIGPIPE 设置忽略
struct sigaction sa_pipe = {.sa_flags = 0, .sa_handler = SIG_IGN};
sigemptyset(&sa_pipe.sa_mask);
sigaction(SIGPIPE, &sa_pipe, NULL);
wlr_log_init(config.log_level, NULL);
/* The Wayland display is managed by libwayland. It handles accepting
@ -6283,13 +6254,13 @@ void overview_restore(Client *c, const Arg *arg) {
resize(c, c->overview_backup_geom, 0);
} else if (c->isfullscreen || c->ismaximizescreen) {
if (want_restore_fullscreen(c) && c->ismaximizescreen) {
setmaximizescreen(c, 1, false);
setmaximizescreen(c, 1);
} else if (want_restore_fullscreen(c) && c->isfullscreen) {
setfullscreen(c, 1, false);
setfullscreen(c, 1);
} else {
client_pending_fullscreen_state(c, 0);
client_pending_maximized_state(c, 0);
setfullscreen(c, false, false);
setfullscreen(c, false);
}
} else {
if (c->is_restoring_from_ov) {
@ -6485,8 +6456,8 @@ void unmapnotify(struct wl_listener *listener, void *data) {
}
if (c->swallowedby) {
setmaximizescreen(c->swallowedby, c->ismaximizescreen, true);
setfullscreen(c->swallowedby, c->isfullscreen, true);
setmaximizescreen(c->swallowedby, c->ismaximizescreen);
setfullscreen(c->swallowedby, c->isfullscreen);
c->swallowedby->swallowing = NULL;
c->swallowedby = NULL;
}
@ -6844,17 +6815,16 @@ void virtualpointer(struct wl_listener *listener, void *data) {
}
#ifdef XWAYLAND
void fix_xwayland_coordinate(struct wlr_box *geom) {
void fix_xwayland_unmanaged_coordinate(Client *c) {
if (!selmon)
return;
// 1. 如果窗口已经在当前活动显示器内,直接返回
if (geom->x >= selmon->m.x && geom->x <= selmon->m.x + selmon->m.width &&
geom->y >= selmon->m.y && geom->y <= selmon->m.y + selmon->m.height)
if (c->geom.x >= selmon->m.x && c->geom.x < selmon->m.x + selmon->m.width &&
c->geom.y >= selmon->m.y && c->geom.y < selmon->m.y + selmon->m.height)
return;
geom->x = selmon->m.x + (selmon->m.width - geom->width) / 2;
geom->y = selmon->m.y + (selmon->m.height - geom->height) / 2;
c->geom = setclient_coordinate_center(c, selmon, c->geom, 0, 0);
}
int32_t synckeymap(void *data) {
@ -6909,41 +6879,24 @@ void activatex11(struct wl_listener *listener, void *data) {
void configurex11(struct wl_listener *listener, void *data) {
Client *c = wl_container_of(listener, c, configure);
struct wlr_xwayland_surface_configure_event *event = data;
struct wlr_box new_geo;
new_geo.x = event->x;
new_geo.y = event->y;
new_geo.width = event->width;
new_geo.height = event->height;
fix_xwayland_coordinate(&new_geo);
if (!client_surface(c) || !client_surface(c)->mapped) {
wlr_xwayland_surface_configure(c->surface.xwayland, new_geo.x,
new_geo.y, new_geo.width,
new_geo.height);
wlr_xwayland_surface_configure(c->surface.xwayland, event->x, event->y,
event->width, event->height);
return;
}
if (client_is_unmanaged(c)) {
wlr_scene_node_set_position(&c->scene->node, new_geo.x, new_geo.y);
wlr_xwayland_surface_configure(c->surface.xwayland, new_geo.x,
new_geo.y, new_geo.width,
new_geo.height);
wlr_scene_node_set_position(&c->scene->node, event->x, event->y);
wlr_xwayland_surface_configure(c->surface.xwayland, event->x, event->y,
event->width, event->height);
return;
}
if (c->isfloating && c != grabc) {
new_geo.x = new_geo.x - c->bw;
new_geo.y = new_geo.y - c->bw;
new_geo.width = new_geo.width + c->bw * 2;
new_geo.height = new_geo.height + c->bw * 2;
fix_xwayland_coordinate(&new_geo);
if ((c->isfloating && c != grabc) ||
!c->mon->pertag->ltidxs[c->mon->pertag->curtag]->arrange) {
resize(c,
(struct wlr_box){.x = new_geo.x,
.y = new_geo.y,
.width = new_geo.width,
.height = new_geo.height},
(struct wlr_box){.x = event->x - c->bw,
.y = event->y - c->bw,
.width = event->width + c->bw * 2,
.height = event->height + c->bw * 2},
0);
} else {
arrange(c->mon, false, false);