Compare commits

...

68 commits
0.12.0 ... main

Author SHA1 Message Date
DreamMaoMao
d98379ff4c feat: support index arg in switch_keyboard_layout 2026-02-19 09:59:58 +08:00
DreamMaoMao
444e2da7fb fix: only apply scroller overspread to head and tile client 2026-02-19 08:41:42 +08:00
DreamMaoMao
6924ca8512 feat: add global option prefer_scroller_overspread 2026-02-19 00:00:58 +08:00
DreamMaoMao
259fdb3a87 bump versiont to 0.12.3 2026-02-18 13:26:24 +08:00
DreamMaoMao
c3dcee2c8e opt: remove useless code 2026-02-17 08:33:45 +08:00
DreamMaoMao
15729db193
Merge pull request #668 from Yappaholic/main
docs: add guix installation instructions
2026-02-16 13:16:56 +08:00
DreamMaoMao
fa88ebace0 project: version not use latest tag 2026-02-16 11:56:51 +08:00
DreamMaoMao
112fb5c007 opt: optimize code struct 2026-02-16 10:06:16 +08:00
DreamMaoMao
1158fb2e3c opt: don't skip frame when grab client 2026-02-16 07:46:42 +08:00
Yappaholic
26a616e3d5 docs: add guix installation instructions 2026-02-15 16:50:07 +03:00
DreamMaoMao
933638d1b8
Merge pull request #666 from squassina/main
fix warning about meson
2026-02-15 19:14:27 +08:00
Ricardo Squassina Lee
f75efa1312
Fix wayland protocol directory variable retrieval 2026-02-15 07:08:35 -03:00
DreamMaoMao
62ab00a7a3 update readme 2026-02-15 16:43:02 +08:00
DreamMaoMao
7ccbeae8b8 fix: if the progress not the child of main, not assume it is stop 2026-02-15 14:08:53 +08:00
DreamMaoMao
49cb5a9d7e feat: support frame skip for x11 app resize 2026-02-15 12:50:42 +08:00
DreamMaoMao
0696fe964d opt: optimize frame skip logic 2026-02-15 10:31:23 +08:00
DreamMaoMao
842b45b584 feat: add skip timer to avoid rermanently block render 2026-02-15 09:02:36 +08:00
DreamMaoMao
02067e3b1e fix: some client property missing init 2026-02-15 08:07:00 +08:00
DreamMaoMao
fdd54afb7e fix: some app frame skip fail when disable animaitons 2026-02-15 08:00:44 +08:00
DreamMaoMao
91110efe0e
Merge pull request #645 from jampe/feature-config-isfakefullscreen
support isfakefullscreen as windowrule property
2026-02-14 08:46:23 +08:00
DreamMaoMao
89413aacf5 fix: fix center tile size per reset 2026-02-14 08:35:30 +08:00
DreamMaoMao
0fe87e6286 fix: fix multi master focus record error 2026-02-13 20:23:03 +08:00
DreamMaoMao
c05eec7f53 feat: support restore stack from non-tile state 2026-02-13 20:02:23 +08:00
DreamMaoMao
8a924494c6 opt: the tagset is current tagset when open window in ov mode 2026-02-13 18:16:06 +08:00
DreamMaoMao
711498490b opt: not back to ov tag when view prev tag 2026-02-13 18:11:18 +08:00
DreamMaoMao
f251615524 opt: flush the blur background cache when unmap a background layer 2026-02-13 11:07:11 +08:00
DreamMaoMao
5ae8975b11 bump version to 0.12.2 2026-02-13 10:44:17 +08:00
DreamMaoMao
313adefd10 opt: better x11 coordinate adjust 2026-02-12 18:55:03 +08:00
DreamMaoMao
17acdae69c opt: make x11 floating window coordinate auto ajust the monitor change 2026-02-12 18:12:01 +08:00
DreamMaoMao
bc52b95c1e opt: make x11 unmanaged window coordinate auto ajust the monitor change 2026-02-12 18:10:02 +08:00
DreamMaoMao
53ee82a726 feat: make force_tiled_state as a option 2026-02-12 11:19:39 +08:00
DreamMaoMao
8484093e32 fix: crash when pointerfocus to a null scene client 2026-02-11 20:44:44 +08:00
DreamMaoMao
b5a157038c opt: tell the synckeymap timer not need to call anymore 2026-02-11 08:31:22 +08:00
DreamMaoMao
783cb86c56 feat: support match monitor make model serial 2026-02-10 10:31:31 +08:00
DreamMaoMao
c7f90cbc69 bump version to 0.12.1 2026-02-09 18:08:28 +08:00
DreamMaoMao
b05bc1ce65 opt: add btn_left and btn_right bind check in config check 2026-02-09 11:50:54 +08:00
DreamMaoMao
6b79a432a4 opt: allow none mode in some mouse button 2026-02-09 11:18:14 +08:00
Daniel Jampen
454145f6e0
support isfakefullscreen as windowrule property 2026-02-08 17:56:26 +01:00
DreamMaoMao
6970315822
Update README.md 2026-02-08 18:17:55 +08:00
DreamMaoMao
e8bf6380fb opt: turn keymap sync into XWAYLAND macro 2026-02-08 12:44:56 +08:00
DreamMaoMao
4820b7a8ab feat: allow single mod keybind 2026-02-08 12:15:44 +08:00
DreamMaoMao
faf2e1e9da opt: sync keymap to xwayland after xwayland ready 2026-02-08 12:13:04 +08:00
DreamMaoMao
acf8363714
Merge pull request #642 from iynaix/source-optional
feat: add a source-optional keyword
2026-02-08 11:27:22 +08:00
DreamMaoMao
241afb4b97 fix: warpcursor not apply in some case 2026-02-08 11:18:38 +08:00
Lin Xianyi
5de87db8ca feat: add a source-optional keyword 2026-02-08 11:15:16 +08:00
DreamMaoMao
9b92f139c0 fix: correct dmabuf version 2026-02-07 21:46:18 +08:00
DreamMaoMao
e658f5c90d opt: fix format 2026-02-07 19:57:07 +08:00
Yujonpradhananga
3db2ac58b4 opt: fix spelling mistake 2026-02-07 17:45:11 +08:00
DreamMaoMao
f8dfeedff1 fix: headless backend cant use keybarod and pointer 2026-02-07 17:32:38 +08:00
DreamMaoMao
2ca2ab739d
Merge pull request #640 from iynaix/mmsg-help
fix: improve help message for mmsg
2026-02-07 17:30:20 +08:00
DreamMaoMao
9e5bccb457
Merge pull request #639 from iynaix/config-exit-code
fix: -p exits with failure if there are parse failures
2026-02-07 17:30:06 +08:00
Lin Xianyi
2734d91e6a fix: improve help message for mmsg 2026-02-07 13:31:30 +08:00
Lin Xianyi
818652d20f fix: -p exits with failure if there are parse failures 2026-02-07 12:12:13 +08:00
DreamMaoMao
4586319bef
Merge pull request #637 from talned/main
Add DesktopNames entry to mango.desktop
2026-02-06 16:14:17 +08:00
Talmed
080dfaa3ae
Add DesktopNames entry to mango.desktop 2026-02-06 19:04:16 +11:00
DreamMaoMao
00a7e579c9 fix: miss reset root color when reload config 2026-02-06 07:43:09 +08:00
DreamMaoMao
8e898417a7 opt: key name case insensitive in keybind 2026-02-05 11:06:52 +08:00
DreamMaoMao
65fcd58949 opt: optimize file detect message 2026-02-04 21:50:44 +08:00
DreamMaoMao
2bda8e3bf1 opt: avoid double reset foreign toplevel handle 2026-02-04 21:42:05 +08:00
DreamMaoMao
a4faf2c494 opt: avoid stack inner per change when switch tty 2026-02-04 21:29:37 +08:00
DreamMaoMao
b0f839468c opt: don't change stack inner per when swallow 2026-02-04 17:42:13 +08:00
DreamMaoMao
8ba259fbb7 opt: avoid opacity flickering in focus animation when open new window 2026-02-04 09:45:26 +08:00
DreamMaoMao
16e361e1ca
Merge pull request #630 from axQuadratic/tagmon_fix
Fix uninitialised argument fields when calling `mmsg -d`
2026-02-04 09:05:01 +08:00
quadratic
336f873d83 fix: uninitialised argument fields when calling mmsg -d 2026-02-03 21:11:41 +01:00
DreamMaoMao
50b67ac539 fix: miss init arg value 2026-02-03 10:15:42 +08:00
DreamMaoMao
0546a2d4c4 opt: allow use comma symbol in spawn shell value 2026-02-03 10:06:26 +08:00
DreamMaoMao
eb0607501d opt: change drag resize request limit to 120hz for floating window 2026-02-02 14:54:09 +08:00
DreamMaoMao
bcee63fa76 feat: add config check in mango cli 2026-02-02 14:54:09 +08:00
16 changed files with 1219 additions and 344 deletions

View file

@ -23,19 +23,9 @@ This project's development is based on [dwl](https://codeberg.org/dwl/dwl/).
- Ipc support(get/send message from/to compositor by external program) - Ipc support(get/send message from/to compositor by external program)
- Hycov-like overview - Hycov-like overview
- Window effects from scenefx (blur, shadow, corner radius, opacity) - Window effects from scenefx (blur, shadow, corner radius, opacity)
- Zero flickering - every frame is perfect.
Master-Stack Layout https://github.com/user-attachments/assets/bb83004a-0563-4b48-ad89-6461a9b78b1f
https://github.com/user-attachments/assets/a9d4776e-b50b-48fb-94ce-651d8a749b8a
Scroller Layout
https://github.com/user-attachments/assets/c9bf9415-fad1-4400-bcdc-3ad2d76de85a
Layer animation
https://github.com/user-attachments/assets/014c893f-115c-4ae9-8342-f9ae3e9a0df0
# Our discord # Our discord
[mangowc](https://discord.gg/CPjbDxesh5) [mangowc](https://discord.gg/CPjbDxesh5)
@ -75,7 +65,7 @@ https://github.com/user-attachments/assets/014c893f-115c-4ae9-8342-f9ae3e9a0df0
- libxcb - libxcb
## Arch Linux ## Arch Linux
The package is in the Arch User Repository and is availble for manual download [here](https://aur.archlinux.org/packages/mangowc-git) or through a AUR helper like yay: The package is in the Arch User Repository and is available for manual download [here](https://aur.archlinux.org/packages/mangowc-git) or through a AUR helper like yay:
```bash ```bash
yay -S mangowc-git yay -S mangowc-git
@ -109,6 +99,34 @@ Then, install the package:
dnf install mangowc dnf install mangowc
``` ```
## GuixSD
The package definition is described in the source repository.
First, add `mangowc` channel to `channels.scm` file:
```scheme
;; In $HOME/.config/guix/channels.scm
(cons (channel
(name 'mangowc)
(url "https://github.com/DreamMaoMao/mangowc.git"))
... ;; Your other channels
%default-channels)
```
Then, run `guix pull` and after update you can either run
`guix install mangowc` or add it to your configuration via:
```scheme
(use-modules (mangowc)) ;; Add mangowc module
;; Add mangowc to packages list
(packages (cons
mangowc
... ;; Other packages you specified
%base-packages))
```
And then rebuild your system.
## Other ## Other
```bash ```bash

View file

@ -240,12 +240,11 @@ bind=CTRL+ALT,Left,resizewin,-50,+0
bind=CTRL+ALT,Right,resizewin,+50,+0 bind=CTRL+ALT,Right,resizewin,+50,+0
# Mouse Button Bindings # Mouse Button Bindings
# NONE mode key only work in ov mode # btn_left and btn_right can't bind none mod key
mousebind=SUPER,btn_left,moveresize,curmove mousebind=SUPER,btn_left,moveresize,curmove
mousebind=NONE,btn_middle,togglemaximizescreen,0 mousebind=NONE,btn_middle,togglemaximizescreen,0
mousebind=SUPER,btn_right,moveresize,curresize mousebind=SUPER,btn_right,moveresize,curresize
mousebind=NONE,btn_left,toggleoverview,1
mousebind=NONE,btn_right,killclient,0
# Axis Bindings # Axis Bindings
axisbind=SUPER,UP,viewtoleft_have_client axisbind=SUPER,UP,viewtoleft_have_client

View file

@ -1,6 +1,7 @@
[Desktop Entry] [Desktop Entry]
Encoding=UTF-8 Encoding=UTF-8
Name=Mango Name=Mango
DesktopNames=mango;wlroots
Comment=mango WM Comment=mango WM
Exec=mango Exec=mango
Icon=mango Icon=mango

View file

@ -1,5 +1,5 @@
project('mango', ['c', 'cpp'], project('mango', ['c', 'cpp'],
version : '0.12.0', version : '0.12.3',
) )
subdir('protocols') subdir('protocols')
@ -56,7 +56,7 @@ endif
if is_git_repo if is_git_repo
# 如果是 Git 目录,获取 Commit Hash 和最新的 tag # 如果是 Git 目录,获取 Commit Hash 和最新的 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 = run_command(git, 'describe', '--tags', '--abbrev=0', check : false).stdout().strip() 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" 字符串 # 如果不是 Git 目录,使用项目版本号和 "release" 字符串

View file

@ -500,12 +500,48 @@ static const struct wl_registry_listener registry_listener = {
static void usage(void) { static void usage(void) {
fprintf(stderr, fprintf(stderr,
"usage:" "mmsg - MangoWC IPC\n"
"\t%s [-OTLq]\n" "\n"
"\t%s [-o <output>] -s [-t <tags>] [-l <layout>] [-c <tags>] [-d " "SYNOPSIS:\n"
"\tmmsg [-OTLq]\n"
"\tmmsg [-o <output>] -s [-t <tags>] [-l <layout>] [-c <tags>] [-d "
"<cmd>,<arg1>,<arg2>,<arg3>,<arg4>,<arg5>]\n" "<cmd>,<arg1>,<arg2>,<arg3>,<arg4>,<arg5>]\n"
"\t%s [-o <output>] (-g | -w) [-OotlcvmfxekbA]\n", "\tmmsg [-o <output>] (-g | -w) [-OotlcvmfxekbA]\n"
argv0, argv0, argv0); "\n"
"OPERATION MODES:\n"
"\t-g Get values (tags, layout, focused client)\n"
"\t-s Set values (switch tags, layouts)\n"
"\t-w Watch mode (stream events)\n"
"\n"
"GENERAL OPTIONS:\n"
"\t-O Get all output (monitor) information\n"
"\t-T Get number of tags\n"
"\t-L Get all available layouts\n"
"\t-q Quit MangoWC\n"
"\t-o <output> Select output (monitor)\n"
"\n"
"GET OPTIONS (used with -g or -w):\n"
"\t-O Get output name\n"
"\t-o Get output (monitor) focus information\n"
"\t-t Get selected tags\n"
"\t-l Get current layout\n"
"\t-c Get title and appid of focused clients\n"
"\t-v Get visibility of statusbar\n"
"\t-m Get fullscreen status\n"
"\t-f Get floating status\n"
"\t-x Get focused client geometry\n"
"\t-e Get name of last focused layer\n"
"\t-k Get current keyboard layout\n"
"\t-b Get current keybind mode\n"
"\t-A Get scale factor of monitor\n"
"\n"
"SET OPTIONS (used with -s):\n"
"\t-o <output> Select output (monitor)\n"
"\t-t <tags> Set selected tags (can be used with [+-^.] "
"modifiers)\n"
"\t-l <layout> Set current layout\n"
"\t-c <tags> Get title and appid of focused client\n"
"\t-d <cmd>,<args...> Dispatch internal command (max 5 args)\n");
exit(2); exit(2);
} }

View file

@ -1,6 +1,6 @@
wayland_scanner = find_program('wayland-scanner') wayland_scanner = find_program('wayland-scanner')
wayland_protos_dep = dependency('wayland-protocols') wayland_protos_dep = dependency('wayland-protocols')
wl_protocol_dir = wayland_protos_dep.get_pkgconfig_variable('pkgdatadir') wl_protocol_dir = wayland_protos_dep.get_variable(pkgconfig:'pkgdatadir')
wayland_scanner_code = generator( wayland_scanner_code = generator(
wayland_scanner, wayland_scanner,
output: '@BASENAME@-protocol.c', output: '@BASENAME@-protocol.c',

View file

@ -47,7 +47,7 @@ bool is_horizontal_right_stack_layout(Monitor *m) {
return false; return false;
} }
int32_t is_special_animaiton_rule(Client *c) { int32_t is_special_animation_rule(Client *c) {
if (is_scroller_layout(c->mon) && !c->isfloating) { if (is_scroller_layout(c->mon) && !c->isfloating) {
return DOWN; return DOWN;
@ -70,7 +70,7 @@ int32_t is_special_animaiton_rule(Client *c) {
} }
} }
void set_client_open_animaiton(Client *c, struct wlr_box geo) { void set_client_open_animation(Client *c, struct wlr_box geo) {
int32_t slide_direction; int32_t slide_direction;
int32_t horizontal, horizontal_value; int32_t horizontal, horizontal_value;
int32_t vertical, vertical_value; int32_t vertical, vertical_value;
@ -96,7 +96,7 @@ void set_client_open_animaiton(Client *c, struct wlr_box geo) {
geo.y + (geo.height - c->animainit_geom.height) / 2; geo.y + (geo.height - c->animainit_geom.height) / 2;
return; return;
} else { } else {
special_direction = is_special_animaiton_rule(c); special_direction = is_special_animation_rule(c);
center_x = c->geom.x + c->geom.width / 2; center_x = c->geom.x + c->geom.width / 2;
center_y = c->geom.y + c->geom.height / 2; center_y = c->geom.y + c->geom.height / 2;
if (special_direction == UNDIR) { if (special_direction == UNDIR) {
@ -772,71 +772,71 @@ void init_fadeout_client(Client *c) {
return; return;
} }
Client *fadeout_cient = ecalloc(1, sizeof(*fadeout_cient)); Client *fadeout_client = ecalloc(1, sizeof(*fadeout_client));
wlr_scene_node_set_enabled(&c->scene->node, true); wlr_scene_node_set_enabled(&c->scene->node, true);
client_set_border_color(c, bordercolor); client_set_border_color(c, bordercolor);
fadeout_cient->scene = fadeout_client->scene =
wlr_scene_tree_snapshot(&c->scene->node, layers[LyrFadeOut]); wlr_scene_tree_snapshot(&c->scene->node, layers[LyrFadeOut]);
wlr_scene_node_set_enabled(&c->scene->node, false); wlr_scene_node_set_enabled(&c->scene->node, false);
if (!fadeout_cient->scene) { if (!fadeout_client->scene) {
free(fadeout_cient); free(fadeout_client);
return; return;
} }
fadeout_cient->animation.duration = animation_duration_close; fadeout_client->animation.duration = animation_duration_close;
fadeout_cient->geom = fadeout_cient->current = fadeout_client->geom = fadeout_client->current =
fadeout_cient->animainit_geom = fadeout_cient->animation.initial = fadeout_client->animainit_geom = fadeout_client->animation.initial =
c->animation.current; c->animation.current;
fadeout_cient->mon = c->mon; fadeout_client->mon = c->mon;
fadeout_cient->animation_type_close = c->animation_type_close; fadeout_client->animation_type_close = c->animation_type_close;
fadeout_cient->animation.action = CLOSE; fadeout_client->animation.action = CLOSE;
fadeout_cient->bw = c->bw; fadeout_client->bw = c->bw;
fadeout_cient->nofadeout = c->nofadeout; fadeout_client->nofadeout = c->nofadeout;
// 这里snap节点的坐标设置是使用的相对坐标所以不能加上原来坐标 // 这里snap节点的坐标设置是使用的相对坐标所以不能加上原来坐标
// 这跟普通node有区别 // 这跟普通node有区别
fadeout_cient->animation.initial.x = 0; fadeout_client->animation.initial.x = 0;
fadeout_cient->animation.initial.y = 0; fadeout_client->animation.initial.y = 0;
if ((!c->animation_type_close && if ((!c->animation_type_close &&
strcmp(animation_type_close, "fade") == 0) || strcmp(animation_type_close, "fade") == 0) ||
(c->animation_type_close && (c->animation_type_close &&
strcmp(c->animation_type_close, "fade") == 0)) { strcmp(c->animation_type_close, "fade") == 0)) {
fadeout_cient->current.x = 0; fadeout_client->current.x = 0;
fadeout_cient->current.y = 0; fadeout_client->current.y = 0;
fadeout_cient->current.width = 0; fadeout_client->current.width = 0;
fadeout_cient->current.height = 0; fadeout_client->current.height = 0;
} else if ((c->animation_type_close && } else if ((c->animation_type_close &&
strcmp(c->animation_type_close, "slide") == 0) || strcmp(c->animation_type_close, "slide") == 0) ||
(!c->animation_type_close && (!c->animation_type_close &&
strcmp(animation_type_close, "slide") == 0)) { strcmp(animation_type_close, "slide") == 0)) {
fadeout_cient->current.y = fadeout_client->current.y =
c->geom.y + c->geom.height / 2 > c->mon->m.y + c->mon->m.height / 2 c->geom.y + c->geom.height / 2 > c->mon->m.y + c->mon->m.height / 2
? c->mon->m.height - ? c->mon->m.height -
(c->animation.current.y - c->mon->m.y) // down out (c->animation.current.y - c->mon->m.y) // down out
: c->mon->m.y - c->geom.height; // up out : c->mon->m.y - c->geom.height; // up out
fadeout_cient->current.x = 0; // x无偏差垂直划出 fadeout_client->current.x = 0; // x无偏差垂直划出
} else { } else {
fadeout_cient->current.y = fadeout_client->current.y =
(fadeout_cient->geom.height - (fadeout_client->geom.height -
fadeout_cient->geom.height * zoom_end_ratio) / fadeout_client->geom.height * zoom_end_ratio) /
2; 2;
fadeout_cient->current.x = fadeout_client->current.x =
(fadeout_cient->geom.width - (fadeout_client->geom.width -
fadeout_cient->geom.width * zoom_end_ratio) / fadeout_client->geom.width * zoom_end_ratio) /
2; 2;
fadeout_cient->current.width = fadeout_client->current.width =
fadeout_cient->geom.width * zoom_end_ratio; fadeout_client->geom.width * zoom_end_ratio;
fadeout_cient->current.height = fadeout_client->current.height =
fadeout_cient->geom.height * zoom_end_ratio; fadeout_client->geom.height * zoom_end_ratio;
} }
fadeout_cient->animation.time_started = get_now_in_ms(); fadeout_client->animation.time_started = get_now_in_ms();
wlr_scene_node_set_enabled(&fadeout_cient->scene->node, true); wlr_scene_node_set_enabled(&fadeout_client->scene->node, true);
wl_list_insert(&fadeout_clients, &fadeout_cient->fadeout_link); wl_list_insert(&fadeout_clients, &fadeout_client->fadeout_link);
// 请求刷新屏幕 // 请求刷新屏幕
request_fresh_all_monitors(); request_fresh_all_monitors();
@ -971,7 +971,7 @@ void resize(Client *c, struct wlr_box geo, int32_t interact) {
c->animainit_geom.height = c->animation.current.height; c->animainit_geom.height = c->animation.current.height;
c->animainit_geom.width = c->animation.current.width; c->animainit_geom.width = c->animation.current.width;
} else if (c->is_pending_open_animation) { } else if (c->is_pending_open_animation) {
set_client_open_animaiton(c, c->geom); set_client_open_animation(c, c->geom);
} else { } else {
c->animainit_geom = c->animation.current; c->animainit_geom = c->animation.current;
} }
@ -1054,20 +1054,11 @@ void client_set_focused_opacity_animation(Client *c) {
sizeof(c->opacity_animation.target_border_color)); sizeof(c->opacity_animation.target_border_color));
c->opacity_animation.target_opacity = c->focused_opacity; c->opacity_animation.target_opacity = c->focused_opacity;
c->opacity_animation.time_started = get_now_in_ms(); c->opacity_animation.time_started = get_now_in_ms();
if (c->opacity_animation.running) { memcpy(c->opacity_animation.initial_border_color,
memcpy(c->opacity_animation.initial_border_color, c->opacity_animation.current_border_color,
c->opacity_animation.current_border_color, sizeof(c->opacity_animation.initial_border_color));
sizeof(c->opacity_animation.initial_border_color)); c->opacity_animation.initial_opacity = c->opacity_animation.current_opacity;
c->opacity_animation.initial_opacity =
c->opacity_animation.current_opacity;
} else {
memcpy(c->opacity_animation.initial_border_color, bordercolor,
sizeof(c->opacity_animation.initial_border_color));
memcpy(c->opacity_animation.current_border_color, bordercolor,
sizeof(c->opacity_animation.current_border_color));
c->opacity_animation.initial_opacity = c->unfocused_opacity;
c->opacity_animation.current_opacity = c->unfocused_opacity;
}
c->opacity_animation.running = true; c->opacity_animation.running = true;
} }
@ -1087,20 +1078,10 @@ void client_set_unfocused_opacity_animation(Client *c) {
c->opacity_animation.target_opacity = c->unfocused_opacity; c->opacity_animation.target_opacity = c->unfocused_opacity;
c->opacity_animation.time_started = get_now_in_ms(); c->opacity_animation.time_started = get_now_in_ms();
if (c->opacity_animation.running) { memcpy(c->opacity_animation.initial_border_color,
memcpy(c->opacity_animation.initial_border_color, c->opacity_animation.current_border_color,
c->opacity_animation.current_border_color, sizeof(c->opacity_animation.initial_border_color));
sizeof(c->opacity_animation.initial_border_color)); c->opacity_animation.initial_opacity = c->opacity_animation.current_opacity;
c->opacity_animation.initial_opacity =
c->opacity_animation.current_opacity;
} else {
memcpy(c->opacity_animation.initial_border_color, border_color,
sizeof(c->opacity_animation.initial_border_color));
memcpy(c->opacity_animation.current_border_color, border_color,
sizeof(c->opacity_animation.current_border_color));
c->opacity_animation.initial_opacity = c->focused_opacity;
c->opacity_animation.current_opacity = c->focused_opacity;
}
c->opacity_animation.running = true; c->opacity_animation.running = true;
} }
@ -1135,6 +1116,10 @@ bool client_apply_focus_opacity(Client *c) {
if (target_opacity > opacity) { if (target_opacity > opacity) {
target_opacity = opacity; target_opacity = opacity;
} }
memcpy(c->opacity_animation.current_border_color,
c->opacity_animation.target_border_color,
sizeof(c->opacity_animation.current_border_color));
c->opacity_animation.current_opacity = target_opacity;
client_set_opacity(c, target_opacity); client_set_opacity(c, target_opacity);
client_set_border_color(c, c->opacity_animation.target_border_color); client_set_border_color(c, c->opacity_animation.target_border_color);
} else if (animations && c->opacity_animation.running) { } else if (animations && c->opacity_animation.running) {

View file

@ -254,10 +254,13 @@ static inline int32_t client_is_stopped(Client *c) {
wl_client_get_credentials(c->surface.xdg->client->client, &pid, NULL, NULL); wl_client_get_credentials(c->surface.xdg->client->client, &pid, NULL, NULL);
if (waitid(P_PID, pid, &in, WNOHANG | WCONTINUED | WSTOPPED | WNOWAIT) < if (waitid(P_PID, pid, &in, WNOHANG | WCONTINUED | WSTOPPED | WNOWAIT) <
0) { 0) {
/* This process is not our child process, while is very unluckely that /* This process is not our child process. We cannot determine its
* it is stopped, in order to do not skip frames assume that it is. */ * stopped state; assume it is not stopped to avoid blocking frame skip.
*/
if (errno == ECHILD) if (errno == ECHILD)
return 1; return 0; // if not our child, assume not stopped
/* Other errors, also assume not stopped. */
return 0;
} else if (in.si_pid) { } else if (in.si_pid) {
if (in.si_code == CLD_STOPPED || in.si_code == CLD_TRAPPED) if (in.si_code == CLD_STOPPED || in.si_code == CLD_TRAPPED)
return 1; return 1;
@ -319,9 +322,24 @@ static inline uint32_t client_set_size(Client *c, uint32_t width,
uint32_t height) { uint32_t height) {
#ifdef XWAYLAND #ifdef XWAYLAND
if (client_is_x11(c)) { if (client_is_x11(c)) {
struct wlr_surface_state *state =
&c->surface.xwayland->surface->current;
if ((int32_t)c->geom.width - 2 * (int32_t)c->bw ==
(int32_t)state->width &&
(int32_t)c->geom.height - 2 * (int32_t)c->bw ==
(int32_t)state->height &&
(int32_t)c->surface.xwayland->x ==
(int32_t)c->geom.x + (int32_t)c->bw &&
(int32_t)c->surface.xwayland->y ==
(int32_t)c->geom.y + (int32_t)c->bw) {
return 0;
}
wlr_xwayland_surface_configure(c->surface.xwayland, c->geom.x + c->bw, wlr_xwayland_surface_configure(c->surface.xwayland, c->geom.x + c->bw,
c->geom.y + c->bw, width, height); c->geom.y + c->bw, width, height);
return 0; return 1;
} }
#endif #endif
if ((int32_t)width == c->surface.xdg->toplevel->current.width && if ((int32_t)width == c->surface.xdg->toplevel->current.width &&

File diff suppressed because it is too large Load diff

View file

@ -66,6 +66,7 @@ float scroller_default_proportion_single = 1.0;
int32_t scroller_ignore_proportion_single = 1; int32_t scroller_ignore_proportion_single = 1;
int32_t scroller_focus_center = 0; int32_t scroller_focus_center = 0;
int32_t scroller_prefer_center = 0; int32_t scroller_prefer_center = 0;
int32_t scroller_prefer_overspread = 1;
int32_t focus_cross_monitor = 0; int32_t focus_cross_monitor = 0;
int32_t focus_cross_tag = 0; int32_t focus_cross_tag = 0;
int32_t exchange_cross_monitor = 0; int32_t exchange_cross_monitor = 0;
@ -108,7 +109,8 @@ int32_t drag_warp_cursor = 1;
int32_t xwayland_persistence = 1; /* xwayland persistence */ int32_t xwayland_persistence = 1; /* xwayland persistence */
int32_t syncobj_enable = 0; int32_t syncobj_enable = 0;
int32_t allow_lock_transparent = 0; int32_t allow_lock_transparent = 0;
double drag_refresh_interval = 16.0; double drag_tile_refresh_interval = 16.0;
double drag_floating_refresh_interval = 8.0;
int32_t allow_tearing = TEARING_DISABLED; int32_t allow_tearing = TEARING_DISABLED;
int32_t allow_shortcuts_inhibit = SHORTCUTS_INHIBIT_ENABLE; int32_t allow_shortcuts_inhibit = SHORTCUTS_INHIBIT_ENABLE;

View file

@ -902,14 +902,16 @@ int32_t switch_keyboard_layout(const Arg *arg) {
} }
xkb_layout_index_t next = (current + 1) % num_layouts; xkb_layout_index_t next = (current + 1) % num_layouts;
if (arg->i > 0 && arg->i <= num_layouts) {
next = arg->i - 1;
}
// 6. 应用新 keymap // 6. 应用新 keymap
uint32_t depressed = keyboard->modifiers.depressed; uint32_t depressed = keyboard->modifiers.depressed;
uint32_t latched = keyboard->modifiers.latched; uint32_t latched = keyboard->modifiers.latched;
uint32_t locked = keyboard->modifiers.locked; uint32_t locked = keyboard->modifiers.locked;
wlr_keyboard_set_keymap(keyboard, keyboard->keymap);
wlr_keyboard_notify_modifiers(keyboard, depressed, latched, locked, next); wlr_keyboard_notify_modifiers(keyboard, depressed, latched, locked, next);
keyboard->modifiers.group = 0;
// 7. 更新 seat // 7. 更新 seat
wlr_seat_set_keyboard(seat, keyboard); wlr_seat_set_keyboard(seat, keyboard);
@ -923,10 +925,7 @@ int32_t switch_keyboard_layout(const Arg *arg) {
struct wlr_keyboard *tkb = (struct wlr_keyboard *)id->device_data; struct wlr_keyboard *tkb = (struct wlr_keyboard *)id->device_data;
wlr_keyboard_set_keymap(tkb, keyboard->keymap);
wlr_keyboard_notify_modifiers(tkb, depressed, latched, locked, next); wlr_keyboard_notify_modifiers(tkb, depressed, latched, locked, next);
tkb->modifiers.group = 0;
// 7. 更新 seat // 7. 更新 seat
wlr_seat_set_keyboard(seat, tkb); wlr_seat_set_keyboard(seat, tkb);
wlr_seat_keyboard_notify_modifiers(seat, &tkb->modifiers); wlr_seat_keyboard_notify_modifiers(seat, &tkb->modifiers);
@ -1222,13 +1221,15 @@ int32_t togglefloating(const Arg *arg) {
if (!sel) if (!sel)
return 0; return 0;
bool isfloating = sel->isfloating;
if ((sel->isfullscreen || sel->ismaximizescreen)) { if ((sel->isfullscreen || sel->ismaximizescreen)) {
sel->isfloating = 1; isfloating = 1;
} else { } else {
sel->isfloating = !sel->isfloating; isfloating = !sel->isfloating;
} }
setfloating(sel, sel->isfloating); setfloating(sel, isfloating);
return 0; return 0;
} }
@ -1526,6 +1527,16 @@ int32_t minimized(const Arg *arg) {
return 0; return 0;
} }
void fix_mon_tagset_from_overview(Monitor *m) {
if (m->tagset[m->seltags] == (m->ovbk_prev_tagset & TAGMASK)) {
m->tagset[m->seltags ^ 1] = m->ovbk_current_tagset;
m->pertag->prevtag = get_tags_first_tag_num(m->ovbk_current_tagset);
} else {
m->tagset[m->seltags ^ 1] = m->ovbk_prev_tagset;
m->pertag->prevtag = get_tags_first_tag_num(m->ovbk_prev_tagset);
}
}
int32_t toggleoverview(const Arg *arg) { int32_t toggleoverview(const Arg *arg) {
Client *c = NULL; Client *c = NULL;
@ -1547,6 +1558,8 @@ int32_t toggleoverview(const Arg *arg) {
visible_client_number++; visible_client_number++;
} }
if (visible_client_number > 0) { if (visible_client_number > 0) {
selmon->ovbk_current_tagset = selmon->tagset[selmon->seltags];
selmon->ovbk_prev_tagset = selmon->tagset[selmon->seltags ^ 1];
target = ~0 & TAGMASK; target = ~0 & TAGMASK;
} else { } else {
selmon->isoverview ^= 1; selmon->isoverview ^= 1;
@ -1557,6 +1570,7 @@ int32_t toggleoverview(const Arg *arg) {
} else if (!selmon->isoverview && !selmon->sel) { } else if (!selmon->isoverview && !selmon->sel) {
target = (1 << (selmon->pertag->prevtag - 1)); target = (1 << (selmon->pertag->prevtag - 1));
view(&(Arg){.ui = target}, false); view(&(Arg){.ui = target}, false);
fix_mon_tagset_from_overview(selmon);
refresh_monitors_workspaces_status(selmon); refresh_monitors_workspaces_status(selmon);
return 0; return 0;
} }
@ -1579,7 +1593,7 @@ int32_t toggleoverview(const Arg *arg) {
} }
view(&(Arg){.ui = target}, false); view(&(Arg){.ui = target}, false);
fix_mon_tagset_from_overview(selmon);
refresh_monitors_workspaces_status(selmon); refresh_monitors_workspaces_status(selmon);
return 0; return 0;
} }

View file

@ -574,23 +574,29 @@ bool client_is_in_same_stack(Client *sc, Client *tc, Client *fc) {
if (id == TILE || id == VERTICAL_TILE || id == DECK || if (id == TILE || id == VERTICAL_TILE || id == DECK ||
id == VERTICAL_DECK || id == RIGHT_TILE) { id == VERTICAL_DECK || id == RIGHT_TILE) {
if (fc && !fc->ismaster) if (tc->ismaster ^ sc->ismaster)
return false; return false;
else if (!sc->ismaster) if (fc && !(fc->ismaster ^ sc->ismaster))
return false;
else
return true; return true;
} }
if (id == TGMIX) { if (id == TGMIX) {
if (fc && !fc->ismaster) if (tc->ismaster ^ sc->ismaster)
return false;
if (fc && !(fc->ismaster ^ sc->ismaster))
return false; return false;
if (!sc->ismaster && sc->mon->visible_tiling_clients <= 3) if (!sc->ismaster && sc->mon->visible_tiling_clients <= 3)
return true; return true;
} }
if (id == CENTER_TILE) { if (id == CENTER_TILE) {
if (fc && !fc->ismaster) if (tc->ismaster ^ sc->ismaster)
return false; return false;
if (!sc->ismaster && sc->geom.x == tc->geom.x) if (fc && !(fc->ismaster ^ sc->ismaster))
return false;
if (sc->geom.x == tc->geom.x)
return true; return true;
else else
return false; return false;

View file

@ -1,3 +1,45 @@
void restore_size_per(Monitor *m, Client *c) {
Client *fc = NULL;
double total_master_inner_per = 0;
double total_stack_inner_per = 0;
if (!m || !c)
return;
const Layout *current_layout = m->pertag->ltidxs[m->pertag->curtag];
if (current_layout->id == SCROLLER ||
current_layout->id == VERTICAL_SCROLLER || current_layout->id == GRID ||
current_layout->id == VERTICAL_GRID || current_layout->id == DECK ||
current_layout->id == VERTICAL_DECK || current_layout->id == MONOCLE) {
return;
}
if (current_layout->id == CENTER_TILE || c->ismaster) {
wl_list_for_each(fc, &clients, link) {
if (VISIBLEON(fc, m) && ISTILED(fc) && !c->ismaster) {
set_size_per(m, fc);
}
}
return;
}
wl_list_for_each(fc, &clients, link) {
if (VISIBLEON(fc, m) && ISTILED(fc) && fc != c) {
if (fc->ismaster) {
total_master_inner_per += fc->master_inner_per;
} else {
total_stack_inner_per += fc->stack_inner_per;
}
}
}
if (!c->ismaster && total_stack_inner_per) {
c->stack_inner_per = total_stack_inner_per * c->stack_inner_per /
(1 - c->stack_inner_per);
}
}
void set_size_per(Monitor *m, Client *c) { void set_size_per(Monitor *m, Client *c) {
Client *fc = NULL; Client *fc = NULL;
bool found = false; bool found = false;
@ -5,8 +47,13 @@ void set_size_per(Monitor *m, Client *c) {
if (!m || !c) if (!m || !c)
return; return;
const Layout *current_layout = m->pertag->ltidxs[m->pertag->curtag];
wl_list_for_each(fc, &clients, link) { wl_list_for_each(fc, &clients, link) {
if (VISIBLEON(fc, m) && ISTILED(fc) && fc != c) { if (VISIBLEON(fc, m) && ISTILED(fc) && fc != c) {
if (current_layout->id == CENTER_TILE &&
!(fc->isleftstack ^ c->isleftstack))
continue;
c->master_mfact_per = fc->master_mfact_per; c->master_mfact_per = fc->master_mfact_per;
c->master_inner_per = fc->master_inner_per; c->master_inner_per = fc->master_inner_per;
c->stack_inner_per = fc->stack_inner_per; c->stack_inner_per = fc->stack_inner_per;
@ -210,7 +257,7 @@ void resize_tile_master_horizontal(Client *grabc, bool isdrag, int32_t offsetx,
} }
if (last_apply_drap_time == 0 || if (last_apply_drap_time == 0 ||
time - last_apply_drap_time > drag_refresh_interval) { time - last_apply_drap_time > drag_tile_refresh_interval) {
arrange(grabc->mon, false, false); arrange(grabc->mon, false, false);
last_apply_drap_time = time; last_apply_drap_time = time;
} }
@ -367,7 +414,7 @@ void resize_tile_master_vertical(Client *grabc, bool isdrag, int32_t offsetx,
} }
if (last_apply_drap_time == 0 || if (last_apply_drap_time == 0 ||
time - last_apply_drap_time > drag_refresh_interval) { time - last_apply_drap_time > drag_tile_refresh_interval) {
arrange(grabc->mon, false, false); arrange(grabc->mon, false, false);
last_apply_drap_time = time; last_apply_drap_time = time;
} }
@ -548,7 +595,7 @@ void resize_tile_scroller(Client *grabc, bool isdrag, int32_t offsetx,
} }
if (last_apply_drap_time == 0 || if (last_apply_drap_time == 0 ||
time - last_apply_drap_time > drag_refresh_interval) { time - last_apply_drap_time > drag_tile_refresh_interval) {
arrange(grabc->mon, false, false); arrange(grabc->mon, false, false);
last_apply_drap_time = time; last_apply_drap_time = time;
} }

View file

@ -283,6 +283,7 @@ void scroller(Monitor *m) {
struct wlr_box target_geom; struct wlr_box target_geom;
int32_t focus_client_index = 0; int32_t focus_client_index = 0;
bool need_scroller = false; bool need_scroller = false;
bool over_overspread_to_left = false;
int32_t cur_gappih = enablegaps ? m->gappih : 0; int32_t cur_gappih = enablegaps ? m->gappih : 0;
int32_t cur_gappoh = enablegaps ? m->gappoh : 0; int32_t cur_gappoh = enablegaps ? m->gappoh : 0;
int32_t cur_gappov = enablegaps ? m->gappov : 0; int32_t cur_gappov = enablegaps ? m->gappov : 0;
@ -371,6 +372,46 @@ void scroller(Monitor *m) {
} }
} }
bool need_apply_overspread =
scroller_prefer_overspread && m->visible_scroll_tiling_clients > 1 &&
(focus_client_index == 0 || focus_client_index == n - 1) &&
tempClients[focus_client_index]->scroller_proportion < 1.0f;
if (need_apply_overspread) {
if (focus_client_index == 0) {
over_overspread_to_left = true;
} else {
over_overspread_to_left = false;
}
if (over_overspread_to_left &&
(!INSIDEMON(tempClients[1]) ||
(tempClients[1]->scroller_proportion +
tempClients[focus_client_index]->scroller_proportion >=
1.0f))) {
need_scroller = true;
} else if (!over_overspread_to_left &&
(!INSIDEMON(tempClients[focus_client_index - 1]) ||
(tempClients[focus_client_index - 1]->scroller_proportion +
tempClients[focus_client_index]->scroller_proportion >=
1.0f))) {
need_scroller = true;
} else {
need_apply_overspread = false;
}
}
bool need_apply_center =
scroller_focus_center || m->visible_scroll_tiling_clients == 1 ||
(scroller_prefer_center && !need_apply_overspread &&
(!m->prevsel ||
(ISSCROLLTILED(m->prevsel) &&
(m->prevsel->scroller_proportion * max_client_width) +
(tempClients[focus_client_index]->scroller_proportion *
max_client_width) >
m->w.width - 2 * scroller_structs - cur_gappih)));
if (n == 1 && scroller_ignore_proportion_single) { if (n == 1 && scroller_ignore_proportion_single) {
need_scroller = true; need_scroller = true;
} }
@ -394,18 +435,26 @@ void scroller(Monitor *m) {
tempClients[focus_client_index], &target_geom); tempClients[focus_client_index], &target_geom);
arrange_stack(tempClients[focus_client_index], target_geom, cur_gappiv); arrange_stack(tempClients[focus_client_index], target_geom, cur_gappiv);
} else if (need_scroller) { } else if (need_scroller) {
if (scroller_focus_center || if (need_apply_center) {
((!m->prevsel ||
(ISSCROLLTILED(m->prevsel) &&
(m->prevsel->scroller_proportion * max_client_width) +
(root_client->scroller_proportion * max_client_width) >
m->w.width - 2 * scroller_structs - cur_gappih)) &&
scroller_prefer_center)) {
target_geom.x = m->w.x + (m->w.width - target_geom.width) / 2; target_geom.x = m->w.x + (m->w.width - target_geom.width) / 2;
} else if (need_apply_overspread) {
if (over_overspread_to_left) {
target_geom.x = m->w.x + scroller_structs;
} else {
target_geom.x =
m->w.x +
(m->w.width -
tempClients[focus_client_index]->scroller_proportion *
max_client_width -
scroller_structs);
}
} else { } else {
target_geom.x = root_client->geom.x > m->w.x + (m->w.width) / 2 target_geom.x = tempClients[focus_client_index]->geom.x >
m->w.x + (m->w.width) / 2
? m->w.x + (m->w.width - ? m->w.x + (m->w.width -
root_client->scroller_proportion * tempClients[focus_client_index]
->scroller_proportion *
max_client_width - max_client_width -
scroller_structs) scroller_structs)
: m->w.x + scroller_structs; : m->w.x + scroller_structs;

View file

@ -270,6 +270,7 @@ void vertical_scroller(Monitor *m) {
struct wlr_box target_geom; struct wlr_box target_geom;
int32_t focus_client_index = 0; int32_t focus_client_index = 0;
bool need_scroller = false; bool need_scroller = false;
bool over_overspread_to_up = false;
int32_t cur_gappiv = enablegaps ? m->gappiv : 0; int32_t cur_gappiv = enablegaps ? m->gappiv : 0;
int32_t cur_gappov = enablegaps ? m->gappov : 0; int32_t cur_gappov = enablegaps ? m->gappov : 0;
int32_t cur_gappoh = enablegaps ? m->gappoh : 0; int32_t cur_gappoh = enablegaps ? m->gappoh : 0;
@ -355,6 +356,46 @@ void vertical_scroller(Monitor *m) {
} }
} }
bool need_apply_overspread =
scroller_prefer_overspread && m->visible_scroll_tiling_clients > 1 &&
(focus_client_index == 0 || focus_client_index == n - 1) &&
tempClients[focus_client_index]->scroller_proportion < 1.0f;
if (need_apply_overspread) {
if (focus_client_index == 0) {
over_overspread_to_up = true;
} else {
over_overspread_to_up = false;
}
if (over_overspread_to_up &&
(!INSIDEMON(tempClients[1]) ||
(tempClients[1]->scroller_proportion +
tempClients[focus_client_index]->scroller_proportion >=
1.0f))) {
need_scroller = true;
} else if (!over_overspread_to_up &&
(!INSIDEMON(tempClients[focus_client_index - 1]) ||
(tempClients[focus_client_index - 1]->scroller_proportion +
tempClients[focus_client_index]->scroller_proportion >=
1.0f))) {
need_scroller = true;
} else {
need_apply_overspread = false;
}
}
bool need_apply_center =
scroller_focus_center || m->visible_scroll_tiling_clients == 1 ||
(scroller_prefer_center && !need_apply_overspread &&
(!m->prevsel ||
(ISSCROLLTILED(m->prevsel) &&
(m->prevsel->scroller_proportion * max_client_height) +
(tempClients[focus_client_index]->scroller_proportion *
max_client_height) >
m->w.height - 2 * scroller_structs - cur_gappiv)));
if (n == 1 && scroller_ignore_proportion_single) { if (n == 1 && scroller_ignore_proportion_single) {
need_scroller = true; need_scroller = true;
} }
@ -381,18 +422,24 @@ void vertical_scroller(Monitor *m) {
arrange_stack_vertical(tempClients[focus_client_index], target_geom, arrange_stack_vertical(tempClients[focus_client_index], target_geom,
cur_gappih); cur_gappih);
} else if (need_scroller) { } else if (need_scroller) {
if (scroller_focus_center || if (need_apply_center) {
((!m->prevsel ||
(ISSCROLLTILED(m->prevsel) &&
(m->prevsel->scroller_proportion * max_client_height) +
(root_client->scroller_proportion * max_client_height) >
m->w.height - 2 * scroller_structs - cur_gappiv)) &&
scroller_prefer_center)) {
target_geom.y = m->w.y + (m->w.height - target_geom.height) / 2; target_geom.y = m->w.y + (m->w.height - target_geom.height) / 2;
} else if (need_apply_overspread) {
if (over_overspread_to_up) {
target_geom.y = m->w.y + scroller_structs;
} else {
target_geom.y =
m->w.y +
(m->w.height -
tempClients[focus_client_index]->scroller_proportion *
max_client_height -
scroller_structs);
}
} else { } else {
target_geom.y = root_client->geom.y > m->w.y + (m->w.height) / 2 target_geom.y = root_client->geom.y > m->w.y + (m->w.height) / 2
? m->w.y + (m->w.height - ? m->w.y + (m->w.height -
root_client->scroller_proportion * tempClients[focus_client_index]
->scroller_proportion *
max_client_height - max_client_height -
scroller_structs) scroller_structs)
: m->w.y + scroller_structs; : m->w.y + scroller_structs;

View file

@ -3,6 +3,7 @@
*/ */
#include "wlr-layer-shell-unstable-v1-protocol.h" #include "wlr-layer-shell-unstable-v1-protocol.h"
#include "wlr/util/box.h" #include "wlr/util/box.h"
#include "wlr/util/edges.h"
#include <getopt.h> #include <getopt.h>
#include <libinput.h> #include <libinput.h>
#include <limits.h> #include <limits.h>
@ -337,6 +338,7 @@ struct Client {
struct wl_listener configure; struct wl_listener configure;
struct wl_listener set_hints; struct wl_listener set_hints;
struct wl_listener set_geometry; struct wl_listener set_geometry;
struct wl_listener commmitx11;
#endif #endif
uint32_t bw; uint32_t bw;
uint32_t tags, oldtags, mini_restore_tag; uint32_t tags, oldtags, mini_restore_tag;
@ -390,6 +392,7 @@ struct Client {
int32_t isterm, noswallow; int32_t isterm, noswallow;
int32_t allow_csd; int32_t allow_csd;
int32_t force_maximize; int32_t force_maximize;
int32_t force_tiled_state;
pid_t pid; pid_t pid;
Client *swallowing, *swallowedby; Client *swallowing, *swallowedby;
bool is_clip_to_hide; bool is_clip_to_hide;
@ -500,11 +503,13 @@ struct Monitor {
struct wl_listener request_state; struct wl_listener request_state;
struct wl_listener destroy_lock_surface; struct wl_listener destroy_lock_surface;
struct wlr_session_lock_surface_v1 *lock_surface; struct wlr_session_lock_surface_v1 *lock_surface;
struct wl_event_source *skip_timeout;
struct wlr_box m; /* monitor area, layout-relative */ struct wlr_box m; /* monitor area, layout-relative */
struct wlr_box w; /* window area, layout-relative */ struct wlr_box w; /* window area, layout-relative */
struct wl_list layers[4]; /* LayerSurface::link */ struct wl_list layers[4]; /* LayerSurface::link */
uint32_t seltags; uint32_t seltags;
uint32_t tagset[2]; uint32_t tagset[2];
bool skiping_frame;
struct wl_list dwl_ipc_outputs; struct wl_list dwl_ipc_outputs;
int32_t gappih; /* horizontal gap between windows */ int32_t gappih; /* horizontal gap between windows */
@ -512,6 +517,8 @@ struct Monitor {
int32_t gappoh; /* horizontal outer gaps */ int32_t gappoh; /* horizontal outer gaps */
int32_t gappov; /* vertical outer gaps */ int32_t gappov; /* vertical outer gaps */
Pertag *pertag; Pertag *pertag;
uint32_t ovbk_current_tagset;
uint32_t ovbk_prev_tagset;
Client *sel, *prevsel; Client *sel, *prevsel;
int32_t isoverview; int32_t isoverview;
int32_t is_in_hotarea; int32_t is_in_hotarea;
@ -779,6 +786,8 @@ static Client *get_scroll_stack_head(Client *c);
static bool client_only_in_one_tag(Client *c); static bool client_only_in_one_tag(Client *c);
static Client *get_focused_stack_client(Client *sc); static Client *get_focused_stack_client(Client *sc);
static bool client_is_in_same_stack(Client *sc, Client *tc, Client *fc); static bool client_is_in_same_stack(Client *sc, Client *tc, Client *fc);
static void monitor_stop_skip_timer(Monitor *m);
static int monitor_skip_frame_timeout_callback(void *data);
#include "data/static_keymap.h" #include "data/static_keymap.h"
#include "dispatch/bind_declare.h" #include "dispatch/bind_declare.h"
@ -942,10 +951,13 @@ static struct wl_listener keyboard_shortcuts_inhibit_new_inhibitor = {
.notify = handle_keyboard_shortcuts_inhibit_new_inhibitor}; .notify = handle_keyboard_shortcuts_inhibit_new_inhibitor};
#ifdef XWAYLAND #ifdef XWAYLAND
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 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);
static void createnotifyx11(struct wl_listener *listener, void *data); static void createnotifyx11(struct wl_listener *listener, void *data);
static void dissociatex11(struct wl_listener *listener, void *data); static void dissociatex11(struct wl_listener *listener, void *data);
static void commitx11(struct wl_listener *listener, void *data);
static void associatex11(struct wl_listener *listener, void *data); static void associatex11(struct wl_listener *listener, void *data);
static void sethints(struct wl_listener *listener, void *data); static void sethints(struct wl_listener *listener, void *data);
static void xwaylandready(struct wl_listener *listener, void *data); static void xwaylandready(struct wl_listener *listener, void *data);
@ -953,6 +965,7 @@ static void setgeometrynotify(struct wl_listener *listener, void *data);
static struct wl_listener new_xwayland_surface = {.notify = createnotifyx11}; static struct wl_listener new_xwayland_surface = {.notify = createnotifyx11};
static struct wl_listener xwayland_ready = {.notify = xwaylandready}; static struct wl_listener xwayland_ready = {.notify = xwaylandready};
static struct wlr_xwayland *xwayland; static struct wlr_xwayland *xwayland;
static struct wl_event_source *sync_keymap;
#endif #endif
#include "animation/client.h" #include "animation/client.h"
@ -969,7 +982,6 @@ static struct wlr_xwayland *xwayland;
void client_change_mon(Client *c, Monitor *m) { void client_change_mon(Client *c, Monitor *m) {
setmon(c, m, c->tags, true); setmon(c, m, c->tags, true);
reset_foreign_tolevel(c);
if (c->isfloating) { if (c->isfloating) {
c->float_geom = c->geom = c->float_geom = c->geom =
setclient_coordinate_center(c, c->mon, c->geom, 0, 0); setclient_coordinate_center(c, c->mon, c->geom, 0, 0);
@ -1071,6 +1083,9 @@ void swallow(Client *c, Client *w) {
c->tags = w->tags; c->tags = w->tags;
c->geom = w->geom; c->geom = w->geom;
c->float_geom = w->float_geom; c->float_geom = w->float_geom;
c->stack_inner_per = w->stack_inner_per;
c->master_inner_per = w->master_inner_per;
c->master_mfact_per = w->master_mfact_per;
c->scroller_proportion = w->scroller_proportion; c->scroller_proportion = w->scroller_proportion;
c->next_in_stack = w->next_in_stack; c->next_in_stack = w->next_in_stack;
c->prev_in_stack = w->prev_in_stack; c->prev_in_stack = w->prev_in_stack;
@ -1279,6 +1294,7 @@ static void apply_rule_properties(Client *c, const ConfigWinRule *r) {
APPLY_INT_PROP(c, r, isterm); APPLY_INT_PROP(c, r, isterm);
APPLY_INT_PROP(c, r, allow_csd); APPLY_INT_PROP(c, r, allow_csd);
APPLY_INT_PROP(c, r, force_maximize); APPLY_INT_PROP(c, r, force_maximize);
APPLY_INT_PROP(c, r, force_tiled_state);
APPLY_INT_PROP(c, r, force_tearing); APPLY_INT_PROP(c, r, force_tearing);
APPLY_INT_PROP(c, r, noswallow); APPLY_INT_PROP(c, r, noswallow);
APPLY_INT_PROP(c, r, nofocus); APPLY_INT_PROP(c, r, nofocus);
@ -1287,6 +1303,7 @@ static void apply_rule_properties(Client *c, const ConfigWinRule *r) {
APPLY_INT_PROP(c, r, no_force_center); APPLY_INT_PROP(c, r, no_force_center);
APPLY_INT_PROP(c, r, isfloating); APPLY_INT_PROP(c, r, isfloating);
APPLY_INT_PROP(c, r, isfullscreen); APPLY_INT_PROP(c, r, isfullscreen);
APPLY_INT_PROP(c, r, isfakefullscreen);
APPLY_INT_PROP(c, r, isnoborder); APPLY_INT_PROP(c, r, isnoborder);
APPLY_INT_PROP(c, r, isnoshadow); APPLY_INT_PROP(c, r, isnoshadow);
APPLY_INT_PROP(c, r, isnoradius); APPLY_INT_PROP(c, r, isnoradius);
@ -1367,6 +1384,14 @@ void applyrules(Client *c) {
Monitor *mon = parent && parent->mon ? parent->mon : selmon; Monitor *mon = parent && parent->mon ? parent->mon : selmon;
c->isfloating = client_is_float_type(c) || parent; c->isfloating = client_is_float_type(c) || parent;
#ifdef XWAYLAND
if (c->isfloating && client_is_x11(c)) {
fix_xwayland_unmanaged_coordinate(c);
c->float_geom = c->geom;
}
#endif
if (!(appid = client_get_appid(c))) if (!(appid = client_get_appid(c)))
appid = broken; appid = broken;
if (!(title = client_get_title(c))) if (!(title = client_get_title(c)))
@ -1480,6 +1505,10 @@ void applyrules(Client *c) {
setfullscreen(c, fullscreen_state_backup); setfullscreen(c, fullscreen_state_backup);
if (c->isfakefullscreen) {
setfakefullscreen(c, 1);
}
/* /*
if there is a new non-floating window in the current tag, the fullscreen if there is a new non-floating window in the current tag, the fullscreen
window in the current tag will exit fullscreen and participate in tiling window in the current tag will exit fullscreen and participate in tiling
@ -1994,14 +2023,21 @@ buttonpress(struct wl_listener *listener, void *data) {
if (config.mouse_bindings_count < 1) if (config.mouse_bindings_count < 1)
break; break;
m = &config.mouse_bindings[ji]; m = &config.mouse_bindings[ji];
if (selmon->isoverview && event->button == BTN_LEFT && c) {
toggleoverview(&(Arg){.i = 1});
return;
}
if (selmon->isoverview && event->button == BTN_RIGHT && c) {
pending_kill_client(c);
return;
}
if (CLEANMASK(mods) == CLEANMASK(m->mod) && if (CLEANMASK(mods) == CLEANMASK(m->mod) &&
event->button == m->button && m->func && event->button == m->button && m->func &&
(selmon->isoverview == 1 || m->button == BTN_MIDDLE) && c) { (CLEANMASK(m->mod) != 0 ||
m->func(&m->arg); (event->button != BTN_LEFT && event->button != BTN_RIGHT))) {
return;
} else if (CLEANMASK(mods) == CLEANMASK(m->mod) &&
event->button == m->button && m->func &&
CLEANMASK(m->mod) != 0) {
m->func(&m->arg); m->func(&m->arg);
return; return;
} }
@ -2023,7 +2059,6 @@ buttonpress(struct wl_listener *listener, void *data) {
selmon = xytomon(cursor->x, cursor->y); selmon = xytomon(cursor->x, cursor->y);
client_update_oldmonname_record(grabc, selmon); client_update_oldmonname_record(grabc, selmon);
setmon(grabc, selmon, 0, true); setmon(grabc, selmon, 0, true);
reset_foreign_tolevel(grabc);
selmon->prevsel = ISTILED(selmon->sel) ? selmon->sel : NULL; selmon->prevsel = ISTILED(selmon->sel) ? selmon->sel : NULL;
selmon->sel = grabc; selmon->sel = grabc;
tmpc = grabc; tmpc = grabc;
@ -2194,6 +2229,11 @@ void cleanupmon(struct wl_listener *listener, void *data) {
wlr_scene_node_destroy(&m->blur->node); wlr_scene_node_destroy(&m->blur->node);
m->blur = NULL; m->blur = NULL;
} }
if (m->skip_timeout) {
monitor_stop_skip_timer(m);
wl_event_source_remove(m->skip_timeout);
m->skip_timeout = NULL;
}
m->wlr_output->data = NULL; m->wlr_output->data = NULL;
free(m->pertag); free(m->pertag);
free(m); free(m);
@ -2253,6 +2293,19 @@ static void iter_layer_scene_buffers(struct wlr_scene_buffer *buffer,
} }
} }
void layer_flush_blur_background(LayerSurface *l) {
if (!blur)
return;
// 如果背景层发生变化,标记优化的模糊背景缓存需要更新
if (l->layer_surface->current.layer ==
ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND) {
if (l->mon) {
wlr_scene_optimized_blur_mark_dirty(l->mon->blur);
}
}
}
void maplayersurfacenotify(struct wl_listener *listener, void *data) { void maplayersurfacenotify(struct wl_listener *listener, void *data) {
LayerSurface *l = wl_container_of(listener, l, map); LayerSurface *l = wl_container_of(listener, l, map);
struct wlr_layer_surface_v1 *layer_surface = l->layer_surface; struct wlr_layer_surface_v1 *layer_surface = l->layer_surface;
@ -2380,15 +2433,7 @@ void commitlayersurfacenotify(struct wl_listener *listener, void *data) {
} }
} }
if (blur) { layer_flush_blur_background(l);
// 如果背景层发生变化,标记优化的模糊背景缓存需要更新
if (layer_surface->current.layer ==
ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND) {
if (l->mon) {
wlr_scene_optimized_blur_mark_dirty(l->mon->blur);
}
}
}
if (layer_surface == exclusive_focus && if (layer_surface == exclusive_focus &&
layer_surface->current.keyboard_interactive != layer_surface->current.keyboard_interactive !=
@ -2428,9 +2473,6 @@ void commitnotify(struct wl_listener *listener, void *data) {
setmon(c, NULL, 0, setmon(c, NULL, 0,
true); /* Make sure to reapply rules in mapnotify() */ true); /* Make sure to reapply rules in mapnotify() */
client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT |
WLR_EDGE_RIGHT);
uint32_t serial = wlr_xdg_surface_schedule_configure(c->surface.xdg); uint32_t serial = wlr_xdg_surface_schedule_configure(c->surface.xdg);
if (serial > 0) { if (serial > 0) {
c->configure_serial = serial; c->configure_serial = serial;
@ -2727,6 +2769,7 @@ void createmon(struct wl_listener *listener, void *data) {
Monitor *m = NULL; Monitor *m = NULL;
struct wlr_output_mode *internal_mode = NULL; struct wlr_output_mode *internal_mode = NULL;
bool custom_monitor_mode = false; bool custom_monitor_mode = false;
bool match_rule = false;
if (!wlr_output_init_render(wlr_output, alloc, drw)) if (!wlr_output_init_render(wlr_output, alloc, drw))
return; return;
@ -2739,7 +2782,13 @@ void createmon(struct wl_listener *listener, void *data) {
return; return;
} }
struct wl_event_loop *loop = wl_display_get_event_loop(dpy);
m = wlr_output->data = ecalloc(1, sizeof(*m)); m = wlr_output->data = ecalloc(1, sizeof(*m));
m->skip_timeout =
wl_event_loop_add_timer(loop, monitor_skip_frame_timeout_callback, m);
m->skiping_frame = false;
m->wlr_output = wlr_output; m->wlr_output = wlr_output;
m->wlr_output->data = m; m->wlr_output->data = m;
@ -2767,7 +2816,39 @@ void createmon(struct wl_listener *listener, void *data) {
break; break;
r = &config.monitor_rules[ji]; r = &config.monitor_rules[ji];
if (regex_match(r->name, wlr_output->name)) {
// 检查是否匹配的变量
match_rule = true;
// 检查四个标识字段的匹配
if (r->name != NULL) {
if (!regex_match(r->name, m->wlr_output->name)) {
match_rule = false;
}
}
if (r->make != NULL) {
if (m->wlr_output->make == NULL ||
strcmp(r->make, m->wlr_output->make) != 0) {
match_rule = false;
}
}
if (r->model != NULL) {
if (m->wlr_output->model == NULL ||
strcmp(r->model, m->wlr_output->model) != 0) {
match_rule = false;
}
}
if (r->serial != NULL) {
if (m->wlr_output->serial == NULL ||
strcmp(r->serial, m->wlr_output->serial) != 0) {
match_rule = false;
}
}
if (match_rule) {
m->m.x = r->x == INT32_MAX ? INT32_MAX : r->x; m->m.x = r->x == INT32_MAX ? INT32_MAX : r->x;
m->m.y = r->y == INT32_MAX ? INT32_MAX : r->y; m->m.y = r->y == INT32_MAX ? INT32_MAX : r->y;
vrr = r->vrr >= 0 ? r->vrr : 0; vrr = r->vrr >= 0 ? r->vrr : 0;
@ -3418,7 +3499,10 @@ void requestmonstate(struct wl_listener *listener, void *data) {
void inputdevice(struct wl_listener *listener, void *data) { void inputdevice(struct wl_listener *listener, void *data) {
/* This event is raised by the backend when a new input device becomes /* This event is raised by the backend when a new input device becomes
* available. */ * available.
* when the backend is a headless backend, this event will never be
* triggered.
*/
struct wlr_input_device *device = data; struct wlr_input_device *device = data;
uint32_t caps; uint32_t caps;
@ -3489,11 +3573,6 @@ keybinding(uint32_t state, bool locked, uint32_t mods, xkb_keysym_t sym,
int32_t ji; int32_t ji;
int32_t isbreak = 0; int32_t isbreak = 0;
// not allow modifier keys to be used as a keybinding
if (keycode == 50 || keycode == 37 || keycode == 133 || keycode == 64 ||
keycode == 62 || keycode == 108 || keycode == 105 || keycode == 134)
return false;
if (is_keyboard_shortcut_inhibitor(seat->keyboard_state.focused_surface)) { if (is_keyboard_shortcut_inhibitor(seat->keyboard_state.focused_surface)) {
return false; return false;
} }
@ -3773,6 +3852,23 @@ static void iter_xdg_scene_buffers(struct wlr_scene_buffer *buffer, int32_t sx,
void init_client_properties(Client *c) { void init_client_properties(Client *c) {
c->isfocusing = false; c->isfocusing = false;
c->isfloating = 0;
c->isfakefullscreen = 0;
c->isnoanimation = 0;
c->isopensilent = 0;
c->istagsilent = 0;
c->noswallow = 0;
c->isterm = 0;
c->noblur = 0;
c->tearing_hint = 0;
c->overview_isfullscreenbak = 0;
c->overview_ismaximizescreenbak = 0;
c->overview_isfloatingbak = 0;
c->pid = 0;
c->swallowing = NULL;
c->swallowedby = NULL;
c->ismaster = 0;
c->isleftstack = 0;
c->ismaximizescreen = 0; c->ismaximizescreen = 0;
c->isfullscreen = 0; c->isfullscreen = 0;
c->need_float_size_reduce = 0; c->need_float_size_reduce = 0;
@ -3815,6 +3911,7 @@ void init_client_properties(Client *c) {
c->isterm = 0; c->isterm = 0;
c->allow_csd = 0; c->allow_csd = 0;
c->force_maximize = 0; c->force_maximize = 0;
c->force_tiled_state = 1;
c->force_tearing = 0; c->force_tearing = 0;
c->allow_shortcuts_inhibit = SHORTCUTS_INHIBIT_ENABLE; c->allow_shortcuts_inhibit = SHORTCUTS_INHIBIT_ENABLE;
c->scroller_proportion_single = 0.0f; c->scroller_proportion_single = 0.0f;
@ -3825,6 +3922,13 @@ void init_client_properties(Client *c) {
c->stack_proportion = 0.0f; c->stack_proportion = 0.0f;
c->next_in_stack = NULL; c->next_in_stack = NULL;
c->prev_in_stack = NULL; c->prev_in_stack = NULL;
memset(c->oldmonname, 0, sizeof(c->oldmonname));
memcpy(c->opacity_animation.initial_border_color, bordercolor,
sizeof(c->opacity_animation.initial_border_color));
memcpy(c->opacity_animation.current_border_color, bordercolor,
sizeof(c->opacity_animation.current_border_color));
c->opacity_animation.initial_opacity = c->unfocused_opacity;
c->opacity_animation.current_opacity = c->unfocused_opacity;
} }
void // old fix to 0.5 void // old fix to 0.5
@ -3866,18 +3970,19 @@ mapnotify(struct wl_listener *listener, void *data) {
*/ */
if (client_is_unmanaged(c)) { if (client_is_unmanaged(c)) {
/* Unmanaged clients always are floating */ /* Unmanaged clients always are floating */
#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_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);
if (client_wants_focus(c)) { if (client_wants_focus(c)) {
focusclient(c, 1); focusclient(c, 1);
exclusive_focus = c; exclusive_focus = c;
} }
#ifdef XWAYLAND
if (client_is_x11(c)) {
LISTEN(&c->surface.xwayland->events.set_geometry, &c->set_geometry,
setgeometrynotify);
}
#endif
return; return;
} }
@ -3923,8 +4028,10 @@ mapnotify(struct wl_listener *listener, void *data) {
applyrules(c); applyrules(c);
client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | if (!c->isfloating || c->force_tiled_state) {
WLR_EDGE_RIGHT); client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT |
WLR_EDGE_RIGHT);
}
// apply buffer effects of client // apply buffer effects of client
wlr_scene_node_for_each_buffer(&c->scene_surface->node, wlr_scene_node_for_each_buffer(&c->scene_surface->node,
@ -4143,7 +4250,7 @@ void motionnotify(uint32_t time, struct wlr_input_device *device, double dx,
if (grabc->isfloating) { if (grabc->isfloating) {
grabc->iscustomsize = 1; grabc->iscustomsize = 1;
if (last_apply_drap_time == 0 || if (last_apply_drap_time == 0 ||
time - last_apply_drap_time > drag_refresh_interval) { time - last_apply_drap_time > drag_floating_refresh_interval) {
resize_floating_window(grabc); resize_floating_window(grabc);
last_apply_drap_time = time; last_apply_drap_time = time;
} }
@ -4275,7 +4382,7 @@ void pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy,
uint32_t time) { uint32_t time) {
struct timespec now; struct timespec now;
if (sloppyfocus && !start_drag_window && c && time && if (sloppyfocus && !start_drag_window && c && time && c->scene &&
c->scene->node.enabled && !c->animation.tagining && c->scene->node.enabled && !c->animation.tagining &&
(surface != seat->pointer_state.focused_surface) && (surface != seat->pointer_state.focused_surface) &&
!client_is_unmanaged(c) && VISIBLEON(c, c->mon)) !client_is_unmanaged(c) && VISIBLEON(c, c->mon))
@ -4329,6 +4436,35 @@ void client_set_opacity(Client *c, double opacity) {
scene_buffer_apply_opacity, &opacity); scene_buffer_apply_opacity, &opacity);
} }
void monitor_stop_skip_timer(Monitor *m) {
if (m->skip_timeout)
wl_event_source_timer_update(m->skip_timeout, 0);
m->skiping_frame = false;
}
static int monitor_skip_frame_timeout_callback(void *data) {
Monitor *m = data;
Client *c, *tmp;
wl_list_for_each_safe(c, tmp, &clients, link) { c->configure_serial = 0; }
monitor_stop_skip_timer(m);
wlr_output_schedule_frame(m->wlr_output);
return 1;
}
void monitor_check_skip_frame_timeout(Monitor *m) {
if (m->skiping_frame) {
return;
}
if (m->skip_timeout) {
wl_event_source_timer_update(m->skip_timeout, 100); // 100ms
m->skiping_frame = true;
}
}
void rendermon(struct wl_listener *listener, void *data) { void rendermon(struct wl_listener *listener, void *data) {
Monitor *m = wl_container_of(listener, m, frame); Monitor *m = wl_container_of(listener, m, frame);
Client *c = NULL, *tmp = NULL; Client *c = NULL, *tmp = NULL;
@ -4369,12 +4505,17 @@ void rendermon(struct wl_listener *listener, void *data) {
wl_list_for_each(c, &clients, link) { wl_list_for_each(c, &clients, link) {
need_more_frames = client_draw_frame(c) || need_more_frames; need_more_frames = client_draw_frame(c) || need_more_frames;
if (!animations && !(allow_tearing && frame_allow_tearing) && if (!animations && !(allow_tearing && frame_allow_tearing) &&
c->configure_serial && !c->isfloating && c->configure_serial && client_is_rendered_on_mon(c, m) &&
client_is_rendered_on_mon(c, m) && !client_is_stopped(c)) { !client_is_stopped(c) && !grabc) {
monitor_check_skip_frame_timeout(m);
goto skip; goto skip;
} }
} }
if (m->skiping_frame) {
monitor_stop_skip_timer(m);
}
// 只有在需要帧时才构建和提交状态 // 只有在需要帧时才构建和提交状态
if (allow_tearing && frame_allow_tearing) { if (allow_tearing && frame_allow_tearing) {
apply_tear_state(m); apply_tear_state(m);
@ -4672,6 +4813,7 @@ setfloating(Client *c, int32_t floating) {
Client *fc = NULL; Client *fc = NULL;
struct wlr_box target_box; struct wlr_box target_box;
int32_t old_floating_state = c->isfloating;
c->isfloating = floating; c->isfloating = floating;
bool window_size_outofrange = false; bool window_size_outofrange = false;
@ -4741,13 +4883,20 @@ setfloating(Client *c, int32_t floating) {
layers[c->isfloating ? LyrTop : LyrTile]); layers[c->isfloating ? LyrTop : LyrTile]);
} }
if (!c->isfloating) { if (!c->isfloating && old_floating_state) {
set_size_per(c->mon, c); restore_size_per(c->mon, c);
} }
if (!c->force_maximize) if (!c->force_maximize)
client_set_maximized(c, false); client_set_maximized(c, false);
if (!c->isfloating || c->force_tiled_state) {
client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT |
WLR_EDGE_RIGHT);
} else {
client_set_tiled(c, WLR_EDGE_NONE);
}
arrange(c->mon, false, false); arrange(c->mon, false, false);
setborder_color(c); setborder_color(c);
printstatus(); printstatus();
@ -4790,6 +4939,7 @@ void setmaximizescreen(Client *c, int32_t maximizescreen) {
if (c->mon->isoverview) if (c->mon->isoverview)
return; return;
int32_t old_maximizescreen_state = c->ismaximizescreen;
c->ismaximizescreen = maximizescreen; c->ismaximizescreen = maximizescreen;
if (maximizescreen) { if (maximizescreen) {
@ -4819,8 +4969,8 @@ void setmaximizescreen(Client *c, int32_t maximizescreen) {
wlr_scene_node_reparent(&c->scene->node, wlr_scene_node_reparent(&c->scene->node,
layers[c->isfloating ? LyrTop : LyrTile]); layers[c->isfloating ? LyrTop : LyrTile]);
if (!c->ismaximizescreen) { if (!c->ismaximizescreen && old_maximizescreen_state) {
set_size_per(c->mon, c); restore_size_per(c->mon, c);
} }
if (!c->force_maximize && !c->ismaximizescreen) { if (!c->force_maximize && !c->ismaximizescreen) {
@ -4852,6 +5002,7 @@ void setfullscreen(Client *c, int32_t fullscreen) // 用自定义全屏代理自
if (c->mon->isoverview) if (c->mon->isoverview)
return; return;
int32_t old_fullscreen_state = c->isfullscreen;
c->isfullscreen = fullscreen; c->isfullscreen = fullscreen;
client_set_fullscreen(c, fullscreen); client_set_fullscreen(c, fullscreen);
@ -4889,8 +5040,8 @@ void setfullscreen(Client *c, int32_t fullscreen) // 用自定义全屏代理自
layers[fullscreen || c->isfloating ? LyrTop : LyrTile]); layers[fullscreen || c->isfloating ? LyrTop : LyrTile]);
} }
if (!c->isfullscreen) { if (!c->isfullscreen && old_fullscreen_state) {
set_size_per(c->mon, c); restore_size_per(c->mon, c);
} }
arrange(c->mon, false, false); arrange(c->mon, false, false);
@ -5018,10 +5169,17 @@ void setmon(Client *c, Monitor *m, uint32_t newtags, bool focus) {
arrange(oldmon, false, false); arrange(oldmon, false, false);
if (m) { if (m) {
/* Make sure window actually overlaps with the monitor */ /* Make sure window actually overlaps with the monitor */
reset_foreign_tolevel(c);
resize(c, c->geom, 0); resize(c, c->geom, 0);
c->tags = if (!newtags && !m->isoverview) {
newtags ? newtags c->tags = m->tagset[m->seltags];
: m->tagset[m->seltags]; /* assign tags of target monitor */ } else if (!newtags && m->isoverview) {
c->tags = m->ovbk_current_tagset;
} else if (newtags) {
c->tags = newtags;
} else {
c->tags = m->tagset[m->seltags];
}
setfloating(c, c->isfloating); setfloating(c, c->isfloating);
setfullscreen(c, c->isfullscreen); /* This will call arrange(c->mon) */ setfullscreen(c, c->isfullscreen); /* This will call arrange(c->mon) */
} }
@ -5029,21 +5187,6 @@ void setmon(Client *c, Monitor *m, uint32_t newtags, bool focus) {
if (focus && !client_is_x11_popup(c)) { if (focus && !client_is_x11_popup(c)) {
focusclient(focustop(selmon), 1); focusclient(focustop(selmon), 1);
} }
if (m) {
if (c->foreign_toplevel) {
remove_foreign_topleve(c);
}
add_foreign_toplevel(c);
if (m->sel && m->sel->foreign_toplevel)
wlr_foreign_toplevel_handle_v1_set_activated(
m->sel->foreign_toplevel, false);
if (c->foreign_toplevel)
wlr_foreign_toplevel_handle_v1_set_activated(c->foreign_toplevel,
true);
}
} }
void setpsel(struct wl_listener *listener, void *data) { void setpsel(struct wl_listener *listener, void *data) {
@ -5181,7 +5324,7 @@ void setup(void) {
if (wlr_renderer_get_texture_formats(drw, WLR_BUFFER_CAP_DMABUF)) { if (wlr_renderer_get_texture_formats(drw, WLR_BUFFER_CAP_DMABUF)) {
wlr_drm_create(dpy, drw); wlr_drm_create(dpy, drw);
wlr_scene_set_linux_dmabuf_v1( wlr_scene_set_linux_dmabuf_v1(
scene, wlr_linux_dmabuf_v1_create_with_renderer(dpy, 5, drw)); scene, wlr_linux_dmabuf_v1_create_with_renderer(dpy, 4, drw));
} }
if (syncobj_enable && (drm_fd = wlr_renderer_get_drm_fd(drw)) >= 0 && if (syncobj_enable && (drm_fd = wlr_renderer_get_drm_fd(drw)) >= 0 &&
@ -5328,7 +5471,6 @@ void setup(void) {
&request_set_cursor_shape); &request_set_cursor_shape);
hide_source = wl_event_loop_add_timer(wl_display_get_event_loop(dpy), hide_source = wl_event_loop_add_timer(wl_display_get_event_loop(dpy),
hidecursor, cursor); hidecursor, cursor);
/* /*
* Configures a seat, which is a single "seat" at which a user sits and * Configures a seat, which is a single "seat" at which a user sits and
* operates the computer. This conceptually includes up to one keyboard, * operates the computer. This conceptually includes up to one keyboard,
@ -5420,6 +5562,8 @@ void setup(void) {
fprintf(stderr, fprintf(stderr,
"failed to setup XWayland X server, continuing without it\n"); "failed to setup XWayland X server, continuing without it\n");
} }
sync_keymap = wl_event_loop_add_timer(wl_display_get_event_loop(dpy),
synckeymap, NULL);
#endif #endif
} }
@ -5494,6 +5638,9 @@ void overview_backup(Client *c) {
c->ismaximizescreen = 0; c->ismaximizescreen = 0;
} }
c->bw = c->isnoborder ? 0 : borderpx; c->bw = c->isnoborder ? 0 : borderpx;
client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT |
WLR_EDGE_RIGHT);
} }
// overview切回到普通视图还原窗口的状态 // overview切回到普通视图还原窗口的状态
@ -5533,6 +5680,10 @@ void overview_restore(Client *c, const Arg *arg) {
!c->isfullscreen) { // 如果是在ov模式中创建的窗口,没有bw记录 !c->isfullscreen) { // 如果是在ov模式中创建的窗口,没有bw记录
c->bw = c->isnoborder ? 0 : borderpx; c->bw = c->isnoborder ? 0 : borderpx;
} }
if (c->isfloating && !c->force_tiled_state) {
client_set_tiled(c, WLR_EDGE_NONE);
}
} }
void handlecursoractivity(void) { void handlecursoractivity(void) {
@ -5579,6 +5730,7 @@ void unmaplayersurfacenotify(struct wl_listener *listener, void *data) {
focusclient(focustop(selmon), 1); focusclient(focustop(selmon), 1);
motionnotify(0, NULL, 0, 0, 0, 0); motionnotify(0, NULL, 0, 0, 0, 0);
l->being_unmapped = false; l->being_unmapped = false;
layer_flush_blur_background(l);
wlr_scene_node_destroy(&l->shadow->node); wlr_scene_node_destroy(&l->shadow->node);
l->shadow = NULL; l->shadow = NULL;
} }
@ -5798,7 +5950,8 @@ void updatemons(struct wl_listener *listener, void *data) {
if (selmon && selmon->wlr_output->enabled) { if (selmon && selmon->wlr_output->enabled) {
wl_list_for_each(c, &clients, link) { wl_list_for_each(c, &clients, link) {
if (!c->mon && client_surface(c)->mapped) { if (!c->mon && client_surface(c)->mapped) {
client_change_mon(c, selmon); c->mon = selmon;
reset_foreign_tolevel(c);
} }
} }
focusclient(focustop(selmon), 1); focusclient(focustop(selmon), 1);
@ -5976,6 +6129,8 @@ void handle_keyboard_shortcuts_inhibit_new_inhibitor(
void virtualkeyboard(struct wl_listener *listener, void *data) { void virtualkeyboard(struct wl_listener *listener, void *data) {
struct wlr_virtual_keyboard_v1 *kb = data; struct wlr_virtual_keyboard_v1 *kb = data;
/* virtual keyboards shouldn't share keyboard group */ /* virtual keyboards shouldn't share keyboard group */
wlr_seat_set_capabilities(seat,
seat->capabilities | WL_SEAT_CAPABILITY_KEYBOARD);
KeyboardGroup *group = createkeyboardgroup(); KeyboardGroup *group = createkeyboardgroup();
/* Set the keymap to match the group keymap */ /* Set the keymap to match the group keymap */
wlr_keyboard_set_keymap(&kb->keyboard, group->wlr_group->keyboard.keymap); wlr_keyboard_set_keymap(&kb->keyboard, group->wlr_group->keyboard.keymap);
@ -5987,8 +6142,7 @@ void virtualkeyboard(struct wl_listener *listener, void *data) {
} }
void warp_cursor(const Client *c) { void warp_cursor(const Client *c) {
if (cursor->x < c->geom.x || cursor->x > c->geom.x + c->geom.width || if (INSIDEMON(c)) {
cursor->y < c->geom.y || cursor->y > c->geom.y + c->geom.height) {
wlr_cursor_warp_closest(cursor, NULL, c->geom.x + c->geom.width / 2.0, wlr_cursor_warp_closest(cursor, NULL, c->geom.x + c->geom.width / 2.0,
c->geom.y + c->geom.height / 2.0); c->geom.y + c->geom.height / 2.0);
motionnotify(0, NULL, 0, 0, 0, 0); motionnotify(0, NULL, 0, 0, 0, 0);
@ -6006,7 +6160,8 @@ void warp_cursor_to_selmon(Monitor *m) {
void virtualpointer(struct wl_listener *listener, void *data) { void virtualpointer(struct wl_listener *listener, void *data) {
struct wlr_virtual_pointer_v1_new_pointer_event *event = data; struct wlr_virtual_pointer_v1_new_pointer_event *event = data;
struct wlr_input_device *device = &event->new_pointer->pointer.base; struct wlr_input_device *device = &event->new_pointer->pointer.base;
wlr_seat_set_capabilities(seat,
seat->capabilities | WL_SEAT_CAPABILITY_POINTER);
wlr_cursor_attach_input_device(cursor, device); wlr_cursor_attach_input_device(cursor, device);
if (event->suggested_output) if (event->suggested_output)
wlr_cursor_map_input_to_output(cursor, device, event->suggested_output); wlr_cursor_map_input_to_output(cursor, device, event->suggested_output);
@ -6015,6 +6170,26 @@ void virtualpointer(struct wl_listener *listener, void *data) {
} }
#ifdef XWAYLAND #ifdef XWAYLAND
void fix_xwayland_unmanaged_coordinate(Client *c) {
if (!selmon)
return;
// 1. 如果窗口已经在当前活动显示器内,直接返回
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;
c->geom = setclient_coordinate_center(c, selmon, c->geom, 0, 0);
}
int32_t synckeymap(void *data) {
reset_keyboard_layout();
// we only need to sync keymap once
wlr_log(WLR_INFO, "timer to synckeymap done");
wl_event_source_timer_update(sync_keymap, 0);
return 0;
}
void activatex11(struct wl_listener *listener, void *data) { void activatex11(struct wl_listener *listener, void *data) {
Client *c = wl_container_of(listener, c, activate); Client *c = wl_container_of(listener, c, activate);
bool need_arrange = false; bool need_arrange = false;
@ -6107,17 +6282,34 @@ void createnotifyx11(struct wl_listener *listener, void *data) {
LISTEN(&xsurface->events.request_minimize, &c->minimize, minimizenotify); LISTEN(&xsurface->events.request_minimize, &c->minimize, minimizenotify);
} }
void commitx11(struct wl_listener *listener, void *data) {
Client *c = wl_container_of(listener, c, commmitx11);
struct wlr_surface_state *state = &c->surface.xwayland->surface->current;
if ((int32_t)c->geom.width - 2 * (int32_t)c->bw == (int32_t)state->width &&
(int32_t)c->geom.height - 2 * (int32_t)c->bw ==
(int32_t)state->height &&
(int32_t)c->surface.xwayland->x ==
(int32_t)c->geom.x + (int32_t)c->bw &&
(int32_t)c->surface.xwayland->y ==
(int32_t)c->geom.y + (int32_t)c->bw) {
c->configure_serial = 0;
}
}
void associatex11(struct wl_listener *listener, void *data) { void associatex11(struct wl_listener *listener, void *data) {
Client *c = wl_container_of(listener, c, associate); Client *c = wl_container_of(listener, c, associate);
LISTEN(&client_surface(c)->events.map, &c->map, mapnotify); LISTEN(&client_surface(c)->events.map, &c->map, mapnotify);
LISTEN(&client_surface(c)->events.unmap, &c->unmap, unmapnotify); LISTEN(&client_surface(c)->events.unmap, &c->unmap, unmapnotify);
LISTEN(&client_surface(c)->events.commit, &c->commmitx11, commitx11);
} }
void dissociatex11(struct wl_listener *listener, void *data) { void dissociatex11(struct wl_listener *listener, void *data) {
Client *c = wl_container_of(listener, c, dissociate); Client *c = wl_container_of(listener, c, dissociate);
wl_list_remove(&c->map.link); wl_list_remove(&c->map.link);
wl_list_remove(&c->unmap.link); wl_list_remove(&c->unmap.link);
wl_list_remove(&c->commmitx11.link);
} }
void sethints(struct wl_listener *listener, void *data) { void sethints(struct wl_listener *listener, void *data) {
@ -6145,6 +6337,10 @@ void xwaylandready(struct wl_listener *listener, void *data) {
xwayland, xcursor->images[0]->buffer, xcursor->images[0]->width * 4, xwayland, xcursor->images[0]->buffer, xcursor->images[0]->width * 4,
xcursor->images[0]->width, xcursor->images[0]->height, xcursor->images[0]->width, xcursor->images[0]->height,
xcursor->images[0]->hotspot_x, xcursor->images[0]->hotspot_y); xcursor->images[0]->hotspot_x, xcursor->images[0]->hotspot_y);
/* xwayland can't auto sync the keymap, so we do it manually
and we need to wait the xwayland completely inited
*/
wl_event_source_timer_update(sync_keymap, 500);
} }
static void setgeometrynotify(struct wl_listener *listener, void *data) { static void setgeometrynotify(struct wl_listener *listener, void *data) {
@ -6160,17 +6356,21 @@ int32_t main(int32_t argc, char *argv[]) {
char *startup_cmd = NULL; char *startup_cmd = NULL;
int32_t c; int32_t c;
while ((c = getopt(argc, argv, "s:c:hdv")) != -1) { while ((c = getopt(argc, argv, "s:c:hdvp")) != -1) {
if (c == 's') if (c == 's') {
startup_cmd = optarg; startup_cmd = optarg;
else if (c == 'd') } else if (c == 'd') {
log_level = WLR_DEBUG; log_level = WLR_DEBUG;
else if (c == 'v') } else if (c == 'v') {
die("mango " VERSION); printf("mango " VERSION "\n");
else if (c == 'c') return EXIT_SUCCESS;
} else if (c == 'c') {
cli_config_path = optarg; cli_config_path = optarg;
else } else if (c == 'p') {
return parse_config() ? EXIT_SUCCESS : EXIT_FAILURE;
} else {
goto usage; goto usage;
}
} }
if (optind < argc) if (optind < argc)
goto usage; goto usage;
@ -6184,7 +6384,14 @@ int32_t main(int32_t argc, char *argv[]) {
run(startup_cmd); run(startup_cmd);
cleanup(); cleanup();
return EXIT_SUCCESS; return EXIT_SUCCESS;
usage: usage:
die("Usage: %s [-v] [-d] [-c config file] [-s startup command]", argv[0]); printf("Usage: mango [OPTIONS]\n"
"\n"
"Options:\n"
" -v Show mango version\n"
" -d Enable debug log\n"
" -c <file> Use custom configuration file\n"
" -s <command> Execute startup command\n"
" -p Check configuration file error\n");
return EXIT_SUCCESS;
} }