diff --git a/docs/bindings/keys.md b/docs/bindings/keys.md index be8757c2..5abc716b 100644 --- a/docs/bindings/keys.md +++ b/docs/bindings/keys.md @@ -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. | diff --git a/docs/configuration/miscellaneous.md b/docs/configuration/miscellaneous.md index cd8d167d..1001c4c1 100644 --- a/docs/configuration/miscellaneous.md +++ b/docs/configuration/miscellaneous.md @@ -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, 1–3: corners, 4: auto-detect). | @@ -49,4 +48,4 @@ description: Advanced settings for XWayland, focus behavior, and system integrat | `idleinhibit_ignore_visible` | `0` | Allow invisible clients (e.g., background audio players) to inhibit idle. | | `tag_carousel` | `0` | Enable tag carousel (cycling through tags). | | `drag_tile_refresh_interval` | `8.0` | Interval (1.0–16.0) to refresh tiled window resize during drag. Too small may cause application lag. | -| `drag_floating_refresh_interval` | `8.0` | Interval (1.0–16.0) to refresh floating window resize during drag. Too small may cause application lag. | +| `drag_floating_refresh_interval` | `8.0` | Interval (1.0–16.0) to refresh floating window resize during drag. Too small may cause application lag. | \ No newline at end of file diff --git a/docs/configuration/monitors.md b/docs/configuration/monitors.md index a8001ae0..084db60c 100644 --- a/docs/configuration/monitors.md +++ b/docs/configuration/monitors.md @@ -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 ``` diff --git a/docs/installation.md b/docs/installation.md index 1fed83d8..48c667c5 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -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`. --- diff --git a/docs/screenshot.md b/docs/screenshot.md index 8c512313..7f85224a 100644 --- a/docs/screenshot.md +++ b/docs/screenshot.md @@ -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. diff --git a/docs/window-management/rules.md b/docs/window-management/rules.md index 7e221bf1..41b4cc53 100644 --- a/docs/window-management/rules.md +++ b/docs/window-management/rules.md @@ -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 diff --git a/mangowm.scm b/mangowm.scm index fcd7f583..c7cd32e9 100644 --- a/mangowm.scm +++ b/mangowm.scm @@ -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) diff --git a/meson.build b/meson.build index 23b59d61..5de13158 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ -project('mango', ['c'], - version : '0.14.2', +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')) diff --git a/mmsg/mmsg.1 b/mmsg/mmsg.1 deleted file mode 100644 index 8a935f50..00000000 --- a/mmsg/mmsg.1 +++ /dev/null @@ -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 [\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 -Return details of the named monitor. -.TP -\fBget focusing\-client\fR -Return details of the currently focused client. -.TP -\fBget client\fR -Return details of the client with the given numeric ID. -.TP -\fBget tag\fR -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 -List tags for a specific monitor. -.TP -\fBdispatch\fR [,arg...] [client,] -Invoke an internal compositor function. -The function name and its arguments are separated by commas. -Optionally add \fBclient,\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 -Stream updates for the named monitor. -.TP -\fBwatch focusing\-client\fR -Stream updates for the focused client. -.TP -\fBwatch client\fR -Stream updates for the client with the given ID. -.TP -\fBwatch tags\fR -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. \ No newline at end of file diff --git a/mmsg/mmsg.c b/mmsg/mmsg.c index adb0b539..10b24afc 100644 --- a/mmsg/mmsg.c +++ b/mmsg/mmsg.c @@ -7,73 +7,7 @@ #include #include -static void usage(void) { - printf("Usage: mmsg [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 Show monitor details\n"); - printf(" get focusing-client Show focused client " - "details\n"); - printf(" get client Show client details by " - "ID\n"); - printf(" get tag Show tag details " - "(1‑based 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 List tags for a monitor\n"); - printf(" dispatch [,arg...] [client,] Call a compositor " - "function\n"); - printf(" and arguments are separated by commas.\n"); - printf(" Add 'client,' 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 Stream monitor changes\n"); - printf(" watch focusing-client Stream focused client " - "changes\n"); - printf( - " watch client Stream client changes\n"); - printf(" watch tags 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 [args...]\n"); fprintf(stderr, " get ... 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; } diff --git a/src/action/client.h b/src/action/client.h index 1b3c9335..b7960d70 100644 --- a/src/action/client.h +++ b/src/action/client.h @@ -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) { @@ -86,10 +86,4 @@ void client_active(Client *c) { target = get_tags_first_tag(c->tags); 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); } \ No newline at end of file diff --git a/src/animation/client.h b/src/animation/client.h index 35d2a30f..238da9fb 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -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; diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 72196c5f..b15e34a5 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -261,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; @@ -560,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]; @@ -1050,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) { @@ -1715,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) { @@ -3349,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); @@ -3512,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; diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index cf0f770a..b834ff5f 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -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; } diff --git a/src/ext-protocol/tablet.h b/src/ext-protocol/tablet.h index 34c82dbf..6aa7ae86 100644 --- a/src/ext-protocol/tablet.h +++ b/src/ext-protocol/tablet.h @@ -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; } diff --git a/src/fetch/client.h b/src/fetch/client.h index 77b2d865..85b296a3 100644 --- a/src/fetch/client.h +++ b/src/fetch/client.h @@ -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 { diff --git a/src/fetch/common.h b/src/fetch/common.h index acb5d0e8..f58bd33a 100644 --- a/src/fetch/common.h +++ b/src/fetch/common.h @@ -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); } } \ No newline at end of file diff --git a/src/ipc/ipc.h b/src/ipc/ipc.h index 1694eb8b..5bbffcc3 100644 --- a/src/ipc/ipc.h +++ b/src/ipc/ipc.h @@ -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); diff --git a/src/layout/arrange.h b/src/layout/arrange.h index eab3ac00..7223b430 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -751,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) @@ -773,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; diff --git a/src/layout/horizontal.h b/src/layout/horizontal.h index 419e218a..92980731 100644 --- a/src/layout/horizontal.h +++ b/src/layout/horizontal.h @@ -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++; } } diff --git a/src/layout/vertical.h b/src/layout/vertical.h index b1de212e..523467f9 100644 --- a/src/layout/vertical.h +++ b/src/layout/vertical.h @@ -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++; } } diff --git a/src/mango.c b/src/mango.c index 1fad3011..4d08abd5 100644 --- a/src/mango.c +++ b/src/mango.c @@ -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, @@ -1073,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); @@ -1615,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 @@ -2202,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 && @@ -2237,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; } @@ -2338,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; @@ -2365,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 || @@ -3144,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) { @@ -4209,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++) @@ -4477,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++) { @@ -4816,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; } @@ -4829,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); } @@ -5166,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; } @@ -5537,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) @@ -5819,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 @@ -6836,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) { @@ -6901,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);