mirror of
https://github.com/DreamMaoMao/maomaowm.git
synced 2026-06-13 14:33:08 -04:00
Compare commits
29 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
792bfac475 | ||
|
|
03e68ba069 | ||
|
|
33cda5afea | ||
|
|
94db68ef88 | ||
|
|
cd6e2883db | ||
|
|
ef59224cdb | ||
|
|
52732c928b | ||
|
|
47f30454e6 | ||
|
|
7faf9b6239 | ||
|
|
36398a1af2 | ||
|
|
a429420b73 | ||
|
|
b8fa9a3043 | ||
|
|
009e2d2111 | ||
|
|
27f4f64173 | ||
|
|
ccb58a4f1a | ||
|
|
db8d22ae8e | ||
|
|
3ab2780b84 | ||
|
|
9459fe51fd | ||
|
|
4e87e3b80d | ||
|
|
8a92184667 | ||
|
|
cc20d5cff0 | ||
|
|
13e9cfb237 | ||
|
|
bea689ca0c | ||
|
|
a11cf12f28 | ||
|
|
6849e5b4db | ||
|
|
8cb3a40ac7 | ||
|
|
c2cfac97b1 | ||
|
|
0aec251028 | ||
|
|
404d664fca |
20 changed files with 464 additions and 170 deletions
|
|
@ -88,7 +88,7 @@ bindr=Super,Super_L,spawn,rofi -show run
|
||||||
|
|
||||||
| Command | Param | Description |
|
| Command | Param | Description |
|
||||||
| :--- | :--- | :--- |
|
| :--- | :--- | :--- |
|
||||||
| `killclient` | - | Close the focused window. |
|
| `killclient` | `force` | Close the focused window. If `force` is specified, sends `SIGKILL`. |
|
||||||
| `togglefloating` | - | Toggle floating state. |
|
| `togglefloating` | - | Toggle floating state. |
|
||||||
| `toggle_all_floating` | - | Toggle all visible clients floating state. |
|
| `toggle_all_floating` | - | Toggle all visible clients floating state. |
|
||||||
| `togglefullscreen` | - | Toggle fullscreen. |
|
| `togglefullscreen` | - | Toggle fullscreen. |
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ description: Advanced settings for XWayland, focus behavior, and system integrat
|
||||||
| `sloppyfocus` | `1` | Focus follows the mouse cursor. |
|
| `sloppyfocus` | `1` | Focus follows the mouse cursor. |
|
||||||
| `warpcursor` | `1` | Warp the cursor to the center of the window when focus changes via keyboard. |
|
| `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_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_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_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). |
|
| `drag_corner` | `3` | Corner for drag-to-tile detection (0: none, 1–3: corners, 4: auto-detect). |
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ You can install it using the `moss` package manager:
|
||||||
```bash
|
```bash
|
||||||
sudo moss install mangowm
|
sudo moss install mangowm
|
||||||
```
|
```
|
||||||
|
* The Default config will be located at `/usr/share/defaults/mango`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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` |
|
| [`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 |
|
| [`wl-copy`](https://github.com/bugaevc/wl-clipboard) | Copy screenshots directly to the clipboard |
|
||||||
| [`satty`](https://github.com/gabm/Satty) | Annotate screenshots before saving |
|
| [`satty`](https://github.com/gabm/Satty) | Annotate screenshots before saving |
|
||||||
| [`wayfreeze`](https://github.com/nicbk/wayfreeze) | Freeze the screen before capture |
|
| [`wayfreeze`](https://github.com/Jappie3/wayfreeze) | Freeze the screen before capture |
|
||||||
|
|
||||||
Install the required with your package manager or from source.
|
Install the required with your package manager or from source.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -115,7 +115,7 @@ windowrule=width:1000,height:900,appid:yesplaymusic,title:Demons
|
||||||
|
|
||||||
# Global keybindings for OBS Studio
|
# Global keybindings for OBS Studio
|
||||||
windowrule=globalkeybinding:ctrl+alt-o,appid:com.obsproject.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
|
windowrule=isopensilent:1,appid:com.obsproject.Studio
|
||||||
|
|
||||||
# Force tearing for games
|
# Force tearing for games
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@
|
||||||
#:use-module (gnu packages pciutils)
|
#:use-module (gnu packages pciutils)
|
||||||
#:use-module (gnu packages admin)
|
#:use-module (gnu packages admin)
|
||||||
#:use-module (gnu packages pcre)
|
#:use-module (gnu packages pcre)
|
||||||
#:use-module (gnu packages cjson)
|
#:use-module (gnu packages javascript)
|
||||||
#:use-module (gnu packages xorg)
|
#:use-module (gnu packages xorg)
|
||||||
#:use-module (gnu packages build-tools)
|
#:use-module (gnu packages build-tools)
|
||||||
#:use-module (gnu packages ninja)
|
#:use-module (gnu packages ninja)
|
||||||
|
|
|
||||||
27
meson.build
27
meson.build
|
|
@ -1,5 +1,5 @@
|
||||||
project('mango', ['c', 'cpp'],
|
project('mango', ['c'],
|
||||||
version : '0.14.0',
|
version : '0.14.2',
|
||||||
)
|
)
|
||||||
|
|
||||||
subdir('protocols')
|
subdir('protocols')
|
||||||
|
|
@ -24,10 +24,6 @@ if sysconfdir.startswith(prefix) and not is_nixos
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# 打印调试信息,确认 sysconfdir 的值
|
|
||||||
# message('prefix: ' + prefix)
|
|
||||||
# message('sysconfdir: ' + sysconfdir)
|
|
||||||
|
|
||||||
cc = meson.get_compiler('c')
|
cc = meson.get_compiler('c')
|
||||||
libm = cc.find_library('m')
|
libm = cc.find_library('m')
|
||||||
xcb = dependency('xcb', required : get_option('xwayland'))
|
xcb = dependency('xcb', required : get_option('xwayland'))
|
||||||
|
|
@ -42,12 +38,11 @@ libscenefx_dep = dependency('scenefx-0.4',version: '>=0.4.1')
|
||||||
pixman_dep = dependency('pixman-1')
|
pixman_dep = dependency('pixman-1')
|
||||||
cjson_dep = dependency('libcjson')
|
cjson_dep = dependency('libcjson')
|
||||||
|
|
||||||
|
# version info
|
||||||
# 获取版本信息
|
|
||||||
git = find_program('git', required : false)
|
git = find_program('git', required : false)
|
||||||
is_git_repo = false
|
is_git_repo = false
|
||||||
|
|
||||||
# 检查当前目录是否是 Git 仓库
|
# check if current directory is a git repo
|
||||||
if git.found()
|
if git.found()
|
||||||
git_status = run_command(git, 'rev-parse', '--is-inside-work-tree', check : false)
|
git_status = run_command(git, 'rev-parse', '--is-inside-work-tree', check : false)
|
||||||
if git_status.returncode() == 0 and git_status.stdout().strip() == 'true'
|
if git_status.returncode() == 0 and git_status.stdout().strip() == 'true'
|
||||||
|
|
@ -56,18 +51,18 @@ if git.found()
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if is_git_repo
|
if is_git_repo
|
||||||
# 如果是 Git 目录,获取 Commit Hash 和最新的 tag
|
# if current directory is a git repo, get commit hash and latest tag
|
||||||
commit_hash = run_command(git, 'rev-parse', '--short', 'HEAD', check : false).stdout().strip()
|
commit_hash = run_command(git, 'rev-parse', '--short', 'HEAD', check : false).stdout().strip()
|
||||||
latest_tag = meson.project_version()
|
latest_tag = meson.project_version()
|
||||||
version_with_hash = '@0@(@1@)'.format(latest_tag, commit_hash)
|
version_with_hash = '@0@(@1@)'.format(latest_tag, commit_hash)
|
||||||
else
|
else
|
||||||
# 如果不是 Git 目录,使用项目版本号和 "release" 字符串
|
# if not a git repo, use project version and "release" string
|
||||||
commit_hash = 'release'
|
commit_hash = 'release'
|
||||||
latest_tag = meson.project_version()
|
latest_tag = meson.project_version()
|
||||||
version_with_hash = '@0@(@1@)'.format(latest_tag, commit_hash)
|
version_with_hash = '@0@(@1@)'.format(latest_tag, commit_hash)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# 定义编译参数
|
# define compilation args
|
||||||
c_args = [
|
c_args = [
|
||||||
'-g',
|
'-g',
|
||||||
'-Wno-unused-function',
|
'-Wno-unused-function',
|
||||||
|
|
@ -77,7 +72,7 @@ c_args = [
|
||||||
'-DSYSCONFDIR="@0@"'.format('/etc'),
|
'-DSYSCONFDIR="@0@"'.format('/etc'),
|
||||||
]
|
]
|
||||||
|
|
||||||
# 仅在 debug 选项启用时添加调试参数
|
# add debug args only when debug option is enabled
|
||||||
if get_option('asan')
|
if get_option('asan')
|
||||||
c_args += [
|
c_args += [
|
||||||
'-fsanitize=address',
|
'-fsanitize=address',
|
||||||
|
|
@ -90,7 +85,7 @@ if xcb.found() and xlibs.found()
|
||||||
c_args += '-DXWAYLAND'
|
c_args += '-DXWAYLAND'
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# 链接参数(根据 debug 状态添加 ASAN)
|
# define link args
|
||||||
link_args = []
|
link_args = []
|
||||||
if get_option('asan')
|
if get_option('asan')
|
||||||
link_args += '-fsanitize=address'
|
link_args += '-fsanitize=address'
|
||||||
|
|
@ -135,7 +130,7 @@ wayland_scanner_private_code = generator(
|
||||||
arguments: ['private-code', '@INPUT@', '@OUTPUT@']
|
arguments: ['private-code', '@INPUT@', '@OUTPUT@']
|
||||||
)
|
)
|
||||||
|
|
||||||
# 在 mmsg 目标中使用生成器
|
# use generator in mmsg target
|
||||||
executable('mmsg',
|
executable('mmsg',
|
||||||
'mmsg/mmsg.c',
|
'mmsg/mmsg.c',
|
||||||
wayland_scanner_private_code.process(dwl_ipc_protocol),
|
wayland_scanner_private_code.process(dwl_ipc_protocol),
|
||||||
|
|
@ -150,8 +145,10 @@ executable('mmsg',
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
mandir = get_option('mandir')
|
||||||
desktop_install_dir = join_paths(prefix, 'share/wayland-sessions')
|
desktop_install_dir = join_paths(prefix, 'share/wayland-sessions')
|
||||||
portal_install_dir = join_paths(prefix, 'share/xdg-desktop-portal')
|
portal_install_dir = join_paths(prefix, 'share/xdg-desktop-portal')
|
||||||
install_data('assets/mango.desktop', install_dir : desktop_install_dir)
|
install_data('assets/mango.desktop', install_dir : desktop_install_dir)
|
||||||
install_data('assets/mango-portals.conf', install_dir : portal_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('assets/config.conf', install_dir : join_paths(sysconfdir, 'mango'))
|
||||||
|
install_data('mmsg/mmsg.1', install_dir : join_paths(mandir, 'man1'))
|
||||||
|
|
|
||||||
122
mmsg/mmsg.1
Normal file
122
mmsg/mmsg.1
Normal file
|
|
@ -0,0 +1,122 @@
|
||||||
|
.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.
|
||||||
74
mmsg/mmsg.c
74
mmsg/mmsg.c
|
|
@ -7,7 +7,73 @@
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
#include <unistd.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 "
|
||||||
|
"(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 <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[]) {
|
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) {
|
if (argc < 2) {
|
||||||
fprintf(stderr, "Usage: mmsg <command> [args...]\n");
|
fprintf(stderr, "Usage: mmsg <command> [args...]\n");
|
||||||
fprintf(stderr, " get <type> ... one-shot request\n");
|
fprintf(stderr, " get <type> ... one-shot request\n");
|
||||||
|
|
@ -37,7 +103,6 @@ int main(int argc, char *argv[]) {
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 拼接命令,缓冲区大小 4096 以容纳较长参数
|
|
||||||
char cmd[4096] = {0};
|
char cmd[4096] = {0};
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
for (int i = 1; i < argc; i++) {
|
for (int i = 1; i < argc; i++) {
|
||||||
|
|
@ -51,7 +116,6 @@ int main(int argc, char *argv[]) {
|
||||||
offset += n;
|
offset += n;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加换行符
|
|
||||||
int n = snprintf(cmd + offset, sizeof(cmd) - offset, "\n");
|
int n = snprintf(cmd + offset, sizeof(cmd) - offset, "\n");
|
||||||
if (n < 0 || n >= (int)(sizeof(cmd) - offset)) {
|
if (n < 0 || n >= (int)(sizeof(cmd) - offset)) {
|
||||||
fprintf(stderr, "Error: command too long to append newline.\n");
|
fprintf(stderr, "Error: command too long to append newline.\n");
|
||||||
|
|
@ -59,14 +123,12 @@ int main(int argc, char *argv[]) {
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 发送命令,使用 MSG_NOSIGNAL 避免 SIGPIPE
|
|
||||||
if (send(sock, cmd, strlen(cmd), MSG_NOSIGNAL) < 0) {
|
if (send(sock, cmd, strlen(cmd), MSG_NOSIGNAL) < 0) {
|
||||||
perror("send");
|
perror("send");
|
||||||
close(sock);
|
close(sock);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 将 socket 封装为行缓冲文件流,自动处理 TCP 拆包,按完整行读取
|
|
||||||
FILE *stream = fdopen(sock, "r");
|
FILE *stream = fdopen(sock, "r");
|
||||||
if (!stream) {
|
if (!stream) {
|
||||||
perror("fdopen");
|
perror("fdopen");
|
||||||
|
|
@ -74,7 +136,6 @@ int main(int argc, char *argv[]) {
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 按行读取并输出,直到连接关闭(get 模式服务端主动 close)或出错
|
|
||||||
char *line = NULL;
|
char *line = NULL;
|
||||||
size_t len = 0;
|
size_t len = 0;
|
||||||
while (getline(&line, &len, stream) != -1) {
|
while (getline(&line, &len, stream) != -1) {
|
||||||
|
|
@ -82,11 +143,10 @@ int main(int argc, char *argv[]) {
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否因读取错误退出(而非正常 EOF)
|
|
||||||
if (ferror(stream)) {
|
if (ferror(stream)) {
|
||||||
perror("recv");
|
perror("recv");
|
||||||
free(line);
|
free(line);
|
||||||
fclose(stream); // 关闭 stream 同时关闭 socket
|
fclose(stream);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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) {
|
void client_tile_resize(Client *c, struct wlr_box geo, int32_t interact) {
|
||||||
if (!ISSCROLLTILED(c))
|
if (!ISFAKETILED(c))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!c->isfullscreen && !c->ismaximizescreen) {
|
if (!c->isfullscreen && !c->ismaximizescreen) {
|
||||||
|
|
@ -87,3 +87,9 @@ void client_active(Client *c) {
|
||||||
view_in_mon(&(Arg){.ui = target}, true, c->mon, true);
|
view_in_mon(&(Arg){.ui = target}, true, c->mon, true);
|
||||||
focusclient(c, 1);
|
focusclient(c, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void client_pending_force_kill(Client *c) {
|
||||||
|
if (!c)
|
||||||
|
return;
|
||||||
|
kill(c->pid, SIGKILL);
|
||||||
|
}
|
||||||
|
|
@ -305,7 +305,8 @@ void client_draw_shadow(Client *c) {
|
||||||
if (c->iskilling || !client_surface(c)->mapped || c->isnoshadow)
|
if (c->iskilling || !client_surface(c)->mapped || c->isnoshadow)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!config.shadows || (!c->isfloating && config.shadow_only_floating)) {
|
if (!config.shadows || c->isfullscreen ||
|
||||||
|
(!c->isfloating && config.shadow_only_floating)) {
|
||||||
if (c->shadow->node.enabled)
|
if (c->shadow->node.enabled)
|
||||||
wlr_scene_node_set_enabled(&c->shadow->node, false);
|
wlr_scene_node_set_enabled(&c->shadow->node, false);
|
||||||
return;
|
return;
|
||||||
|
|
@ -405,7 +406,7 @@ void apply_split_border(Client *c, bool hit_no_border) {
|
||||||
const Layout *layout = c->mon->pertag->ltidxs[c->mon->pertag->curtag];
|
const Layout *layout = c->mon->pertag->ltidxs[c->mon->pertag->curtag];
|
||||||
|
|
||||||
if (hit_no_border || !ISTILED(c) || layout->id != DWINDLE ||
|
if (hit_no_border || !ISTILED(c) || layout->id != DWINDLE ||
|
||||||
!config.dwindle_manual_split) {
|
!config.dwindle_manual_split || c->isfullscreen) {
|
||||||
if (c->splitindicator[0]->node.enabled) {
|
if (c->splitindicator[0]->node.enabled) {
|
||||||
wlr_scene_node_set_enabled(&c->splitindicator[0]->node, false);
|
wlr_scene_node_set_enabled(&c->splitindicator[0]->node, false);
|
||||||
}
|
}
|
||||||
|
|
@ -492,6 +493,18 @@ void apply_border(Client *c) {
|
||||||
if (!c || c->iskilling || !client_surface(c)->mapped)
|
if (!c || c->iskilling || !client_surface(c)->mapped)
|
||||||
return;
|
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);
|
bool hit_no_border = check_hit_no_border(c);
|
||||||
|
|
||||||
apply_split_border(c, hit_no_border);
|
apply_split_border(c, hit_no_border);
|
||||||
|
|
|
||||||
|
|
@ -261,6 +261,7 @@ typedef struct {
|
||||||
int32_t overviewgappi;
|
int32_t overviewgappi;
|
||||||
int32_t overviewgappo;
|
int32_t overviewgappo;
|
||||||
uint32_t cursor_hide_timeout;
|
uint32_t cursor_hide_timeout;
|
||||||
|
uint32_t cursor_hide_on_keypress;
|
||||||
|
|
||||||
uint32_t axis_bind_apply_timeout;
|
uint32_t axis_bind_apply_timeout;
|
||||||
uint32_t focus_on_activate;
|
uint32_t focus_on_activate;
|
||||||
|
|
@ -559,6 +560,26 @@ 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) {
|
int32_t parse_fold_state(const char *str) {
|
||||||
// 将输入字符串转换为小写
|
// 将输入字符串转换为小写
|
||||||
char lowerStr[10];
|
char lowerStr[10];
|
||||||
|
|
@ -1029,6 +1050,7 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value,
|
||||||
(*arg).i = atoi(arg_value);
|
(*arg).i = atoi(arg_value);
|
||||||
} else if (strcmp(func_name, "killclient") == 0) {
|
} else if (strcmp(func_name, "killclient") == 0) {
|
||||||
func = killclient;
|
func = killclient;
|
||||||
|
(*arg).i = parse_force(arg_value);
|
||||||
} else if (strcmp(func_name, "centerwin") == 0) {
|
} else if (strcmp(func_name, "centerwin") == 0) {
|
||||||
func = centerwin;
|
func = centerwin;
|
||||||
} else if (strcmp(func_name, "focuslast") == 0) {
|
} else if (strcmp(func_name, "focuslast") == 0) {
|
||||||
|
|
@ -1693,6 +1715,8 @@ bool parse_option(Config *config, char *key, char *value) {
|
||||||
config->overviewgappo = atoi(value);
|
config->overviewgappo = atoi(value);
|
||||||
} else if (strcmp(key, "cursor_hide_timeout") == 0) {
|
} else if (strcmp(key, "cursor_hide_timeout") == 0) {
|
||||||
config->cursor_hide_timeout = atoi(value);
|
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) {
|
} else if (strcmp(key, "axis_bind_apply_timeout") == 0) {
|
||||||
config->axis_bind_apply_timeout = atoi(value);
|
config->axis_bind_apply_timeout = atoi(value);
|
||||||
} else if (strcmp(key, "focus_on_activate") == 0) {
|
} else if (strcmp(key, "focus_on_activate") == 0) {
|
||||||
|
|
@ -3325,6 +3349,8 @@ void override_config(void) {
|
||||||
CLAMP_INT(config.no_radius_when_single, 0, 1);
|
CLAMP_INT(config.no_radius_when_single, 0, 1);
|
||||||
config.cursor_hide_timeout =
|
config.cursor_hide_timeout =
|
||||||
CLAMP_INT(config.cursor_hide_timeout, 0, 36000);
|
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.single_scratchpad = CLAMP_INT(config.single_scratchpad, 0, 1);
|
||||||
config.repeat_rate = CLAMP_INT(config.repeat_rate, 1, 1000);
|
config.repeat_rate = CLAMP_INT(config.repeat_rate, 1, 1000);
|
||||||
config.repeat_delay = CLAMP_INT(config.repeat_delay, 1, 20000);
|
config.repeat_delay = CLAMP_INT(config.repeat_delay, 1, 20000);
|
||||||
|
|
@ -3486,6 +3512,7 @@ void set_value_default() {
|
||||||
config.overviewgappi = 5;
|
config.overviewgappi = 5;
|
||||||
config.overviewgappo = 30;
|
config.overviewgappo = 30;
|
||||||
config.cursor_hide_timeout = 0;
|
config.cursor_hide_timeout = 0;
|
||||||
|
config.cursor_hide_on_keypress = 0;
|
||||||
|
|
||||||
config.warpcursor = 1;
|
config.warpcursor = 1;
|
||||||
config.drag_corner = 3;
|
config.drag_corner = 3;
|
||||||
|
|
|
||||||
|
|
@ -345,7 +345,11 @@ int32_t setmfact(const Arg *arg) {
|
||||||
int32_t killclient(const Arg *arg) {
|
int32_t killclient(const Arg *arg) {
|
||||||
Client *c = arg->tc ? arg->tc : (selmon ? selmon->sel : NULL);
|
Client *c = arg->tc ? arg->tc : (selmon ? selmon->sel : NULL);
|
||||||
if (c) {
|
if (c) {
|
||||||
pending_kill_client(c);
|
if (arg->i == FORCE) {
|
||||||
|
client_pending_force_kill(c);
|
||||||
|
} else {
|
||||||
|
pending_kill_client(c);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ static struct wlr_tablet_manager_v2 *tablet_mgr;
|
||||||
struct Tablet {
|
struct Tablet {
|
||||||
struct wlr_tablet_v2_tablet *tablet_v2;
|
struct wlr_tablet_v2_tablet *tablet_v2;
|
||||||
struct wl_listener destroy;
|
struct wl_listener destroy;
|
||||||
|
struct wlr_input_device *device;
|
||||||
struct wl_list link;
|
struct wl_list link;
|
||||||
};
|
};
|
||||||
static struct wl_list tablets;
|
static struct wl_list tablets;
|
||||||
|
|
@ -38,6 +39,7 @@ struct TabletTool {
|
||||||
|
|
||||||
struct TabletPad {
|
struct TabletPad {
|
||||||
struct wlr_tablet_v2_tablet_pad *pad_v2;
|
struct wlr_tablet_v2_tablet_pad *pad_v2;
|
||||||
|
struct wlr_input_device *device;
|
||||||
struct Tablet *tablet;
|
struct Tablet *tablet;
|
||||||
struct wl_listener tablet_destroy;
|
struct wl_listener tablet_destroy;
|
||||||
struct wl_listener attach;
|
struct wl_listener attach;
|
||||||
|
|
@ -72,11 +74,18 @@ void createtablet(struct wlr_input_device *device) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tablet->device = device;
|
||||||
tablet->tablet_v2 = wlr_tablet_create(tablet_mgr, seat, 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->tablet_v2->wlr_tablet->data = tablet;
|
||||||
tablet->destroy.notify = destroytablet;
|
tablet->destroy.notify = destroytablet;
|
||||||
wl_signal_add(&tablet->tablet_v2->wlr_device->events.destroy,
|
wl_signal_add(&tablet->device->events.destroy, &tablet->destroy);
|
||||||
&tablet->destroy);
|
|
||||||
if (libinput_device_config_send_events_get_modes(device_handle)) {
|
if (libinput_device_config_send_events_get_modes(device_handle)) {
|
||||||
libinput_device_config_send_events_set_mode(device_handle,
|
libinput_device_config_send_events_set_mode(device_handle,
|
||||||
config.send_events_mode);
|
config.send_events_mode);
|
||||||
|
|
@ -90,7 +99,7 @@ void createtablet(struct wlr_input_device *device) {
|
||||||
wlr_libinput_get_device_handle(device));
|
wlr_libinput_get_device_handle(device));
|
||||||
struct TabletPad *tablet_pad;
|
struct TabletPad *tablet_pad;
|
||||||
wl_list_for_each(tablet_pad, &tablet_pads, link) {
|
wl_list_for_each(tablet_pad, &tablet_pads, link) {
|
||||||
struct wlr_input_device *pad_device = tablet_pad->pad_v2->wlr_device;
|
struct wlr_input_device *pad_device = tablet_pad->device;
|
||||||
if (!wlr_input_device_is_libinput(pad_device)) {
|
if (!wlr_input_device_is_libinput(pad_device)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -129,8 +138,7 @@ void attach_tablet_pad(struct TabletPad *tablet_pad, struct Tablet *tablet) {
|
||||||
|
|
||||||
wl_list_remove(&tablet_pad->tablet_destroy.link);
|
wl_list_remove(&tablet_pad->tablet_destroy.link);
|
||||||
tablet_pad->tablet_destroy.notify = tabletpadtabletdestroy;
|
tablet_pad->tablet_destroy.notify = tabletpadtabletdestroy;
|
||||||
wl_signal_add(&tablet->tablet_v2->wlr_device->events.destroy,
|
wl_signal_add(&tablet->device->events.destroy, &tablet_pad->tablet_destroy);
|
||||||
&tablet_pad->tablet_destroy);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void tabletpadattach(struct wl_listener *listener, void *data) {
|
void tabletpadattach(struct wl_listener *listener, void *data) {
|
||||||
|
|
@ -152,27 +160,38 @@ void createtabletpad(struct wlr_input_device *device) {
|
||||||
wlr_log(WLR_ERROR, "could not allocate tablet_pad");
|
wlr_log(WLR_ERROR, "could not allocate tablet_pad");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tablet_pad->device = device;
|
||||||
tablet_pad->pad_v2 = wlr_tablet_pad_create(tablet_mgr, seat, 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->destroy.notify = destroytabletpad;
|
||||||
tablet_pad->attach.notify = tabletpadattach;
|
tablet_pad->attach.notify = tabletpadattach;
|
||||||
wl_list_init(&tablet_pad->tablet_destroy.link);
|
wl_list_init(&tablet_pad->tablet_destroy.link);
|
||||||
wl_signal_add(&tablet_pad->pad_v2->wlr_device->events.destroy,
|
|
||||||
&tablet_pad->destroy);
|
wl_signal_add(&device->events.destroy, &tablet_pad->destroy);
|
||||||
|
|
||||||
wl_signal_add(&tablet_pad->pad_v2->wlr_pad->events.attach_tablet,
|
wl_signal_add(&tablet_pad->pad_v2->wlr_pad->events.attach_tablet,
|
||||||
&tablet_pad->attach);
|
&tablet_pad->attach);
|
||||||
wl_list_insert(&tablet_pads, &tablet_pad->link);
|
wl_list_insert(&tablet_pads, &tablet_pad->link);
|
||||||
|
|
||||||
/* Search for a sibling tablet */
|
/* Search for a sibling tablet */
|
||||||
if (!wlr_input_device_is_libinput(tablet_pad->pad_v2->wlr_device)) {
|
if (!wlr_input_device_is_libinput(device)) {
|
||||||
/* We can only do this on libinput devices */
|
/* We can only do this on libinput devices */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct libinput_device_group *group = libinput_device_get_device_group(
|
struct libinput_device_group *group = libinput_device_get_device_group(
|
||||||
wlr_libinput_get_device_handle(tablet_pad->pad_v2->wlr_device));
|
wlr_libinput_get_device_handle(device));
|
||||||
|
|
||||||
struct Tablet *tablet;
|
struct Tablet *tablet;
|
||||||
wl_list_for_each(tablet, &tablets, link) {
|
wl_list_for_each(tablet, &tablets, link) {
|
||||||
struct wlr_input_device *tablet_device = tablet->tablet_v2->wlr_device;
|
struct wlr_input_device *tablet_device = tablet->device;
|
||||||
if (!wlr_input_device_is_libinput(tablet_device)) {
|
if (!wlr_input_device_is_libinput(tablet_device)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -249,11 +268,11 @@ void tablettoolmotion(struct TabletTool *tool, bool change_x, bool change_y,
|
||||||
switch (tool->tool_v2->wlr_tool->type) {
|
switch (tool->tool_v2->wlr_tool->type) {
|
||||||
case WLR_TABLET_TOOL_TYPE_LENS:
|
case WLR_TABLET_TOOL_TYPE_LENS:
|
||||||
case WLR_TABLET_TOOL_TYPE_MOUSE:
|
case WLR_TABLET_TOOL_TYPE_MOUSE:
|
||||||
wlr_cursor_move(cursor, tablet->tablet_v2->wlr_device, dx, dy);
|
wlr_cursor_move(cursor, tablet->device, dx, dy);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
wlr_cursor_warp_absolute(cursor, tablet->tablet_v2->wlr_device,
|
wlr_cursor_warp_absolute(cursor, tablet->device, change_x ? x : NAN,
|
||||||
change_x ? x : NAN, change_y ? y : NAN);
|
change_y ? y : NAN);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -91,9 +91,9 @@ setclient_coordinate_center(Client *c, Monitor *tm, struct wlr_box geom,
|
||||||
if (!m)
|
if (!m)
|
||||||
return geom;
|
return geom;
|
||||||
|
|
||||||
uint32_t cbw = check_hit_no_border(c) ? c->bw : 0;
|
uint32_t cbw = c && check_hit_no_border(c) ? c->bw : 0;
|
||||||
|
|
||||||
if (!c->no_force_center && m) {
|
if ((!c || !c->no_force_center) && m) {
|
||||||
tempbox.x = m->w.x + (m->w.width - geom.width) / 2;
|
tempbox.x = m->w.x + (m->w.width - geom.width) / 2;
|
||||||
tempbox.y = m->w.y + (m->w.height - geom.height) / 2;
|
tempbox.y = m->w.y + (m->w.height - geom.height) / 2;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -217,7 +217,7 @@ static cJSON *build_monitor_tags_response(Monitor *m) {
|
||||||
|
|
||||||
static void send_static_json(int fd, const char *json_str) {
|
static void send_static_json(int fd, const char *json_str) {
|
||||||
size_t len = strlen(json_str);
|
size_t len = strlen(json_str);
|
||||||
send(fd, json_str, len, MSG_NOSIGNAL);
|
send(fd, json_str, len, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ---------- 一次性命令处理 ---------- */
|
/* ---------- 一次性命令处理 ---------- */
|
||||||
|
|
@ -413,7 +413,7 @@ static void handle_command(int client_fd, const char *cmd_raw) {
|
||||||
char *msg = malloc(len + 2);
|
char *msg = malloc(len + 2);
|
||||||
if (msg) {
|
if (msg) {
|
||||||
snprintf(msg, len + 2, "%s\n", json_str);
|
snprintf(msg, len + 2, "%s\n", json_str);
|
||||||
send(client_fd, msg, len + 1, MSG_NOSIGNAL);
|
send(client_fd, msg, len + 1, 0);
|
||||||
free(msg);
|
free(msg);
|
||||||
}
|
}
|
||||||
free(json_str);
|
free(json_str);
|
||||||
|
|
@ -434,7 +434,7 @@ static void ipc_notify_json_to_fd(int fd, cJSON *json) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
snprintf(msg, len + 2, "%s\n", str);
|
snprintf(msg, len + 2, "%s\n", str);
|
||||||
if (send(fd, msg, len + 1, MSG_NOSIGNAL) < 0) {
|
if (send(fd, msg, len + 1, 0) < 0) {
|
||||||
struct ipc_watch_client *wc, *tmp;
|
struct ipc_watch_client *wc, *tmp;
|
||||||
wl_list_for_each_safe(wc, tmp, &watch_clients, link) {
|
wl_list_for_each_safe(wc, tmp, &watch_clients, link) {
|
||||||
if (wc->fd == fd) {
|
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) {
|
if (mask & WL_EVENT_READABLE) {
|
||||||
char buf[64];
|
char buf[64];
|
||||||
ssize_t n = recv(fd, buf, sizeof(buf), MSG_DONTWAIT);
|
ssize_t n = recv(fd, buf, sizeof(buf), 0);
|
||||||
if (n == 0 || (n < 0 && errno != EAGAIN && errno != EWOULDBLOCK)) {
|
if (n == 0 || (n < 0 && errno != EAGAIN && errno != EWOULDBLOCK)) {
|
||||||
ipc_remove_watch_client(wc);
|
ipc_remove_watch_client(wc);
|
||||||
}
|
}
|
||||||
|
|
@ -643,8 +643,7 @@ static int ipc_handle_client_data(int fd, uint32_t mask, void *data) {
|
||||||
available = client->buf_cap - client->buf_len;
|
available = client->buf_cap - client->buf_len;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t n = recv(fd, client->buf + client->buf_len, available - 1,
|
ssize_t n = recv(fd, client->buf + client->buf_len, available - 1, 0);
|
||||||
MSG_DONTWAIT);
|
|
||||||
if (n <= 0)
|
if (n <= 0)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
|
|
@ -683,8 +682,12 @@ static int ipc_handle_connection(int fd, uint32_t mask, void *data) {
|
||||||
if (client_fd < 0)
|
if (client_fd < 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
// 设置 O_NONBLOCK
|
||||||
int flags = fcntl(client_fd, F_GETFL, 0);
|
int flags = fcntl(client_fd, F_GETFL, 0);
|
||||||
fcntl(client_fd, F_SETFL, flags | O_NONBLOCK);
|
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));
|
struct ipc_client_state *client = calloc(1, sizeof(*client));
|
||||||
client->fd = client_fd;
|
client->fd = client_fd;
|
||||||
|
|
@ -715,7 +718,7 @@ void ipc_notify_monitor(Monitor *m) {
|
||||||
snprintf(json_str, len + 2, "%s\n", raw);
|
snprintf(json_str, len + 2, "%s\n", raw);
|
||||||
free(raw);
|
free(raw);
|
||||||
}
|
}
|
||||||
if (send(wc->fd, json_str, len + 1, MSG_NOSIGNAL) < 0)
|
if (send(wc->fd, json_str, len + 1, 0) < 0)
|
||||||
ipc_remove_watch_client(wc);
|
ipc_remove_watch_client(wc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -731,10 +734,8 @@ void ipc_notify_last_surface_ws_name(Monitor *m) {
|
||||||
if (wc->type != IPC_WATCH_LAST_OPEN_SURFACE)
|
if (wc->type != IPC_WATCH_LAST_OPEN_SURFACE)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* 匹配具体 monitor 名称,或空名称表示默认 selmon */
|
|
||||||
bool match = false;
|
bool match = false;
|
||||||
if (wc->target.monitor.name[0] == '\0') {
|
if (wc->target.monitor.name[0] == '\0') {
|
||||||
/* 订阅的是 selmon */
|
|
||||||
if (m == selmon)
|
if (m == selmon)
|
||||||
match = true;
|
match = true;
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -759,7 +760,7 @@ void ipc_notify_last_surface_ws_name(Monitor *m) {
|
||||||
snprintf(json_str, len + 2, "%s\n", raw);
|
snprintf(json_str, len + 2, "%s\n", raw);
|
||||||
free(raw);
|
free(raw);
|
||||||
}
|
}
|
||||||
if (send(wc->fd, json_str, len + 1, MSG_NOSIGNAL) < 0)
|
if (send(wc->fd, json_str, len + 1, 0) < 0)
|
||||||
ipc_remove_watch_client(wc);
|
ipc_remove_watch_client(wc);
|
||||||
}
|
}
|
||||||
free(json_str);
|
free(json_str);
|
||||||
|
|
@ -790,7 +791,7 @@ void ipc_notify_focusing_client(void) {
|
||||||
snprintf(json_str, len + 2, "%s\n", raw);
|
snprintf(json_str, len + 2, "%s\n", raw);
|
||||||
free(raw);
|
free(raw);
|
||||||
}
|
}
|
||||||
if (send(wc->fd, json_str, len + 1, MSG_NOSIGNAL) < 0)
|
if (send(wc->fd, json_str, len + 1, 0) < 0)
|
||||||
ipc_remove_watch_client(wc);
|
ipc_remove_watch_client(wc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -814,7 +815,7 @@ void ipc_notify_client(Client *c) {
|
||||||
snprintf(json_str, len + 2, "%s\n", raw);
|
snprintf(json_str, len + 2, "%s\n", raw);
|
||||||
free(raw);
|
free(raw);
|
||||||
}
|
}
|
||||||
if (send(wc->fd, json_str, len + 1, MSG_NOSIGNAL) < 0)
|
if (send(wc->fd, json_str, len + 1, 0) < 0)
|
||||||
ipc_remove_watch_client(wc);
|
ipc_remove_watch_client(wc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -840,7 +841,7 @@ void ipc_notify_tags(Monitor *m) {
|
||||||
snprintf(json_str, len + 2, "%s\n", raw);
|
snprintf(json_str, len + 2, "%s\n", raw);
|
||||||
free(raw);
|
free(raw);
|
||||||
}
|
}
|
||||||
if (send(wc->fd, json_str, len + 1, MSG_NOSIGNAL) < 0)
|
if (send(wc->fd, json_str, len + 1, 0) < 0)
|
||||||
ipc_remove_watch_client(wc);
|
ipc_remove_watch_client(wc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -870,7 +871,7 @@ void ipc_notify_all_monitors(void) {
|
||||||
snprintf(json_str, len + 2, "%s\n", raw);
|
snprintf(json_str, len + 2, "%s\n", raw);
|
||||||
free(raw);
|
free(raw);
|
||||||
}
|
}
|
||||||
if (send(wc->fd, json_str, len + 1, MSG_NOSIGNAL) < 0)
|
if (send(wc->fd, json_str, len + 1, 0) < 0)
|
||||||
ipc_remove_watch_client(wc);
|
ipc_remove_watch_client(wc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -900,7 +901,7 @@ void ipc_notify_all_clients(void) {
|
||||||
snprintf(json_str, len + 2, "%s\n", raw);
|
snprintf(json_str, len + 2, "%s\n", raw);
|
||||||
free(raw);
|
free(raw);
|
||||||
}
|
}
|
||||||
if (send(wc->fd, json_str, len + 1, MSG_NOSIGNAL) < 0)
|
if (send(wc->fd, json_str, len + 1, 0) < 0)
|
||||||
ipc_remove_watch_client(wc);
|
ipc_remove_watch_client(wc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -925,7 +926,7 @@ void ipc_notify_all_tags(void) {
|
||||||
snprintf(json_str, len + 2, "%s\n", raw);
|
snprintf(json_str, len + 2, "%s\n", raw);
|
||||||
free(raw);
|
free(raw);
|
||||||
}
|
}
|
||||||
if (send(wc->fd, json_str, len + 1, MSG_NOSIGNAL) < 0)
|
if (send(wc->fd, json_str, len + 1, 0) < 0)
|
||||||
ipc_remove_watch_client(wc);
|
ipc_remove_watch_client(wc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -951,7 +952,7 @@ void ipc_notify_keymode(void) {
|
||||||
snprintf(json_str, len + 2, "%s\n", raw);
|
snprintf(json_str, len + 2, "%s\n", raw);
|
||||||
free(raw);
|
free(raw);
|
||||||
}
|
}
|
||||||
if (send(wc->fd, json_str, len + 1, MSG_NOSIGNAL) < 0)
|
if (send(wc->fd, json_str, len + 1, 0) < 0)
|
||||||
ipc_remove_watch_client(wc);
|
ipc_remove_watch_client(wc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -977,7 +978,7 @@ void ipc_notify_kb_layout(void) {
|
||||||
snprintf(json_str, len + 2, "%s\n", raw);
|
snprintf(json_str, len + 2, "%s\n", raw);
|
||||||
free(raw);
|
free(raw);
|
||||||
}
|
}
|
||||||
if (send(wc->fd, json_str, len + 1, MSG_NOSIGNAL) < 0)
|
if (send(wc->fd, json_str, len + 1, 0) < 0)
|
||||||
ipc_remove_watch_client(wc);
|
ipc_remove_watch_client(wc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1000,11 +1001,25 @@ void ipc_init(struct wl_event_loop *event_loop) {
|
||||||
snprintf(ipc_socket_path, sizeof(ipc_socket_path), "%s/mango-%d.sock",
|
snprintf(ipc_socket_path, sizeof(ipc_socket_path), "%s/mango-%d.sock",
|
||||||
xdg_runtime, getpid());
|
xdg_runtime, getpid());
|
||||||
|
|
||||||
ipc_sock_fd =
|
ipc_sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
socket(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
|
|
||||||
if (ipc_sock_fd < 0)
|
if (ipc_sock_fd < 0)
|
||||||
return;
|
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};
|
struct sockaddr_un addr = {.sun_family = AF_UNIX};
|
||||||
strncpy(addr.sun_path, ipc_socket_path, sizeof(addr.sun_path) - 1);
|
strncpy(addr.sun_path, ipc_socket_path, sizeof(addr.sun_path) - 1);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -751,6 +751,7 @@ void resize_tile_grid_fair(Client *grabc, bool isdrag, int32_t offsetx,
|
||||||
|
|
||||||
void resize_tile_scroller(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) {
|
int32_t offsety, uint32_t time, bool isvertical) {
|
||||||
|
|
||||||
if (!grabc || grabc->isfullscreen || grabc->ismaximizescreen)
|
if (!grabc || grabc->isfullscreen || grabc->ismaximizescreen)
|
||||||
return;
|
return;
|
||||||
if (grabc->mon->isoverview)
|
if (grabc->mon->isoverview)
|
||||||
|
|
@ -772,7 +773,7 @@ void resize_tile_scroller(Client *grabc, bool isdrag, int32_t offsetx,
|
||||||
|
|
||||||
Client *stack_head_client = headnode->client;
|
Client *stack_head_client = headnode->client;
|
||||||
|
|
||||||
if (m->visible_tiling_clients == 1 &&
|
if (m->visible_scroll_tiling_clients == 1 &&
|
||||||
!config.scroller_ignore_proportion_single)
|
!config.scroller_ignore_proportion_single)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -500,16 +500,13 @@ void deck(Monitor *m) {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
wl_list_for_each(fc, &clients, link) {
|
wl_list_for_each(fc, &clients, link) {
|
||||||
|
|
||||||
if (VISIBLEON(fc, m) && ISFAKETILED(fc))
|
if (VISIBLEON(fc, m) && ISFAKETILED(fc))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate master width using mfact from pertag
|
|
||||||
mfact = fc->master_mfact_per > 0.0f ? fc->master_mfact_per
|
mfact = fc->master_mfact_per > 0.0f ? fc->master_mfact_per
|
||||||
: m->pertag->mfacts[m->pertag->curtag];
|
: m->pertag->mfacts[m->pertag->curtag];
|
||||||
|
|
||||||
// Calculate master width including outer gaps
|
|
||||||
if (n > nmasters)
|
if (n > nmasters)
|
||||||
mw = nmasters ? round((m->w.width - 2 * cur_gappoh) * mfact) : 0;
|
mw = nmasters ? round((m->w.width - 2 * cur_gappoh) * mfact) : 0;
|
||||||
else
|
else
|
||||||
|
|
@ -521,16 +518,15 @@ void deck(Monitor *m) {
|
||||||
continue;
|
continue;
|
||||||
if (i < nmasters) {
|
if (i < nmasters) {
|
||||||
c->master_mfact_per = mfact;
|
c->master_mfact_per = mfact;
|
||||||
// Master area clients
|
int32_t h =
|
||||||
client_tile_resize(
|
(m->w.height - 2 * cur_gappov - my) / (MIN(n, nmasters) - i);
|
||||||
c,
|
client_tile_resize(c,
|
||||||
(struct wlr_box){.x = m->w.x + cur_gappoh,
|
(struct wlr_box){.x = m->w.x + cur_gappoh,
|
||||||
.y = m->w.y + cur_gappov + my,
|
.y = m->w.y + cur_gappov + my,
|
||||||
.width = mw,
|
.width = mw,
|
||||||
.height = (m->w.height - 2 * cur_gappov - my) /
|
.height = h},
|
||||||
(MIN(n, nmasters) - i)},
|
0);
|
||||||
0);
|
my += h;
|
||||||
my += c->geom.height;
|
|
||||||
} else {
|
} else {
|
||||||
// Stack area clients
|
// Stack area clients
|
||||||
c->master_mfact_per = mfact;
|
c->master_mfact_per = mfact;
|
||||||
|
|
@ -588,6 +584,7 @@ void grid(Monitor *m) {
|
||||||
int32_t target_gappi = enablegaps ? config.gappih : 0;
|
int32_t target_gappi = enablegaps ? config.gappih : 0;
|
||||||
float single_width_ratio = 0.9;
|
float single_width_ratio = 0.9;
|
||||||
float single_height_ratio = 0.9;
|
float single_height_ratio = 0.9;
|
||||||
|
struct wlr_box target_geom;
|
||||||
|
|
||||||
n = m->visible_fake_tiling_clients;
|
n = m->visible_fake_tiling_clients;
|
||||||
|
|
||||||
|
|
@ -603,11 +600,11 @@ void grid(Monitor *m) {
|
||||||
ISFAKETILED(c))) {
|
ISFAKETILED(c))) {
|
||||||
cw = (m->w.width - 2 * target_gappo) * single_width_ratio;
|
cw = (m->w.width - 2 * target_gappo) * single_width_ratio;
|
||||||
ch = (m->w.height - 2 * target_gappo) * single_height_ratio;
|
ch = (m->w.height - 2 * target_gappo) * single_height_ratio;
|
||||||
c->geom.x = m->w.x + (m->w.width - cw) / 2;
|
target_geom.x = m->w.x + (m->w.width - cw) / 2;
|
||||||
c->geom.y = m->w.y + (m->w.height - ch) / 2;
|
target_geom.y = m->w.y + (m->w.height - ch) / 2;
|
||||||
c->geom.width = cw;
|
target_geom.width = cw;
|
||||||
c->geom.height = ch;
|
target_geom.height = ch;
|
||||||
client_tile_resize(c, c->geom, 0);
|
client_tile_resize(c, target_geom, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -651,16 +648,16 @@ void grid(Monitor *m) {
|
||||||
cw = avail_w * (col_pers[i] / sum_col);
|
cw = avail_w * (col_pers[i] / sum_col);
|
||||||
|
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
c->geom.x = m->w.x + target_gappo;
|
target_geom.x = m->w.x + target_gappo;
|
||||||
} else if (i == 1) {
|
} else if (i == 1) {
|
||||||
// 第二个窗口的 X 坐标紧跟第一个窗口后面
|
// 第二个窗口的 X 坐标紧跟第一个窗口后面
|
||||||
float cw0 = avail_w * (col_pers[0] / sum_col);
|
float cw0 = avail_w * (col_pers[0] / sum_col);
|
||||||
c->geom.x = m->w.x + target_gappo + cw0 + target_gappi;
|
target_geom.x = m->w.x + target_gappo + cw0 + target_gappi;
|
||||||
}
|
}
|
||||||
c->geom.y = m->w.y + (m->w.height - ch) / 2 + target_gappo;
|
target_geom.y = m->w.y + (m->w.height - ch) / 2 + target_gappo;
|
||||||
c->geom.width = cw;
|
target_geom.width = cw;
|
||||||
c->geom.height = ch;
|
target_geom.height = ch;
|
||||||
client_tile_resize(c, c->geom, 0);
|
client_tile_resize(c, target_geom, 0);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -757,11 +754,11 @@ void grid(Monitor *m) {
|
||||||
? (m->w.y + m->w.height - target_gappo - fl_cy)
|
? (m->w.y + m->w.height - target_gappo - fl_cy)
|
||||||
: avail_h * (row_pers[r_idx] / sum_row);
|
: avail_h * (row_pers[r_idx] / sum_row);
|
||||||
|
|
||||||
c->geom.x = (int32_t)fl_cx;
|
target_geom.x = (int32_t)fl_cx;
|
||||||
c->geom.y = (int32_t)fl_cy;
|
target_geom.y = (int32_t)fl_cy;
|
||||||
c->geom.width = (int32_t)fl_cw;
|
target_geom.width = (int32_t)fl_cw;
|
||||||
c->geom.height = (int32_t)fl_ch;
|
target_geom.height = (int32_t)fl_ch;
|
||||||
client_tile_resize(c, c->geom, 0);
|
client_tile_resize(c, target_geom, 0);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -137,12 +137,10 @@ void vertical_deck(Monitor *m) {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
wl_list_for_each(fc, &clients, link) {
|
wl_list_for_each(fc, &clients, link) {
|
||||||
|
|
||||||
if (VISIBLEON(fc, m) && ISFAKETILED(fc))
|
if (VISIBLEON(fc, m) && ISFAKETILED(fc))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate master width using mfact from pertag
|
|
||||||
mfact = fc->master_mfact_per > 0.0f ? fc->master_mfact_per
|
mfact = fc->master_mfact_per > 0.0f ? fc->master_mfact_per
|
||||||
: m->pertag->mfacts[m->pertag->curtag];
|
: m->pertag->mfacts[m->pertag->curtag];
|
||||||
|
|
||||||
|
|
@ -156,16 +154,18 @@ void vertical_deck(Monitor *m) {
|
||||||
if (!VISIBLEON(c, m) || !ISFAKETILED(c))
|
if (!VISIBLEON(c, m) || !ISFAKETILED(c))
|
||||||
continue;
|
continue;
|
||||||
if (i < nmasters) {
|
if (i < nmasters) {
|
||||||
client_tile_resize(
|
c->master_mfact_per = mfact;
|
||||||
c,
|
int32_t w =
|
||||||
(struct wlr_box){.x = m->w.x + cur_gappoh + mx,
|
(m->w.width - 2 * cur_gappoh - mx) / (MIN(n, nmasters) - i);
|
||||||
.y = m->w.y + cur_gappov,
|
client_tile_resize(c,
|
||||||
.width = (m->w.width - 2 * cur_gappoh - mx) /
|
(struct wlr_box){.x = m->w.x + cur_gappoh + mx,
|
||||||
(MIN(n, nmasters) - i),
|
.y = m->w.y + cur_gappov,
|
||||||
.height = mh},
|
.width = w,
|
||||||
0);
|
.height = mh},
|
||||||
mx += c->geom.width;
|
0);
|
||||||
|
mx += w;
|
||||||
} else {
|
} else {
|
||||||
|
c->master_mfact_per = mfact;
|
||||||
client_tile_resize(
|
client_tile_resize(
|
||||||
c,
|
c,
|
||||||
(struct wlr_box){.x = m->w.x + cur_gappoh,
|
(struct wlr_box){.x = m->w.x + cur_gappoh,
|
||||||
|
|
@ -186,14 +186,13 @@ void vertical_grid(Monitor *m) {
|
||||||
int32_t cw, ch;
|
int32_t cw, ch;
|
||||||
int32_t rows, cols, overrows;
|
int32_t rows, cols, overrows;
|
||||||
Client *c = NULL;
|
Client *c = NULL;
|
||||||
int32_t target_gappo =
|
int32_t target_gappo = enablegaps ? config.gappov : 0;
|
||||||
enablegaps ? m->isoverview ? config.overviewgappo : config.gappov : 0;
|
int32_t target_gappi = enablegaps ? config.gappiv : 0;
|
||||||
int32_t target_gappi =
|
float single_width_ratio = 0.9;
|
||||||
enablegaps ? m->isoverview ? config.overviewgappi : config.gappiv : 0;
|
float single_height_ratio = 0.9;
|
||||||
float single_width_ratio = m->isoverview ? 0.7 : 0.9;
|
struct wlr_box target_geom;
|
||||||
float single_height_ratio = m->isoverview ? 0.8 : 0.9;
|
|
||||||
|
|
||||||
n = m->isoverview ? m->visible_clients : m->visible_fake_tiling_clients;
|
n = m->visible_fake_tiling_clients;
|
||||||
if (n == 0)
|
if (n == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -202,15 +201,14 @@ void vertical_grid(Monitor *m) {
|
||||||
if (c->mon != m)
|
if (c->mon != m)
|
||||||
continue;
|
continue;
|
||||||
if (VISIBLEON(c, m) && !c->isunglobal &&
|
if (VISIBLEON(c, m) && !c->isunglobal &&
|
||||||
((m->isoverview && !client_is_x11_popup(c)) ||
|
(!client_is_x11_popup(c) || ISFAKETILED(c))) {
|
||||||
ISFAKETILED(c))) {
|
|
||||||
ch = (m->w.height - 2 * target_gappo) * single_height_ratio;
|
ch = (m->w.height - 2 * target_gappo) * single_height_ratio;
|
||||||
cw = (m->w.width - 2 * target_gappo) * single_width_ratio;
|
cw = (m->w.width - 2 * target_gappo) * single_width_ratio;
|
||||||
c->geom.x = m->w.x + (m->w.width - cw) / 2;
|
target_geom.x = m->w.x + (m->w.width - cw) / 2;
|
||||||
c->geom.y = m->w.y + (m->w.height - ch) / 2;
|
target_geom.y = m->w.y + (m->w.height - ch) / 2;
|
||||||
c->geom.width = cw;
|
target_geom.width = cw;
|
||||||
c->geom.height = ch;
|
target_geom.height = ch;
|
||||||
client_tile_resize(c, c->geom, 0);
|
client_tile_resize(c, target_geom, 0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -224,8 +222,7 @@ void vertical_grid(Monitor *m) {
|
||||||
if (c->mon != m)
|
if (c->mon != m)
|
||||||
continue;
|
continue;
|
||||||
if (VISIBLEON(c, m) && !c->isunglobal &&
|
if (VISIBLEON(c, m) && !c->isunglobal &&
|
||||||
((m->isoverview && !client_is_x11_popup(c)) ||
|
(!client_is_x11_popup(c) || ISFAKETILED(c))) {
|
||||||
ISFAKETILED(c))) {
|
|
||||||
if (i < 2)
|
if (i < 2)
|
||||||
row_pers[i] =
|
row_pers[i] =
|
||||||
(c->grid_row_per > 0.0f) ? c->grid_row_per : 1.0f;
|
(c->grid_row_per > 0.0f) ? c->grid_row_per : 1.0f;
|
||||||
|
|
@ -242,8 +239,7 @@ void vertical_grid(Monitor *m) {
|
||||||
if (c->mon != m)
|
if (c->mon != m)
|
||||||
continue;
|
continue;
|
||||||
if (VISIBLEON(c, m) && !c->isunglobal &&
|
if (VISIBLEON(c, m) && !c->isunglobal &&
|
||||||
((m->isoverview && !client_is_x11_popup(c)) ||
|
(!client_is_x11_popup(c) || ISFAKETILED(c))) {
|
||||||
ISFAKETILED(c))) {
|
|
||||||
c->grid_col_idx = 0;
|
c->grid_col_idx = 0;
|
||||||
c->grid_row_idx = i;
|
c->grid_row_idx = i;
|
||||||
c->grid_col_per = 1.0f;
|
c->grid_col_per = 1.0f;
|
||||||
|
|
@ -252,17 +248,17 @@ void vertical_grid(Monitor *m) {
|
||||||
// 根据分配的权重动态计算当前窗口的高度
|
// 根据分配的权重动态计算当前窗口的高度
|
||||||
ch = avail_h * (row_pers[i] / sum_row);
|
ch = avail_h * (row_pers[i] / sum_row);
|
||||||
|
|
||||||
c->geom.x = m->w.x + (m->w.width - cw) / 2 + target_gappo;
|
target_geom.x = m->w.x + (m->w.width - cw) / 2 + target_gappo;
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
c->geom.y = m->w.y + target_gappo;
|
target_geom.y = m->w.y + target_gappo;
|
||||||
} else if (i == 1) {
|
} else if (i == 1) {
|
||||||
// 第二个窗口的 Y 坐标紧跟第一个窗口下面
|
// 第二个窗口的 Y 坐标紧跟第一个窗口下面
|
||||||
float ch0 = avail_h * (row_pers[0] / sum_row);
|
float ch0 = avail_h * (row_pers[0] / sum_row);
|
||||||
c->geom.y = m->w.y + target_gappo + ch0 + target_gappi;
|
target_geom.y = m->w.y + target_gappo + ch0 + target_gappi;
|
||||||
}
|
}
|
||||||
c->geom.width = cw;
|
target_geom.width = cw;
|
||||||
c->geom.height = ch;
|
target_geom.height = ch;
|
||||||
client_tile_resize(c, c->geom, 0);
|
client_tile_resize(c, target_geom, 0);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -287,7 +283,7 @@ void vertical_grid(Monitor *m) {
|
||||||
if (c->mon != m)
|
if (c->mon != m)
|
||||||
continue;
|
continue;
|
||||||
if (VISIBLEON(c, m) && !c->isunglobal &&
|
if (VISIBLEON(c, m) && !c->isunglobal &&
|
||||||
((m->isoverview && !client_is_x11_popup(c)) || ISFAKETILED(c))) {
|
(!client_is_x11_popup(c) || ISFAKETILED(c))) {
|
||||||
int32_t c_idx = i / rows;
|
int32_t c_idx = i / rows;
|
||||||
int32_t r_idx = i % rows;
|
int32_t r_idx = i % rows;
|
||||||
if (r_idx == 0)
|
if (r_idx == 0)
|
||||||
|
|
@ -314,7 +310,7 @@ void vertical_grid(Monitor *m) {
|
||||||
if (c->mon != m)
|
if (c->mon != m)
|
||||||
continue;
|
continue;
|
||||||
if (VISIBLEON(c, m) && !c->isunglobal &&
|
if (VISIBLEON(c, m) && !c->isunglobal &&
|
||||||
((m->isoverview && !client_is_x11_popup(c)) || ISFAKETILED(c))) {
|
(!client_is_x11_popup(c) || ISFAKETILED(c))) {
|
||||||
int32_t c_idx = i / rows;
|
int32_t c_idx = i / rows;
|
||||||
int32_t r_idx = i % rows;
|
int32_t r_idx = i % rows;
|
||||||
|
|
||||||
|
|
@ -352,11 +348,11 @@ void vertical_grid(Monitor *m) {
|
||||||
? (m->w.x + m->w.width - target_gappo - fl_cx)
|
? (m->w.x + m->w.width - target_gappo - fl_cx)
|
||||||
: avail_w * (col_pers[c_idx] / sum_col);
|
: avail_w * (col_pers[c_idx] / sum_col);
|
||||||
|
|
||||||
c->geom.x = (int32_t)fl_cx;
|
target_geom.x = (int32_t)fl_cx;
|
||||||
c->geom.y = (int32_t)fl_cy;
|
target_geom.y = (int32_t)fl_cy;
|
||||||
c->geom.width = (int32_t)fl_cw;
|
target_geom.width = (int32_t)fl_cw;
|
||||||
c->geom.height = (int32_t)fl_ch;
|
target_geom.height = (int32_t)fl_ch;
|
||||||
client_tile_resize(c, c->geom, 0);
|
client_tile_resize(c, target_geom, 0);
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
99
src/mango.c
99
src/mango.c
|
|
@ -190,6 +190,7 @@ enum { NONE, OPEN, MOVE, CLOSE, TAG, FOCUS, OPAFADEIN, OPAFADEOUT, OVERVIEW };
|
||||||
enum { UNFOLD, FOLD, INVALIDFOLD };
|
enum { UNFOLD, FOLD, INVALIDFOLD };
|
||||||
enum { PREV, NEXT };
|
enum { PREV, NEXT };
|
||||||
enum { STATE_UNSPECIFIED = 0, STATE_ENABLED, STATE_DISABLED };
|
enum { STATE_UNSPECIFIED = 0, STATE_ENABLED, STATE_DISABLED };
|
||||||
|
enum { FORCE, UNFORCE };
|
||||||
|
|
||||||
enum tearing_mode {
|
enum tearing_mode {
|
||||||
TEARING_DISABLED = 0,
|
TEARING_DISABLED = 0,
|
||||||
|
|
@ -1072,7 +1073,7 @@ static struct wl_listener last_cursor_surface_destroy_listener = {
|
||||||
.notify = last_cursor_surface_destroy};
|
.notify = last_cursor_surface_destroy};
|
||||||
|
|
||||||
#ifdef XWAYLAND
|
#ifdef XWAYLAND
|
||||||
static void fix_xwayland_unmanaged_coordinate(Client *c);
|
static void fix_xwayland_coordinate(struct wlr_box *geom);
|
||||||
static int32_t synckeymap(void *data);
|
static int32_t synckeymap(void *data);
|
||||||
static void activatex11(struct wl_listener *listener, void *data);
|
static void activatex11(struct wl_listener *listener, void *data);
|
||||||
static void configurex11(struct wl_listener *listener, void *data);
|
static void configurex11(struct wl_listener *listener, void *data);
|
||||||
|
|
@ -1614,7 +1615,7 @@ void applyrules(Client *c) {
|
||||||
|
|
||||||
#ifdef XWAYLAND
|
#ifdef XWAYLAND
|
||||||
if (c->isfloating && client_is_x11(c)) {
|
if (c->isfloating && client_is_x11(c)) {
|
||||||
fix_xwayland_unmanaged_coordinate(c);
|
fix_xwayland_coordinate(&c->geom);
|
||||||
c->float_geom = c->geom;
|
c->float_geom = c->geom;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -3139,7 +3140,6 @@ void createlayersurface(struct wl_listener *listener, void *data) {
|
||||||
LISTEN(&l->scene->node.events.destroy, &l->destroy, destroylayernodenotify);
|
LISTEN(&l->scene->node.events.destroy, &l->destroy, destroylayernodenotify);
|
||||||
|
|
||||||
wl_list_insert(&l->mon->layers[layer_surface->pending.layer], &l->link);
|
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) {
|
void createlocksurface(struct wl_listener *listener, void *data) {
|
||||||
|
|
@ -4205,6 +4205,11 @@ 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,
|
/* On _press_ if there is no active screen locker,
|
||||||
* attempt to process a compositor keybinding. */
|
* attempt to process a compositor keybinding. */
|
||||||
for (i = 0; i < nsyms; i++)
|
for (i = 0; i < nsyms; i++)
|
||||||
|
|
@ -4468,24 +4473,24 @@ mapnotify(struct wl_listener *listener, void *data) {
|
||||||
|
|
||||||
/* Handle unmanaged clients first so we can return prior create borders
|
/* Handle unmanaged clients first so we can return prior create borders
|
||||||
*/
|
*/
|
||||||
|
#ifdef XWAYLAND
|
||||||
if (client_is_unmanaged(c)) {
|
if (client_is_unmanaged(c)) {
|
||||||
/* Unmanaged clients always are floating */
|
/* Unmanaged clients always are floating */
|
||||||
#ifdef XWAYLAND
|
fix_xwayland_coordinate(&c->geom);
|
||||||
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);
|
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);
|
||||||
|
wlr_scene_node_reparent(&c->scene->node, layers[LyrOverlay]);
|
||||||
if (client_wants_focus(c)) {
|
if (client_wants_focus(c)) {
|
||||||
focusclient(c, 1);
|
focusclient(c, 1);
|
||||||
exclusive_focus = c;
|
exclusive_focus = c;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
// extra node
|
// extra node
|
||||||
|
|
||||||
for (i = 0; i < 2; i++) {
|
for (i = 0; i < 2; i++) {
|
||||||
|
|
@ -4807,7 +4812,8 @@ void motionnotify(uint32_t time, struct wlr_input_device *device, double dx,
|
||||||
if (!surface && !seat->drag && !cursor_hidden)
|
if (!surface && !seat->drag && !cursor_hidden)
|
||||||
wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
|
wlr_cursor_set_xcursor(cursor, cursor_mgr, "default");
|
||||||
|
|
||||||
if (c && c->mon && !c->animation.running && (INSIDEMON(c) || !ISTILED(c))) {
|
if (c && c->mon && !c->animation.running &&
|
||||||
|
(INSIDEMON(c) || !ISSCROLLTILED(c))) {
|
||||||
scroller_focus_lock = 0;
|
scroller_focus_lock = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -4819,13 +4825,15 @@ void motionnotify(uint32_t time, struct wlr_input_device *device, double dx,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!scroller_focus_lock || !(c && c->mon && !INSIDEMON(c))) {
|
if (!scroller_focus_lock || !(c && c->mon && !INSIDEMON(c))) {
|
||||||
if (c && c->mon && is_scroller_layout(c->mon) && !INSIDEMON(c)) {
|
if (c && c->mon && ISSCROLLTILED(c) && is_scroller_layout(c->mon) &&
|
||||||
|
!INSIDEMON(c)) {
|
||||||
should_lock = true;
|
should_lock = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!((!config.edge_scroller_pointer_focus ||
|
if (!((!config.edge_scroller_pointer_focus ||
|
||||||
speed < config.edge_scroller_focus_allow_speed) &&
|
speed < config.edge_scroller_focus_allow_speed) &&
|
||||||
c && c->mon && is_scroller_layout(c->mon) && !INSIDEMON(c))) {
|
c && c->mon && ISSCROLLTILED(c) && is_scroller_layout(c->mon) &&
|
||||||
|
!INSIDEMON(c))) {
|
||||||
pointerfocus(c, surface, sx, sy, time);
|
pointerfocus(c, surface, sx, sy, time);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -5154,7 +5162,8 @@ void exchange_two_client(Client *c1, Client *c2) {
|
||||||
const Layout *layout1 = m1->pertag->ltidxs[m1->pertag->curtag];
|
const Layout *layout1 = m1->pertag->ltidxs[m1->pertag->curtag];
|
||||||
const Layout *layout2 = m2->pertag->ltidxs[m2->pertag->curtag];
|
const Layout *layout2 = m2->pertag->ltidxs[m2->pertag->curtag];
|
||||||
|
|
||||||
if (layout1->id == SCROLLER || layout2->id == SCROLLER) {
|
if (layout1->id == SCROLLER || layout2->id == SCROLLER ||
|
||||||
|
layout1->id == VERTICAL_SCROLLER || layout2->id == VERTICAL_SCROLLER) {
|
||||||
exchange_two_scroller_clients(c1, c2);
|
exchange_two_scroller_clients(c1, c2);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -5524,6 +5533,7 @@ void setfullscreen(Client *c, int32_t fullscreen) // 用自定义全屏代理自
|
||||||
wlr_scene_node_raise_to_top(&c->scene->node); // 将视图提升到顶层
|
wlr_scene_node_raise_to_top(&c->scene->node); // 将视图提升到顶层
|
||||||
if (!is_scroller_layout(c->mon) || c->isfloating)
|
if (!is_scroller_layout(c->mon) || c->isfloating)
|
||||||
resize(c, c->mon->m, 1);
|
resize(c, c->mon->m, 1);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
c->bw = c->isnoborder ? 0 : config.borderpx;
|
c->bw = c->isnoborder ? 0 : config.borderpx;
|
||||||
if (c->isfloating)
|
if (c->isfloating)
|
||||||
|
|
@ -5805,13 +5815,20 @@ void setup(void) {
|
||||||
}
|
}
|
||||||
init_baked_points();
|
init_baked_points();
|
||||||
|
|
||||||
int32_t drm_fd, i, sig[] = {SIGCHLD, SIGINT, SIGTERM, SIGPIPE};
|
int32_t drm_fd, i;
|
||||||
|
int32_t sig[] = {SIGCHLD, SIGINT,
|
||||||
|
SIGTERM}; // 不设置SIGPIPE,因为ipc发送失败不应该影响主程序
|
||||||
struct sigaction sa = {.sa_flags = SA_RESTART, .sa_handler = handlesig};
|
struct sigaction sa = {.sa_flags = SA_RESTART, .sa_handler = handlesig};
|
||||||
sigemptyset(&sa.sa_mask);
|
sigemptyset(&sa.sa_mask);
|
||||||
|
|
||||||
for (i = 0; i < LENGTH(sig); i++)
|
for (i = 0; i < LENGTH(sig); i++)
|
||||||
sigaction(sig[i], &sa, NULL);
|
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);
|
wlr_log_init(config.log_level, NULL);
|
||||||
|
|
||||||
/* The Wayland display is managed by libwayland. It handles accepting
|
/* The Wayland display is managed by libwayland. It handles accepting
|
||||||
|
|
@ -6815,16 +6832,17 @@ void virtualpointer(struct wl_listener *listener, void *data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef XWAYLAND
|
#ifdef XWAYLAND
|
||||||
void fix_xwayland_unmanaged_coordinate(Client *c) {
|
void fix_xwayland_coordinate(struct wlr_box *geom) {
|
||||||
if (!selmon)
|
if (!selmon)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// 1. 如果窗口已经在当前活动显示器内,直接返回
|
// 1. 如果窗口已经在当前活动显示器内,直接返回
|
||||||
if (c->geom.x >= selmon->m.x && c->geom.x < selmon->m.x + selmon->m.width &&
|
if (geom->x >= selmon->m.x && geom->x <= selmon->m.x + selmon->m.width &&
|
||||||
c->geom.y >= selmon->m.y && c->geom.y < selmon->m.y + selmon->m.height)
|
geom->y >= selmon->m.y && geom->y <= selmon->m.y + selmon->m.height)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
c->geom = setclient_coordinate_center(c, selmon, c->geom, 0, 0);
|
geom->x = selmon->m.x + (selmon->m.width - geom->width) / 2;
|
||||||
|
geom->y = selmon->m.y + (selmon->m.height - geom->height) / 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t synckeymap(void *data) {
|
int32_t synckeymap(void *data) {
|
||||||
|
|
@ -6879,24 +6897,41 @@ void activatex11(struct wl_listener *listener, void *data) {
|
||||||
void configurex11(struct wl_listener *listener, void *data) {
|
void configurex11(struct wl_listener *listener, void *data) {
|
||||||
Client *c = wl_container_of(listener, c, configure);
|
Client *c = wl_container_of(listener, c, configure);
|
||||||
struct wlr_xwayland_surface_configure_event *event = data;
|
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) {
|
if (!client_surface(c) || !client_surface(c)->mapped) {
|
||||||
wlr_xwayland_surface_configure(c->surface.xwayland, event->x, event->y,
|
|
||||||
event->width, event->height);
|
wlr_xwayland_surface_configure(c->surface.xwayland, new_geo.x,
|
||||||
|
new_geo.y, new_geo.width,
|
||||||
|
new_geo.height);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (client_is_unmanaged(c)) {
|
if (client_is_unmanaged(c)) {
|
||||||
wlr_scene_node_set_position(&c->scene->node, event->x, event->y);
|
wlr_scene_node_set_position(&c->scene->node, new_geo.x, new_geo.y);
|
||||||
wlr_xwayland_surface_configure(c->surface.xwayland, event->x, event->y,
|
wlr_xwayland_surface_configure(c->surface.xwayland, new_geo.x,
|
||||||
event->width, event->height);
|
new_geo.y, new_geo.width,
|
||||||
|
new_geo.height);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ((c->isfloating && c != grabc) ||
|
|
||||||
!c->mon->pertag->ltidxs[c->mon->pertag->curtag]->arrange) {
|
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);
|
||||||
|
|
||||||
resize(c,
|
resize(c,
|
||||||
(struct wlr_box){.x = event->x - c->bw,
|
(struct wlr_box){.x = new_geo.x,
|
||||||
.y = event->y - c->bw,
|
.y = new_geo.y,
|
||||||
.width = event->width + c->bw * 2,
|
.width = new_geo.width,
|
||||||
.height = event->height + c->bw * 2},
|
.height = new_geo.height},
|
||||||
0);
|
0);
|
||||||
} else {
|
} else {
|
||||||
arrange(c->mon, false, false);
|
arrange(c->mon, false, false);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue