Merge branch 'main' into shield

This commit is contained in:
DreamMaoMao 2026-03-08 13:14:04 +08:00 committed by GitHub
commit e03e7e6ab4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
22 changed files with 962 additions and 382 deletions

View file

@ -16,7 +16,7 @@ jobs:
days-before-issue-stale: -1
# 手动标记后14 天后关闭
days-before-issue-close: 7
# 使用的标签(必须和你手动添加的标签一致)
# 使用的标签
stale-issue-label: "stale"
# 自动关闭时自动加上的标签
close-issue-label: "automatic-closing"

View file

@ -1,6 +1,6 @@
# Mango Wayland Compositor
<div>
<img src="https://github.com/DreamMaoMao/mangowc/blob/main/assets/mango-transparency-256.png" alt="MangoWC Logo" width="120"/>
<img src="https://github.com/mangowm/mango/blob/main/assets/mango-transparency-256.png" alt="MangoWM Logo" width="120"/>
</div>
This project's development is based on [dwl](https://codeberg.org/dwl/dwl/).
@ -27,11 +27,18 @@ This project's development is based on [dwl](https://codeberg.org/dwl/dwl/).
https://github.com/user-attachments/assets/bb83004a-0563-4b48-ad89-6461a9b78b1f
# Mango's Vision
**Mango's primary goal is stability**: After months of testing and development—and aside from a few lingering GPU compatibility issues—it should now be stable enough. I don't plan on making many breaking changes.
**Mango's preference is practicality**: I tend to add features that genuinely help with daily workflows—things that make our work more convenient.
**Mango won't cater to every user preference**: For niche feature requests, I'll take a wait-and-see approach. I'll only consider adding them if they get a significant number of upvotes.
# Our discord
[mangowc](https://discord.gg/CPjbDxesh5)
[mangowm](https://discord.gg/CPjbDxesh5)
# Supported layouts
- tile
- scroller
- monocle
@ -41,21 +48,20 @@ https://github.com/user-attachments/assets/bb83004a-0563-4b48-ad89-6461a9b78b1f
- vertical_tile
- vertical_grid
- vertical_scroller
- tgmix
# Installation
[![Packaging status](https://repology.org/badge/vertical-allrepos/mangowm.svg)](https://repology.org/project/mangowm/versions)
## Dependencies
- glibc
- wayland
- wayland-protocols
- libinput
- libdrm
- libxkbcommon
- pixman
- git
- meson
- ninja
- libdisplay-info
- libliftoff
- hwdata
@ -65,9 +71,9 @@ https://github.com/user-attachments/assets/bb83004a-0563-4b48-ad89-6461a9b78b1f
- libxcb
## Arch Linux
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:
The package is in the Arch User Repository and is available for manual download [here](https://aur.archlinux.org/packages/mangowm-git) or through a AUR helper like yay:
```bash
yay -S mangowc-git
yay -S mangowm-git
```
@ -81,12 +87,12 @@ eselect repository enable guru
emerge --sync guru
```
Then, add `gui-libs/scenefx` and `gui-wm/mangowc` to the `package.accept_keywords`.
Then, add `gui-libs/scenefx` and `gui-wm/mangowm` to the `package.accept_keywords`.
Finally, install the package:
```bash
emerge --ask --verbose gui-wm/mangowc
emerge --ask --verbose gui-wm/mangowm
```
## Fedora Linux
@ -96,31 +102,32 @@ First, add the [Terra Repository](https://terra.fyralabs.com/).
Then, install the package:
```bash
dnf install mangowc
dnf install mangowm
```
## GuixSD
## Guix System
The package definition is described in the source repository.
First, add `mangowc` channel to `channels.scm` file:
First, add `mangowm` channel to `channels.scm` file:
```scheme
;; In $HOME/.config/guix/channels.scm
(cons (channel
(name 'mangowc)
(url "https://github.com/DreamMaoMao/mangowc.git"))
(name 'mangowm)
(url "https://github.com/mangowm/mango.git")
(branch "main"))
... ;; 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:
`guix install mangowm` or add it to your configuration via:
```scheme
(use-modules (mangowc)) ;; Add mangowc module
(use-modules (mangowm)) ;; Add mangowm module
;; Add mangowc to packages list
(packages (cons
mangowc
;; Add mangowm to packages list
(packages (cons*
mangowm-git
... ;; Other packages you specified
%base-packages))
```
@ -140,8 +147,8 @@ cd scenefx
meson build -Dprefix=/usr
sudo ninja -C build install
git clone https://github.com/DreamMaoMao/mangowc.git
cd mangowc
git clone https://github.com/mangowm/mango.git
cd mangowm
meson build -Dprefix=/usr
sudo ninja -C build install
```
@ -199,9 +206,9 @@ git clone https://github.com/DreamMaoMao/mango-config.git ~/.config/mango
## Config Documentation
Refer to the repo wiki [wiki](https://github.com/DreamMaoMao/mango/wiki/)
Refer to the repo wiki [wiki](https://github.com/mangowm/mango/wiki/)
or the website docs [docs](https://mangowc.vercel.app/docs)
or the website docs [docs](https://mangowm.github.io/)
# NixOS + Home-manager
@ -221,7 +228,7 @@ Here's an example of using the modules in a flake:
};
flake-parts.url = "github:hercules-ci/flake-parts";
mango = {
url = "github:DreamMaoMao/mango";
url = "github:mangowm/mango";
inputs.nixpkgs.follows = "nixpkgs";
};
};
@ -283,9 +290,9 @@ Here's an example of using the modules in a flake:
To package mango for other distributions, you can check the reference setup for:
- [nix](https://github.com/DreamMaoMao/mangowc/blob/main/nix/default.nix)
- [arch](https://aur.archlinux.org/cgit/aur.git/tree/PKGBUILD?h=mangowc-git).
- [gentoo](https://data.gpo.zugaina.org/guru/gui-wm/mangowc)
- [nix](https://github.com/mangowm/mango/blob/main/nix/default.nix)
- [arch](https://aur.archlinux.org/cgit/aur.git/tree/PKGBUILD?h=mangowm-git).
- [gentoo](https://data.gpo.zugaina.org/guru/gui-wm/mangowm)
You might need to package `scenefx` for your distribution, check availability [here](https://github.com/wlrfx/scenefx.git).

View file

@ -0,0 +1,5 @@
[preferred]
default=gtk
org.freedesktop.impl.portal.ScreenCast=wlr
org.freedesktop.impl.portal.Screenshot=wlr
org.freedesktop.impl.portal.Inhibit=none

View file

@ -1,4 +1,4 @@
(define-module (mangowc)
(define-module (mangowm)
#:use-module (guix download)
#:use-module (guix git-download)
#:use-module (guix gexp)
@ -18,11 +18,11 @@
#:use-module (guix licenses))
(define-public mangowc-git
(define-public mangowm-git
(package
(name "mangowc")
(name "mangowm")
(version "git")
(source (local-file "." "mangowc-checkout"
(source (local-file "." "mangowm-checkout"
#:recursive? #t
#:select? (or (git-predicate (current-source-directory))
(const #t))))
@ -55,10 +55,13 @@
wlroots
scenefx))
(native-inputs (list pkg-config wayland-protocols))
(home-page "https://github.com/DreamMaoMao/mangowc")
(home-page "https://github.com/DreamMaoMao/mangowm")
(synopsis "Wayland compositor based on wlroots and scenefx")
(description "A Wayland compositor based on wlroots and scenefx,
inspired by dwl but aiming to be more feature-rich.")
(license gpl3)))
mangowc-git
(define-deprecated-package mangowc
mangowm-git)
mangowm-git

View file

@ -1,5 +1,5 @@
project('mango', ['c', 'cpp'],
version : '0.12.3',
version : '0.12.5',
)
subdir('protocols')
@ -147,5 +147,7 @@ executable('mmsg',
)
desktop_install_dir = join_paths(prefix, 'share/wayland-sessions')
install_data('mango.desktop', install_dir : desktop_install_dir)
install_data('config.conf', install_dir : join_paths(sysconfdir, 'mango'))
portal_install_dir = join_paths(prefix, 'share/xdg-desktop-portal')
install_data('assets/mango.desktop', install_dir : desktop_install_dir)
install_data('assets/mango-portals.conf', install_dir : portal_install_dir)
install_data('assets/config.conf', install_dir : join_paths(sysconfdir, 'mango'))

View file

@ -500,7 +500,7 @@ static const struct wl_registry_listener registry_listener = {
static void usage(void) {
fprintf(stderr,
"mmsg - MangoWC IPC\n"
"mmsg - MangoWM IPC\n"
"\n"
"SYNOPSIS:\n"
"\tmmsg [-OTLq]\n"
@ -517,7 +517,7 @@ static void usage(void) {
"\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-q Quit mango\n"
"\t-o <output> Select output (monitor)\n"
"\n"
"GET OPTIONS (used with -g or -w):\n"

View file

@ -11,7 +11,7 @@
wayland,
wayland-protocols,
wayland-scanner,
xcbutilwm,
libxcb-wm,
xwayland,
meson,
ninja,
@ -57,7 +57,7 @@ stdenv.mkDerivation {
]
++ lib.optionals enableXWayland [
libX11
xcbutilwm
libxcb-wm
xwayland
];

View file

@ -1012,6 +1012,10 @@ void resize(Client *c, struct wlr_box geo, int32_t interact) {
c->configure_serial = client_set_size(c, c->geom.width - 2 * c->bw,
c->geom.height - 2 * c->bw);
if (c->configure_serial != 0) {
c->mon->resizing_count_pending++;
}
if (c == grabc) {
c->animation.running = false;
c->need_output_flush = false;

View file

@ -243,34 +243,6 @@ static inline int32_t client_is_rendered_on_mon(Client *c, Monitor *m) {
return 0;
}
static inline int32_t client_is_stopped(Client *c) {
int32_t pid;
siginfo_t in = {0};
#ifdef XWAYLAND
if (client_is_x11(c))
return 0;
#endif
wl_client_get_credentials(c->surface.xdg->client->client, &pid, NULL, NULL);
if (waitid(P_PID, pid, &in, WNOHANG | WCONTINUED | WSTOPPED | WNOWAIT) <
0) {
/* This process is not our child process. We cannot determine its
* stopped state; assume it is not stopped to avoid blocking frame skip.
*/
if (errno == ECHILD)
return 0; // if not our child, assume not stopped
/* Other errors, also assume not stopped. */
return 0;
} else if (in.si_pid) {
if (in.si_code == CLD_STOPPED || in.si_code == CLD_TRAPPED)
return 1;
if (in.si_code == CLD_CONTINUED)
return 0;
}
return 0;
}
static inline int32_t client_is_unmanaged(Client *c) {
#ifdef XWAYLAND
if (client_is_x11(c))

View file

@ -92,3 +92,85 @@ uint32_t get_now_in_ms(void) {
uint32_t timespec_to_ms(struct timespec *ts) {
return (uint32_t)ts->tv_sec * 1000 + (uint32_t)ts->tv_nsec / 1000000;
}
char *join_strings(char *arr[], const char *sep) {
if (!arr || !arr[0]) {
char *empty = malloc(1);
if (empty)
empty[0] = '\0';
return empty;
}
size_t total_len = 0;
int count = 0;
for (int i = 0; arr[i] != NULL; i++) {
total_len += strlen(arr[i]);
count++;
}
if (count > 0) {
total_len += strlen(sep) * (count - 1);
}
char *result = malloc(total_len + 1);
if (!result)
return NULL;
result[0] = '\0';
for (int i = 0; arr[i] != NULL; i++) {
if (i > 0)
strcat(result, sep);
strcat(result, arr[i]);
}
return result;
}
char *join_strings_with_suffix(char *arr[], const char *suffix,
const char *sep) {
if (!arr || !arr[0]) {
char *empty = malloc(1);
if (empty)
empty[0] = '\0';
return empty;
}
size_t total_len = 0;
int count = 0;
for (int i = 0; arr[i] != NULL; i++) {
total_len += strlen(arr[i]) + strlen(suffix);
count++;
}
if (count > 0) {
total_len += strlen(sep) * (count - 1);
}
char *result = malloc(total_len + 1);
if (!result)
return NULL;
result[0] = '\0';
for (int i = 0; arr[i] != NULL; i++) {
if (i > 0)
strcat(result, sep);
strcat(result, arr[i]);
strcat(result, suffix);
}
return result;
}
char *string_printf(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
int len = vsnprintf(NULL, 0, fmt, args);
va_end(args);
if (len < 0)
return NULL;
char *str = malloc(len + 1);
if (!str)
return NULL;
va_start(args, fmt);
vsnprintf(str, len + 1, fmt, args);
va_end(args);
return str;
}

View file

@ -7,4 +7,8 @@ int32_t fd_set_nonblock(int32_t fd);
int32_t regex_match(const char *pattern_mb, const char *str_mb);
void wl_list_append(struct wl_list *list, struct wl_list *object);
uint32_t get_now_in_ms(void);
uint32_t timespec_to_ms(struct timespec *ts);
uint32_t timespec_to_ms(struct timespec *ts);
char *join_strings(char *arr[], const char *sep);
char *join_strings_with_suffix(char *arr[], const char *suffix,
const char *sep);
char *string_printf(const char *fmt, ...);

View file

@ -79,7 +79,8 @@ typedef struct {
int32_t ignore_maximize;
int32_t ignore_minimize;
int32_t isnosizehint;
const char *monitor;
int32_t indleinhibit_when_focus;
char *monitor;
int32_t offsetx;
int32_t offsety;
int32_t width;
@ -112,6 +113,7 @@ typedef struct {
int32_t width, height; // Monitor resolution
float refresh; // Refresh rate
int32_t vrr; // variable refresh rate
int32_t custom; // enable custom mode
} ConfigMonitorRule;
// 修改后的宏定义
@ -355,6 +357,8 @@ typedef struct {
int32_t single_scratchpad;
int32_t xwayland_persistence;
int32_t syncobj_enable;
float drag_tile_refresh_interval;
float drag_floating_refresh_interval;
int32_t allow_tearing;
int32_t allow_shortcuts_inhibit;
int32_t allow_lock_transparent;
@ -371,6 +375,9 @@ typedef int32_t (*FuncType)(const Arg *);
Config config;
bool parse_config_file(Config *config, const char *file_path, bool must_exist);
bool apply_rule_to_state(Monitor *m, const ConfigMonitorRule *rule,
struct wlr_output_state *state, int vrr, int custom);
bool monitor_matches_rule(Monitor *m, const ConfigMonitorRule *rule);
// Helper function to trim whitespace from start and end of a string
void trim_whitespace(char *str) {
@ -946,6 +953,7 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value,
(*arg).f = atof(arg_value);
} else if (strcmp(func_name, "switch_proportion_preset") == 0) {
func = switch_proportion_preset;
(*arg).i = parse_circle_direction(arg_value);
} else if (strcmp(func_name, "viewtoleft") == 0) {
func = viewtoleft;
(*arg).i = atoi(arg_value);
@ -1394,6 +1402,10 @@ bool parse_option(Config *config, char *key, char *value) {
config->xwayland_persistence = atoi(value);
} else if (strcmp(key, "syncobj_enable") == 0) {
config->syncobj_enable = atoi(value);
} else if (strcmp(key, "drag_tile_refresh_interval") == 0) {
config->drag_tile_refresh_interval = atof(value);
} else if (strcmp(key, "drag_floating_refresh_interval") == 0) {
config->drag_floating_refresh_interval = atof(value);
} else if (strcmp(key, "allow_tearing") == 0) {
config->allow_tearing = atoi(value);
} else if (strcmp(key, "allow_shortcuts_inhibit") == 0) {
@ -1796,6 +1808,7 @@ bool parse_option(Config *config, char *key, char *value) {
rule->height = -1;
rule->refresh = 0.0f;
rule->vrr = 0;
rule->custom = 0;
bool parse_error = false;
char *token = strtok(value, ",");
@ -1833,6 +1846,8 @@ bool parse_option(Config *config, char *key, char *value) {
rule->refresh = CLAMP_FLOAT(atof(val), 0.001f, 1000.0f);
} else if (strcmp(key, "vrr") == 0) {
rule->vrr = CLAMP_INT(atoi(val), 0, 1);
} else if (strcmp(key, "custom") == 0) {
rule->custom = CLAMP_INT(atoi(val), 0, 1);
} else {
fprintf(stderr,
"\033[1m\033[31m[ERROR]:\033[33m Unknown "
@ -1845,6 +1860,13 @@ bool parse_option(Config *config, char *key, char *value) {
token = strtok(NULL, ",");
}
if (!rule->name && !rule->make && !rule->model && !rule->serial) {
fprintf(stderr, "\033[1m\033[31m[ERROR]:\033[33m Monitor rule "
"must have at least one of the following "
"options: name, make, model, serial\n");
return false;
}
config->monitor_rules_count++;
return !parse_error;
} else if (strcmp(key, "tagrule") == 0) {
@ -2017,6 +2039,7 @@ bool parse_option(Config *config, char *key, char *value) {
rule->ignore_maximize = -1;
rule->ignore_minimize = -1;
rule->isnosizehint = -1;
rule->indleinhibit_when_focus = -1;
rule->isterm = -1;
rule->allow_csd = -1;
rule->force_maximize = -1;
@ -2129,6 +2152,8 @@ bool parse_option(Config *config, char *key, char *value) {
rule->ignore_minimize = atoi(val);
} else if (strcmp(key, "isnosizehint") == 0) {
rule->isnosizehint = atoi(val);
} else if (strcmp(key, "indleinhibit_when_focus") == 0) {
rule->indleinhibit_when_focus = atoi(val);
} else if (strcmp(key, "isterm") == 0) {
rule->isterm = atoi(val);
} else if (strcmp(key, "allow_csd") == 0) {
@ -3134,6 +3159,13 @@ void override_config(void) {
// 杂项设置
xwayland_persistence = CLAMP_INT(config.xwayland_persistence, 0, 1);
syncobj_enable = CLAMP_INT(config.syncobj_enable, 0, 1);
drag_tile_refresh_interval =
CLAMP_FLOAT(config.drag_tile_refresh_interval, 1.0f, 16.0f);
drag_floating_refresh_interval =
CLAMP_FLOAT(config.drag_floating_refresh_interval, 1.0f, 16.0f);
drag_tile_to_tile = CLAMP_INT(config.drag_tile_to_tile, 0, 1);
drag_floating_refresh_interval =
CLAMP_FLOAT(config.drag_floating_refresh_interval, 0.0f, 1000.0f);
allow_tearing = CLAMP_INT(config.allow_tearing, 0, 2);
allow_shortcuts_inhibit = CLAMP_INT(config.allow_shortcuts_inhibit, 0, 1);
allow_lock_transparent = CLAMP_INT(config.allow_lock_transparent, 0, 1);
@ -3322,6 +3354,8 @@ void set_value_default() {
config.single_scratchpad = single_scratchpad;
config.xwayland_persistence = xwayland_persistence;
config.syncobj_enable = syncobj_enable;
config.drag_tile_refresh_interval = drag_tile_refresh_interval;
config.drag_floating_refresh_interval = drag_floating_refresh_interval;
config.allow_tearing = allow_tearing;
config.allow_shortcuts_inhibit = allow_shortcuts_inhibit;
config.allow_lock_transparent = allow_lock_transparent;
@ -3548,17 +3582,15 @@ void reset_blur_params(void) {
void reapply_monitor_rules(void) {
ConfigMonitorRule *mr;
Monitor *m = NULL;
int32_t ji, vrr;
int32_t ji, vrr, custom;
int32_t mx, my;
struct wlr_output_state state;
struct wlr_output_mode *internal_mode = NULL;
wlr_output_state_init(&state);
bool match_rule = false;
wl_list_for_each(m, &mons, link) {
if (!m->wlr_output->enabled) {
if (!m->wlr_output->enabled)
continue;
}
wlr_output_state_init(&state);
for (ji = 0; ji < config.monitor_rules_count; ji++) {
if (config.monitor_rules_count < 1)
@ -3566,78 +3598,29 @@ void reapply_monitor_rules(void) {
mr = &config.monitor_rules[ji];
// 检查是否匹配的变量
match_rule = true;
// 检查四个标识字段的匹配
if (mr->name != NULL) {
if (!regex_match(mr->name, m->wlr_output->name)) {
match_rule = false;
}
}
if (mr->make != NULL) {
if (m->wlr_output->make == NULL ||
strcmp(mr->make, m->wlr_output->make) != 0) {
match_rule = false;
}
}
if (mr->model != NULL) {
if (m->wlr_output->model == NULL ||
strcmp(mr->model, m->wlr_output->model) != 0) {
match_rule = false;
}
}
if (mr->serial != NULL) {
if (m->wlr_output->serial == NULL ||
strcmp(mr->serial, m->wlr_output->serial) != 0) {
match_rule = false;
}
}
// 只有当所有指定的标识都匹配时才应用规则
if (match_rule) {
if (monitor_matches_rule(m, mr)) {
mx = mr->x == INT32_MAX ? m->m.x : mr->x;
my = mr->y == INT32_MAX ? m->m.y : mr->y;
vrr = mr->vrr >= 0 ? mr->vrr : 0;
custom = mr->custom >= 0 ? mr->custom : 0;
if (mr->width > 0 && mr->height > 0 && mr->refresh > 0) {
internal_mode = get_nearest_output_mode(
m->wlr_output, mr->width, mr->height, mr->refresh);
if (internal_mode) {
wlr_output_state_set_mode(&state, internal_mode);
} else if (wlr_output_is_headless(m->wlr_output)) {
wlr_output_state_set_custom_mode(
&state, mr->width, mr->height,
(int32_t)roundf(mr->refresh * 1000));
}
}
if (vrr) {
enable_adaptive_sync(m, &state);
} else {
wlr_output_state_set_adaptive_sync_enabled(&state, false);
}
wlr_output_state_set_scale(&state, mr->scale);
wlr_output_state_set_transform(&state, mr->rr);
(void)apply_rule_to_state(m, mr, &state, vrr, custom);
wlr_output_layout_add(output_layout, m->wlr_output, mx, my);
wlr_output_commit_state(m->wlr_output, &state);
break;
}
}
wlr_output_commit_state(m->wlr_output, &state);
wlr_output_state_finish(&state);
updatemons(NULL, NULL);
}
updatemons(NULL, NULL);
}
void reapply_cursor_style(void) {
if (hide_source) {
wl_event_source_timer_update(hide_source, 0);
wl_event_source_remove(hide_source);
hide_source = NULL;
if (hide_cursor_source) {
wl_event_source_timer_update(hide_cursor_source, 0);
wl_event_source_remove(hide_cursor_source);
hide_cursor_source = NULL;
}
wlr_cursor_unset_image(cursor);
@ -3651,6 +3634,16 @@ void reapply_cursor_style(void) {
cursor_mgr = wlr_xcursor_manager_create(config.cursor_theme, cursor_size);
if (cursor_size > 0) {
char size_str[16];
snprintf(size_str, sizeof(size_str), "%d", cursor_size);
setenv("XCURSOR_SIZE", size_str, 1);
}
if (config.cursor_theme) {
setenv("XCURSOR_THEME", config.cursor_theme, 1);
}
Monitor *m = NULL;
wl_list_for_each(m, &mons, link) {
wlr_xcursor_manager_load(cursor_mgr, m->wlr_output->scale);
@ -3658,12 +3651,13 @@ void reapply_cursor_style(void) {
wlr_cursor_set_xcursor(cursor, cursor_mgr, "left_ptr");
hide_source = wl_event_loop_add_timer(wl_display_get_event_loop(dpy),
hidecursor, cursor);
hide_cursor_source = wl_event_loop_add_timer(wl_display_get_event_loop(dpy),
hidecursor, cursor);
if (cursor_hidden) {
wlr_cursor_unset_image(cursor);
} else {
wl_event_source_timer_update(hide_source, cursor_hide_timeout * 1000);
wl_event_source_timer_update(hide_cursor_source,
cursor_hide_timeout * 1000);
}
}

View file

@ -109,7 +109,7 @@ int32_t drag_warp_cursor = 1;
int32_t xwayland_persistence = 1; /* xwayland persistence */
int32_t syncobj_enable = 0;
int32_t allow_lock_transparent = 0;
double drag_tile_refresh_interval = 16.0;
double drag_tile_refresh_interval = 8.0;
double drag_floating_refresh_interval = 8.0;
int32_t allow_tearing = TEARING_DISABLED;
int32_t allow_shortcuts_inhibit = SHORTCUTS_INHIBIT_ENABLE;

View file

@ -69,4 +69,4 @@ int32_t setoption(const Arg *arg);
int32_t disable_monitor(const Arg *arg);
int32_t enable_monitor(const Arg *arg);
int32_t toggle_monitor(const Arg *arg);
int32_t scroller_stack(const Arg *arg);
int32_t scroller_stack(const Arg *arg);

View file

@ -1,5 +1,6 @@
int32_t bind_to_view(const Arg *arg) {
if (!selmon)
return 0;
uint32_t target = arg->ui;
if (view_current_to_back && selmon->pertag->curtag &&
@ -100,6 +101,8 @@ int32_t defaultgaps(const Arg *arg) {
}
int32_t exchange_client(const Arg *arg) {
if (!selmon)
return 0;
Client *c = selmon->sel;
if (!c || c->isfloating)
return 0;
@ -107,11 +110,16 @@ int32_t exchange_client(const Arg *arg) {
if ((c->isfullscreen || c->ismaximizescreen) && !is_scroller_layout(c->mon))
return 0;
exchange_two_client(c, direction_select(arg));
Client *tc = direction_select(arg);
tc = get_focused_stack_client(tc);
exchange_two_client(c, tc);
return 0;
}
int32_t exchange_stack_client(const Arg *arg) {
if (!selmon)
return 0;
Client *c = selmon->sel;
Client *tc = NULL;
if (!c || c->isfloating || c->isfullscreen || c->ismaximizescreen)
@ -204,7 +212,7 @@ int32_t focusmon(const Arg *arg) {
if (!m->wlr_output->enabled) {
continue;
}
if (regex_match(arg->v, m->wlr_output->name)) {
if (match_monitor_spec(arg->v, m)) {
tm = m;
break;
}
@ -265,42 +273,56 @@ int32_t incnmaster(const Arg *arg) {
}
int32_t incgaps(const Arg *arg) {
if (!selmon)
return 0;
setgaps(selmon->gappoh + arg->i, selmon->gappov + arg->i,
selmon->gappih + arg->i, selmon->gappiv + arg->i);
return 0;
}
int32_t incigaps(const Arg *arg) {
if (!selmon)
return 0;
setgaps(selmon->gappoh, selmon->gappov, selmon->gappih + arg->i,
selmon->gappiv + arg->i);
return 0;
}
int32_t incogaps(const Arg *arg) {
if (!selmon)
return 0;
setgaps(selmon->gappoh + arg->i, selmon->gappov + arg->i, selmon->gappih,
selmon->gappiv);
return 0;
}
int32_t incihgaps(const Arg *arg) {
if (!selmon)
return 0;
setgaps(selmon->gappoh, selmon->gappov, selmon->gappih + arg->i,
selmon->gappiv);
return 0;
}
int32_t incivgaps(const Arg *arg) {
if (!selmon)
return 0;
setgaps(selmon->gappoh, selmon->gappov, selmon->gappih,
selmon->gappiv + arg->i);
return 0;
}
int32_t incohgaps(const Arg *arg) {
if (!selmon)
return 0;
setgaps(selmon->gappoh + arg->i, selmon->gappov, selmon->gappih,
selmon->gappiv);
return 0;
}
int32_t incovgaps(const Arg *arg) {
if (!selmon)
return 0;
setgaps(selmon->gappoh, selmon->gappov + arg->i, selmon->gappih,
selmon->gappiv);
return 0;
@ -330,6 +352,8 @@ int32_t setmfact(const Arg *arg) {
int32_t killclient(const Arg *arg) {
Client *c = NULL;
if (!selmon)
return 0;
c = selmon->sel;
if (c) {
pending_kill_client(c);
@ -399,6 +423,8 @@ int32_t moveresize(const Arg *arg) {
int32_t movewin(const Arg *arg) {
Client *c = NULL;
if (!selmon)
return 0;
c = selmon->sel;
if (!c || c->isfullscreen)
return 0;
@ -442,6 +468,8 @@ int32_t quit(const Arg *arg) {
int32_t resizewin(const Arg *arg) {
Client *c = NULL;
if (!selmon)
return 0;
c = selmon->sel;
int32_t offsetx = 0, offsety = 0;
@ -546,6 +574,8 @@ int32_t restore_minimized(const Arg *arg) {
int32_t setlayout(const Arg *arg) {
int32_t jk;
if (!selmon)
return 0;
for (jk = 0; jk < LENGTH(layouts); jk++) {
if (strcmp(layouts[jk].name, arg->v) == 0) {
@ -571,6 +601,8 @@ int32_t setkeymode(const Arg *arg) {
}
int32_t set_proportion(const Arg *arg) {
if (!selmon)
return 0;
if (selmon->isoverview || !is_scroller_layout(selmon))
return 0;
@ -596,6 +628,8 @@ int32_t smartmovewin(const Arg *arg) {
Client *c = NULL, *tc = NULL;
int32_t nx, ny;
int32_t buttom, top, left, right, tar;
if (!selmon)
return 0;
c = selmon->sel;
if (!c || c->isfullscreen)
return 0;
@ -697,6 +731,8 @@ int32_t smartresizewin(const Arg *arg) {
Client *c = NULL, *tc = NULL;
int32_t nw, nh;
int32_t buttom, top, left, right, tar;
if (!selmon)
return 0;
c = selmon->sel;
if (!c || c->isfullscreen)
return 0;
@ -765,6 +801,8 @@ int32_t smartresizewin(const Arg *arg) {
int32_t centerwin(const Arg *arg) {
Client *c = NULL;
if (!selmon)
return 0;
c = selmon->sel;
if (!c || c->isfullscreen || c->ismaximizescreen)
@ -812,7 +850,7 @@ int32_t spawn_shell(const Arg *arg) {
execlp("bash", "bash", "-c", arg->v, (char *)NULL);
// if execlp fails, we should not reach here
wlr_log(WLR_ERROR,
wlr_log(WLR_DEBUG,
"mango: failed to execute command '%s' with shell: %s\n",
arg->v, strerror(errno));
_exit(EXIT_FAILURE);
@ -853,7 +891,7 @@ int32_t spawn(const Arg *arg) {
execvp(argv[0], argv);
// 4. execvp 失败时:打印错误并直接退出(避免 coredump
wlr_log(WLR_ERROR, "mango: execvp '%s' failed: %s\n", argv[0],
wlr_log(WLR_DEBUG, "mango: execvp '%s' failed: %s\n", argv[0],
strerror(errno));
_exit(EXIT_FAILURE); // 使用 _exit 避免缓冲区刷新等操作
}
@ -943,6 +981,9 @@ int32_t switch_layout(const Arg *arg) {
char *target_layout_name = NULL;
uint32_t len;
if (!selmon)
return 0;
if (config.circle_layout_count != 0) {
for (jk = 0; jk < config.circle_layout_count; jk++) {
@ -994,6 +1035,8 @@ int32_t switch_layout(const Arg *arg) {
int32_t switch_proportion_preset(const Arg *arg) {
float target_proportion = 0;
if (!selmon)
return 0;
if (config.scroller_proportion_preset_count == 0) {
return 0;
@ -1013,13 +1056,28 @@ int32_t switch_proportion_preset(const Arg *arg) {
for (int32_t i = 0; i < config.scroller_proportion_preset_count; i++) {
if (config.scroller_proportion_preset[i] ==
tc->scroller_proportion) {
if (i == config.scroller_proportion_preset_count - 1) {
target_proportion = config.scroller_proportion_preset[0];
break;
if (arg->i == NEXT) {
if (i == config.scroller_proportion_preset_count - 1) {
target_proportion =
config.scroller_proportion_preset[0];
break;
} else {
target_proportion =
config.scroller_proportion_preset[i + 1];
break;
}
} else {
target_proportion =
config.scroller_proportion_preset[i + 1];
break;
if (i == 0) {
target_proportion =
config.scroller_proportion_preset
[config.scroller_proportion_preset_count - 1];
break;
} else {
target_proportion =
config.scroller_proportion_preset[i - 1];
break;
}
}
}
}
@ -1038,6 +1096,8 @@ int32_t switch_proportion_preset(const Arg *arg) {
}
int32_t tag(const Arg *arg) {
if (!selmon)
return 0;
Client *target_client = selmon->sel;
tag_client(arg, target_client);
return 0;
@ -1045,6 +1105,8 @@ int32_t tag(const Arg *arg) {
int32_t tagmon(const Arg *arg) {
Monitor *m = NULL, *cm = NULL;
if (!selmon)
return 0;
Client *c = focustop(selmon);
if (!c)
@ -1057,7 +1119,7 @@ int32_t tagmon(const Arg *arg) {
if (!cm->wlr_output->enabled) {
continue;
}
if (regex_match(arg->v, cm->wlr_output->name)) {
if (match_monitor_spec(arg->v, cm)) {
m = cm;
break;
}
@ -1136,6 +1198,9 @@ int32_t tagsilent(const Arg *arg) {
}
int32_t tagtoleft(const Arg *arg) {
if (!selmon)
return 0;
if (selmon->sel != NULL &&
__builtin_popcount(selmon->tagset[selmon->seltags] & TAGMASK) == 1 &&
selmon->tagset[selmon->seltags] > 1) {
@ -1145,6 +1210,9 @@ int32_t tagtoleft(const Arg *arg) {
}
int32_t tagtoright(const Arg *arg) {
if (!selmon)
return 0;
if (selmon->sel != NULL &&
__builtin_popcount(selmon->tagset[selmon->seltags] & TAGMASK) == 1 &&
selmon->tagset[selmon->seltags] & (TAGMASK >> 1)) {
@ -1173,6 +1241,8 @@ int32_t toggle_named_scratchpad(const Arg *arg) {
}
int32_t toggle_render_border(const Arg *arg) {
if (!selmon)
return 0;
render_border = !render_border;
arrange(selmon, false, false);
return 0;
@ -1208,6 +1278,8 @@ int32_t toggle_scratchpad(const Arg *arg) {
}
int32_t togglefakefullscreen(const Arg *arg) {
if (!selmon)
return 0;
Client *sel = focustop(selmon);
if (sel)
setfakefullscreen(sel, !sel->isfakefullscreen);
@ -1215,6 +1287,9 @@ int32_t togglefakefullscreen(const Arg *arg) {
}
int32_t togglefloating(const Arg *arg) {
if (!selmon)
return 0;
Client *sel = focustop(selmon);
if (selmon && selmon->isoverview)
@ -1236,6 +1311,9 @@ int32_t togglefloating(const Arg *arg) {
}
int32_t togglefullscreen(const Arg *arg) {
if (!selmon)
return 0;
Client *sel = focustop(selmon);
if (!sel)
return 0;
@ -1252,6 +1330,9 @@ int32_t togglefullscreen(const Arg *arg) {
}
int32_t toggleglobal(const Arg *arg) {
if (!selmon)
return 0;
if (!selmon->sel)
return 0;
if (selmon->sel->is_in_scratchpad) {
@ -1270,12 +1351,18 @@ int32_t toggleglobal(const Arg *arg) {
}
int32_t togglegaps(const Arg *arg) {
if (!selmon)
return 0;
enablegaps ^= 1;
arrange(selmon, false, false);
return 0;
}
int32_t togglemaximizescreen(const Arg *arg) {
if (!selmon)
return 0;
Client *sel = focustop(selmon);
if (!sel)
return 0;
@ -1294,6 +1381,9 @@ int32_t togglemaximizescreen(const Arg *arg) {
}
int32_t toggleoverlay(const Arg *arg) {
if (!selmon)
return 0;
if (!selmon->sel || !selmon->sel->mon || selmon->sel->isfullscreen) {
return 0;
}
@ -1315,6 +1405,9 @@ int32_t toggleoverlay(const Arg *arg) {
}
int32_t toggletag(const Arg *arg) {
if (!selmon)
return 0;
uint32_t newtags;
Client *sel = focustop(selmon);
if (!sel)
@ -1338,13 +1431,15 @@ int32_t toggletag(const Arg *arg) {
}
int32_t toggleview(const Arg *arg) {
if (!selmon)
return 0;
uint32_t newtagset;
uint32_t target;
target = arg->ui == 0 ? ~0 & TAGMASK : arg->ui;
newtagset =
selmon ? selmon->tagset[selmon->seltags] ^ (target & TAGMASK) : 0;
newtagset = selmon->tagset[selmon->seltags] ^ (target & TAGMASK);
if (newtagset) {
selmon->tagset[selmon->seltags] = newtagset;
@ -1356,6 +1451,9 @@ int32_t toggleview(const Arg *arg) {
}
int32_t viewtoleft(const Arg *arg) {
if (!selmon)
return 0;
uint32_t target = selmon->tagset[selmon->seltags];
if (selmon->isoverview || selmon->pertag->curtag == 0) {
@ -1376,6 +1474,9 @@ int32_t viewtoleft(const Arg *arg) {
}
int32_t viewtoright(const Arg *arg) {
if (!selmon)
return 0;
if (selmon->isoverview || selmon->pertag->curtag == 0) {
return 0;
}
@ -1393,6 +1494,9 @@ int32_t viewtoright(const Arg *arg) {
}
int32_t viewtoleft_have_client(const Arg *arg) {
if (!selmon)
return 0;
uint32_t n;
uint32_t current = get_tags_first_tag_num(selmon->tagset[selmon->seltags]);
bool found = false;
@ -1417,6 +1521,9 @@ int32_t viewtoleft_have_client(const Arg *arg) {
}
int32_t viewtoright_have_client(const Arg *arg) {
if (!selmon)
return 0;
uint32_t n;
uint32_t current = get_tags_first_tag_num(selmon->tagset[selmon->seltags]);
bool found = false;
@ -1441,6 +1548,9 @@ int32_t viewtoright_have_client(const Arg *arg) {
}
int32_t viewcrossmon(const Arg *arg) {
if (!selmon)
return 0;
focusmon(&(Arg){.v = arg->v, .i = UNDIR});
view_in_mon(arg, true, selmon, true);
return 0;
@ -1450,7 +1560,7 @@ int32_t tagcrossmon(const Arg *arg) {
if (!selmon || !selmon->sel)
return 0;
if (regex_match(selmon->wlr_output->name, arg->v)) {
if (match_monitor_spec(arg->v, selmon)) {
tag_client(arg, selmon->sel);
return 0;
}
@ -1519,6 +1629,8 @@ int32_t setoption(const Arg *arg) {
}
int32_t minimized(const Arg *arg) {
if (!selmon)
return 0;
if (selmon && selmon->isoverview)
return 0;
@ -1541,6 +1653,8 @@ void fix_mon_tagset_from_overview(Monitor *m) {
int32_t toggleoverview(const Arg *arg) {
Client *c = NULL;
if (!selmon)
return 0;
if (selmon->isoverview && ov_tab_mode && arg->i != 1 && selmon->sel) {
focusstack(&(Arg){.i = 1});
@ -1604,7 +1718,7 @@ int32_t disable_monitor(const Arg *arg) {
Monitor *m = NULL;
struct wlr_output_state state = {0};
wl_list_for_each(m, &mons, link) {
if (regex_match(arg->v, m->wlr_output->name)) {
if (match_monitor_spec(arg->v, m)) {
wlr_output_state_set_enabled(&state, false);
wlr_output_commit_state(m->wlr_output, &state);
m->asleep = 1;
@ -1619,7 +1733,7 @@ int32_t enable_monitor(const Arg *arg) {
Monitor *m = NULL;
struct wlr_output_state state = {0};
wl_list_for_each(m, &mons, link) {
if (regex_match(arg->v, m->wlr_output->name)) {
if (match_monitor_spec(arg->v, m)) {
wlr_output_state_set_enabled(&state, true);
wlr_output_commit_state(m->wlr_output, &state);
m->asleep = 0;
@ -1634,7 +1748,7 @@ int32_t toggle_monitor(const Arg *arg) {
Monitor *m = NULL;
struct wlr_output_state state = {0};
wl_list_for_each(m, &mons, link) {
if (regex_match(arg->v, m->wlr_output->name)) {
if (match_monitor_spec(arg->v, m)) {
wlr_output_state_set_enabled(&state, !m->wlr_output->enabled);
wlr_output_commit_state(m->wlr_output, &state);
m->asleep = !m->wlr_output->enabled;
@ -1646,6 +1760,8 @@ int32_t toggle_monitor(const Arg *arg) {
}
int32_t scroller_stack(const Arg *arg) {
if (!selmon)
return 0;
Client *c = selmon->sel;
Client *stack_head = NULL;
Client *source_stack_head = NULL;
@ -1746,4 +1862,4 @@ int32_t scroller_stack(const Arg *arg) {
arrange(selmon, false, false);
return 0;
}
}

View file

@ -77,15 +77,6 @@ Monitor *output_from_wlr_output(struct wlr_output *wlr_output) {
return NULL;
}
Monitor *output_nearest_to(int32_t lx, int32_t ly) {
double closest_x, closest_y;
wlr_output_layout_closest_point(output_layout, NULL, lx, ly, &closest_x,
&closest_y);
return output_from_wlr_output(
wlr_output_layout_output_at(output_layout, closest_x, closest_y));
}
bool output_is_usable(Monitor *m) { return m && m->wlr_output->enabled; }
static bool
@ -255,7 +246,7 @@ static void update_popup_position(struct dwl_input_method_popup *popup) {
cursor_rect = (struct wlr_box){0};
}
output = output_nearest_to(cursor_rect.x, cursor_rect.y);
output = get_monitor_nearest_to(cursor_rect.x, cursor_rect.y);
if (!output_is_usable(output)) {
return;
}

View file

@ -83,6 +83,9 @@ setclient_coordinate_center(Client *c, Monitor *tm, struct wlr_box geom,
int32_t len = 0;
Monitor *m = tm ? tm : selmon;
if (!m)
return geom;
uint32_t cbw = check_hit_no_border(c) ? c->bw : 0;
if (!c->no_force_center && m) {

View file

@ -96,3 +96,81 @@ Monitor *xytomon(double x, double y) {
struct wlr_output *o = wlr_output_layout_output_at(output_layout, x, y);
return o ? o->data : NULL;
}
Monitor *get_monitor_nearest_to(int32_t lx, int32_t ly) {
double closest_x, closest_y;
wlr_output_layout_closest_point(output_layout, NULL, lx, ly, &closest_x,
&closest_y);
return output_from_wlr_output(
wlr_output_layout_output_at(output_layout, closest_x, closest_y));
}
bool match_monitor_spec(char *spec, Monitor *m) {
if (!spec || !m)
return false;
// if the spec does not contain a colon, treat it as a match on the monitor
// name
if (strchr(spec, ':') == NULL) {
return regex_match(spec, m->wlr_output->name);
}
char *spec_copy = strdup(spec);
if (!spec_copy)
return false;
char *name_rule = NULL;
char *make_rule = NULL;
char *model_rule = NULL;
char *serial_rule = NULL;
char *token = strtok(spec_copy, "&&");
while (token) {
char *colon = strchr(token, ':');
if (colon) {
*colon = '\0';
char *key = token;
char *value = colon + 1;
if (strcmp(key, "name") == 0)
name_rule = strdup(value);
else if (strcmp(key, "make") == 0)
make_rule = strdup(value);
else if (strcmp(key, "model") == 0)
model_rule = strdup(value);
else if (strcmp(key, "serial") == 0)
serial_rule = strdup(value);
}
token = strtok(NULL, "&&");
}
bool match = true;
if (name_rule) {
if (!regex_match(name_rule, m->wlr_output->name))
match = false;
}
if (make_rule) {
if (!m->wlr_output->make || strcmp(make_rule, m->wlr_output->make) != 0)
match = false;
}
if (model_rule) {
if (!m->wlr_output->model ||
strcmp(model_rule, m->wlr_output->model) != 0)
match = false;
}
if (serial_rule) {
if (!m->wlr_output->serial ||
strcmp(serial_rule, m->wlr_output->serial) != 0)
match = false;
}
free(spec_copy);
free(name_rule);
free(make_rule);
free(model_rule);
free(serial_rule);
return match;
}

View file

@ -1,11 +1,31 @@
void save_old_size_per(Monitor *m) {
Client *c = NULL;
wl_list_for_each(c, &clients, link) {
if (VISIBLEON(c, m) && ISTILED(c)) {
c->old_master_inner_per = c->master_inner_per;
c->old_stack_inner_per = c->stack_inner_per;
}
}
}
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;
wl_list_for_each(fc, &clients, link) {
if (VISIBLEON(fc, m) && ISTILED(fc)) {
fc->old_ismaster = fc->ismaster;
}
}
c->old_master_inner_per = c->master_inner_per;
c->old_stack_inner_per = c->stack_inner_per;
pre_caculate_before_arrange(m, false, false, true);
const Layout *current_layout = m->pertag->ltidxs[m->pertag->curtag];
if (current_layout->id == SCROLLER ||
@ -15,7 +35,7 @@ void restore_size_per(Monitor *m, Client *c) {
return;
}
if (current_layout->id == CENTER_TILE || c->ismaster) {
if (current_layout->id == CENTER_TILE) {
wl_list_for_each(fc, &clients, link) {
if (VISIBLEON(fc, m) && ISTILED(fc) && !c->ismaster) {
set_size_per(m, fc);
@ -24,19 +44,36 @@ void restore_size_per(Monitor *m, Client *c) {
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;
}
}
// it is possible that the current floating window is moved to another tag,
// but the tag has not executed save_old_size_per
// so it must be judged whether their old size values are initial values
if (!c->ismaster && c->old_stack_inner_per < 1.0 &&
c->old_stack_inner_per > 0.0f && c->stack_inner_per < 1.0 &&
c->stack_inner_per > 0.0f) {
c->stack_inner_per = (1.0 - c->stack_inner_per) *
c->old_stack_inner_per /
(1.0 - c->old_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);
if (c->ismaster && c->old_master_inner_per < 1.0 &&
c->old_master_inner_per > 0.0f && c->master_inner_per < 1.0 &&
c->master_inner_per > 0.0f) {
c->master_inner_per = (1.0 - c->master_inner_per) *
c->old_master_inner_per /
(1.0 - c->old_master_inner_per);
}
wl_list_for_each(fc, &clients, link) {
if (VISIBLEON(fc, m) && ISTILED(fc) && fc != c && !fc->ismaster &&
fc->old_ismaster && fc->old_stack_inner_per < 1.0 &&
fc->old_stack_inner_per > 0.0f && fc->stack_inner_per < 1.0 &&
fc->stack_inner_per > 0.0f) {
fc->stack_inner_per = (1.0 - fc->stack_inner_per) *
fc->old_stack_inner_per /
(1.0 - fc->old_stack_inner_per);
fc->old_ismaster = false;
}
}
}
@ -52,7 +89,7 @@ void set_size_per(Monitor *m, Client *c) {
wl_list_for_each(fc, &clients, link) {
if (VISIBLEON(fc, m) && ISTILED(fc) && fc != c) {
if (current_layout->id == CENTER_TILE &&
!(fc->isleftstack ^ c->isleftstack))
(fc->isleftstack ^ c->isleftstack))
continue;
c->master_mfact_per = fc->master_mfact_per;
c->master_inner_per = fc->master_inner_per;
@ -90,8 +127,7 @@ void resize_tile_master_horizontal(Client *grabc, bool isdrag, int32_t offsetx,
break;
}
if (!begin_find_nextnext && VISIBLEON(tc, grabc->mon) &&
ISTILED(tc)) { // 根据你的实际字段名调整
if (!begin_find_nextnext && VISIBLEON(tc, grabc->mon) && ISTILED(tc)) {
next = tc;
begin_find_nextnext = true;
continue;
@ -107,8 +143,7 @@ void resize_tile_master_horizontal(Client *grabc, bool isdrag, int32_t offsetx,
break;
}
if (!begin_find_prevprev && VISIBLEON(tc, grabc->mon) &&
ISTILED(tc)) { // 根据你的实际字段名调整
if (!begin_find_prevprev && VISIBLEON(tc, grabc->mon) && ISTILED(tc)) {
prev = tc;
begin_find_prevprev = true;
continue;
@ -244,6 +279,23 @@ void resize_tile_master_horizontal(Client *grabc, bool isdrag, int32_t offsetx,
// 应用到所有平铺窗口
wl_list_for_each(tc, &clients, link) {
if (VISIBLEON(tc, grabc->mon) && ISTILED(tc)) {
if (!isdrag && tc != grabc) {
if (!tc->ismaster && new_stack_inner_per != 1.0f &&
grabc->old_stack_inner_per != 1.0f &&
(type != CENTER_TILE ||
!(grabc->isleftstack ^ tc->isleftstack)))
tc->stack_inner_per = (1 - new_stack_inner_per) /
(1 - grabc->old_stack_inner_per) *
tc->stack_inner_per;
if (tc->ismaster && new_master_inner_per != 1.0f &&
grabc->old_master_inner_per != 1.0f)
tc->master_inner_per =
(1.0f - new_master_inner_per) /
(1.0f - grabc->old_master_inner_per) *
tc->master_inner_per;
}
tc->master_mfact_per = new_master_mfact_per;
}
}
@ -276,8 +328,7 @@ void resize_tile_master_vertical(Client *grabc, bool isdrag, int32_t offsetx,
for (node = grabc->link.next; node != &clients; node = node->next) {
tc = wl_container_of(node, tc, link);
if (VISIBLEON(tc, grabc->mon) &&
ISTILED(tc)) { // 根据你的实际字段名调整
if (VISIBLEON(tc, grabc->mon) && ISTILED(tc)) {
next = tc;
break;
}
@ -287,8 +338,7 @@ void resize_tile_master_vertical(Client *grabc, bool isdrag, int32_t offsetx,
for (node = grabc->link.prev; node != &clients; node = node->prev) {
tc = wl_container_of(node, tc, link);
if (VISIBLEON(tc, grabc->mon) &&
ISTILED(tc)) { // 根据你的实际字段名调整
if (VISIBLEON(tc, grabc->mon) && ISTILED(tc)) {
prev = tc;
break;
}
@ -401,6 +451,20 @@ void resize_tile_master_vertical(Client *grabc, bool isdrag, int32_t offsetx,
// 应用到所有平铺窗口
wl_list_for_each(tc, &clients, link) {
if (VISIBLEON(tc, grabc->mon) && ISTILED(tc)) {
if (!isdrag && tc != grabc && type != CENTER_TILE) {
if (!tc->ismaster && new_stack_inner_per != 1.0f &&
grabc->old_stack_inner_per != 1.0f)
tc->stack_inner_per = (1 - new_stack_inner_per) /
(1 - grabc->old_stack_inner_per) *
tc->stack_inner_per;
if (tc->ismaster && new_master_inner_per != 1.0f &&
grabc->old_master_inner_per != 1.0f)
tc->master_inner_per =
(1.0f - new_master_inner_per) /
(1.0f - grabc->old_master_inner_per) *
tc->master_inner_per;
}
tc->master_mfact_per = new_master_mfact_per;
}
}
@ -423,6 +487,7 @@ void resize_tile_master_vertical(Client *grabc, bool isdrag, int32_t offsetx,
void resize_tile_scroller(Client *grabc, bool isdrag, int32_t offsetx,
int32_t offsety, uint32_t time, bool isvertical) {
Client *tc = NULL;
float delta_x, delta_y;
float new_scroller_proportion;
float new_stack_proportion;
@ -583,12 +648,22 @@ void resize_tile_scroller(Client *grabc, bool isdrag, int32_t offsetx,
// 应用限制,确保比例在合理范围内
new_scroller_proportion =
fmaxf(0.1f, fminf(1.0f, new_scroller_proportion));
new_stack_proportion = fmaxf(0.1f, fminf(1.0f, new_stack_proportion));
new_stack_proportion = fmaxf(0.1f, fminf(0.9f, new_stack_proportion));
grabc->stack_proportion = new_stack_proportion;
stack_head->scroller_proportion = new_scroller_proportion;
wl_list_for_each(tc, &clients, link) {
if (!isdrag && new_stack_proportion != 1.0f &&
grabc->old_stack_proportion != 1.0f && tc != grabc &&
ISTILED(tc) && get_scroll_stack_head(tc) == stack_head) {
tc->stack_proportion = (1.0f - new_stack_proportion) /
(1.0f - grabc->old_stack_proportion) *
tc->stack_proportion;
}
}
if (!isdrag) {
arrange(grabc->mon, false, false);
return;
@ -631,6 +706,18 @@ void resize_tile_client(Client *grabc, bool isdrag, int32_t offsetx,
}
}
/* If there are no calculation omissions,
these two functions will never be triggered.
Just in case to facilitate the final investigation*/
void check_size_per_valid(Client *c) {
if (c->ismaster) {
assert(c->master_inner_per > 0.0f && c->master_inner_per <= 1.0f);
} else {
assert(c->stack_inner_per > 0.0f && c->stack_inner_per <= 1.0f);
}
}
void reset_size_per_mon(Monitor *m, int32_t tile_cilent_num,
double total_left_stack_hight_percent,
double total_right_stack_hight_percent,
@ -646,6 +733,7 @@ void reset_size_per_mon(Monitor *m, int32_t tile_cilent_num,
wl_list_for_each(c, &clients, link) {
if (VISIBLEON(c, m) && ISTILED(c)) {
if (total_master_inner_percent > 0.0 && i < nmasters) {
c->ismaster = true;
c->stack_inner_per = stack_num ? 1.0f / stack_num : 1.0f;
@ -661,17 +749,20 @@ void reset_size_per_mon(Monitor *m, int32_t tile_cilent_num,
: 1.0f;
}
i++;
check_size_per_valid(c);
}
}
} else {
wl_list_for_each(c, &clients, link) {
if (VISIBLEON(c, m) && ISTILED(c)) {
if (total_master_inner_percent > 0.0 && i < nmasters) {
c->ismaster = true;
if ((stack_index % 2) ^ (tile_cilent_num % 2 == 0)) {
c->stack_inner_per =
stack_num > 1 ? 1.0f / ((stack_num - 1) / 2) : 1.0f;
stack_num > 1 ? 1.0f / ((stack_num - 1) / 2.0f)
: 1.0f;
} else {
c->stack_inner_per =
stack_num > 1 ? 2.0f / stack_num : 1.0f;
@ -700,13 +791,15 @@ void reset_size_per_mon(Monitor *m, int32_t tile_cilent_num,
}
}
i++;
check_size_per_valid(c);
}
}
}
}
void // 17
arrange(Monitor *m, bool want_animation, bool from_view) {
void pre_caculate_before_arrange(Monitor *m, bool want_animation,
bool from_view, bool only_caculate) {
Client *c = NULL;
double total_stack_inner_percent = 0;
double total_master_inner_percent = 0;
@ -795,14 +888,17 @@ arrange(Monitor *m, bool want_animation, bool from_view) {
i++;
}
set_arrange_visible(m, c, want_animation);
if (!only_caculate)
set_arrange_visible(m, c, want_animation);
} else {
set_arrange_hidden(m, c, want_animation);
if (!only_caculate)
set_arrange_hidden(m, c, want_animation);
}
}
if (c->mon == m && c->ismaximizescreen && !c->animation.tagouted &&
!c->animation.tagouting && VISIBLEON(c, m)) {
if (!only_caculate && c->mon == m && c->ismaximizescreen &&
!c->animation.tagouted && !c->animation.tagouting &&
VISIBLEON(c, m)) {
reset_maximizescreen_size(c);
}
}
@ -811,6 +907,12 @@ arrange(Monitor *m, bool want_animation, bool from_view) {
m, m->visible_tiling_clients, total_left_stack_hight_percent,
total_right_stack_hight_percent, total_stack_inner_percent,
total_master_inner_percent, master_num, stack_num);
}
void // 17
arrange(Monitor *m, bool want_animation, bool from_view) {
pre_caculate_before_arrange(m, want_animation, from_view, false);
if (m->isoverview) {
overviewlayout.arrange(m);

File diff suppressed because it is too large Load diff