Compare commits

..

No commits in common. "main" and "0.12.8" have entirely different histories.
main ... 0.12.8

6 changed files with 92 additions and 566 deletions

View file

@ -185,7 +185,7 @@ mangowm is available in the **PikaOS package repository**.
You can install it using the `pikman` package manager: You can install it using the `pikman` package manager:
```bash ```bash
pikman install mangowm pikman install mangowc
``` ```
--- ---

View file

@ -15,7 +15,7 @@
#:use-module (gnu packages ninja) #:use-module (gnu packages ninja)
#:use-module (gnu packages pkg-config) #:use-module (gnu packages pkg-config)
#:use-module (guix build-system meson) #:use-module (guix build-system meson)
#:use-module ((guix licenses) #:prefix license:)) #:use-module (guix licenses))
(define-public mangowm-git (define-public mangowm-git
@ -36,13 +36,10 @@
(add-before 'configure 'patch-meson (add-before 'configure 'patch-meson
(lambda _ (lambda _
(substitute* "meson.build" (substitute* "meson.build"
;; MangoWM ignores sysconfdir handling for NixOS.
;; We also need to skip that sysconfdir edits.
(("is_nixos = false")
"is_nixos = true")
;; Unhardcode path. Fixes loading default config.
(("'-DSYSCONFDIR=\\\"@0@\\\"'.format\\('/etc'\\)") (("'-DSYSCONFDIR=\\\"@0@\\\"'.format\\('/etc'\\)")
"'-DSYSCONFDIR=\"@0@\"'.format(sysconfdir)"))))))) "'-DSYSCONFDIR=\"@0@\"'.format(sysconfdir)")
(("sysconfdir = sysconfdir.substring\\(prefix.length\\(\\)\\)")
"")))))))
(inputs (list wayland (inputs (list wayland
libinput libinput
libdrm libdrm
@ -55,17 +52,14 @@
pcre2 pcre2
libxcb libxcb
xcb-util-wm xcb-util-wm
wlroots-0.19 wlroots
scenefx)) scenefx))
(native-inputs (list pkg-config wayland-protocols)) (native-inputs (list pkg-config wayland-protocols))
(home-page "https://github.com/mangowm/mango") (home-page "https://github.com/DreamMaoMao/mangowm")
(synopsis "Wayland compositor based on wlroots and scenefx") (synopsis "Wayland compositor based on wlroots and scenefx")
(description (description "A Wayland compositor based on wlroots and scenefx,
"MangoWM is a modern, lightweight, high-performance Wayland compositor inspired by dwl but aiming to be more feature-rich.")
built on dwl crafted for speed, flexibility, and a customizable desktop experience.") (license gpl3)))
(license (list license:gpl3 ;mangowm itself, dwl
license:expat ;dwm, sway, wlroots
license:cc0)))) ;tinywl
(define-deprecated-package mangowc (define-deprecated-package mangowc
mangowm-git) mangowm-git)

View file

@ -1,22 +1,18 @@
self: self: {
{
lib, lib,
config, config,
pkgs, pkgs,
... ...
}: }: let
let
cfg = config.wayland.windowManager.mango; cfg = config.wayland.windowManager.mango;
selflib = import ./lib.nix lib;
variables = lib.concatStringsSep " " cfg.systemd.variables; variables = lib.concatStringsSep " " cfg.systemd.variables;
extraCommands = lib.concatStringsSep " && " cfg.systemd.extraCommands; extraCommands = lib.concatStringsSep " && " cfg.systemd.extraCommands;
systemdActivation = "${pkgs.dbus}/bin/dbus-update-activation-environment --systemd ${variables}; ${extraCommands}"; systemdActivation = ''${pkgs.dbus}/bin/dbus-update-activation-environment --systemd ${variables}; ${extraCommands}'';
autostart_sh = pkgs.writeShellScript "autostart.sh" '' autostart_sh = pkgs.writeShellScript "autostart.sh" ''
${lib.optionalString cfg.systemd.enable systemdActivation} ${lib.optionalString cfg.systemd.enable systemdActivation}
${cfg.autostart_sh} ${cfg.autostart_sh}
''; '';
in in {
{
options = { options = {
wayland.windowManager.mango = with lib; { wayland.windowManager.mango = with lib; {
enable = mkOption { enable = mkOption {
@ -79,176 +75,31 @@ in
''; '';
}; };
settings = mkOption { settings = mkOption {
type = description = "mango config content";
with lib.types;
let
valueType =
nullOr (oneOf [
bool
int
float
str
path
(attrsOf valueType)
(listOf valueType)
])
// {
description = "Mango configuration value";
};
in
valueType;
default = { };
description = ''
Mango configuration written in Nix. Entries with the same key
should be written as lists. Variables and colors names should be
quoted. See <https://mangowc.vercel.app/docs> for more examples.
::: {.note}
This option uses a structured format that is converted to Mango's
configuration syntax. Nested attributes are flattened with underscore separators.
For example: `animation.duration_open = 400` becomes `animation_duration_open = 400`
Keymodes (submaps) are supported via the special `keymode` attribute. Each keymode
is a nested attribute set under `keymode` that contains its own bindings.
:::
'';
example = lib.literalExpression ''
{
# Window effects
blur = 1;
blur_optimized = 1;
blur_params = {
radius = 5;
num_passes = 2;
};
border_radius = 6;
focused_opacity = 1.0;
# Animations - use underscores for multi-part keys
animations = 1;
animation_type_open = "slide";
animation_type_close = "slide";
animation_duration_open = 400;
animation_duration_close = 800;
# Or use nested attrs (will be flattened with underscores)
animation_curve = {
open = "0.46,1.0,0.29,1";
close = "0.08,0.92,0,1";
};
# Use lists for duplicate keys like bind and tagrule
bind = [
"SUPER,r,reload_config"
"Alt,space,spawn,rofi -show drun"
"Alt,Return,spawn,foot"
"ALT,R,setkeymode,resize" # Enter resize mode
];
tagrule = [
"id:1,layout_name:tile"
"id:2,layout_name:scroller"
];
# Keymodes (submaps) for modal keybindings
keymode = {
resize = {
bind = [
"NONE,Left,resizewin,-10,0"
"NONE,Escape,setkeymode,default"
];
};
};
}
'';
};
extraConfig = mkOption {
type = types.lines; type = types.lines;
default = ""; default = "";
description = ''
Extra configuration lines to add to `~/.config/mango/config.conf`.
This is useful for advanced configurations that don't fit the structured
settings format, or for options that aren't yet supported by the module.
'';
example = '' example = ''
# Advanced config that doesn't fit structured format # menu and terminal
special_option = 1 bind=Alt,space,spawn,rofi -show drun
bind=Alt,Return,spawn,foot
''; '';
}; };
topPrefixes = mkOption {
type = with lib.types; listOf str;
default = [ ];
description = ''
List of prefixes for attributes that should appear at the top of the config file.
Attributes starting with these prefixes will be sorted to the beginning.
'';
example = [ "source" ];
};
bottomPrefixes = mkOption {
type = with lib.types; listOf str;
default = [ ];
description = ''
List of prefixes for attributes that should appear at the bottom of the config file.
Attributes starting with these prefixes will be sorted to the end.
'';
example = [ "source" ];
};
autostart_sh = mkOption { autostart_sh = mkOption {
description = '' description = "WARRNING: This is a shell script, but no need to add shebang";
Shell script to run on mango startup. No shebang needed.
When this option is set, the script will be written to
`~/.config/mango/autostart.sh` and an `exec-once` line
will be automatically added to the config to execute it.
'';
type = types.lines; type = types.lines;
default = ""; default = "";
example = '' example = ''
waybar & waybar &
dunst &
''; '';
}; };
}; };
}; };
config = lib.mkIf cfg.enable ( config = lib.mkIf cfg.enable {
let
finalConfigText =
# Support old string-based config during transition period
(
if builtins.isString cfg.settings then
cfg.settings
else
lib.optionalString (cfg.settings != { }) (
selflib.toMango {
topCommandsPrefixes = cfg.topPrefixes;
bottomCommandsPrefixes = cfg.bottomPrefixes;
} cfg.settings
)
)
+ lib.optionalString (cfg.extraConfig != "") cfg.extraConfig
+ lib.optionalString (cfg.autostart_sh != "") "\nexec-once=~/.config/mango/autostart.sh\n";
validatedConfig = pkgs.runCommand "mango-config.conf" { } ''
cp ${pkgs.writeText "mango-config.conf" finalConfigText} "$out"
${cfg.package}/bin/mango -c "$out" -p || exit 1
'';
in
{
# Backwards compatibility warning for old string-based config
warnings = lib.optional (builtins.isString cfg.settings) ''
wayland.windowManager.mango.settings: Using a string for settings is deprecated.
Please migrate to the new structured attribute set format.
See the module documentation for examples, or use the 'extraConfig' option for raw config strings.
The old string format will be removed in a future release.
'';
home.packages = [cfg.package]; home.packages = [cfg.package];
xdg.configFile = { xdg.configFile = {
"mango/config.conf" = "mango/config.conf" = lib.mkIf (cfg.settings != "") {
lib.mkIf (cfg.settings != { } || cfg.extraConfig != "" || cfg.autostart_sh != "") text = cfg.settings;
{
source = validatedConfig;
}; };
"mango/autostart.sh" = lib.mkIf (cfg.autostart_sh != "") { "mango/autostart.sh" = lib.mkIf (cfg.autostart_sh != "") {
source = autostart_sh; source = autostart_sh;
@ -260,7 +111,8 @@ in
Description = "mango compositor session"; Description = "mango compositor session";
Documentation = ["man:systemd.special(7)"]; Documentation = ["man:systemd.special(7)"];
BindsTo = ["graphical-session.target"]; BindsTo = ["graphical-session.target"];
Wants = [ Wants =
[
"graphical-session-pre.target" "graphical-session-pre.target"
] ]
++ lib.optional cfg.systemd.xdgAutostart "xdg-desktop-autostart.target"; ++ lib.optional cfg.systemd.xdgAutostart "xdg-desktop-autostart.target";
@ -268,6 +120,5 @@ in
Before = lib.optional cfg.systemd.xdgAutostart "xdg-desktop-autostart.target"; Before = lib.optional cfg.systemd.xdgAutostart "xdg-desktop-autostart.target";
}; };
}; };
} };
);
} }

View file

@ -1,312 +0,0 @@
lib:
let
inherit (lib)
attrNames
filterAttrs
foldl
generators
partition
removeAttrs
;
inherit (lib.strings)
concatMapStrings
hasPrefix
;
/**
Convert a structured Nix attribute set into Mango's configuration format.
This function takes a nested attribute set and converts it into Mango-compatible
configuration syntax, supporting top, bottom, and regular command sections.
Commands are flattened using the `flattenAttrs` function, and attributes are formatted as
`key = value` pairs. Lists are expanded as duplicate keys to match Mango's expected format.
Configuration:
* `topCommandsPrefixes` - A list of prefixes to define **top** commands (default: `[]`).
* `bottomCommandsPrefixes` - A list of prefixes to define **bottom** commands (default: `[]`).
Attention:
- The function ensures top commands appear **first** and bottom commands **last**.
- The generated configuration is a **single string**, suitable for writing to a config file.
- Lists are converted into multiple entries, ensuring compatibility with Mango.
# Inputs
Structured function argument:
: topCommandsPrefixes (optional, default: `[]`)
: A list of prefixes that define **top** commands. Any key starting with one of these
prefixes will be placed at the beginning of the configuration.
: bottomCommandsPrefixes (optional, default: `[]`)
: A list of prefixes that define **bottom** commands. Any key starting with one of these
prefixes will be placed at the end of the configuration.
Value:
: The attribute set to be converted to Hyprland configuration format.
# Type
```
toMango :: AttrSet -> AttrSet -> String
```
# Examples
:::{.example}
## Basic mangowc configuration
```nix
let
config = {
blur = 1;
blur_params_radius = 5;
border_radius = 6;
animations = 1;
animation_duration_open = 400;
};
in lib.toMango {} config
```
**Output:**
```
animations = 1
animation_duration_open = 400
blur = 1
blur_params_radius = 5
border_radius = 6
```
## Using nested attributes
```nix
let
config = {
blur = 1;
blur_params = {
radius = 5;
num_passes = 2;
noise = 0.02;
};
animation_curve = {
open = "0.46,1.0,0.29,1";
close = "0.08,0.92,0,1";
};
};
in lib.toMango {} config
```
**Output:**
```
animation_curve_close = 0.08,0.92,0,1
animation_curve_open = 0.46,1.0,0.29,1
blur = 1
blur_params_noise = 0.02
blur_params_num_passes = 2
blur_params_radius = 5
```
## Using lists for duplicate keys
```nix
let
config = {
bind = [
"SUPER,r,reload_config"
"Alt,space,spawn,rofi -show drun"
"Alt,Return,spawn,foot"
];
tagrule = [
"id:1,layout_name:tile"
"id:2,layout_name:scroller"
];
};
in lib.toMango {} config
```
**Output:**
```
bind = SUPER,r,reload_config
bind = Alt,space,spawn,rofi -show drun
bind = Alt,Return,spawn,foot
tagrule = id:1,layout_name:tile
tagrule = id:2,layout_name:scroller
```
## Using keymodes (submaps)
```nix
let
config = {
bind = [
"SUPER,Q,killclient"
"ALT,R,setkeymode,resize"
];
keymode = {
resize = {
bind = [
"NONE,Left,resizewin,-10,0"
"NONE,Right,resizewin,10,0"
"NONE,Escape,setkeymode,default"
];
};
};
};
in lib.toMango {} config
```
**Output:**
```
bind = SUPER,Q,killclient
bind = ALT,R,setkeymode,resize
keymode = resize
bind = NONE,Left,resizewin,-10,0
bind = NONE,Right,resizewin,10,0
bind = NONE,Escape,setkeymode,default
```
:::
*/
toMango =
{
topCommandsPrefixes ? [ ],
bottomCommandsPrefixes ? [ ],
}:
attrs:
let
toMango' =
attrs:
let
# Specially configured `toKeyValue` generator with support for duplicate keys
# and a legible key-value separator.
mkCommands = generators.toKeyValue {
mkKeyValue = generators.mkKeyValueDefault { } " = ";
listsAsDuplicateKeys = true;
indent = ""; # No indent, since we don't have nesting
};
# Extract keymode definitions if they exist
keymodes = attrs.keymode or { };
attrsWithoutKeymodes = removeAttrs attrs [ "keymode" ];
# Generate keymode blocks
# Format: keymode=name\nbind=...\nbind=...\n
mkKeymodeBlock =
name: modeAttrs:
let
modeCommands = flattenAttrs (p: k: "${p}_${k}") modeAttrs;
in
"keymode = ${name}\n${mkCommands modeCommands}";
keymodeBlocks =
if keymodes == { } then
""
else
"\n" + concatMapStrings (name: mkKeymodeBlock name keymodes.${name} + "\n") (attrNames keymodes);
# Flatten the attrset, combining keys in a "path" like `"a_b_c" = "x"`.
# Uses `flattenAttrs` with an underscore separator.
commands = flattenAttrs (p: k: "${p}_${k}") attrsWithoutKeymodes;
# General filtering function to check if a key starts with any prefix in a given list.
filterCommands = list: n: foldl (acc: prefix: acc || hasPrefix prefix n) false list;
# Partition keys into top commands and the rest
result = partition (filterCommands topCommandsPrefixes) (attrNames commands);
topCommands = filterAttrs (n: _: builtins.elem n result.right) commands;
remainingCommands = removeAttrs commands result.right;
# Partition remaining commands into bottom commands and regular commands
result2 = partition (filterCommands bottomCommandsPrefixes) result.wrong;
bottomCommands = filterAttrs (n: _: builtins.elem n result2.right) remainingCommands;
regularCommands = removeAttrs remainingCommands result2.right;
in
# Concatenate strings from mapping `mkCommands` over top, regular, and bottom commands.
# Keymodes are appended at the end.
concatMapStrings mkCommands [
topCommands
regularCommands
bottomCommands
]
+ keymodeBlocks;
in
toMango' attrs;
/**
Flatten a nested attribute set into a flat attribute set, using a custom key separator function.
This function recursively traverses a nested attribute set and produces a flat attribute set
where keys are joined using a user-defined function (`pred`). It allows transforming deeply
nested structures into a single-level attribute set while preserving key-value relationships.
Configuration:
* `pred` - A function `(string -> string -> string)` defining how keys should be concatenated.
# Inputs
Structured function argument:
: pred (required)
: A function that determines how parent and child keys should be combined into a single key.
It takes a `prefix` (parent key) and `key` (current key) and returns the joined key.
Value:
: The nested attribute set to be flattened.
# Type
```
flattenAttrs :: (String -> String -> String) -> AttrSet -> AttrSet
```
# Examples
:::{.example}
```nix
let
nested = {
a = "3";
b = { c = "4"; d = "5"; };
};
separator = (prefix: key: "${prefix}.${key}"); # Use dot notation
in lib.flattenAttrs separator nested
```
**Output:**
```nix
{
"a" = "3";
"b.c" = "4";
"b.d" = "5";
}
```
:::
*/
flattenAttrs =
pred: attrs:
let
flattenAttrs' =
prefix: attrs:
builtins.foldl' (
acc: key:
let
value = attrs.${key};
newKey = if prefix == "" then key else pred prefix key;
in
acc // (if builtins.isAttrs value then flattenAttrs' newKey value else { "${newKey}" = value; })
) { } (builtins.attrNames attrs);
in
flattenAttrs' "" attrs;
in
{
inherit flattenAttrs toMango;
}

View file

@ -552,7 +552,7 @@ int32_t restore_minimized(const Arg *arg) {
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) {
client_pending_minimized_state(selmon->sel, 0); selmon->sel->isminimized = 0;
selmon->sel->is_scratchpad_show = 0; selmon->sel->is_scratchpad_show = 0;
selmon->sel->is_in_scratchpad = 0; selmon->sel->is_in_scratchpad = 0;
selmon->sel->isnamedscratchpad = 0; selmon->sel->isnamedscratchpad = 0;
@ -863,6 +863,7 @@ int32_t spawn_shell(const Arg *arg) {
} }
int32_t spawn(const Arg *arg) { int32_t spawn(const Arg *arg) {
if (!arg->v) if (!arg->v)
return 0; return 0;
@ -875,21 +876,28 @@ int32_t spawn(const Arg *arg) {
dup2(STDERR_FILENO, STDOUT_FILENO); dup2(STDERR_FILENO, STDOUT_FILENO);
setsid(); setsid();
// 2. 对整个参数字符串进行单词展开 // 2. 解析参数
char *argv[64];
int32_t argc = 0;
char *token = strtok((char *)arg->v, " ");
while (token != NULL && argc < 63) {
wordexp_t p; wordexp_t p;
if (wordexp(arg->v, &p, 0) != 0) { if (wordexp(token, &p, 0) == 0) {
wlr_log(WLR_DEBUG, "mango: wordexp failed for '%s'\n", arg->v); argv[argc++] = p.we_wordv[0];
_exit(EXIT_FAILURE); } else {
argv[argc++] = token;
} }
token = strtok(NULL, " ");
}
argv[argc] = NULL;
// 3. 执行命令p.we_wordv 已经是 argv 数组) // 3. 执行命令
execvp(p.we_wordv[0], p.we_wordv); execvp(argv[0], argv);
// 4. execvp 失败时:打印错误,释放 wordexp 资源,然后退出 // 4. execvp 失败时:打印错误并直接退出(避免 coredump
wlr_log(WLR_DEBUG, "mango: execvp '%s' failed: %s\n", p.we_wordv[0], wlr_log(WLR_DEBUG, "mango: execvp '%s' failed: %s\n", argv[0],
strerror(errno)); strerror(errno));
wordfree(&p); // 释放 wordexp 分配的内存 _exit(EXIT_FAILURE); // 使用 _exit 避免缓冲区刷新等操作
_exit(EXIT_FAILURE);
} }
return 0; return 0;
} }

View file

@ -806,10 +806,6 @@ static int32_t keep_idle_inhibit(void *data);
static void check_keep_idle_inhibit(Client *c); static void check_keep_idle_inhibit(Client *c);
static void pre_caculate_before_arrange(Monitor *m, bool want_animation, static void pre_caculate_before_arrange(Monitor *m, bool want_animation,
bool from_view, bool only_caculate); bool from_view, bool only_caculate);
static void client_pending_fullscreen_state(Client *c, int32_t isfullscreen);
static void client_pending_maximized_state(Client *c, int32_t ismaximized);
static void client_pending_minimized_state(Client *c, int32_t isminimized);
#include "data/static_keymap.h" #include "data/static_keymap.h"
#include "dispatch/bind_declare.h" #include "dispatch/bind_declare.h"
#include "layout/layout.h" #include "layout/layout.h"
@ -1067,33 +1063,11 @@ void clear_fullscreen_flag(Client *c) {
} }
} }
void client_pending_fullscreen_state(Client *c, int32_t isfullscreen) {
c->isfullscreen = isfullscreen;
if (c->foreign_toplevel && !c->iskilling)
wlr_foreign_toplevel_handle_v1_set_fullscreen(c->foreign_toplevel,
isfullscreen);
}
void client_pending_maximized_state(Client *c, int32_t ismaximized) {
c->ismaximizescreen = ismaximized;
if (c->foreign_toplevel && !c->iskilling)
wlr_foreign_toplevel_handle_v1_set_maximized(c->foreign_toplevel,
ismaximized);
}
void client_pending_minimized_state(Client *c, int32_t isminimized) {
c->isminimized = isminimized;
if (c->foreign_toplevel && !c->iskilling)
wlr_foreign_toplevel_handle_v1_set_minimized(c->foreign_toplevel,
isminimized);
}
void show_scratchpad(Client *c) { void show_scratchpad(Client *c) {
c->is_scratchpad_show = 1; c->is_scratchpad_show = 1;
if (c->isfullscreen || c->ismaximizescreen) { if (c->isfullscreen || c->ismaximizescreen) {
client_pending_fullscreen_state(c, 0); c->isfullscreen = 0; // 清除窗口全屏标志
client_pending_maximized_state(c, 0); c->ismaximizescreen = 0;
c->bw = c->isnoborder ? 0 : config.borderpx; c->bw = c->isnoborder ? 0 : config.borderpx;
} }
@ -1132,6 +1106,9 @@ void swallow(Client *c, Client *w) {
c->bw = w->bw; c->bw = w->bw;
c->isfloating = w->isfloating; c->isfloating = w->isfloating;
c->isurgent = w->isurgent; c->isurgent = w->isurgent;
c->isfullscreen = w->isfullscreen;
c->ismaximizescreen = w->ismaximizescreen;
c->isminimized = w->isminimized;
c->is_in_scratchpad = w->is_in_scratchpad; c->is_in_scratchpad = w->is_in_scratchpad;
c->is_scratchpad_show = w->is_scratchpad_show; c->is_scratchpad_show = w->is_scratchpad_show;
c->tags = w->tags; c->tags = w->tags;
@ -1143,7 +1120,6 @@ void swallow(Client *c, Client *w) {
c->scroller_proportion = w->scroller_proportion; c->scroller_proportion = w->scroller_proportion;
c->next_in_stack = w->next_in_stack; c->next_in_stack = w->next_in_stack;
c->prev_in_stack = w->prev_in_stack; c->prev_in_stack = w->prev_in_stack;
if (w->next_in_stack) if (w->next_in_stack)
w->next_in_stack->prev_in_stack = c; w->next_in_stack->prev_in_stack = c;
if (w->prev_in_stack) if (w->prev_in_stack)
@ -1162,9 +1138,11 @@ void swallow(Client *c, Client *w) {
if (!c->foreign_toplevel && c->mon) if (!c->foreign_toplevel && c->mon)
add_foreign_toplevel(c); add_foreign_toplevel(c);
client_pending_fullscreen_state(c, w->isfullscreen); if (c->isminimized && c->foreign_toplevel) {
client_pending_maximized_state(c, w->ismaximizescreen); wlr_foreign_toplevel_handle_v1_set_activated(c->foreign_toplevel,
client_pending_minimized_state(c, w->isminimized); false);
wlr_foreign_toplevel_handle_v1_set_minimized(c->foreign_toplevel, true);
}
} }
bool switch_scratchpad_client_state(Client *c) { bool switch_scratchpad_client_state(Client *c) {
@ -4253,7 +4231,7 @@ void maximizenotify(struct wl_listener *listener, void *data) {
void unminimize(Client *c) { void unminimize(Client *c) {
if (c && c->is_in_scratchpad && c->is_scratchpad_show) { if (c && c->is_in_scratchpad && c->is_scratchpad_show) {
client_pending_minimized_state(c, 0); c->isminimized = 0;
c->is_scratchpad_show = 0; c->is_scratchpad_show = 0;
c->is_in_scratchpad = 0; c->is_in_scratchpad = 0;
c->isnamedscratchpad = 0; c->isnamedscratchpad = 0;
@ -4281,12 +4259,13 @@ void set_minimized(Client *c) {
c->oldtags = c->mon->tagset[c->mon->seltags]; c->oldtags = c->mon->tagset[c->mon->seltags];
c->mini_restore_tag = c->tags; c->mini_restore_tag = c->tags;
c->tags = 0; c->tags = 0;
client_pending_minimized_state(c, 1); c->isminimized = 1;
c->is_in_scratchpad = 1; c->is_in_scratchpad = 1;
c->is_scratchpad_show = 0; c->is_scratchpad_show = 0;
focusclient(focustop(selmon), 1); focusclient(focustop(selmon), 1);
arrange(c->mon, false, false); arrange(c->mon, false, false);
wlr_foreign_toplevel_handle_v1_set_activated(c->foreign_toplevel, false); wlr_foreign_toplevel_handle_v1_set_activated(c->foreign_toplevel, false);
wlr_foreign_toplevel_handle_v1_set_minimized(c->foreign_toplevel, true);
wl_list_remove(&c->link); // 从原来位置移除 wl_list_remove(&c->link); // 从原来位置移除
wl_list_insert(clients.prev, &c->link); // 插入尾部 wl_list_insert(clients.prev, &c->link); // 插入尾部
} }
@ -5063,11 +5042,11 @@ setfloating(Client *c, int32_t floating) {
if (floating == 1 && c != grabc) { if (floating == 1 && c != grabc) {
if (c->isfullscreen) { if (c->isfullscreen) {
client_pending_fullscreen_state(c, 0); c->isfullscreen = 0;
client_set_fullscreen(c, 0); client_set_fullscreen(c, 0);
} }
client_pending_maximized_state(c, 0); c->ismaximizescreen = 0;
exit_scroller_stack(c); exit_scroller_stack(c);
// 重新计算居中的坐标 // 重新计算居中的坐标
@ -5192,12 +5171,12 @@ void setmaximizescreen(Client *c, int32_t maximizescreen) {
return; return;
int32_t old_maximizescreen_state = c->ismaximizescreen; int32_t old_maximizescreen_state = c->ismaximizescreen;
client_pending_maximized_state(c, maximizescreen); c->ismaximizescreen = maximizescreen;
if (maximizescreen) { if (maximizescreen) {
if (c->isfullscreen) { if (c->isfullscreen) {
client_pending_fullscreen_state(c, 0); c->isfullscreen = 0;
client_set_fullscreen(c, 0); client_set_fullscreen(c, 0);
} }
@ -5210,8 +5189,10 @@ void setmaximizescreen(Client *c, int32_t maximizescreen) {
wlr_scene_node_raise_to_top(&c->scene->node); wlr_scene_node_raise_to_top(&c->scene->node);
if (!is_scroller_layout(c->mon) || c->isfloating) if (!is_scroller_layout(c->mon) || c->isfloating)
resize(c, maximizescreen_box, 0); resize(c, maximizescreen_box, 0);
c->ismaximizescreen = 1;
} else { } else {
c->bw = c->isnoborder ? 0 : config.borderpx; c->bw = c->isnoborder ? 0 : config.borderpx;
c->ismaximizescreen = 0;
if (c->isfloating) if (c->isfloating)
setfloating(c, 1); setfloating(c, 1);
} }
@ -5259,7 +5240,6 @@ void setfullscreen(Client *c, int32_t fullscreen) // 用自定义全屏代理自
c->isfullscreen = fullscreen; c->isfullscreen = fullscreen;
client_set_fullscreen(c, fullscreen); client_set_fullscreen(c, fullscreen);
client_pending_fullscreen_state(c, fullscreen);
if (fullscreen) { if (fullscreen) {
@ -5267,7 +5247,7 @@ void setfullscreen(Client *c, int32_t fullscreen) // 用自定义全屏代理自
client_set_maximized(c, false); client_set_maximized(c, false);
} }
client_pending_maximized_state(c, 0); c->ismaximizescreen = 0;
exit_scroller_stack(c); exit_scroller_stack(c);
c->isfakefullscreen = 0; c->isfakefullscreen = 0;
@ -5276,8 +5256,10 @@ void setfullscreen(Client *c, int32_t fullscreen) // 用自定义全屏代理自
wlr_scene_node_raise_to_top(&c->scene->node); // 将视图提升到顶层 wlr_scene_node_raise_to_top(&c->scene->node); // 将视图提升到顶层
if (!is_scroller_layout(c->mon) || c->isfloating) if (!is_scroller_layout(c->mon) || c->isfloating)
resize(c, c->mon->m, 1); resize(c, c->mon->m, 1);
c->isfullscreen = 1;
} else { } else {
c->bw = c->isnoborder ? 0 : config.borderpx; c->bw = c->isnoborder ? 0 : config.borderpx;
c->isfullscreen = 0;
if (c->isfloating) if (c->isfloating)
setfloating(c, 1); setfloating(c, 1);
} }
@ -5469,7 +5451,8 @@ void show_hide_client(Client *c) {
c->tags = c->oldtags; c->tags = c->oldtags;
arrange(c->mon, false, false); arrange(c->mon, false, false);
} }
client_pending_minimized_state(c, 0); c->isminimized = 0;
wlr_foreign_toplevel_handle_v1_set_minimized(c->foreign_toplevel, false);
focusclient(c, 1); focusclient(c, 1);
wlr_foreign_toplevel_handle_v1_set_activated(c->foreign_toplevel, true); wlr_foreign_toplevel_handle_v1_set_activated(c->foreign_toplevel, true);
} }
@ -5893,8 +5876,8 @@ void overview_backup(Client *c) {
c->isfloating = 0; c->isfloating = 0;
} }
if (c->isfullscreen || c->ismaximizescreen) { if (c->isfullscreen || c->ismaximizescreen) {
client_pending_fullscreen_state(c, 0); // 清除窗口全屏标志 c->isfullscreen = 0; // 清除窗口全屏标志
client_pending_maximized_state(c, 0); c->ismaximizescreen = 0;
} }
c->bw = c->isnoborder ? 0 : config.borderpx; c->bw = c->isnoborder ? 0 : config.borderpx;
@ -5924,8 +5907,8 @@ void overview_restore(Client *c, const Arg *arg) {
} else if (want_restore_fullscreen(c) && c->isfullscreen) { } else if (want_restore_fullscreen(c) && c->isfullscreen) {
setfullscreen(c, 1); setfullscreen(c, 1);
} else { } else {
client_pending_fullscreen_state(c, 0); c->isfullscreen = 0;
client_pending_maximized_state(c, 0); c->ismaximizescreen = 0;
setfullscreen(c, false); setfullscreen(c, false);
} }
} else { } else {
@ -6498,11 +6481,13 @@ void activatex11(struct wl_listener *listener, void *data) {
return; return;
if (c->isminimized) { if (c->isminimized) {
client_pending_minimized_state(c, 0); c->isminimized = 0;
c->tags = c->mini_restore_tag; c->tags = c->mini_restore_tag;
c->is_scratchpad_show = 0; c->is_scratchpad_show = 0;
c->is_in_scratchpad = 0; c->is_in_scratchpad = 0;
c->isnamedscratchpad = 0; c->isnamedscratchpad = 0;
wlr_foreign_toplevel_handle_v1_set_minimized(c->foreign_toplevel,
false);
setborder_color(c); setborder_color(c);
if (VISIBLEON(c, c->mon)) { if (VISIBLEON(c, c->mon)) {
need_arrange = true; need_arrange = true;