Merge remote-tracking branch 'origin/main' into tablet-test

This commit is contained in:
DreamMaoMao 2025-09-26 14:45:26 +08:00
commit 4e8af666e8
17 changed files with 540 additions and 314 deletions

View file

@ -18,14 +18,14 @@ This project's development is based on [dwl](https://codeberg.org/dwl/dwl/).
- Excellent input method support (text input v2/v3) - Excellent input method support (text input v2/v3)
- Flexible window layouts with easy switching (scroller, master, monocle, spiral, etc.) - Flexible window layouts with easy switching (scroller, master, monocle, spiral, etc.)
- Rich window states (swallow, minimize, maximize, unglobal, global, fakefullscreen, overlay, etc.) - Rich window states (swallow, minimize, maximize, unglobal, global, fakefullscreen, overlay, etc.)
- Simple yet powerful external configuration - Simple yet powerful external configuration(support shortcuts hot-reload)
- Sway-like scratchpad and named scratchpad - Sway-like scratchpad and named scratchpad
- 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)
3. **Some disadvantages** 3. **Some disadvantages**
- Since it uses the fully automatic layout like dwm style, it does not allow you to manually adjust the window size when the window is in tiled state. It only allows you to change the layout parameters to adjust the window ratio. - Since it uses the fully automatic layout like dwm style, it does not allow you to manually adjust the window size when the window is in tiled state. It only allows you to use dispatch like `setmfact` or `increase_proportion` bind to adjust the tiled window ratio.
Master-Stack Layout Master-Stack Layout
@ -107,13 +107,10 @@ Finally, install the package:
emerge --ask --verbose gui-wm/mangowc emerge --ask --verbose gui-wm/mangowc
``` ```
Patching wlroots is done by getting the patch with git from [the repository](https://github.com/DreamMaoMao/wlroots.git)
and then copying it to `/etc/portage/patches/gui-libs/wlroots/`.
## Other ## Other
```bash ```bash
git clone -b 0.19.0 https://gitlab.freedesktop.org/wlroots/wlroots.git git clone -b 0.19.1 https://gitlab.freedesktop.org/wlroots/wlroots.git
cd wlroots cd wlroots
meson build -Dprefix=/usr meson build -Dprefix=/usr
sudo ninja -C build install sudo ninja -C build install
@ -245,13 +242,11 @@ Here's an example of using the modules in a flake:
To package mango for other distributions, you can check the reference setup for: To package mango for other distributions, you can check the reference setup for:
- [nix](https://github.com/DreamMaoMao/mango/blob/main/nix/default.nix) - [nix](https://github.com/DreamMaoMao/mangowc/blob/main/nix/default.nix)
- [arch](https://aur.archlinux.org/cgit/aur.git/tree/PKGBUILD?h=mango-git). - [arch](https://aur.archlinux.org/cgit/aur.git/tree/PKGBUILD?h=mangowc-git).
- [gentoo](https://data.gpo.zugaina.org/guru/gui-wm/mangowc) - [gentoo](https://data.gpo.zugaina.org/guru/gui-wm/mangowc)
Currently building mango requires a patched version of `wlroots-0.19`. If possible, the patch can be extracted from the [latest commit](https://github.com/DreamMaoMao/wlroots.git) You might need to package `scenefx` for your distribution, check availability [here](https://github.com/wlrfx/scenefx.git).
and applied on `prepare` step. If it is not possible, you will need to create a separate `wlroots` package and make it a build dependency.
You might also need to package `scenefx` for your distribution, check availability [here](https://github.com/wlrfx/scenefx.git).
If you encounter build errors when packaging `mango`, feel free to create an issue and ask a question, but If you encounter build errors when packaging `mango`, feel free to create an issue and ask a question, but
Read The Friendly Manual on packaging software in your distribution first. Read The Friendly Manual on packaging software in your distribution first.

View file

@ -28,7 +28,7 @@ unfocused_opacity=1.0
# Animation Configuration(support type:zoom,slide) # Animation Configuration(support type:zoom,slide)
# tag_animation_direction: 0-horizontal,1-vertical # tag_animation_direction: 0-horizontal,1-vertical
animations=1 animations=1
layer_animations=0 layer_animations=1
animation_type_open=slide animation_type_open=slide
animation_type_close=slide animation_type_close=slide
animation_fade_in=1 animation_fade_in=1
@ -183,35 +183,35 @@ bind=ALT,x,switch_proportion_preset,
bind=SUPER,n,switch_layout bind=SUPER,n,switch_layout
# tag switch # tag switch
bind=SUPER,Left,viewtoleft, bind=SUPER,Left,viewtoleft,0
bind=CTRL,Left,viewtoleft_have_client, bind=CTRL,Left,viewtoleft_have_client,0
bind=SUPER,Right,viewtoright, bind=SUPER,Right,viewtoright,0
bind=CTRL,Right,viewtoright_have_client, bind=CTRL,Right,viewtoright_have_client,0
bind=CTRL+SUPER,Left,tagtoleft, bind=CTRL+SUPER,Left,tagtoleft,0
bind=CTRL+SUPER,Right,tagtoright, bind=CTRL+SUPER,Right,tagtoright,0
bind=Ctrl,1,view,1 bind=Ctrl,1,view,1,0
bind=Ctrl,2,view,2 bind=Ctrl,2,view,2,0
bind=Ctrl,3,view,3 bind=Ctrl,3,view,3,0
bind=Ctrl,4,view,4 bind=Ctrl,4,view,4,0
bind=Ctrl,5,view,5 bind=Ctrl,5,view,5,0
bind=Ctrl,6,view,6 bind=Ctrl,6,view,6,0
bind=Ctrl,7,view,7 bind=Ctrl,7,view,7,0
bind=Ctrl,8,view,8 bind=Ctrl,8,view,8,0
bind=Ctrl,9,view,9 bind=Ctrl,9,view,9,0
# tag: move client to the tag and focus it # tag: move client to the tag and focus it
# tagsilent: move client to the tag and not focus it # tagsilent: move client to the tag and not focus it
# bind=Alt,1,tagsilent,1 # bind=Alt,1,tagsilent,1
bind=Alt,1,tag,1 bind=Alt,1,tag,1,0
bind=Alt,2,tag,2 bind=Alt,2,tag,2,0
bind=Alt,3,tag,3 bind=Alt,3,tag,3,0
bind=Alt,4,tag,4 bind=Alt,4,tag,4,0
bind=Alt,5,tag,5 bind=Alt,5,tag,5,0
bind=Alt,6,tag,6 bind=Alt,6,tag,6,0
bind=Alt,7,tag,7 bind=Alt,7,tag,7,0
bind=Alt,8,tag,8 bind=Alt,8,tag,8,0
bind=Alt,9,tag,9 bind=Alt,9,tag,9,0
# monitor switch # monitor switch
bind=alt+shift,Left,focusmon,left bind=alt+shift,Left,focusmon,left
@ -224,6 +224,17 @@ bind=ALT+SHIFT,X,incgaps,1
bind=ALT+SHIFT,Z,incgaps,-1 bind=ALT+SHIFT,Z,incgaps,-1
bind=ALT+SHIFT,R,togglegaps bind=ALT+SHIFT,R,togglegaps
# adjust tile window size
# change master fact for tile,spiral,deck,dwindle
bind=ALT+SUPER,h,setmfact,-0.05
bind=ALT+SUPER,l,setmfact,+0.05
# change sub master fact for dwindle,spiral
bind=ALT+SUPER,k,setsmfact,-0.05
bind=ALT+SUPER,j,setsmfact,+0.05
# change scroller proportion
bind=ctrl+super,j,increase_proportion,0.1
bind=ctrl+super,k,increase_proportion,-0.1
# movewin # movewin
bind=CTRL+SHIFT,Up,movewin,+0,-50 bind=CTRL+SHIFT,Up,movewin,+0,-50
bind=CTRL+SHIFT,Down,movewin,+0,+50 bind=CTRL+SHIFT,Down,movewin,+0,+50
@ -247,3 +258,8 @@ mousebind=NONE,btn_right,killclient,0
# Axis Bindings # Axis Bindings
axisbind=SUPER,UP,viewtoleft_have_client axisbind=SUPER,UP,viewtoleft_have_client
axisbind=SUPER,DOWN,viewtoright_have_client axisbind=SUPER,DOWN,viewtoright_have_client
# layer rule
layerrule=animation_type_open:zoom,layer_name:rofi
layerrule=animation_type_close:zoom,layer_name:rofi

View file

@ -1,5 +1,5 @@
project('mango', ['c', 'cpp'], project('mango', ['c', 'cpp'],
version : '0.8.6', version : '0.8.9',
) )
subdir('protocols') subdir('protocols')

View file

@ -1,6 +1,5 @@
{ {
lib, lib,
fetchFromGitHub,
libX11, libX11,
libinput, libinput,
libxcb, libxcb,
@ -23,17 +22,6 @@
libGL, libGL,
}: let }: let
pname = "mango"; pname = "mango";
# Use patched wlroots from github.com/DreamMaoMao/wlroots
wlroots-git = wlroots_0_19.overrideAttrs (
final: prev: {
src = fetchFromGitHub {
owner = "DreamMaoMao";
repo = "wlroots";
rev = "afbb5b7c2b14152730b57aa11119b1b16a299d5b";
sha256 = "sha256-pVU+CuiqvduMTpsnDHX/+EWY2qxHX2lXKiVzdGtcnYY=";
};
}
);
in in
stdenv.mkDerivation { stdenv.mkDerivation {
inherit pname; inherit pname;
@ -60,7 +48,7 @@ in
pixman pixman
wayland wayland
wayland-protocols wayland-protocols
wlroots-git wlroots_0_19
scenefx scenefx
libGL libGL
] ]
@ -83,4 +71,4 @@ in
maintainers = []; maintainers = [];
platforms = lib.platforms.unix; platforms = lib.platforms.unix;
}; };
} }

View file

@ -30,13 +30,6 @@ enum corner_location set_client_corner_location(Client *c) {
bool is_horizontal_stack_layout(Monitor *m) { bool is_horizontal_stack_layout(Monitor *m) {
if (!m->pertag->curtag &&
(strcmp(m->pertag->ltidxs[m->pertag->prevtag]->name, "tile") == 0 ||
strcmp(m->pertag->ltidxs[m->pertag->prevtag]->name, "spiral") == 0 ||
strcmp(m->pertag->ltidxs[m->pertag->prevtag]->name, "dwindle") == 0 ||
strcmp(m->pertag->ltidxs[m->pertag->prevtag]->name, "deck") == 0))
return true;
if (m->pertag->curtag && if (m->pertag->curtag &&
(strcmp(m->pertag->ltidxs[m->pertag->curtag]->name, "tile") == 0 || (strcmp(m->pertag->ltidxs[m->pertag->curtag]->name, "tile") == 0 ||
strcmp(m->pertag->ltidxs[m->pertag->curtag]->name, "spiral") == 0 || strcmp(m->pertag->ltidxs[m->pertag->curtag]->name, "spiral") == 0 ||
@ -899,6 +892,11 @@ void client_set_pending_state(Client *c) {
c->animation.duration = 0; c->animation.duration = 0;
} }
if (c->istagswitching) {
c->animation.duration = 0;
c->istagswitching = 0;
}
// 开始动画 // 开始动画
client_commit(c); client_commit(c);
c->dirty = true; c->dirty = true;
@ -1014,6 +1012,10 @@ void resize(Client *c, struct wlr_box geo, int interact) {
c->animainit_geom = c->geom; c->animainit_geom = c->geom;
} }
if (c->scratchpad_switching_mon) {
c->animainit_geom = c->geom;
}
// 开始应用动画设置 // 开始应用动画设置
client_set_pending_state(c); client_set_pending_state(c);

85
src/animation/tag.h Normal file
View file

@ -0,0 +1,85 @@
void set_tagin_animation(Monitor *m, Client *c) {
if (c->animation.running) {
c->animainit_geom.x = c->animation.current.x;
c->animainit_geom.y = c->animation.current.y;
return;
}
if (m->pertag->curtag > m->pertag->prevtag) {
c->animainit_geom.x = tag_animation_direction == VERTICAL
? c->animation.current.x
: c->mon->m.x + c->mon->m.width;
c->animainit_geom.y = tag_animation_direction == VERTICAL
? c->mon->m.y + c->mon->m.height
: c->animation.current.y;
} else {
c->animainit_geom.x = tag_animation_direction == VERTICAL
? c->animation.current.x
: m->m.x - c->geom.width;
c->animainit_geom.y = tag_animation_direction == VERTICAL
? m->m.y - c->geom.height
: c->animation.current.y;
}
}
void set_arrange_visible(Monitor *m, Client *c, bool want_animation) {
if (!c->is_clip_to_hide || !ISTILED(c) || !is_scroller_layout(c->mon)) {
c->is_clip_to_hide = false;
wlr_scene_node_set_enabled(&c->scene->node, true);
wlr_scene_node_set_enabled(&c->scene_surface->node, true);
}
client_set_suspended(c, false);
if (!c->animation.tag_from_rule && want_animation &&
m->pertag->prevtag != 0 && m->pertag->curtag != 0 && animations) {
c->animation.tagining = true;
set_tagin_animation(m, c);
} else {
c->animainit_geom.x = c->animation.current.x;
c->animainit_geom.y = c->animation.current.y;
}
c->animation.tag_from_rule = false;
c->animation.tagouting = false;
c->animation.tagouted = false;
resize(c, c->geom, 0);
}
void set_tagout_animation(Monitor *m, Client *c) {
if (m->pertag->curtag > m->pertag->prevtag) {
c->pending = c->geom;
c->pending.x = tag_animation_direction == VERTICAL
? c->animation.current.x
: c->mon->m.x - c->geom.width;
c->pending.y = tag_animation_direction == VERTICAL
? c->mon->m.y - c->geom.height
: c->animation.current.y;
resize(c, c->geom, 0);
} else {
c->pending = c->geom;
c->pending.x = tag_animation_direction == VERTICAL
? c->animation.current.x
: c->mon->m.x + c->mon->m.width;
c->pending.y = tag_animation_direction == VERTICAL
? c->mon->m.y + c->mon->m.height
: c->animation.current.y;
resize(c, c->geom, 0);
}
}
void set_arrange_hidden(Monitor *m, Client *c, bool want_animation) {
if ((c->tags & (1 << (m->pertag->prevtag - 1))) &&
m->pertag->prevtag != 0 && m->pertag->curtag != 0 && animations) {
c->animation.tagouting = true;
c->animation.tagining = false;
set_tagout_animation(m, c);
} else {
wlr_scene_node_set_enabled(&c->scene->node, false);
client_set_suspended(c, true);
}
}

View file

@ -132,6 +132,7 @@ typedef struct {
char *layout_name; // 布局名称 char *layout_name; // 布局名称
char *monitor_name; char *monitor_name;
int no_render_border; int no_render_border;
int no_hide;
} ConfigTagRule; } ConfigTagRule;
typedef struct { typedef struct {
@ -173,7 +174,10 @@ typedef struct {
int scroller_prefer_center; int scroller_prefer_center;
int edge_scroller_pointer_focus; int edge_scroller_pointer_focus;
int focus_cross_monitor; int focus_cross_monitor;
int exchange_cross_monitor;
int scratchpad_cross_monitor;
int focus_cross_tag; int focus_cross_tag;
int view_current_to_back;
int no_border_when_single; int no_border_when_single;
int no_radius_when_single; int no_radius_when_single;
int snap_distance; int snap_distance;
@ -301,6 +305,7 @@ typedef struct {
int single_scratchpad; int single_scratchpad;
int xwayland_persistence; int xwayland_persistence;
int syncobj_enable; int syncobj_enable;
int adaptive_sync;
struct xkb_rule_names xkb_rules; struct xkb_rule_names xkb_rules;
} Config; } Config;
@ -724,15 +729,19 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value,
func = switch_proportion_preset; func = switch_proportion_preset;
} else if (strcmp(func_name, "viewtoleft") == 0) { } else if (strcmp(func_name, "viewtoleft") == 0) {
func = viewtoleft; func = viewtoleft;
(*arg).i = atoi(arg_value);
} else if (strcmp(func_name, "viewtoright") == 0) { } else if (strcmp(func_name, "viewtoright") == 0) {
func = viewtoright; func = viewtoright;
(*arg).i = atoi(arg_value);
} else if (strcmp(func_name, "tagsilent") == 0) { } else if (strcmp(func_name, "tagsilent") == 0) {
func = tagsilent; func = tagsilent;
(*arg).ui = 1 << (atoi(arg_value) - 1); (*arg).ui = 1 << (atoi(arg_value) - 1);
} else if (strcmp(func_name, "tagtoleft") == 0) { } else if (strcmp(func_name, "tagtoleft") == 0) {
func = tagtoleft; func = tagtoleft;
(*arg).i = atoi(arg_value);
} else if (strcmp(func_name, "tagtoright") == 0) { } else if (strcmp(func_name, "tagtoright") == 0) {
func = tagtoright; func = tagtoright;
(*arg).i = atoi(arg_value);
} else if (strcmp(func_name, "killclient") == 0) { } else if (strcmp(func_name, "killclient") == 0) {
func = killclient; func = killclient;
} else if (strcmp(func_name, "centerwin") == 0) { } else if (strcmp(func_name, "centerwin") == 0) {
@ -808,22 +817,29 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value,
func = togglemaxmizescreen; func = togglemaxmizescreen;
} else if (strcmp(func_name, "viewtoleft_have_client") == 0) { } else if (strcmp(func_name, "viewtoleft_have_client") == 0) {
func = viewtoleft_have_client; func = viewtoleft_have_client;
(*arg).i = atoi(arg_value);
} else if (strcmp(func_name, "viewtoright_have_client") == 0) { } else if (strcmp(func_name, "viewtoright_have_client") == 0) {
func = viewtoright_have_client; func = viewtoright_have_client;
(*arg).i = atoi(arg_value);
} else if (strcmp(func_name, "reload_config") == 0) { } else if (strcmp(func_name, "reload_config") == 0) {
func = reload_config; func = reload_config;
} else if (strcmp(func_name, "tag") == 0) { } else if (strcmp(func_name, "tag") == 0) {
func = tag; func = tag;
(*arg).ui = 1 << (atoi(arg_value) - 1); (*arg).ui = 1 << (atoi(arg_value) - 1);
(*arg).i = atoi(arg_value2);
} else if (strcmp(func_name, "view") == 0) { } else if (strcmp(func_name, "view") == 0) {
func = bind_to_view; func = bind_to_view;
(*arg).ui = 1 << (atoi(arg_value) - 1); (*arg).ui = 1 << (atoi(arg_value) - 1);
(*arg).i = atoi(arg_value2);
} else if (strcmp(func_name, "toggletag") == 0) { } else if (strcmp(func_name, "toggletag") == 0) {
func = toggletag; func = toggletag;
(*arg).ui = 1 << (atoi(arg_value) - 1); (*arg).ui = 1 << (atoi(arg_value) - 1);
} else if (strcmp(func_name, "toggleview") == 0) { } else if (strcmp(func_name, "toggleview") == 0) {
func = toggleview; func = toggleview;
(*arg).ui = 1 << (atoi(arg_value) - 1); (*arg).ui = 1 << (atoi(arg_value) - 1);
} else if (strcmp(func_name, "comboview") == 0) {
func = comboview;
(*arg).ui = 1 << (atoi(arg_value) - 1);
} else if (strcmp(func_name, "smartmovewin") == 0) { } else if (strcmp(func_name, "smartmovewin") == 0) {
func = smartmovewin; func = smartmovewin;
(*arg).i = parse_direction(arg_value); (*arg).i = parse_direction(arg_value);
@ -967,10 +983,14 @@ void parse_config_line(Config *config, const char *line) {
config->edge_scroller_pointer_focus = atoi(value); config->edge_scroller_pointer_focus = atoi(value);
} else if (strcmp(key, "focus_cross_monitor") == 0) { } else if (strcmp(key, "focus_cross_monitor") == 0) {
config->focus_cross_monitor = atoi(value); config->focus_cross_monitor = atoi(value);
} else if (strcmp(key, "exchange_cross_monitor") == 0) {
config->exchange_cross_monitor = atoi(value);
} else if (strcmp(key, "scratchpad_cross_monitor") == 0) {
config->scratchpad_cross_monitor = atoi(value);
} else if (strcmp(key, "focus_cross_tag") == 0) { } else if (strcmp(key, "focus_cross_tag") == 0) {
config->focus_cross_tag = atoi(value); config->focus_cross_tag = atoi(value);
} else if (strcmp(key, "focus_cross_tag") == 0) { } else if (strcmp(key, "view_current_to_back") == 0) {
config->focus_cross_tag = atoi(value); config->view_current_to_back = atoi(value);
} else if (strcmp(key, "blur") == 0) { } else if (strcmp(key, "blur") == 0) {
config->blur = atoi(value); config->blur = atoi(value);
} else if (strcmp(key, "blur_layer") == 0) { } else if (strcmp(key, "blur_layer") == 0) {
@ -1011,6 +1031,8 @@ void parse_config_line(Config *config, const char *line) {
config->xwayland_persistence = atoi(value); config->xwayland_persistence = atoi(value);
} else if (strcmp(key, "syncobj_enable") == 0) { } else if (strcmp(key, "syncobj_enable") == 0) {
config->syncobj_enable = atoi(value); config->syncobj_enable = atoi(value);
} else if (strcmp(key, "adaptive_sync") == 0) {
config->adaptive_sync = atoi(value);
} else if (strcmp(key, "no_border_when_single") == 0) { } else if (strcmp(key, "no_border_when_single") == 0) {
config->no_border_when_single = atoi(value); config->no_border_when_single = atoi(value);
} else if (strcmp(key, "no_radius_when_single") == 0) { } else if (strcmp(key, "no_radius_when_single") == 0) {
@ -1359,13 +1381,15 @@ void parse_config_line(Config *config, const char *line) {
trim_whitespace(val); trim_whitespace(val);
if (strcmp(key, "id") == 0) { if (strcmp(key, "id") == 0) {
rule->id = CLAMP_INT(atoi(val), 1, LENGTH(tags)); rule->id = CLAMP_INT(atoi(val), 0, LENGTH(tags));
} else if (strcmp(key, "layout_name") == 0) { } else if (strcmp(key, "layout_name") == 0) {
rule->layout_name = strdup(val); rule->layout_name = strdup(val);
} else if (strcmp(key, "monitor_name") == 0) { } else if (strcmp(key, "monitor_name") == 0) {
rule->monitor_name = strdup(val); rule->monitor_name = strdup(val);
} else if (strcmp(key, "no_render_border") == 0) { } else if (strcmp(key, "no_render_border") == 0) {
rule->no_render_border = CLAMP_INT(atoi(val), 0, 1); rule->no_render_border = CLAMP_INT(atoi(val), 0, 1);
} else if (strcmp(key, "no_hide") == 0) {
rule->no_hide = CLAMP_INT(atoi(val), 0, 1);
} }
} }
token = strtok(NULL, ","); token = strtok(NULL, ",");
@ -1695,9 +1719,9 @@ void parse_config_line(Config *config, const char *line) {
memset(binding, 0, sizeof(KeyBinding)); memset(binding, 0, sizeof(KeyBinding));
char mod_str[256], keysym_str[256], func_name[256], char mod_str[256], keysym_str[256], func_name[256],
arg_value[256] = "none", arg_value2[256] = "none", arg_value[256] = "0\0", arg_value2[256] = "0\0",
arg_value3[256] = "none", arg_value4[256] = "none", arg_value3[256] = "0\0", arg_value4[256] = "0\0",
arg_value5[256] = "none"; arg_value5[256] = "0\0";
if (sscanf(value, "%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^\n]", if (sscanf(value, "%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^\n]",
mod_str, keysym_str, func_name, arg_value, arg_value2, mod_str, keysym_str, func_name, arg_value, arg_value2,
arg_value3, arg_value4, arg_value5) < 3) { arg_value3, arg_value4, arg_value5) < 3) {
@ -1754,9 +1778,9 @@ void parse_config_line(Config *config, const char *line) {
memset(binding, 0, sizeof(MouseBinding)); memset(binding, 0, sizeof(MouseBinding));
char mod_str[256], button_str[256], func_name[256], char mod_str[256], button_str[256], func_name[256],
arg_value[256] = "none", arg_value2[256] = "none", arg_value[256] = "0\0", arg_value2[256] = "0\0",
arg_value3[256] = "none", arg_value4[256] = "none", arg_value3[256] = "0\0", arg_value4[256] = "0\0",
arg_value5[256] = "none"; arg_value5[256] = "0\0";
if (sscanf(value, "%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^\n]", if (sscanf(value, "%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^\n]",
mod_str, button_str, func_name, arg_value, arg_value2, mod_str, button_str, func_name, arg_value, arg_value2,
arg_value3, arg_value4, arg_value5) < 3) { arg_value3, arg_value4, arg_value5) < 3) {
@ -1813,9 +1837,9 @@ void parse_config_line(Config *config, const char *line) {
memset(binding, 0, sizeof(AxisBinding)); memset(binding, 0, sizeof(AxisBinding));
char mod_str[256], dir_str[256], func_name[256], char mod_str[256], dir_str[256], func_name[256],
arg_value[256] = "none", arg_value2[256] = "none", arg_value[256] = "0\0", arg_value2[256] = "0\0",
arg_value3[256] = "none", arg_value4[256] = "none", arg_value3[256] = "0\0", arg_value4[256] = "0\0",
arg_value5[256] = "none"; arg_value5[256] = "0\0";
if (sscanf(value, "%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^\n]", if (sscanf(value, "%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^\n]",
mod_str, dir_str, func_name, arg_value, arg_value2, mod_str, dir_str, func_name, arg_value, arg_value2,
arg_value3, arg_value4, arg_value5) < 3) { arg_value3, arg_value4, arg_value5) < 3) {
@ -1875,9 +1899,9 @@ void parse_config_line(Config *config, const char *line) {
memset(binding, 0, sizeof(SwitchBinding)); memset(binding, 0, sizeof(SwitchBinding));
char fold_str[256], func_name[256], char fold_str[256], func_name[256],
arg_value[256] = "none", arg_value2[256] = "none", arg_value[256] = "0\0", arg_value2[256] = "0\0",
arg_value3[256] = "none", arg_value4[256] = "none", arg_value3[256] = "0\0", arg_value4[256] = "0\0",
arg_value5[256] = "none"; arg_value5[256] = "0\0";
if (sscanf(value, "%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^\n]", if (sscanf(value, "%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^\n]",
fold_str, func_name, arg_value, arg_value2, arg_value3, fold_str, func_name, arg_value, arg_value2, arg_value3,
arg_value4, arg_value5) < 3) { arg_value4, arg_value5) < 3) {
@ -1931,9 +1955,9 @@ void parse_config_line(Config *config, const char *line) {
memset(binding, 0, sizeof(GestureBinding)); memset(binding, 0, sizeof(GestureBinding));
char mod_str[256], motion_str[256], fingers_count_str[256], char mod_str[256], motion_str[256], fingers_count_str[256],
func_name[256], arg_value[256] = "none", arg_value2[256] = "none", func_name[256], arg_value[256] = "0\0", arg_value2[256] = "0\0",
arg_value3[256] = "none", arg_value4[256] = "none", arg_value3[256] = "0\0", arg_value4[256] = "0\0",
arg_value5[256] = "none"; arg_value5[256] = "0\0";
if (sscanf(value, if (sscanf(value,
"%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^\n]", "%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^,],%[^\n]",
mod_str, motion_str, fingers_count_str, func_name, arg_value, mod_str, motion_str, fingers_count_str, func_name, arg_value,
@ -2338,6 +2362,7 @@ void override_config(void) {
// 杂项设置 // 杂项设置
xwayland_persistence = CLAMP_INT(config.xwayland_persistence, 0, 1); xwayland_persistence = CLAMP_INT(config.xwayland_persistence, 0, 1);
syncobj_enable = CLAMP_INT(config.syncobj_enable, 0, 1); syncobj_enable = CLAMP_INT(config.syncobj_enable, 0, 1);
adaptive_sync = CLAMP_INT(config.adaptive_sync, 0, 1);
axis_bind_apply_timeout = axis_bind_apply_timeout =
CLAMP_INT(config.axis_bind_apply_timeout, 0, 1000); CLAMP_INT(config.axis_bind_apply_timeout, 0, 1000);
focus_on_activate = CLAMP_INT(config.focus_on_activate, 0, 1); focus_on_activate = CLAMP_INT(config.focus_on_activate, 0, 1);
@ -2346,7 +2371,10 @@ void override_config(void) {
sloppyfocus = CLAMP_INT(config.sloppyfocus, 0, 1); sloppyfocus = CLAMP_INT(config.sloppyfocus, 0, 1);
warpcursor = CLAMP_INT(config.warpcursor, 0, 1); warpcursor = CLAMP_INT(config.warpcursor, 0, 1);
focus_cross_monitor = CLAMP_INT(config.focus_cross_monitor, 0, 1); focus_cross_monitor = CLAMP_INT(config.focus_cross_monitor, 0, 1);
exchange_cross_monitor = CLAMP_INT(config.exchange_cross_monitor, 0, 1);
scratchpad_cross_monitor = CLAMP_INT(config.scratchpad_cross_monitor, 0, 1);
focus_cross_tag = CLAMP_INT(config.focus_cross_tag, 0, 1); focus_cross_tag = CLAMP_INT(config.focus_cross_tag, 0, 1);
view_current_to_back = CLAMP_INT(config.view_current_to_back, 0, 1);
enable_floating_snap = CLAMP_INT(config.enable_floating_snap, 0, 1); enable_floating_snap = CLAMP_INT(config.enable_floating_snap, 0, 1);
snap_distance = CLAMP_INT(config.snap_distance, 0, 99999); snap_distance = CLAMP_INT(config.snap_distance, 0, 99999);
cursor_size = CLAMP_INT(config.cursor_size, 4, 512); cursor_size = CLAMP_INT(config.cursor_size, 4, 512);
@ -2494,10 +2522,14 @@ void set_value_default() {
config.scroller_prefer_center = scroller_prefer_center; config.scroller_prefer_center = scroller_prefer_center;
config.edge_scroller_pointer_focus = edge_scroller_pointer_focus; config.edge_scroller_pointer_focus = edge_scroller_pointer_focus;
config.focus_cross_monitor = focus_cross_monitor; config.focus_cross_monitor = focus_cross_monitor;
config.exchange_cross_monitor = exchange_cross_monitor;
config.scratchpad_cross_monitor = scratchpad_cross_monitor;
config.focus_cross_tag = focus_cross_tag; config.focus_cross_tag = focus_cross_tag;
config.view_current_to_back = view_current_to_back;
config.single_scratchpad = single_scratchpad; config.single_scratchpad = single_scratchpad;
config.xwayland_persistence = xwayland_persistence; config.xwayland_persistence = xwayland_persistence;
config.syncobj_enable = syncobj_enable; config.syncobj_enable = syncobj_enable;
config.adaptive_sync = adaptive_sync;
config.no_border_when_single = no_border_when_single; config.no_border_when_single = no_border_when_single;
config.no_radius_when_single = no_radius_when_single; config.no_radius_when_single = no_radius_when_single;
config.snap_distance = snap_distance; config.snap_distance = snap_distance;
@ -2734,11 +2766,11 @@ void reapply_monitor_rules(void) {
} }
if (mr->width > 0 && mr->height > 0 && mr->refresh > 0) { if (mr->width > 0 && mr->height > 0 && mr->refresh > 0) {
internal_mode = get_output_mode(m->wlr_output, mr->width, internal_mode = get_nearest_output_mode(
mr->height, mr->refresh); m->wlr_output, mr->width, mr->height, mr->refresh);
if (internal_mode) { if (internal_mode) {
wlr_output_state_set_mode(&state, internal_mode); wlr_output_state_set_mode(&state, internal_mode);
} else { } else if (wlr_output_is_headless(m->wlr_output)) {
wlr_output_state_set_custom_mode( wlr_output_state_set_custom_mode(
&state, mr->width, mr->height, &state, mr->width, mr->height,
(int)roundf(mr->refresh * 1000)); (int)roundf(mr->refresh * 1000));
@ -2752,6 +2784,10 @@ void reapply_monitor_rules(void) {
} }
} }
if (adaptive_sync) {
enable_adaptive_sync(m, &state);
}
wlr_output_commit_state(m->wlr_output, &state); wlr_output_commit_state(m->wlr_output, &state);
wlr_output_state_finish(&state); wlr_output_state_finish(&state);
updatemons(NULL, NULL); updatemons(NULL, NULL);
@ -2836,6 +2872,8 @@ void reapply_tagrule(void) {
config.tag_rules[i - 1].layout_name) == 0) { config.tag_rules[i - 1].layout_name) == 0) {
m->pertag->ltidxs[config.tag_rules[i - 1].id] = m->pertag->ltidxs[config.tag_rules[i - 1].id] =
&layouts[jk]; &layouts[jk];
m->pertag->no_hide[config.tag_rules[i - 1].id] =
config.tag_rules[i - 1].no_hide;
} }
} }
} }

View file

@ -61,6 +61,9 @@ int scroller_focus_center = 0;
int scroller_prefer_center = 0; int scroller_prefer_center = 0;
int focus_cross_monitor = 0; int focus_cross_monitor = 0;
int focus_cross_tag = 0; int focus_cross_tag = 0;
int exchange_cross_monitor = 0;
int scratchpad_cross_monitor = 0;
int view_current_to_back = 1;
int no_border_when_single = 0; int no_border_when_single = 0;
int no_radius_when_single = 0; int no_radius_when_single = 0;
int snap_distance = 30; int snap_distance = 30;
@ -95,6 +98,7 @@ float fullscreen_bg[] = {0.1, 0.1, 0.1, 1.0};
int warpcursor = 1; /* Warp cursor to focused client */ int warpcursor = 1; /* Warp cursor to focused client */
int xwayland_persistence = 1; /* xwayland persistence */ int xwayland_persistence = 1; /* xwayland persistence */
int syncobj_enable = 0; int syncobj_enable = 0;
int adaptive_sync = 0;
/* keyboard */ /* keyboard */

View file

@ -44,6 +44,7 @@ void bind_to_view(const Arg *arg);
void toggletag(const Arg *arg); void toggletag(const Arg *arg);
void toggleview(const Arg *arg); void toggleview(const Arg *arg);
void tag(const Arg *arg); void tag(const Arg *arg);
void comboview(const Arg *arg);
void incgaps(const Arg *arg); void incgaps(const Arg *arg);
void incigaps(const Arg *arg); void incigaps(const Arg *arg);
void incihgaps(const Arg *arg); void incihgaps(const Arg *arg);

View file

@ -2,7 +2,7 @@ void bind_to_view(const Arg *arg) {
unsigned int target = arg->ui; unsigned int target = arg->ui;
if (selmon->pertag->curtag && if (view_current_to_back && selmon->pertag->curtag &&
(target & TAGMASK) == (selmon->tagset[selmon->seltags])) { (target & TAGMASK) == (selmon->tagset[selmon->seltags])) {
if (selmon->pertag->prevtag) if (selmon->pertag->prevtag)
target = 1 << (selmon->pertag->prevtag - 1); target = 1 << (selmon->pertag->prevtag - 1);
@ -11,16 +11,16 @@ void bind_to_view(const Arg *arg) {
} }
if ((int)target == INT_MIN && selmon->pertag->curtag == 0) { if ((int)target == INT_MIN && selmon->pertag->curtag == 0) {
if (selmon->pertag->prevtag) if (view_current_to_back && selmon->pertag->prevtag)
target = 1 << (selmon->pertag->prevtag - 1); target = 1 << (selmon->pertag->prevtag - 1);
else else
target = 0; target = 0;
} }
if (target == 0 || (int)target == INT_MIN) { if (target == 0 || (int)target == INT_MIN) {
view(&(Arg){.ui = ~0 & TAGMASK}, false); view(&(Arg){.ui = ~0 & TAGMASK, .i = arg->i}, false);
} else { } else {
view(&(Arg){.ui = target}, true); view(&(Arg){.ui = target, .i = arg->i}, true);
} }
} }
@ -86,6 +86,8 @@ void focusdir(const Arg *arg) {
viewtoleft_have_client(NULL); viewtoleft_have_client(NULL);
if (arg->i == RIGHT || arg->i == DOWN) if (arg->i == RIGHT || arg->i == DOWN)
viewtoright_have_client(NULL); viewtoright_have_client(NULL);
} else if (config.focus_cross_monitor) {
focusmon(arg);
} }
} }
} }
@ -129,7 +131,7 @@ void toggle_trackpad_enable(const Arg *arg) {
} }
void focusmon(const Arg *arg) { void focusmon(const Arg *arg) {
Client *c; Client *c, *old_selmon_sel;
Monitor *m = NULL; Monitor *m = NULL;
if (arg->i != UNDIR) { if (arg->i != UNDIR) {
@ -150,6 +152,7 @@ void focusmon(const Arg *arg) {
if (!m || !m->wlr_output->enabled) if (!m || !m->wlr_output->enabled)
return; return;
old_selmon_sel = selmon->sel;
selmon = m; selmon = m;
warp_cursor_to_selmon(selmon); warp_cursor_to_selmon(selmon);
c = focustop(selmon); c = focustop(selmon);
@ -159,6 +162,10 @@ void focusmon(const Arg *arg) {
wlr_seat_keyboard_notify_clear_focus(seat); wlr_seat_keyboard_notify_clear_focus(seat);
} else } else
focusclient(c, 1); focusclient(c, 1);
if (old_selmon_sel) {
setborder_color(old_selmon_sel);
}
} }
void // 17 void // 17
@ -392,6 +399,10 @@ void resizewin(const Arg *arg) {
void restore_minimized(const Arg *arg) { void restore_minimized(const Arg *arg) {
Client *c; Client *c;
if (selmon && selmon->isoverview)
return;
if (selmon && selmon->sel && selmon->sel->is_in_scratchpad && if (selmon && selmon->sel && selmon->sel->is_in_scratchpad &&
selmon->sel->is_scratchpad_show) { selmon->sel->is_scratchpad_show) {
selmon->sel->isminied = 0; selmon->sel->isminied = 0;
@ -410,6 +421,8 @@ void restore_minimized(const Arg *arg) {
c->isnamedscratchpad = 0; c->isnamedscratchpad = 0;
setborder_color(c); setborder_color(c);
arrange(c->mon, false); arrange(c->mon, false);
focusclient(c, 0);
warp_cursor(c);
return; return;
} }
} }
@ -418,6 +431,7 @@ void restore_minimized(const Arg *arg) {
void // 17 void // 17
setlayout(const Arg *arg) { setlayout(const Arg *arg) {
int jk; int jk;
for (jk = 0; jk < LENGTH(layouts); jk++) { for (jk = 0; jk < LENGTH(layouts); jk++) {
if (strcmp(layouts[jk].name, arg->v) == 0) { if (strcmp(layouts[jk].name, arg->v) == 0) {
selmon->pertag->ltidxs[selmon->pertag->curtag] = &layouts[jk]; selmon->pertag->ltidxs[selmon->pertag->curtag] = &layouts[jk];
@ -846,6 +860,7 @@ void switch_layout(const Arg *arg) {
len = MAX(strlen(layouts[ji].name), strlen(target_layout_name)); len = MAX(strlen(layouts[ji].name), strlen(target_layout_name));
if (strncmp(layouts[ji].name, target_layout_name, len) == 0) { if (strncmp(layouts[ji].name, target_layout_name, len) == 0) {
selmon->pertag->ltidxs[selmon->pertag->curtag] = &layouts[ji]; selmon->pertag->ltidxs[selmon->pertag->curtag] = &layouts[ji];
break; break;
} }
} }
@ -990,7 +1005,7 @@ void tagtoleft(const Arg *arg) {
if (selmon->sel != NULL && if (selmon->sel != NULL &&
__builtin_popcount(selmon->tagset[selmon->seltags] & TAGMASK) == 1 && __builtin_popcount(selmon->tagset[selmon->seltags] & TAGMASK) == 1 &&
selmon->tagset[selmon->seltags] > 1) { selmon->tagset[selmon->seltags] > 1) {
tag(&(Arg){.ui = selmon->tagset[selmon->seltags] >> 1}); tag(&(Arg){.ui = selmon->tagset[selmon->seltags] >> 1, .i = arg->i});
} }
} }
@ -998,7 +1013,7 @@ void tagtoright(const Arg *arg) {
if (selmon->sel != NULL && if (selmon->sel != NULL &&
__builtin_popcount(selmon->tagset[selmon->seltags] & TAGMASK) == 1 && __builtin_popcount(selmon->tagset[selmon->seltags] & TAGMASK) == 1 &&
selmon->tagset[selmon->seltags] & (TAGMASK >> 1)) { selmon->tagset[selmon->seltags] & (TAGMASK >> 1)) {
tag(&(Arg){.ui = selmon->tagset[selmon->seltags] << 1}); tag(&(Arg){.ui = selmon->tagset[selmon->seltags] << 1, .i = arg->i});
} }
} }
@ -1027,8 +1042,12 @@ void toggle_scratchpad(const Arg *arg) {
Client *c; Client *c;
bool hit = false; bool hit = false;
Client *tmp = NULL; Client *tmp = NULL;
if (selmon && selmon->isoverview)
return;
wl_list_for_each_safe(c, tmp, &clients, link) { wl_list_for_each_safe(c, tmp, &clients, link) {
if (c->mon != selmon) { if (!scratchpad_cross_monitor && c->mon != selmon) {
continue; continue;
} }
@ -1055,6 +1074,9 @@ void togglefakefullscreen(const Arg *arg) {
void togglefloating(const Arg *arg) { void togglefloating(const Arg *arg) {
Client *sel = focustop(selmon); Client *sel = focustop(selmon);
if (selmon && selmon->isoverview)
return;
if (!sel) if (!sel)
return; return;
@ -1192,7 +1214,7 @@ void viewtoleft(const Arg *arg) {
if (!selmon || (target) == selmon->tagset[selmon->seltags]) if (!selmon || (target) == selmon->tagset[selmon->seltags])
return; return;
view(&(Arg){.ui = target & TAGMASK}, true); view(&(Arg){.ui = target & TAGMASK, .i = arg->i}, true);
} }
void viewtoright(const Arg *arg) { void viewtoright(const Arg *arg) {
if (selmon->isoverview || selmon->pertag->curtag == 0) { if (selmon->isoverview || selmon->pertag->curtag == 0) {
@ -1207,7 +1229,7 @@ void viewtoright(const Arg *arg) {
return; return;
} }
view(&(Arg){.ui = target & TAGMASK}, true); view(&(Arg){.ui = target & TAGMASK, .i = arg->i}, true);
} }
void viewtoleft_have_client(const Arg *arg) { void viewtoleft_have_client(const Arg *arg) {
@ -1231,7 +1253,7 @@ void viewtoleft_have_client(const Arg *arg) {
} }
if (found) if (found)
view(&(Arg){.ui = (1 << (n - 1)) & TAGMASK}, true); view(&(Arg){.ui = (1 << (n - 1)) & TAGMASK, .i = arg->i}, true);
} }
void viewtoright_have_client(const Arg *arg) { void viewtoright_have_client(const Arg *arg) {
@ -1255,7 +1277,25 @@ void viewtoright_have_client(const Arg *arg) {
} }
if (found) if (found)
view(&(Arg){.ui = (1 << (n - 1)) & TAGMASK}, true); view(&(Arg){.ui = (1 << (n - 1)) & TAGMASK, .i = arg->i}, true);
}
void comboview(const Arg *arg) {
unsigned int newtags = arg->ui & TAGMASK;
unsigned int target_tag = selmon->tagset[selmon->seltags];
if (!newtags || !selmon)
return;
if (tag_combo)
target_tag |= newtags;
else {
tag_combo = true;
target_tag = newtags;
}
view(&(Arg){.ui = target_tag}, false);
printstatus();
} }
void zoom(const Arg *arg) { void zoom(const Arg *arg) {

View file

@ -140,12 +140,10 @@ void dwl_ipc_output_printstatus_to(DwlIpcOutput *ipc_output) {
title = focused ? client_get_title(focused) : ""; title = focused ? client_get_title(focused) : "";
appid = focused ? client_get_appid(focused) : ""; appid = focused ? client_get_appid(focused) : "";
if (monitor->pertag->curtag) { if (monitor->isoverview) {
symbol = monitor->pertag->ltidxs[monitor->pertag->curtag]->symbol;
} else if (monitor->isoverview) {
symbol = overviewlayout.symbol; symbol = overviewlayout.symbol;
} else { } else {
symbol = monitor->pertag->ltidxs[monitor->pertag->prevtag]->symbol; symbol = monitor->pertag->ltidxs[monitor->pertag->curtag]->symbol;
} }
keyboard = &kb_group->wlr_group->keyboard; keyboard = &kb_group->wlr_group->keyboard;
@ -264,7 +262,7 @@ void dwl_ipc_output_set_tags(struct wl_client *client,
return; return;
monitor = ipc_output->mon; monitor = ipc_output->mon;
view_in_mon(&(Arg){.ui = newtags}, true, monitor); view_in_mon(&(Arg){.ui = newtags}, true, monitor, true);
} }
void dwl_ipc_output_quit(struct wl_client *client, void dwl_ipc_output_quit(struct wl_client *client,

View file

@ -102,7 +102,9 @@ void dwl_ext_workspace_printstatus(Monitor *m) {
wlr_ext_workspace_handle_v1_set_hidden(w->ext_workspace, false); wlr_ext_workspace_handle_v1_set_hidden(w->ext_workspace, false);
} else { } else {
wlr_ext_workspace_handle_v1_set_urgent(w->ext_workspace, false); wlr_ext_workspace_handle_v1_set_urgent(w->ext_workspace, false);
wlr_ext_workspace_handle_v1_set_hidden(w->ext_workspace, true); if (!w->m->pertag->no_hide[w->tag])
wlr_ext_workspace_handle_v1_set_hidden(w->ext_workspace,
true);
} }
if ((m->tagset[m->seltags] & (1 << (w->tag - 1)) & TAGMASK) || if ((m->tagset[m->seltags] & (1 << (w->tag - 1)) & TAGMASK) ||

View file

@ -37,7 +37,7 @@ Client *get_client_by_id_or_title(const char *arg_id, const char *arg_title) {
const char *appid, *title; const char *appid, *title;
Client *c = NULL; Client *c = NULL;
wl_list_for_each(c, &clients, link) { wl_list_for_each(c, &clients, link) {
if (c->mon != selmon) { if (!scratchpad_cross_monitor && c->mon != selmon) {
continue; continue;
} }
@ -121,14 +121,14 @@ static bool is_window_rule_matches(const ConfigWinRule *r, const char *appid,
regex_match(r->title, title)); regex_match(r->title, title));
} }
Client *center_select(Monitor *m) { Client *center_tiled_select(Monitor *m) {
Client *c = NULL; Client *c = NULL;
Client *target_c = NULL; Client *target_c = NULL;
long int mini_distance = -1; long int mini_distance = -1;
int dirx, diry; int dirx, diry;
long int distance; long int distance;
wl_list_for_each(c, &clients, link) { wl_list_for_each(c, &clients, link) {
if (c && VISIBLEON(c, m) && client_surface(c)->mapped && if (c && VISIBLEON(c, m) && ISTILED(c) && client_surface(c)->mapped &&
!c->isfloating && !client_is_unmanaged(c)) { !c->isfloating && !client_is_unmanaged(c)) {
dirx = c->geom.x + c->geom.width / 2 - (m->w.x + m->w.width / 2); dirx = c->geom.x + c->geom.width / 2 - (m->w.x + m->w.width / 2);
diry = c->geom.y + c->geom.height / 2 - (m->w.y + m->w.height / 2); diry = c->geom.y + c->geom.height / 2 - (m->w.y + m->w.height / 2);

View file

@ -17,20 +17,13 @@ Monitor *dirtomon(enum wlr_direction dir) {
bool is_scroller_layout(Monitor *m) { bool is_scroller_layout(Monitor *m) {
if (!m->pertag->curtag &&
strcmp(m->pertag->ltidxs[m->pertag->prevtag]->name, "scroller") == 0)
return true;
if (!m->pertag->curtag &&
strcmp(m->pertag->ltidxs[m->pertag->prevtag]->name,
"vertical_scroller") == 0)
return true;
if (strcmp(m->pertag->ltidxs[m->pertag->curtag]->name, "scroller") == 0) if (strcmp(m->pertag->ltidxs[m->pertag->curtag]->name, "scroller") == 0)
return true; return true;
if (strcmp(m->pertag->ltidxs[m->pertag->curtag]->name, if (strcmp(m->pertag->ltidxs[m->pertag->curtag]->name,
"vertical_scroller") == 0) "vertical_scroller") == 0)
return true; return true;
return false; return false;
} }

View file

@ -140,6 +140,10 @@ void grid(Monitor *m) {
if (n == 1) { if (n == 1) {
wl_list_for_each(c, &clients, link) { wl_list_for_each(c, &clients, link) {
if (c->mon != m)
continue;
c->bw = m->visible_tiling_clients == 1 && no_border_when_single && c->bw = m->visible_tiling_clients == 1 && no_border_when_single &&
smartgaps smartgaps
? 0 ? 0
@ -164,6 +168,9 @@ void grid(Monitor *m) {
ch = (m->w.height - 2 * overviewgappo) * 0.65; ch = (m->w.height - 2 * overviewgappo) * 0.65;
i = 0; i = 0;
wl_list_for_each(c, &clients, link) { wl_list_for_each(c, &clients, link) {
if (c->mon != m)
continue;
c->bw = m->visible_tiling_clients == 1 && no_border_when_single && c->bw = m->visible_tiling_clients == 1 && no_border_when_single &&
smartgaps smartgaps
? 0 ? 0
@ -212,6 +219,9 @@ void grid(Monitor *m) {
// 调整每个客户端的位置和大小 // 调整每个客户端的位置和大小
i = 0; i = 0;
wl_list_for_each(c, &clients, link) { wl_list_for_each(c, &clients, link) {
if (c->mon != m)
continue;
c->bw = c->bw =
m->visible_tiling_clients == 1 && no_border_when_single && smartgaps m->visible_tiling_clients == 1 && no_border_when_single && smartgaps
? 0 ? 0
@ -347,10 +357,11 @@ void scroller(Monitor *m) {
if (m->sel && !client_is_unmanaged(m->sel) && !m->sel->isfloating && if (m->sel && !client_is_unmanaged(m->sel) && !m->sel->isfloating &&
!m->sel->ismaxmizescreen && !m->sel->isfullscreen) { !m->sel->ismaxmizescreen && !m->sel->isfullscreen) {
root_client = m->sel; root_client = m->sel;
} else if (m->prevtilesel && !client_is_unmanaged(m->prevtilesel)) { } else if (m->prevsel && ISTILED(m->prevsel) && VISIBLEON(m->prevsel, m) &&
root_client = m->prevtilesel; !client_is_unmanaged(m->prevsel)) {
root_client = m->prevsel;
} else { } else {
root_client = center_select(m); root_client = center_tiled_select(m);
} }
if (!root_client) { if (!root_client) {
@ -380,10 +391,11 @@ void scroller(Monitor *m) {
if (need_scroller) { if (need_scroller) {
if (scroller_focus_center || if (scroller_focus_center ||
((!m->prevtilesel || ((!m->prevsel ||
(m->prevtilesel->scroller_proportion * max_client_width) + (ISTILED(m->prevsel) &&
(root_client->scroller_proportion * max_client_width) > (m->prevsel->scroller_proportion * max_client_width) +
m->w.width - 2 * scroller_structs - cur_gappih) && (root_client->scroller_proportion * max_client_width) >
m->w.width - 2 * scroller_structs - cur_gappih)) &&
scroller_prefer_center)) { 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 { } else {
@ -439,10 +451,10 @@ void tile(Monitor *m) {
cur_gappov = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappov; cur_gappov = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappov;
cur_gappoh = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappoh; cur_gappoh = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappoh;
if (n > selmon->pertag->nmasters[selmon->pertag->curtag]) if (n > m->pertag->nmasters[m->pertag->curtag])
mw = selmon->pertag->nmasters[selmon->pertag->curtag] mw = m->pertag->nmasters[m->pertag->curtag]
? (m->w.width + cur_gappih * ie) * ? (m->w.width + cur_gappih * ie) *
selmon->pertag->mfacts[selmon->pertag->curtag] m->pertag->mfacts[m->pertag->curtag]
: 0; : 0;
else else
mw = m->w.width - 2 * cur_gappoh + cur_gappih * ie; mw = m->w.width - 2 * cur_gappoh + cur_gappih * ie;
@ -451,8 +463,8 @@ void tile(Monitor *m) {
wl_list_for_each(c, &clients, link) { wl_list_for_each(c, &clients, link) {
if (!VISIBLEON(c, m) || !ISTILED(c)) if (!VISIBLEON(c, m) || !ISTILED(c))
continue; continue;
if (i < selmon->pertag->nmasters[selmon->pertag->curtag]) { if (i < m->pertag->nmasters[m->pertag->curtag]) {
r = MIN(n, selmon->pertag->nmasters[selmon->pertag->curtag]) - i; r = MIN(n, m->pertag->nmasters[m->pertag->curtag]) - i;
h = (m->w.height - my - cur_gappov - cur_gappiv * ie * (r - 1)) / r; h = (m->w.height - my - cur_gappov - cur_gappiv * ie * (r - 1)) / r;
resize(c, resize(c,
(struct wlr_box){.x = m->w.x + cur_gappoh, (struct wlr_box){.x = m->w.x + cur_gappoh,

View file

@ -138,6 +138,10 @@ void vertical_grid(Monitor *m) {
if (n == 1) { if (n == 1) {
wl_list_for_each(c, &clients, link) { wl_list_for_each(c, &clients, link) {
if (c->mon != m)
continue;
c->bw = m->visible_tiling_clients == 1 && no_border_when_single && c->bw = m->visible_tiling_clients == 1 && no_border_when_single &&
smartgaps smartgaps
? 0 ? 0
@ -162,6 +166,10 @@ void vertical_grid(Monitor *m) {
cw = (m->w.width - 2 * overviewgappo) * 0.65; cw = (m->w.width - 2 * overviewgappo) * 0.65;
i = 0; i = 0;
wl_list_for_each(c, &clients, link) { wl_list_for_each(c, &clients, link) {
if (c->mon != m)
continue;
c->bw = m->visible_tiling_clients == 1 && no_border_when_single && c->bw = m->visible_tiling_clients == 1 && no_border_when_single &&
smartgaps smartgaps
? 0 ? 0
@ -207,6 +215,9 @@ void vertical_grid(Monitor *m) {
i = 0; i = 0;
wl_list_for_each(c, &clients, link) { wl_list_for_each(c, &clients, link) {
if (c->mon != m)
continue;
c->bw = c->bw =
m->visible_tiling_clients == 1 && no_border_when_single && smartgaps m->visible_tiling_clients == 1 && no_border_when_single && smartgaps
? 0 ? 0
@ -333,10 +344,11 @@ void vertical_scroller(Monitor *m) {
if (m->sel && !client_is_unmanaged(m->sel) && !m->sel->isfloating && if (m->sel && !client_is_unmanaged(m->sel) && !m->sel->isfloating &&
!m->sel->ismaxmizescreen && !m->sel->isfullscreen) { !m->sel->ismaxmizescreen && !m->sel->isfullscreen) {
root_client = m->sel; root_client = m->sel;
} else if (m->prevtilesel && !client_is_unmanaged(m->prevtilesel)) { } else if (m->prevsel && ISTILED(m->prevsel) && VISIBLEON(m->prevsel, m) &&
root_client = m->prevtilesel; !client_is_unmanaged(m->prevsel)) {
root_client = m->prevsel;
} else { } else {
root_client = center_select(m); root_client = center_tiled_select(m);
} }
if (!root_client) { if (!root_client) {
@ -366,10 +378,11 @@ void vertical_scroller(Monitor *m) {
if (need_scroller) { if (need_scroller) {
if (scroller_focus_center || if (scroller_focus_center ||
((!m->prevtilesel || ((!m->prevsel ||
(m->prevtilesel->scroller_proportion * max_client_height) + (ISTILED(m->prevsel) &&
(root_client->scroller_proportion * max_client_height) > (m->prevsel->scroller_proportion * max_client_height) +
m->w.height - 2 * scroller_structs - cur_gappiv) && (root_client->scroller_proportion * max_client_height) >
m->w.height - 2 * scroller_structs - cur_gappiv)) &&
scroller_prefer_center)) { 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 { } else {
@ -425,10 +438,10 @@ void vertical_tile(Monitor *m) {
cur_gappov = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappov; cur_gappov = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappov;
cur_gappoh = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappoh; cur_gappoh = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappoh;
if (n > selmon->pertag->nmasters[selmon->pertag->curtag]) if (n > m->pertag->nmasters[m->pertag->curtag])
mh = selmon->pertag->nmasters[selmon->pertag->curtag] mh = m->pertag->nmasters[m->pertag->curtag]
? (m->w.height + cur_gappiv * ie) * ? (m->w.height + cur_gappiv * ie) *
selmon->pertag->mfacts[selmon->pertag->curtag] m->pertag->mfacts[m->pertag->curtag]
: 0; : 0;
else else
mh = m->w.height - 2 * cur_gappoh + cur_gappiv * ie; mh = m->w.height - 2 * cur_gappoh + cur_gappiv * ie;
@ -437,8 +450,8 @@ void vertical_tile(Monitor *m) {
wl_list_for_each(c, &clients, link) { wl_list_for_each(c, &clients, link) {
if (!VISIBLEON(c, m) || !ISTILED(c)) if (!VISIBLEON(c, m) || !ISTILED(c))
continue; continue;
if (i < selmon->pertag->nmasters[selmon->pertag->curtag]) { if (i < m->pertag->nmasters[m->pertag->curtag]) {
r = MIN(n, selmon->pertag->nmasters[selmon->pertag->curtag]) - i; r = MIN(n, m->pertag->nmasters[m->pertag->curtag]) - i;
w = (m->w.width - mx - cur_gappov - cur_gappiv * ie * (r - 1)) / r; w = (m->w.width - mx - cur_gappov - cur_gappiv * ie * (r - 1)) / r;
resize(c, resize(c,
(struct wlr_box){.x = m->w.x + mx, (struct wlr_box){.x = m->w.x + mx,

View file

@ -314,6 +314,7 @@ struct Client {
int isopensilent; int isopensilent;
int istagsilent; int istagsilent;
int iskilling; int iskilling;
int istagswitching;
int isnamedscratchpad; int isnamedscratchpad;
bool is_pending_open_animation; bool is_pending_open_animation;
bool is_restoring_from_ov; bool is_restoring_from_ov;
@ -325,6 +326,7 @@ struct Client {
Client *swallowing, *swallowedby; Client *swallowing, *swallowedby;
bool is_clip_to_hide; bool is_clip_to_hide;
bool drag_to_tile; bool drag_to_tile;
bool scratchpad_switching_mon;
bool fake_no_border; bool fake_no_border;
int nofadein; int nofadein;
int nofadeout; int nofadeout;
@ -436,7 +438,7 @@ struct Monitor {
int gappoh; /* horizontal outer gaps */ int gappoh; /* horizontal outer gaps */
int gappov; /* vertical outer gaps */ int gappov; /* vertical outer gaps */
Pertag *pertag; Pertag *pertag;
Client *sel, *prevtilesel; Client *sel, *prevsel;
int isoverview; int isoverview;
int is_in_hotarea; int is_in_hotarea;
int gamma_lut_changed; int gamma_lut_changed;
@ -644,9 +646,9 @@ static struct wlr_box setclient_coordinate_center(Client *c,
int offsetx, int offsety); int offsetx, int offsety);
static unsigned int get_tags_first_tag(unsigned int tags); static unsigned int get_tags_first_tag(unsigned int tags);
static struct wlr_output_mode *get_output_mode(struct wlr_output *output, static struct wlr_output_mode *
int width, int height, get_nearest_output_mode(struct wlr_output *output, int width, int height,
float refresh); float refresh);
static void client_commit(Client *c); static void client_commit(Client *c);
static void layer_commit(LayerSurface *l); static void layer_commit(LayerSurface *l);
@ -657,7 +659,8 @@ static void scene_buffer_apply_opacity(struct wlr_scene_buffer *buffer, int sx,
int sy, void *data); int sy, void *data);
static Client *direction_select(const Arg *arg); static Client *direction_select(const Arg *arg);
static void view_in_mon(const Arg *arg, bool want_animation, Monitor *m); static void view_in_mon(const Arg *arg, bool want_animation, Monitor *m,
bool changefocus);
static void buffer_set_effect(Client *c, BufferData buffer_data); static void buffer_set_effect(Client *c, BufferData buffer_data);
static void snap_scene_buffer_apply_effect(struct wlr_scene_buffer *buffer, static void snap_scene_buffer_apply_effect(struct wlr_scene_buffer *buffer,
@ -665,7 +668,7 @@ static void snap_scene_buffer_apply_effect(struct wlr_scene_buffer *buffer,
static void client_set_pending_state(Client *c); static void client_set_pending_state(Client *c);
static void layer_set_pending_state(LayerSurface *l); static void layer_set_pending_state(LayerSurface *l);
static void set_rect_size(struct wlr_scene_rect *rect, int width, int height); static void set_rect_size(struct wlr_scene_rect *rect, int width, int height);
static Client *center_select(Monitor *m); static Client *center_tiled_select(Monitor *m);
static void handlecursoractivity(void); static void handlecursoractivity(void);
static int hidecursor(void *data); static int hidecursor(void *data);
static bool check_hit_no_border(Client *c); static bool check_hit_no_border(Client *c);
@ -691,13 +694,15 @@ static struct wlr_scene_tree *
wlr_scene_tree_snapshot(struct wlr_scene_node *node, wlr_scene_tree_snapshot(struct wlr_scene_node *node,
struct wlr_scene_tree *parent); struct wlr_scene_tree *parent);
static bool is_scroller_layout(Monitor *m); static bool is_scroller_layout(Monitor *m);
void create_output(struct wlr_backend *backend, void *data); static void create_output(struct wlr_backend *backend, void *data);
static const char *get_layout_abbr(const char *full_name); static const char *get_layout_abbr(const char *full_name);
void apply_named_scratchpad(Client *target_client); static void apply_named_scratchpad(Client *target_client);
Client *get_client_by_id_or_title(const char *arg_id, const char *arg_title); static Client *get_client_by_id_or_title(const char *arg_id,
bool switch_scratchpad_client_state(Client *c); const char *arg_title);
bool check_trackpad_disabled(struct wlr_pointer *pointer); static bool switch_scratchpad_client_state(Client *c);
unsigned int get_tag_status(unsigned int tag, Monitor *m); static bool check_trackpad_disabled(struct wlr_pointer *pointer);
static unsigned int get_tag_status(unsigned int tag, Monitor *m);
static void enable_adaptive_sync(Monitor *m, struct wlr_output_state *state);
#include "data/static_keymap.h" #include "data/static_keymap.h"
#include "dispatch/bind_declare.h" #include "dispatch/bind_declare.h"
@ -782,6 +787,8 @@ struct dvec2 *baked_points_close;
static struct wl_event_source *hide_source; static struct wl_event_source *hide_source;
static bool cursor_hidden = false; static bool cursor_hidden = false;
static bool tag_combo = false;
static struct { static struct {
enum wp_cursor_shape_device_v1_shape shape; enum wp_cursor_shape_device_v1_shape shape;
struct wlr_surface *surface; struct wlr_surface *surface;
@ -797,6 +804,7 @@ struct Pertag {
int nmasters[LENGTH(tags) + 1]; /* number of windows in master area */ int nmasters[LENGTH(tags) + 1]; /* number of windows in master area */
float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */ float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */
float smfacts[LENGTH(tags) + 1]; /* smfacts per tag */ float smfacts[LENGTH(tags) + 1]; /* smfacts per tag */
bool no_hide[LENGTH(tags) + 1]; /* no_hide per tag */
const Layout const Layout
*ltidxs[LENGTH(tags) + 1]; /* matrix of tags and layouts indexes */ *ltidxs[LENGTH(tags) + 1]; /* matrix of tags and layouts indexes */
}; };
@ -849,6 +857,7 @@ static struct wlr_xwayland *xwayland;
#include "animation/client.h" #include "animation/client.h"
#include "animation/common.h" #include "animation/common.h"
#include "animation/layer.h" #include "animation/layer.h"
#include "animation/tag.h"
#include "config/parse_config.h" #include "config/parse_config.h"
#include "dispatch/bind_define.h" #include "dispatch/bind_define.h"
#include "ext-protocol/all.h" #include "ext-protocol/all.h"
@ -891,6 +900,10 @@ void clear_fullscreen_flag(Client *c) {
} }
void minimized(const Arg *arg) { void minimized(const Arg *arg) {
if (selmon && selmon->isoverview)
return;
if (selmon->sel && !selmon->sel->isminied) { if (selmon->sel && !selmon->sel->isminied) {
set_minimized(selmon->sel); set_minimized(selmon->sel);
} }
@ -920,7 +933,7 @@ void show_scratchpad(Client *c) {
resize(c, c->geom, 0); resize(c, c->geom, 0);
} }
c->oldtags = selmon->tagset[selmon->seltags]; c->oldtags = c->mon->tagset[c->mon->seltags];
wl_list_remove(&c->link); // 从原来位置移除 wl_list_remove(&c->link); // 从原来位置移除
wl_list_insert(clients.prev->next, &c->link); // 插入开头 wl_list_insert(clients.prev->next, &c->link); // 插入开头
show_hide_client(c); show_hide_client(c);
@ -969,6 +982,38 @@ void swallow(Client *c, Client *w) {
} }
bool switch_scratchpad_client_state(Client *c) { bool switch_scratchpad_client_state(Client *c) {
if (scratchpad_cross_monitor && selmon && c->mon != selmon &&
c->is_in_scratchpad) {
// 保存原始monitor用于尺寸计算
Monitor *oldmon = c->mon;
c->scratchpad_switching_mon = true;
c->mon = selmon;
reset_foreign_tolevel(c);
client_update_oldmonname_record(c, selmon);
// 根据新monitor调整窗口尺寸
c->float_geom.width =
(int)(c->float_geom.width * c->mon->w.width / oldmon->w.width);
c->float_geom.height =
(int)(c->float_geom.height * c->mon->w.height / oldmon->w.height);
c->float_geom = setclient_coordinate_center(c, c->float_geom, 0, 0);
// 只有显示状态的scratchpad才需要聚焦和返回true
if (c->is_scratchpad_show) {
c->tags = get_tags_first_tag(selmon->tagset[selmon->seltags]);
resize(c, c->float_geom, 0);
arrange(selmon, false);
focusclient(c, true);
c->scratchpad_switching_mon = false;
return true;
} else {
resize(c, c->float_geom, 0);
c->scratchpad_switching_mon = false;
}
}
if (c->is_in_scratchpad && c->is_scratchpad_show && if (c->is_in_scratchpad && c->is_scratchpad_show &&
(selmon->tagset[selmon->seltags] & c->tags) == 0) { (selmon->tagset[selmon->seltags] & c->tags) == 0) {
unsigned int target = unsigned int target =
@ -990,9 +1035,11 @@ bool switch_scratchpad_client_state(Client *c) {
void apply_named_scratchpad(Client *target_client) { void apply_named_scratchpad(Client *target_client) {
Client *c = NULL; Client *c = NULL;
wl_list_for_each(c, &clients, link) { wl_list_for_each(c, &clients, link) {
if (c->mon != selmon) {
if (!scratchpad_cross_monitor && c->mon != selmon) {
continue; continue;
} }
if (single_scratchpad && c->is_in_scratchpad && c->is_scratchpad_show && if (single_scratchpad && c->is_in_scratchpad && c->is_scratchpad_show &&
c != target_client) { c != target_client) {
set_minimized(c); set_minimized(c);
@ -1237,7 +1284,7 @@ void applyrules(Client *c) {
!(c->mon == selmon && c->tags & c->mon->tagset[c->mon->seltags]) && !(c->mon == selmon && c->tags & c->mon->tagset[c->mon->seltags]) &&
!c->isopensilent && !c->istagsilent) { !c->isopensilent && !c->istagsilent) {
c->animation.tag_from_rule = true; c->animation.tag_from_rule = true;
view_in_mon(&(Arg){.ui = c->tags}, true, c->mon); view_in_mon(&(Arg){.ui = c->tags}, true, c->mon, true);
} }
setfullscreen(c, fullscreen_state_backup); setfullscreen(c, fullscreen_state_backup);
@ -1248,7 +1295,8 @@ void applyrules(Client *c) {
*/ */
wl_list_for_each(fc, &clients, wl_list_for_each(fc, &clients,
link) if (fc && fc != c && c->tags & fc->tags && link) if (fc && fc != c && c->tags & fc->tags &&
ISFULLSCREEN(fc) && !c->isfloating) { VISIBLEON(fc, c->mon) && ISFULLSCREEN(fc) &&
!c->isfloating) {
clear_fullscreen_flag(fc); clear_fullscreen_flag(fc);
arrange(c->mon, false); arrange(c->mon, false);
} }
@ -1265,92 +1313,6 @@ void applyrules(Client *c) {
} }
} }
void set_tagin_animation(Monitor *m, Client *c) {
if (c->animation.running) {
c->animainit_geom.x = c->animation.current.x;
c->animainit_geom.y = c->animation.current.y;
return;
}
if (m->pertag->curtag > m->pertag->prevtag) {
c->animainit_geom.x = tag_animation_direction == VERTICAL
? c->animation.current.x
: c->mon->m.x + c->mon->m.width;
c->animainit_geom.y = tag_animation_direction == VERTICAL
? c->mon->m.y + c->mon->m.height
: c->animation.current.y;
} else {
c->animainit_geom.x = tag_animation_direction == VERTICAL
? c->animation.current.x
: m->m.x - c->geom.width;
c->animainit_geom.y = tag_animation_direction == VERTICAL
? m->m.y - c->geom.height
: c->animation.current.y;
}
}
void set_arrange_visible(Monitor *m, Client *c, bool want_animation) {
if (!c->is_clip_to_hide || !ISTILED(c) || !is_scroller_layout(c->mon)) {
c->is_clip_to_hide = false;
wlr_scene_node_set_enabled(&c->scene->node, true);
wlr_scene_node_set_enabled(&c->scene_surface->node, true);
}
client_set_suspended(c, false);
if (!c->animation.tag_from_rule && want_animation &&
m->pertag->prevtag != 0 && m->pertag->curtag != 0 && animations) {
c->animation.tagining = true;
set_tagin_animation(m, c);
} else {
c->animainit_geom.x = c->animation.current.x;
c->animainit_geom.y = c->animation.current.y;
}
c->animation.tag_from_rule = false;
c->animation.tagouting = false;
c->animation.tagouted = false;
resize(c, c->geom, 0);
}
void set_tagout_animation(Monitor *m, Client *c) {
if (m->pertag->curtag > m->pertag->prevtag) {
c->pending = c->geom;
c->pending.x = tag_animation_direction == VERTICAL
? c->animation.current.x
: c->mon->m.x - c->geom.width;
c->pending.y = tag_animation_direction == VERTICAL
? c->mon->m.y - c->geom.height
: c->animation.current.y;
resize(c, c->geom, 0);
} else {
c->pending = c->geom;
c->pending.x = tag_animation_direction == VERTICAL
? c->animation.current.x
: c->mon->m.x + c->mon->m.width;
c->pending.y = tag_animation_direction == VERTICAL
? c->mon->m.y + c->mon->m.height
: c->animation.current.y;
resize(c, c->geom, 0);
}
}
void set_arrange_hidden(Monitor *m, Client *c, bool want_animation) {
if ((c->tags & (1 << (m->pertag->prevtag - 1))) &&
m->pertag->prevtag != 0 && m->pertag->curtag != 0 && animations) {
c->animation.tagouting = true;
c->animation.tagining = false;
set_tagout_animation(m, c);
} else {
wlr_scene_node_set_enabled(&c->scene->node, false);
client_set_suspended(c, true);
}
}
void // 17 void // 17
arrange(Monitor *m, bool want_animation) { arrange(Monitor *m, bool want_animation) {
Client *c; Client *c;
@ -1369,7 +1331,7 @@ arrange(Monitor *m, bool want_animation) {
if (c->mon == m && (c->isglobal || c->isunglobal)) { if (c->mon == m && (c->isglobal || c->isunglobal)) {
c->tags = m->tagset[m->seltags]; c->tags = m->tagset[m->seltags];
if (selmon->sel == NULL) if (c->mon->sel == NULL)
focusclient(c, 0); focusclient(c, 0);
} }
@ -1394,12 +1356,8 @@ arrange(Monitor *m, bool want_animation) {
if (m->isoverview) { if (m->isoverview) {
overviewlayout.arrange(m); overviewlayout.arrange(m);
} else if (m && m->pertag->curtag && } else {
m->pertag->ltidxs[m->pertag->curtag]->arrange) {
m->pertag->ltidxs[m->pertag->curtag]->arrange(m); m->pertag->ltidxs[m->pertag->curtag]->arrange(m);
} else if (m && m->pertag->prevtag &&
m->pertag->ltidxs[m->pertag->prevtag]->arrange) {
m->pertag->ltidxs[m->pertag->prevtag]->arrange(m);
} }
motionnotify(0, NULL, 0, 0, 0, 0); motionnotify(0, NULL, 0, 0, 0, 0);
@ -1902,7 +1860,7 @@ buttonpress(struct wl_listener *listener, void *data) {
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); reset_foreign_tolevel(grabc);
selmon->prevtilesel = ISTILED(selmon->sel) ? selmon->sel : NULL; selmon->prevsel = ISTILED(selmon->sel) ? selmon->sel : NULL;
selmon->sel = grabc; selmon->sel = grabc;
tmpc = grabc; tmpc = grabc;
grabc = NULL; grabc = NULL;
@ -2510,17 +2468,37 @@ void createlocksurface(struct wl_listener *listener, void *data) {
client_notify_enter(lock_surface->surface, wlr_seat_get_keyboard(seat)); client_notify_enter(lock_surface->surface, wlr_seat_get_keyboard(seat));
} }
struct wlr_output_mode *get_output_mode(struct wlr_output *output, int width, struct wlr_output_mode *get_nearest_output_mode(struct wlr_output *output,
int height, float refresh) { int width, int height,
struct wlr_output_mode *mode; float refresh) {
struct wlr_output_mode *mode, *nearest_mode = NULL;
float min_diff = 99999.0f;
wl_list_for_each(mode, &output->modes, link) { wl_list_for_each(mode, &output->modes, link) {
if (mode->width == width && mode->height == height && if (mode->width == width && mode->height == height) {
(int)round(mode->refresh / 1000) == (int)round(refresh)) { float mode_refresh = mode->refresh / 1000.0f;
return mode; float diff = fabsf(mode_refresh - refresh);
if (diff < min_diff) {
min_diff = diff;
nearest_mode = mode;
}
} }
} }
return NULL; return nearest_mode;
}
void enable_adaptive_sync(Monitor *m, struct wlr_output_state *state) {
wlr_output_state_set_adaptive_sync_enabled(state, true);
if (!wlr_output_test_state(m->wlr_output, state)) {
wlr_output_state_set_adaptive_sync_enabled(state, false);
wlr_log(WLR_DEBUG, "failed to enable adaptive sync for output %s",
m->wlr_output->name);
} else {
wlr_log(WLR_INFO, "adaptive sync enabled for output %s",
m->wlr_output->name);
}
} }
void createmon(struct wl_listener *listener, void *data) { void createmon(struct wl_listener *listener, void *data) {
@ -2585,12 +2563,13 @@ void createmon(struct wl_listener *listener, void *data) {
rr = r->rr; rr = r->rr;
if (r->width > 0 && r->height > 0 && r->refresh > 0) { if (r->width > 0 && r->height > 0 && r->refresh > 0) {
custom_monitor_mode = true; internal_mode = get_nearest_output_mode(m->wlr_output, r->width,
internal_mode = get_output_mode(m->wlr_output, r->width, r->height, r->refresh);
r->height, r->refresh);
if (internal_mode) { if (internal_mode) {
custom_monitor_mode = true;
wlr_output_state_set_mode(&state, internal_mode); wlr_output_state_set_mode(&state, internal_mode);
} else { } else if (wlr_output_is_headless(m->wlr_output)) {
custom_monitor_mode = true;
wlr_output_state_set_custom_mode( wlr_output_state_set_custom_mode(
&state, r->width, r->height, &state, r->width, r->height,
(int)roundf(r->refresh * 1000)); (int)roundf(r->refresh * 1000));
@ -2610,6 +2589,10 @@ void createmon(struct wl_listener *listener, void *data) {
wlr_output_state_set_mode(&state, wlr_output_state_set_mode(&state,
wlr_output_preferred_mode(wlr_output)); wlr_output_preferred_mode(wlr_output));
if (adaptive_sync) {
enable_adaptive_sync(m, &state);
}
/* Set up event listeners */ /* Set up event listeners */
LISTEN(&wlr_output->events.frame, &m->frame, rendermon); LISTEN(&wlr_output->events.frame, &m->frame, rendermon);
LISTEN(&wlr_output->events.destroy, &m->destroy, cleanupmon); LISTEN(&wlr_output->events.destroy, &m->destroy, cleanupmon);
@ -2639,6 +2622,8 @@ void createmon(struct wl_listener *listener, void *data) {
strcmp(layouts[jk].name, config.tag_rules[i - 1].layout_name) == strcmp(layouts[jk].name, config.tag_rules[i - 1].layout_name) ==
0) { 0) {
m->pertag->ltidxs[config.tag_rules[i - 1].id] = &layouts[jk]; m->pertag->ltidxs[config.tag_rules[i - 1].id] = &layouts[jk];
m->pertag->no_hide[config.tag_rules[i - 1].id] =
config.tag_rules[i - 1].no_hide;
} }
} }
} }
@ -2783,22 +2768,24 @@ void configure_pointer(struct libinput_device *device) {
} }
void createpointer(struct wlr_pointer *pointer) { void createpointer(struct wlr_pointer *pointer) {
struct libinput_device *device =
wlr_libinput_get_device_handle(&pointer->base);
if (device && wlr_input_device_is_libinput(&pointer->base)) { struct libinput_device *device = NULL;
if (wlr_input_device_is_libinput(&pointer->base) &&
(device = wlr_libinput_get_device_handle(&pointer->base))) {
configure_pointer(device); configure_pointer(device);
InputDevice *input_dev = calloc(1, sizeof(InputDevice));
input_dev->wlr_device = &pointer->base;
input_dev->libinput_device = device;
input_dev->destroy_listener.notify = destroyinputdevice;
wl_signal_add(&pointer->base.events.destroy,
&input_dev->destroy_listener);
wl_list_insert(&inputdevices, &input_dev->link);
} }
InputDevice *input_dev = calloc(1, sizeof(InputDevice));
input_dev->wlr_device = &pointer->base;
input_dev->libinput_device = device;
input_dev->destroy_listener.notify = destroyinputdevice;
wl_signal_add(&pointer->base.events.destroy, &input_dev->destroy_listener);
wl_list_insert(&inputdevices, &input_dev->link);
wlr_cursor_attach_input_device(cursor, &pointer->base); wlr_cursor_attach_input_device(cursor, &pointer->base);
} }
@ -2823,32 +2810,36 @@ void switch_toggle(struct wl_listener *listener, void *data) {
} }
void createswitch(struct wlr_switch *switch_device) { void createswitch(struct wlr_switch *switch_device) {
struct libinput_device *device =
wlr_libinput_get_device_handle(&switch_device->base);
InputDevice *input_dev = calloc(1, sizeof(InputDevice)); struct libinput_device *device = NULL;
input_dev->wlr_device = &switch_device->base;
input_dev->libinput_device = device;
input_dev->device_data = NULL; // 初始化为 NULL
input_dev->destroy_listener.notify = destroyinputdevice; if (wlr_input_device_is_libinput(&switch_device->base) &&
wl_signal_add(&switch_device->base.events.destroy, (device = wlr_libinput_get_device_handle(&switch_device->base))) {
&input_dev->destroy_listener);
// 创建 Switch 特定数据 InputDevice *input_dev = calloc(1, sizeof(InputDevice));
Switch *sw = calloc(1, sizeof(Switch)); input_dev->wlr_device = &switch_device->base;
sw->wlr_switch = switch_device; input_dev->libinput_device = device;
sw->toggle.notify = switch_toggle; input_dev->device_data = NULL; // 初始化为 NULL
sw->input_dev = input_dev;
// 将 Switch 指针保存到 input_device 中 input_dev->destroy_listener.notify = destroyinputdevice;
input_dev->device_data = sw; wl_signal_add(&switch_device->base.events.destroy,
&input_dev->destroy_listener);
// 添加 toggle 监听器 // 创建 Switch 特定数据
wl_signal_add(&switch_device->events.toggle, &sw->toggle); Switch *sw = calloc(1, sizeof(Switch));
sw->wlr_switch = switch_device;
sw->toggle.notify = switch_toggle;
sw->input_dev = input_dev;
// 添加到全局列表 // 将 Switch 指针保存到 input_device 中
wl_list_insert(&inputdevices, &input_dev->link); input_dev->device_data = sw;
// 添加 toggle 监听器
wl_signal_add(&switch_device->events.toggle, &sw->toggle);
// 添加到全局列表
wl_list_insert(&inputdevices, &input_dev->link);
}
} }
void createpointerconstraint(struct wl_listener *listener, void *data) { void createpointerconstraint(struct wl_listener *listener, void *data) {
@ -3066,12 +3057,15 @@ void focusclient(Client *c, int lift) {
if (c && !c->iskilling && !client_is_unmanaged(c) && c->mon) { if (c && !c->iskilling && !client_is_unmanaged(c) && c->mon) {
selmon = c->mon; selmon = c->mon;
selmon->prevtilesel = ISTILED(selmon->sel) ? selmon->sel : NULL; selmon->prevsel = selmon->sel;
selmon->sel = c; selmon->sel = c;
// decide whether need to re-arrange // decide whether need to re-arrange
if (c && ISTILED(c) && VISIBLEON(c, selmon) && !INSIDEMON(c) && if (c && selmon->prevsel &&
(selmon->prevsel->tags & selmon->tagset[selmon->seltags]) &&
(c->tags & selmon->tagset[selmon->seltags]) && !c->isfloating &&
!c->isfullscreen && !c->ismaxmizescreen &&
is_scroller_layout(selmon)) { is_scroller_layout(selmon)) {
arrange(selmon, false); arrange(selmon, false);
} }
@ -3343,6 +3337,8 @@ void keypress(struct wl_listener *listener, void *data) {
if (!locked && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { if (!locked && event->state == WL_KEYBOARD_KEY_STATE_PRESSED) {
for (i = 0; i < nsyms; i++) for (i = 0; i < nsyms; i++)
handled = keybinding(mods, syms[i], keycode) || handled; handled = keybinding(mods, syms[i], keycode) || handled;
} else if (event->state == WL_KEYBOARD_KEY_STATE_RELEASED) {
tag_combo = false;
} }
if (handled && group->wlr_group->keyboard.repeat_info.delay > 0) { if (handled && group->wlr_group->keyboard.repeat_info.delay > 0) {
@ -3445,7 +3441,7 @@ static void iter_xdg_scene_buffers(struct wlr_scene_buffer *buffer, int sx,
if (blur && c && !c->noblur) { if (blur && c && !c->noblur) {
wlr_scene_buffer_set_backdrop_blur(buffer, true); wlr_scene_buffer_set_backdrop_blur(buffer, true);
wlr_scene_buffer_set_backdrop_blur_ignore_transparent(buffer, true); wlr_scene_buffer_set_backdrop_blur_ignore_transparent(buffer, false);
if (blur_optimized) { if (blur_optimized) {
wlr_scene_buffer_set_backdrop_blur_optimized(buffer, true); wlr_scene_buffer_set_backdrop_blur_optimized(buffer, true);
} else { } else {
@ -3461,6 +3457,7 @@ void init_client_properties(Client *c) {
c->isfullscreen = 0; c->isfullscreen = 0;
c->need_float_size_reduce = 0; c->need_float_size_reduce = 0;
c->iskilling = 0; c->iskilling = 0;
c->istagswitching = 0;
c->isglobal = 0; c->isglobal = 0;
c->isminied = 0; c->isminied = 0;
c->isoverlay = 0; c->isoverlay = 0;
@ -3476,6 +3473,7 @@ void init_client_properties(Client *c) {
c->scroller_proportion = scroller_default_proportion; c->scroller_proportion = scroller_default_proportion;
c->is_pending_open_animation = true; c->is_pending_open_animation = true;
c->drag_to_tile = false; c->drag_to_tile = false;
c->scratchpad_switching_mon = false;
c->fake_no_border = false; c->fake_no_border = false;
c->focused_opacity = focused_opacity; c->focused_opacity = focused_opacity;
c->unfocused_opacity = unfocused_opacity; c->unfocused_opacity = unfocused_opacity;
@ -3568,13 +3566,17 @@ mapnotify(struct wl_listener *listener, void *data) {
VISIBLEON(selmon->sel, selmon)) { VISIBLEON(selmon->sel, selmon)) {
at_client = selmon->sel; at_client = selmon->sel;
} else { } else {
at_client = center_select(selmon); at_client = center_tiled_select(selmon);
} }
at_client->link.next->prev = &c->link; if (at_client) {
c->link.prev = &at_client->link; at_client->link.next->prev = &c->link;
c->link.next = at_client->link.next; c->link.prev = &at_client->link;
at_client->link.next = &c->link; c->link.next = at_client->link.next;
at_client->link.next = &c->link;
} else {
wl_list_insert(clients.prev, &c->link); // 尾部入栈
}
} else } else
wl_list_insert(clients.prev, &c->link); // 尾部入栈 wl_list_insert(clients.prev, &c->link); // 尾部入栈
wl_list_insert(&fstack, &c->flink); wl_list_insert(&fstack, &c->flink);
@ -4112,7 +4114,12 @@ void setborder_color(Client *c) {
} }
void exchange_two_client(Client *c1, Client *c2) { void exchange_two_client(Client *c1, Client *c2) {
if (c1 == NULL || c2 == NULL || c1->mon != c2->mon) {
Monitor *tmp_mon;
unsigned int tmp_tags;
if (c1 == NULL || c2 == NULL ||
(!exchange_cross_monitor && c1->mon != c2->mon)) {
return; return;
} }
@ -4153,8 +4160,18 @@ void exchange_two_client(Client *c1, Client *c2) {
tmp2_next->prev = &c1->link; tmp2_next->prev = &c1->link;
} }
arrange(c1->mon, false); if (exchange_cross_monitor) {
focusclient(c1, 0); tmp_mon = c2->mon;
tmp_tags = c2->tags;
setmon(c2, c1->mon, c1->tags, false);
setmon(c1, tmp_mon, tmp_tags, false);
arrange(c1->mon, false);
arrange(c2->mon, false);
focusclient(c1, 0);
} else {
arrange(c1->mon, false);
focusclient(c1, 0);
}
} }
void // 17 void // 17
@ -4310,9 +4327,9 @@ setfloating(Client *c, int floating) {
c->is_in_scratchpad = 0; c->is_in_scratchpad = 0;
c->isnamedscratchpad = 0; c->isnamedscratchpad = 0;
// 让当前tag中的全屏窗口退出全屏参与平铺 // 让当前tag中的全屏窗口退出全屏参与平铺
wl_list_for_each(fc, &clients, link) if (fc && fc != c && wl_list_for_each(fc, &clients,
c->tags & fc->tags && link) if (fc && fc != c && VISIBLEON(fc, c->mon) &&
ISFULLSCREEN(fc)) { c->tags & fc->tags && ISFULLSCREEN(fc)) {
clear_fullscreen_flag(fc); clear_fullscreen_flag(fc);
} }
} }
@ -4533,8 +4550,8 @@ void setmon(Client *c, Monitor *m, unsigned int newtags, bool focus) {
oldmon->sel = NULL; oldmon->sel = NULL;
} }
if (oldmon && oldmon->prevtilesel == c) { if (oldmon && oldmon->prevsel == c) {
oldmon->prevtilesel = NULL; oldmon->prevsel = NULL;
} }
c->mon = m; c->mon = m;
@ -4554,7 +4571,12 @@ void setmon(Client *c, Monitor *m, unsigned int newtags, bool focus) {
if (m && focus) if (m && focus)
focusclient(focustop(m), 1); focusclient(focustop(m), 1);
if (!c->foreign_toplevel && m) { if (m) {
if (c->foreign_toplevel) {
remove_foreign_topleve(c);
}
add_foreign_toplevel(c); add_foreign_toplevel(c);
if (m->sel && m->sel->foreign_toplevel) if (m->sel && m->sel->foreign_toplevel)
wlr_foreign_toplevel_handle_v1_set_activated( wlr_foreign_toplevel_handle_v1_set_activated(
@ -4586,6 +4608,7 @@ void setsel(struct wl_listener *listener, void *data) {
} }
void show_hide_client(Client *c) { void show_hide_client(Client *c) {
unsigned int target = get_tags_first_tag(c->oldtags); unsigned int target = get_tags_first_tag(c->oldtags);
tag_client(&(Arg){.ui = target}, c); tag_client(&(Arg){.ui = target}, c);
// c->tags = c->oldtags; // c->tags = c->oldtags;
@ -4920,17 +4943,20 @@ void startdrag(struct wl_listener *listener, void *data) {
void tag_client(const Arg *arg, Client *target_client) { void tag_client(const Arg *arg, Client *target_client) {
Client *fc; Client *fc;
if (target_client && arg->ui & TAGMASK) { if (target_client && arg->ui & TAGMASK) {
target_client->tags = arg->ui & TAGMASK; target_client->tags = arg->ui & TAGMASK;
target_client->istagswitching = 1;
wl_list_for_each(fc, &clients, link) { wl_list_for_each(fc, &clients, link) {
if (fc && fc != target_client && target_client->tags & fc->tags && if (fc && fc != target_client && target_client->tags & fc->tags &&
ISFULLSCREEN(fc) && !target_client->isfloating) { ISFULLSCREEN(fc) && !target_client->isfloating) {
clear_fullscreen_flag(fc); clear_fullscreen_flag(fc);
} }
} }
view(&(Arg){.ui = arg->ui}, false); view(&(Arg){.ui = arg->ui, .i = arg->i}, true);
} else { } else {
view(arg, false); view(arg, true);
} }
focusclient(target_client, 1); focusclient(target_client, 1);
@ -5074,15 +5100,15 @@ void toggleoverview(const Arg *arg) {
// overview到正常视图,还原之前退出的浮动和全屏窗口状态 // overview到正常视图,还原之前退出的浮动和全屏窗口状态
if (selmon->isoverview) { if (selmon->isoverview) {
wl_list_for_each(c, &clients, link) { wl_list_for_each(c, &clients, link) {
if (c && !client_is_unmanaged(c) && if (c && c->mon == selmon && !client_is_unmanaged(c) &&
!client_should_ignore_focus(c) && !c->isunglobal) !client_should_ignore_focus(c) && !c->isunglobal)
overview_backup(c); overview_backup(c);
} }
} else { } else {
wl_list_for_each(c, &clients, link) { wl_list_for_each(c, &clients, link) {
if (c && !c->iskilling && !client_is_unmanaged(c) && if (c && c->mon == selmon && !c->iskilling &&
!c->isunglobal && !client_should_ignore_focus(c) && !client_is_unmanaged(c) && !c->isunglobal &&
client_surface(c)->mapped) !client_should_ignore_focus(c) && client_surface(c)->mapped)
overview_restore(c, &(Arg){.ui = target}); overview_restore(c, &(Arg){.ui = target});
} }
} }
@ -5146,8 +5172,8 @@ void unmapnotify(struct wl_listener *listener, void *data) {
if (c == m->sel) { if (c == m->sel) {
m->sel = NULL; m->sel = NULL;
} }
if (c == m->prevtilesel) { if (c == m->prevsel) {
m->prevtilesel = NULL; m->prevsel = NULL;
} }
} }
@ -5377,7 +5403,8 @@ urgent(struct wl_listener *listener, void *data) {
} }
} }
void view_in_mon(const Arg *arg, bool want_animation, Monitor *m) { void view_in_mon(const Arg *arg, bool want_animation, Monitor *m,
bool changefocus) {
unsigned int i, tmptag; unsigned int i, tmptag;
if (!m || (arg->ui != (~0 & TAGMASK) && m->isoverview)) { if (!m || (arg->ui != (~0 & TAGMASK) && m->isoverview)) {
@ -5424,13 +5451,25 @@ void view_in_mon(const Arg *arg, bool want_animation, Monitor *m) {
toggleseltags: toggleseltags:
focusclient(focustop(m), 1); if (changefocus)
focusclient(focustop(m), 1);
arrange(m, want_animation); arrange(m, want_animation);
printstatus(); printstatus();
} }
void view(const Arg *arg, bool want_animation) { void view(const Arg *arg, bool want_animation) {
view_in_mon(arg, want_animation, selmon); Monitor *m;
if (arg->i) {
view_in_mon(arg, want_animation, selmon, true);
wl_list_for_each(m, &mons, link) {
if (!m->wlr_output->enabled || m == selmon)
continue;
// only arrange, not change monitor focus
view_in_mon(arg, want_animation, m, false);
}
} else {
view_in_mon(arg, want_animation, selmon, true);
}
} }
void virtualkeyboard(struct wl_listener *listener, void *data) { void virtualkeyboard(struct wl_listener *listener, void *data) {