mirror of
https://github.com/DreamMaoMao/maomaowm.git
synced 2026-04-05 07:15:49 -04:00
Compare commits
38 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e3a0d54b9a | ||
|
|
c44d12314c | ||
|
|
bb0160d7cf | ||
|
|
a8afc0dc4d | ||
|
|
b63e93fc09 | ||
|
|
c7c41c3103 | ||
|
|
52676492fe | ||
|
|
254eb8a4d4 | ||
|
|
c89f8147f9 | ||
|
|
bccdb651bd | ||
|
|
f94ddc671e | ||
|
|
b55de28749 | ||
|
|
63256ea31b | ||
|
|
91e10b239f | ||
|
|
958a6d8768 | ||
|
|
4ccd56ad01 | ||
|
|
585e9ae4b6 | ||
|
|
d69682aef9 | ||
|
|
e6429f8733 | ||
|
|
d967153c73 | ||
|
|
064bcad6f7 | ||
|
|
0232dcda82 | ||
|
|
225fbda574 | ||
|
|
ccefa572e1 | ||
|
|
c55e069364 | ||
|
|
ab6e8a6545 | ||
|
|
deb47e8ab9 | ||
|
|
ca665cc6f8 | ||
|
|
c776356efe | ||
|
|
6eb3378c0c | ||
|
|
c2559f6c7c | ||
|
|
949063804a | ||
|
|
17c037171a | ||
|
|
6c81384c53 | ||
|
|
833d8a2ef1 | ||
|
|
17434d6262 | ||
|
|
6c88999ada | ||
|
|
47b5c9aa2e |
20 changed files with 729 additions and 143 deletions
|
|
@ -137,7 +137,7 @@ And then rebuild your system.
|
||||||
## Other
|
## Other
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone -b 0.19.2 https://gitlab.freedesktop.org/wlroots/wlroots.git
|
git clone -b 0.19.3 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
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ animation_type_close=slide
|
||||||
animation_fade_in=1
|
animation_fade_in=1
|
||||||
animation_fade_out=1
|
animation_fade_out=1
|
||||||
tag_animation_direction=1
|
tag_animation_direction=1
|
||||||
zoom_initial_ratio=0.3
|
zoom_initial_ratio=0.4
|
||||||
zoom_end_ratio=0.8
|
zoom_end_ratio=0.8
|
||||||
fadein_begin_opacity=0.5
|
fadein_begin_opacity=0.5
|
||||||
fadeout_begin_opacity=0.8
|
fadeout_begin_opacity=0.8
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,7 @@ bindr=Super,Super_L,spawn,rofi -show run
|
||||||
| :--- | :--- | :--- |
|
| :--- | :--- | :--- |
|
||||||
| `killclient` | - | Close the focused window. |
|
| `killclient` | - | Close the focused window. |
|
||||||
| `togglefloating` | - | Toggle floating state. |
|
| `togglefloating` | - | Toggle floating state. |
|
||||||
|
| `toggle_all_floating` | - | Toggle all visible clients floating state. |
|
||||||
| `togglefullscreen` | - | Toggle fullscreen. |
|
| `togglefullscreen` | - | Toggle fullscreen. |
|
||||||
| `togglefakefullscreen` | - | Toggle "fake" fullscreen (remains constrained). |
|
| `togglefakefullscreen` | - | Toggle "fake" fullscreen (remains constrained). |
|
||||||
| `togglemaximizescreen` | - | Maximize window (keep decoration/bar). |
|
| `togglemaximizescreen` | - | Maximize window (keep decoration/bar). |
|
||||||
|
|
@ -194,6 +195,16 @@ bind=NONE,XF86AudioMute,spawn,wpctl set-mute @DEFAULT_SINK@ toggle
|
||||||
bind=SHIFT,XF86AudioMute,spawn,wpctl set-mute @DEFAULT_SOURCE@ toggle
|
bind=SHIFT,XF86AudioMute,spawn,wpctl set-mute @DEFAULT_SOURCE@ toggle
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Playback
|
||||||
|
|
||||||
|
Requires: `playerctl`
|
||||||
|
|
||||||
|
```ini
|
||||||
|
bind=NONE,XF86AudioNext,spawn,playerctl next
|
||||||
|
bind=NONE,XF86AudioPrev,spawn,playerctl previous
|
||||||
|
bind=NONE,XF86AudioPlay,spawn,playerctl play-pause
|
||||||
|
```
|
||||||
|
|
||||||
### Floating Window Movement
|
### Floating Window Movement
|
||||||
|
|
||||||
| Command | Param | Description |
|
| Command | Param | Description |
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ Specific settings for laptop touchpads. Some settings may require a relogin to t
|
||||||
| `tap_to_click` | `1` | Tap to trigger a left click. |
|
| `tap_to_click` | `1` | Tap to trigger a left click. |
|
||||||
| `tap_and_drag` | `1` | Tap and hold to drag items. |
|
| `tap_and_drag` | `1` | Tap and hold to drag items. |
|
||||||
| `trackpad_natural_scrolling` | `0` | Invert scrolling direction (natural scrolling). |
|
| `trackpad_natural_scrolling` | `0` | Invert scrolling direction (natural scrolling). |
|
||||||
|
| `scroll_button` | `274` | The mouse button that use for scrolling(272 to 279).
|
||||||
| `scroll_method` | `1` | `1` (Two-finger), `2` (Edge), `4` (Button). |
|
| `scroll_method` | `1` | `1` (Two-finger), `2` (Edge), `4` (Button). |
|
||||||
| `click_method` | `1` | `1` (Button areas), `2` (Clickfinger). |
|
| `click_method` | `1` | `1` (Button areas), `2` (Clickfinger). |
|
||||||
| `drag_lock` | `1` | Lock dragging after tapping. |
|
| `drag_lock` | `1` | Lock dragging after tapping. |
|
||||||
|
|
@ -57,6 +58,16 @@ Specific settings for laptop touchpads. Some settings may require a relogin to t
|
||||||
|
|
||||||
**Detailed descriptions:**
|
**Detailed descriptions:**
|
||||||
|
|
||||||
|
- `scroll_button` values:
|
||||||
|
- `272` — Left button.
|
||||||
|
- `273` — Right button.
|
||||||
|
- `274` — Middle button.
|
||||||
|
- `275` — Side button.
|
||||||
|
- `276` — Extra button.
|
||||||
|
- `277` — Forward button.
|
||||||
|
- `278` — Back button.
|
||||||
|
- `279` — Task button.
|
||||||
|
|
||||||
- `scroll_method` values:
|
- `scroll_method` values:
|
||||||
- `0` — Never send scroll events (no scrolling).
|
- `0` — Never send scroll events (no scrolling).
|
||||||
- `1` — Two-finger scrolling: send scroll events when two fingers are logically down on the device.
|
- `1` — Two-finger scrolling: send scroll events when two fingers are logically down on the device.
|
||||||
|
|
|
||||||
|
|
@ -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 mangowc
|
pikman install mangowm
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -214,7 +214,7 @@ You will need to build `wlroots` and `scenefx` manually as well.
|
||||||
1. **Build wlroots**
|
1. **Build wlroots**
|
||||||
Clone and install the specific version required (check README for latest version).
|
Clone and install the specific version required (check README for latest version).
|
||||||
```bash
|
```bash
|
||||||
git clone -b 0.19.2 https://gitlab.freedesktop.org/wlroots/wlroots.git
|
git clone -b 0.19.3 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
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ fadeout_begin_opacity=0.5
|
||||||
Adjust the zoom ratios for zoom animations.
|
Adjust the zoom ratios for zoom animations.
|
||||||
|
|
||||||
```ini
|
```ini
|
||||||
zoom_initial_ratio=0.3
|
zoom_initial_ratio=0.4
|
||||||
zoom_end_ratio=0.8
|
zoom_end_ratio=0.8
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ windowrule=Parameter:Values,Parameter:Values,appid:Values,title:Values
|
||||||
| `isoverlay` | integer | `0` / `1` | Make it always in top layer |
|
| `isoverlay` | integer | `0` / `1` | Make it always in top layer |
|
||||||
| `isopensilent` | integer | `0` / `1` | Open without focus |
|
| `isopensilent` | integer | `0` / `1` | Open without focus |
|
||||||
| `istagsilent` | integer | `0` / `1` | Don't focus if client is not in current view tag |
|
| `istagsilent` | integer | `0` / `1` | Don't focus if client is not in current view tag |
|
||||||
| `force_maximize` | integer | `0` / `1` (default 1) | The state of client default to maximized |
|
| `force_fakemaximize` | integer | `0` / `1` (default 1) | The state of client set to fake maximized |
|
||||||
| `ignore_maximize` | integer | `0` / `1` (default 1) | Don't handle maximize request from client |
|
| `ignore_maximize` | integer | `0` / `1` (default 1) | Don't handle maximize request from client |
|
||||||
| `ignore_minimize` | integer | `0` / `1` (default 1) | Don't handle minimize request from client |
|
| `ignore_minimize` | integer | `0` / `1` (default 1) | Don't handle minimize request from client |
|
||||||
| `force_tiled_state` | integer | `0` / `1` | Deceive the window into thinking it is tiling, so it better adheres to assigned dimensions |
|
| `force_tiled_state` | integer | `0` / `1` | Deceive the window into thinking it is tiling, so it better adheres to assigned dimensions |
|
||||||
|
|
@ -179,6 +179,7 @@ tagrule=id:Values,monitor_make:xxx,monitor_model:xxx,Parameter:Values
|
||||||
| `monitor_serial` | string | monitor serial | Match by monitor serial number |
|
| `monitor_serial` | string | monitor serial | Match by monitor serial number |
|
||||||
| `layout_name` | string | layout name | Layout name to set |
|
| `layout_name` | string | layout name | Layout name to set |
|
||||||
| `no_render_border` | integer | `0` / `1` | Disable render border |
|
| `no_render_border` | integer | `0` / `1` | Disable render border |
|
||||||
|
| `open_as_floating` | integer | `0` / `1` | New open window will be floating|
|
||||||
| `no_hide` | integer | `0` / `1` | Not hide even if the tag is empty |
|
| `no_hide` | integer | `0` / `1` | Not hide even if the tag is empty |
|
||||||
| `nmaster` | integer | 0, 99 | Number of master windows |
|
| `nmaster` | integer | 0, 99 | Number of master windows |
|
||||||
| `mfact` | float | 0.1–0.9 | Master area factor |
|
| `mfact` | float | 0.1–0.9 | Master area factor |
|
||||||
|
|
|
||||||
24
mangowm.scm
24
mangowm.scm
|
|
@ -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))
|
#:use-module ((guix licenses) #:prefix license:))
|
||||||
|
|
||||||
|
|
||||||
(define-public mangowm-git
|
(define-public mangowm-git
|
||||||
|
|
@ -36,10 +36,13 @@
|
||||||
(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
|
||||||
|
|
@ -52,14 +55,17 @@
|
||||||
pcre2
|
pcre2
|
||||||
libxcb
|
libxcb
|
||||||
xcb-util-wm
|
xcb-util-wm
|
||||||
wlroots
|
wlroots-0.19
|
||||||
scenefx))
|
scenefx))
|
||||||
(native-inputs (list pkg-config wayland-protocols))
|
(native-inputs (list pkg-config wayland-protocols))
|
||||||
(home-page "https://github.com/DreamMaoMao/mangowm")
|
(home-page "https://github.com/mangowm/mango")
|
||||||
(synopsis "Wayland compositor based on wlroots and scenefx")
|
(synopsis "Wayland compositor based on wlroots and scenefx")
|
||||||
(description "A Wayland compositor based on wlroots and scenefx,
|
(description
|
||||||
inspired by dwl but aiming to be more feature-rich.")
|
"MangoWM is a modern, lightweight, high-performance Wayland compositor
|
||||||
(license gpl3)))
|
built on dwl — crafted for speed, flexibility, and a customizable desktop experience.")
|
||||||
|
(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)
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
project('mango', ['c', 'cpp'],
|
project('mango', ['c', 'cpp'],
|
||||||
version : '0.12.7',
|
version : '0.12.8',
|
||||||
)
|
)
|
||||||
|
|
||||||
subdir('protocols')
|
subdir('protocols')
|
||||||
|
|
|
||||||
|
|
@ -569,12 +569,12 @@ int32_t main(int32_t argc, char *argv[]) {
|
||||||
mode = WATCH;
|
mode = WATCH;
|
||||||
break;
|
break;
|
||||||
case 'o':
|
case 'o':
|
||||||
if (mode == SET)
|
if (mode == GET || mode == WATCH)
|
||||||
|
oflag = 1;
|
||||||
|
else if (mode == SET)
|
||||||
output_name = EARGF(usage());
|
output_name = EARGF(usage());
|
||||||
else
|
else
|
||||||
output_name = ARGF();
|
output_name = ARGF();
|
||||||
if (!output_name)
|
|
||||||
oflag = 1;
|
|
||||||
break;
|
break;
|
||||||
case 't':
|
case 't':
|
||||||
tflag = 1;
|
tflag = 1;
|
||||||
|
|
|
||||||
|
|
@ -67,8 +67,8 @@ stdenv.mkDerivation {
|
||||||
|
|
||||||
meta = {
|
meta = {
|
||||||
mainProgram = "mango";
|
mainProgram = "mango";
|
||||||
description = "A streamlined but feature-rich Wayland compositor";
|
description = "Practical and Powerful wayland compositor (dwm but wayland)";
|
||||||
homepage = "https://github.com/DreamMaoMao/mango";
|
homepage = "https://github.com/mangowm/mango";
|
||||||
license = lib.licenses.gpl3Plus;
|
license = lib.licenses.gpl3Plus;
|
||||||
maintainers = [];
|
maintainers = [];
|
||||||
platforms = lib.platforms.unix;
|
platforms = lib.platforms.unix;
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,22 @@
|
||||||
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 {
|
||||||
|
|
@ -54,7 +58,7 @@ in {
|
||||||
"XCURSOR_THEME"
|
"XCURSOR_THEME"
|
||||||
"XCURSOR_SIZE"
|
"XCURSOR_SIZE"
|
||||||
];
|
];
|
||||||
example = ["--all"];
|
example = [ "--all" ];
|
||||||
description = ''
|
description = ''
|
||||||
Environment variables imported into the systemd and D-Bus user environment.
|
Environment variables imported into the systemd and D-Bus user environment.
|
||||||
'';
|
'';
|
||||||
|
|
@ -75,50 +79,195 @@ in {
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
settings = mkOption {
|
settings = mkOption {
|
||||||
description = "mango config content";
|
type =
|
||||||
type = types.lines;
|
with lib.types;
|
||||||
default = "";
|
let
|
||||||
example = ''
|
valueType =
|
||||||
# menu and terminal
|
nullOr (oneOf [
|
||||||
bind=Alt,space,spawn,rofi -show drun
|
bool
|
||||||
bind=Alt,Return,spawn,foot
|
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;
|
||||||
|
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 = ''
|
||||||
|
# Advanced config that doesn't fit structured format
|
||||||
|
special_option = 1
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
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 = "WARRNING: This is a shell script, but no need to add shebang";
|
description = ''
|
||||||
|
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 (
|
||||||
home.packages = [cfg.package];
|
let
|
||||||
xdg.configFile = {
|
finalConfigText =
|
||||||
"mango/config.conf" = lib.mkIf (cfg.settings != "") {
|
# Support old string-based config during transition period
|
||||||
text = cfg.settings;
|
(
|
||||||
|
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 ];
|
||||||
|
xdg.configFile = {
|
||||||
|
"mango/config.conf" =
|
||||||
|
lib.mkIf (cfg.settings != { } || cfg.extraConfig != "" || cfg.autostart_sh != "")
|
||||||
|
{
|
||||||
|
source = validatedConfig;
|
||||||
|
};
|
||||||
|
"mango/autostart.sh" = lib.mkIf (cfg.autostart_sh != "") {
|
||||||
|
source = autostart_sh;
|
||||||
|
executable = true;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
"mango/autostart.sh" = lib.mkIf (cfg.autostart_sh != "") {
|
systemd.user.targets.mango-session = lib.mkIf cfg.systemd.enable {
|
||||||
source = autostart_sh;
|
Unit = {
|
||||||
executable = true;
|
Description = "mango compositor session";
|
||||||
};
|
Documentation = [ "man:systemd.special(7)" ];
|
||||||
};
|
BindsTo = [ "graphical-session.target" ];
|
||||||
systemd.user.targets.mango-session = lib.mkIf cfg.systemd.enable {
|
Wants = [
|
||||||
Unit = {
|
|
||||||
Description = "mango compositor session";
|
|
||||||
Documentation = ["man:systemd.special(7)"];
|
|
||||||
BindsTo = ["graphical-session.target"];
|
|
||||||
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";
|
||||||
After = ["graphical-session-pre.target"];
|
After = [ "graphical-session-pre.target" ];
|
||||||
Before = lib.optional cfg.systemd.xdgAutostart "xdg-desktop-autostart.target";
|
Before = lib.optional cfg.systemd.xdgAutostart "xdg-desktop-autostart.target";
|
||||||
|
};
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
};
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
312
nix/lib.nix
Normal file
312
nix/lib.nix
Normal file
|
|
@ -0,0 +1,312 @@
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
@ -723,6 +723,8 @@ void client_animation_next_tick(Client *c) {
|
||||||
|
|
||||||
c->is_pending_open_animation = false;
|
c->is_pending_open_animation = false;
|
||||||
|
|
||||||
|
client_apply_clip(c, factor);
|
||||||
|
|
||||||
if (animation_passed >= 1.0) {
|
if (animation_passed >= 1.0) {
|
||||||
|
|
||||||
// clear the open action state
|
// clear the open action state
|
||||||
|
|
@ -752,8 +754,6 @@ void client_animation_next_tick(Client *c) {
|
||||||
// end flush in next frame, not the current frame
|
// end flush in next frame, not the current frame
|
||||||
c->need_output_flush = false;
|
c->need_output_flush = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
client_apply_clip(c, factor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_fadeout_client(Client *c) {
|
void init_fadeout_client(Client *c) {
|
||||||
|
|
|
||||||
|
|
@ -294,9 +294,8 @@ static inline uint32_t client_set_size(Client *c, uint32_t width,
|
||||||
uint32_t height) {
|
uint32_t height) {
|
||||||
#ifdef XWAYLAND
|
#ifdef XWAYLAND
|
||||||
if (client_is_x11(c)) {
|
if (client_is_x11(c)) {
|
||||||
|
struct wlr_xwayland_surface *surface = c->surface.xwayland;
|
||||||
struct wlr_surface_state *state =
|
struct wlr_surface_state *state = &surface->surface->current;
|
||||||
&c->surface.xwayland->surface->current;
|
|
||||||
|
|
||||||
if ((int32_t)c->geom.width - 2 * (int32_t)c->bw ==
|
if ((int32_t)c->geom.width - 2 * (int32_t)c->bw ==
|
||||||
(int32_t)state->width &&
|
(int32_t)state->width &&
|
||||||
|
|
@ -309,6 +308,22 @@ static inline uint32_t client_set_size(Client *c, uint32_t width,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
xcb_size_hints_t *size_hints = surface->size_hints;
|
||||||
|
int32_t width = c->geom.width - 2 * c->bw;
|
||||||
|
int32_t height = c->geom.height - 2 * c->bw;
|
||||||
|
|
||||||
|
if (c->mon && c->mon->isoverview && size_hints &&
|
||||||
|
c->geom.width - 2 * (int32_t)c->bw < size_hints->min_width &&
|
||||||
|
c->geom.height - 2 * (int32_t)c->bw < size_hints->min_height)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (size_hints &&
|
||||||
|
c->geom.width - 2 * (int32_t)c->bw < size_hints->min_width)
|
||||||
|
width = size_hints->min_width;
|
||||||
|
if (size_hints &&
|
||||||
|
c->geom.height - 2 * (int32_t)c->bw < size_hints->min_height)
|
||||||
|
height = size_hints->min_height;
|
||||||
|
|
||||||
wlr_xwayland_surface_configure(c->surface.xwayland, c->geom.x + c->bw,
|
wlr_xwayland_surface_configure(c->surface.xwayland, c->geom.x + c->bw,
|
||||||
c->geom.y + c->bw, width, height);
|
c->geom.y + c->bw, width, height);
|
||||||
return 1;
|
return 1;
|
||||||
|
|
@ -350,7 +365,7 @@ static inline void client_set_maximized(Client *c, bool maximized) {
|
||||||
static inline void client_set_tiled(Client *c, uint32_t edges) {
|
static inline void client_set_tiled(Client *c, uint32_t edges) {
|
||||||
struct wlr_xdg_toplevel *toplevel;
|
struct wlr_xdg_toplevel *toplevel;
|
||||||
#ifdef XWAYLAND
|
#ifdef XWAYLAND
|
||||||
if (client_is_x11(c) && c->force_maximize) {
|
if (client_is_x11(c) && c->force_fakemaximize) {
|
||||||
wlr_xwayland_surface_set_maximized(c->surface.xwayland,
|
wlr_xwayland_surface_set_maximized(c->surface.xwayland,
|
||||||
edges != WLR_EDGE_NONE,
|
edges != WLR_EDGE_NONE,
|
||||||
edges != WLR_EDGE_NONE);
|
edges != WLR_EDGE_NONE);
|
||||||
|
|
@ -365,7 +380,7 @@ static inline void client_set_tiled(Client *c, uint32_t edges) {
|
||||||
wlr_xdg_toplevel_set_tiled(c->surface.xdg->toplevel, edges);
|
wlr_xdg_toplevel_set_tiled(c->surface.xdg->toplevel, edges);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (c->force_maximize) {
|
if (c->force_fakemaximize) {
|
||||||
wlr_xdg_toplevel_set_maximized(toplevel, edges != WLR_EDGE_NONE);
|
wlr_xdg_toplevel_set_maximized(toplevel, edges != WLR_EDGE_NONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -90,7 +90,7 @@ typedef struct {
|
||||||
int32_t no_force_center;
|
int32_t no_force_center;
|
||||||
int32_t isterm;
|
int32_t isterm;
|
||||||
int32_t allow_csd;
|
int32_t allow_csd;
|
||||||
int32_t force_maximize;
|
int32_t force_fakemaximize;
|
||||||
int32_t force_tiled_state;
|
int32_t force_tiled_state;
|
||||||
int32_t force_tearing;
|
int32_t force_tearing;
|
||||||
int32_t noswallow;
|
int32_t noswallow;
|
||||||
|
|
@ -168,6 +168,7 @@ typedef struct {
|
||||||
float mfact;
|
float mfact;
|
||||||
int32_t nmaster;
|
int32_t nmaster;
|
||||||
int32_t no_render_border;
|
int32_t no_render_border;
|
||||||
|
int32_t open_as_floating;
|
||||||
int32_t no_hide;
|
int32_t no_hide;
|
||||||
} ConfigTagRule;
|
} ConfigTagRule;
|
||||||
|
|
||||||
|
|
@ -634,9 +635,14 @@ uint32_t parse_mod(const char *mod_str) {
|
||||||
// 分割处理每个部分
|
// 分割处理每个部分
|
||||||
token = strtok_r(input_copy, "+", &saveptr);
|
token = strtok_r(input_copy, "+", &saveptr);
|
||||||
while (token != NULL) {
|
while (token != NULL) {
|
||||||
// 去除空白
|
// 去除前后空白
|
||||||
while (*token == ' ' || *token == '\t')
|
trim_whitespace(token);
|
||||||
token++;
|
|
||||||
|
// 如果 token 变成空字符串则跳过
|
||||||
|
if (*token == '\0') {
|
||||||
|
token = strtok_r(NULL, "+", &saveptr);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (strncmp(token, "code:", 5) == 0) {
|
if (strncmp(token, "code:", 5) == 0) {
|
||||||
// 处理 code: 形式
|
// 处理 code: 形式
|
||||||
|
|
@ -1196,6 +1202,8 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value,
|
||||||
} else if (strcmp(func_name, "scroller_stack") == 0) {
|
} else if (strcmp(func_name, "scroller_stack") == 0) {
|
||||||
func = scroller_stack;
|
func = scroller_stack;
|
||||||
(*arg).i = parse_direction(arg_value);
|
(*arg).i = parse_direction(arg_value);
|
||||||
|
} else if (strcmp(func_name, "toggle_all_floating") == 0) {
|
||||||
|
func = toggle_all_floating;
|
||||||
} else {
|
} else {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
@ -1899,6 +1907,7 @@ bool parse_option(Config *config, char *key, char *value) {
|
||||||
rule->nmaster = 0;
|
rule->nmaster = 0;
|
||||||
rule->mfact = 0.0f;
|
rule->mfact = 0.0f;
|
||||||
rule->no_render_border = 0;
|
rule->no_render_border = 0;
|
||||||
|
rule->open_as_floating = 0;
|
||||||
rule->no_hide = 0;
|
rule->no_hide = 0;
|
||||||
|
|
||||||
bool parse_error = false;
|
bool parse_error = false;
|
||||||
|
|
@ -1927,6 +1936,8 @@ bool parse_option(Config *config, char *key, char *value) {
|
||||||
rule->monitor_serial = strdup(val);
|
rule->monitor_serial = 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, "open_as_floating") == 0) {
|
||||||
|
rule->open_as_floating = CLAMP_INT(atoi(val), 0, 1);
|
||||||
} else if (strcmp(key, "no_hide") == 0) {
|
} else if (strcmp(key, "no_hide") == 0) {
|
||||||
rule->no_hide = CLAMP_INT(atoi(val), 0, 1);
|
rule->no_hide = CLAMP_INT(atoi(val), 0, 1);
|
||||||
} else if (strcmp(key, "nmaster") == 0) {
|
} else if (strcmp(key, "nmaster") == 0) {
|
||||||
|
|
@ -2047,7 +2058,7 @@ bool parse_option(Config *config, char *key, char *value) {
|
||||||
rule->indleinhibit_when_focus = -1;
|
rule->indleinhibit_when_focus = -1;
|
||||||
rule->isterm = -1;
|
rule->isterm = -1;
|
||||||
rule->allow_csd = -1;
|
rule->allow_csd = -1;
|
||||||
rule->force_maximize = -1;
|
rule->force_fakemaximize = -1;
|
||||||
rule->force_tiled_state = -1;
|
rule->force_tiled_state = -1;
|
||||||
rule->force_tearing = -1;
|
rule->force_tearing = -1;
|
||||||
rule->noswallow = -1;
|
rule->noswallow = -1;
|
||||||
|
|
@ -2161,8 +2172,8 @@ bool parse_option(Config *config, char *key, char *value) {
|
||||||
rule->isterm = atoi(val);
|
rule->isterm = atoi(val);
|
||||||
} else if (strcmp(key, "allow_csd") == 0) {
|
} else if (strcmp(key, "allow_csd") == 0) {
|
||||||
rule->allow_csd = atoi(val);
|
rule->allow_csd = atoi(val);
|
||||||
} else if (strcmp(key, "force_maximize") == 0) {
|
} else if (strcmp(key, "force_fakemaximize") == 0) {
|
||||||
rule->force_maximize = atoi(val);
|
rule->force_fakemaximize = atoi(val);
|
||||||
} else if (strcmp(key, "force_tiled_state") == 0) {
|
} else if (strcmp(key, "force_tiled_state") == 0) {
|
||||||
rule->force_tiled_state = atoi(val);
|
rule->force_tiled_state = atoi(val);
|
||||||
} else if (strcmp(key, "force_tearing") == 0) {
|
} else if (strcmp(key, "force_tearing") == 0) {
|
||||||
|
|
@ -3202,7 +3213,7 @@ void override_config(void) {
|
||||||
config.accel_profile = CLAMP_INT(config.accel_profile, 0, 2);
|
config.accel_profile = CLAMP_INT(config.accel_profile, 0, 2);
|
||||||
config.accel_speed = CLAMP_FLOAT(config.accel_speed, -1.0f, 1.0f);
|
config.accel_speed = CLAMP_FLOAT(config.accel_speed, -1.0f, 1.0f);
|
||||||
config.scroll_method = CLAMP_INT(config.scroll_method, 0, 4);
|
config.scroll_method = CLAMP_INT(config.scroll_method, 0, 4);
|
||||||
config.scroll_button = CLAMP_INT(config.scroll_button, 272, 276);
|
config.scroll_button = CLAMP_INT(config.scroll_button, 272, 279);
|
||||||
config.click_method = CLAMP_INT(config.click_method, 0, 2);
|
config.click_method = CLAMP_INT(config.click_method, 0, 2);
|
||||||
config.send_events_mode = CLAMP_INT(config.send_events_mode, 0, 2);
|
config.send_events_mode = CLAMP_INT(config.send_events_mode, 0, 2);
|
||||||
config.button_map = CLAMP_INT(config.button_map, 0, 1);
|
config.button_map = CLAMP_INT(config.button_map, 0, 1);
|
||||||
|
|
@ -3252,7 +3263,7 @@ void set_value_default() {
|
||||||
config.animation_fade_in = 1;
|
config.animation_fade_in = 1;
|
||||||
config.animation_fade_out = 1;
|
config.animation_fade_out = 1;
|
||||||
config.tag_animation_direction = HORIZONTAL;
|
config.tag_animation_direction = HORIZONTAL;
|
||||||
config.zoom_initial_ratio = 0.3f;
|
config.zoom_initial_ratio = 0.4f;
|
||||||
config.zoom_end_ratio = 0.8f;
|
config.zoom_end_ratio = 0.8f;
|
||||||
config.fadein_begin_opacity = 0.5f;
|
config.fadein_begin_opacity = 0.5f;
|
||||||
config.fadeout_begin_opacity = 0.5f;
|
config.fadeout_begin_opacity = 0.5f;
|
||||||
|
|
@ -3780,6 +3791,8 @@ void parse_tagrule(Monitor *m) {
|
||||||
m->pertag->mfacts[tr.id] = tr.mfact;
|
m->pertag->mfacts[tr.id] = tr.mfact;
|
||||||
if (tr.no_render_border >= 0)
|
if (tr.no_render_border >= 0)
|
||||||
m->pertag->no_render_border[tr.id] = tr.no_render_border;
|
m->pertag->no_render_border[tr.id] = tr.no_render_border;
|
||||||
|
if (tr.open_as_floating >= 0)
|
||||||
|
m->pertag->open_as_floating[tr.id] = tr.open_as_floating;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -70,3 +70,4 @@ int32_t disable_monitor(const Arg *arg);
|
||||||
int32_t enable_monitor(const Arg *arg);
|
int32_t enable_monitor(const Arg *arg);
|
||||||
int32_t toggle_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);
|
||||||
|
int32_t toggle_all_floating(const Arg *arg);
|
||||||
|
|
@ -376,7 +376,11 @@ int32_t moveresize(const Arg *arg) {
|
||||||
/* Float the window and tell motionnotify to grab it */
|
/* Float the window and tell motionnotify to grab it */
|
||||||
if (grabc->isfloating == 0 && arg->ui == CurMove) {
|
if (grabc->isfloating == 0 && arg->ui == CurMove) {
|
||||||
grabc->drag_to_tile = true;
|
grabc->drag_to_tile = true;
|
||||||
|
exit_scroller_stack(grabc);
|
||||||
setfloating(grabc, 1);
|
setfloating(grabc, 1);
|
||||||
|
grabc->old_stack_inner_per = 0.0f;
|
||||||
|
grabc->old_master_inner_per = 0.0f;
|
||||||
|
set_size_per(grabc->mon, grabc);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (cursor_mode = arg->ui) {
|
switch (cursor_mode = arg->ui) {
|
||||||
|
|
@ -548,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) {
|
||||||
selmon->sel->isminimized = 0;
|
client_pending_minimized_state(selmon->sel, 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;
|
||||||
|
|
@ -1866,3 +1870,27 @@ int32_t scroller_stack(const Arg *arg) {
|
||||||
arrange(selmon, false, false);
|
arrange(selmon, false, false);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32_t toggle_all_floating(const Arg *arg) {
|
||||||
|
if (!selmon || !selmon->sel)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
Client *c = NULL;
|
||||||
|
bool should_floating = !selmon->sel->isfloating;
|
||||||
|
|
||||||
|
wl_list_for_each(c, &clients, link) {
|
||||||
|
if (VISIBLEON(c, selmon)) {
|
||||||
|
|
||||||
|
if (c->isfloating && !should_floating) {
|
||||||
|
c->old_master_inner_per = 0.0f;
|
||||||
|
c->old_stack_inner_per = 0.0f;
|
||||||
|
set_size_per(selmon, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c->isfloating != should_floating) {
|
||||||
|
setfloating(c, should_floating);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,12 @@
|
||||||
bool check_hit_no_border(Client *c) {
|
bool check_hit_no_border(Client *c) {
|
||||||
int32_t i;
|
|
||||||
bool hit_no_border = false;
|
bool hit_no_border = false;
|
||||||
if (!render_border) {
|
if (!render_border) {
|
||||||
hit_no_border = true;
|
hit_no_border = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < config.tag_rules_count; i++) {
|
if (c->mon && !c->mon->isoverview &&
|
||||||
if (c->tags & (1 << (config.tag_rules[i].id - 1)) &&
|
c->mon->pertag->no_render_border[get_tags_first_tag_num(c->tags)]) {
|
||||||
config.tag_rules[i].no_render_border) {
|
hit_no_border = true;
|
||||||
hit_no_border = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.no_border_when_single && c && c->mon &&
|
if (config.no_border_when_single && c && c->mon &&
|
||||||
|
|
@ -19,6 +16,7 @@ bool check_hit_no_border(Client *c) {
|
||||||
}
|
}
|
||||||
return hit_no_border;
|
return hit_no_border;
|
||||||
}
|
}
|
||||||
|
|
||||||
Client *termforwin(Client *w) {
|
Client *termforwin(Client *w) {
|
||||||
Client *c = NULL;
|
Client *c = NULL;
|
||||||
|
|
||||||
|
|
|
||||||
169
src/mango.c
169
src/mango.c
|
|
@ -391,7 +391,7 @@ struct Client {
|
||||||
struct dwl_opacity_animation opacity_animation;
|
struct dwl_opacity_animation opacity_animation;
|
||||||
int32_t isterm, noswallow;
|
int32_t isterm, noswallow;
|
||||||
int32_t allow_csd;
|
int32_t allow_csd;
|
||||||
int32_t force_maximize;
|
int32_t force_fakemaximize;
|
||||||
int32_t force_tiled_state;
|
int32_t force_tiled_state;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
Client *swallowing, *swallowedby;
|
Client *swallowing, *swallowedby;
|
||||||
|
|
@ -806,6 +806,10 @@ 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"
|
||||||
|
|
@ -933,8 +937,9 @@ struct Pertag {
|
||||||
uint32_t curtag, prevtag; /* current and previous tag */
|
uint32_t curtag, prevtag; /* current and previous tag */
|
||||||
int32_t nmasters[LENGTH(tags) + 1]; /* number of windows in master area */
|
int32_t 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 */
|
||||||
bool no_hide[LENGTH(tags) + 1]; /* no_hide per tag */
|
int32_t no_hide[LENGTH(tags) + 1]; /* no_hide per tag */
|
||||||
bool no_render_border[LENGTH(tags) + 1]; /* no_render_border per tag */
|
int32_t no_render_border[LENGTH(tags) + 1]; /* no_render_border per tag */
|
||||||
|
int32_t open_as_floating[LENGTH(tags) + 1]; /* open_as_floating 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 */
|
||||||
};
|
};
|
||||||
|
|
@ -1062,11 +1067,33 @@ 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) {
|
||||||
c->isfullscreen = 0; // 清除窗口全屏标志
|
client_pending_fullscreen_state(c, 0);
|
||||||
c->ismaximizescreen = 0;
|
client_pending_maximized_state(c, 0);
|
||||||
c->bw = c->isnoborder ? 0 : config.borderpx;
|
c->bw = c->isnoborder ? 0 : config.borderpx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1105,9 +1132,6 @@ 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;
|
||||||
|
|
@ -1119,6 +1143,7 @@ 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)
|
||||||
|
|
@ -1137,11 +1162,9 @@ 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);
|
||||||
|
|
||||||
if (c->isminimized && c->foreign_toplevel) {
|
client_pending_fullscreen_state(c, w->isfullscreen);
|
||||||
wlr_foreign_toplevel_handle_v1_set_activated(c->foreign_toplevel,
|
client_pending_maximized_state(c, w->ismaximizescreen);
|
||||||
false);
|
client_pending_minimized_state(c, w->isminimized);
|
||||||
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) {
|
||||||
|
|
@ -1324,7 +1347,7 @@ void toggle_hotarea(int32_t x_root, int32_t y_root) {
|
||||||
static void apply_rule_properties(Client *c, const ConfigWinRule *r) {
|
static void apply_rule_properties(Client *c, const ConfigWinRule *r) {
|
||||||
APPLY_INT_PROP(c, r, isterm);
|
APPLY_INT_PROP(c, r, isterm);
|
||||||
APPLY_INT_PROP(c, r, allow_csd);
|
APPLY_INT_PROP(c, r, allow_csd);
|
||||||
APPLY_INT_PROP(c, r, force_maximize);
|
APPLY_INT_PROP(c, r, force_fakemaximize);
|
||||||
APPLY_INT_PROP(c, r, force_tiled_state);
|
APPLY_INT_PROP(c, r, force_tiled_state);
|
||||||
APPLY_INT_PROP(c, r, force_tearing);
|
APPLY_INT_PROP(c, r, force_tearing);
|
||||||
APPLY_INT_PROP(c, r, noswallow);
|
APPLY_INT_PROP(c, r, noswallow);
|
||||||
|
|
@ -1402,6 +1425,25 @@ void set_float_malposition(Client *tc) {
|
||||||
tc->float_geom.y = tc->geom.y = y;
|
tc->float_geom.y = tc->geom.y = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void client_reset_mon_tags(Client *c, Monitor *mon, uint32_t newtags) {
|
||||||
|
if (!newtags && mon && !mon->isoverview) {
|
||||||
|
c->tags = mon->tagset[mon->seltags];
|
||||||
|
} else if (!newtags && mon && mon->isoverview) {
|
||||||
|
c->tags = mon->ovbk_current_tagset;
|
||||||
|
} else if (newtags) {
|
||||||
|
c->tags = newtags;
|
||||||
|
} else {
|
||||||
|
c->tags = mon->tagset[mon->seltags];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void check_match_tag_floating_rule(Client *c, Monitor *mon) {
|
||||||
|
if (c->tags && !c->isfloating && mon && !c->swallowedby &&
|
||||||
|
mon->pertag->open_as_floating[get_tags_first_tag_num(c->tags)]) {
|
||||||
|
c->isfloating = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void applyrules(Client *c) {
|
void applyrules(Client *c) {
|
||||||
/* rule matching */
|
/* rule matching */
|
||||||
const char *appid, *title;
|
const char *appid, *title;
|
||||||
|
|
@ -1526,6 +1568,7 @@ void applyrules(Client *c) {
|
||||||
|
|
||||||
int32_t fullscreen_state_backup =
|
int32_t fullscreen_state_backup =
|
||||||
c->isfullscreen || client_wants_fullscreen(c);
|
c->isfullscreen || client_wants_fullscreen(c);
|
||||||
|
|
||||||
setmon(c, mon, newtags,
|
setmon(c, mon, newtags,
|
||||||
!c->isopensilent &&
|
!c->isopensilent &&
|
||||||
!(client_is_x11_popup(c) && client_should_ignore_focus(c)) &&
|
!(client_is_x11_popup(c) && client_should_ignore_focus(c)) &&
|
||||||
|
|
@ -1533,6 +1576,11 @@ void applyrules(Client *c) {
|
||||||
(!c->istagsilent || !newtags ||
|
(!c->istagsilent || !newtags ||
|
||||||
newtags & mon->tagset[mon->seltags]));
|
newtags & mon->tagset[mon->seltags]));
|
||||||
|
|
||||||
|
if (!c->isfloating) {
|
||||||
|
c->old_stack_inner_per = c->stack_inner_per;
|
||||||
|
c->old_master_inner_per = c->master_inner_per;
|
||||||
|
}
|
||||||
|
|
||||||
if (c->mon &&
|
if (c->mon &&
|
||||||
!(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) {
|
||||||
|
|
@ -4042,12 +4090,12 @@ void init_client_properties(Client *c) {
|
||||||
c->master_mfact_per = 0.0f;
|
c->master_mfact_per = 0.0f;
|
||||||
c->master_inner_per = 0.0f;
|
c->master_inner_per = 0.0f;
|
||||||
c->stack_inner_per = 0.0f;
|
c->stack_inner_per = 0.0f;
|
||||||
c->old_stack_inner_per = 1.0f;
|
c->old_stack_inner_per = 0.0f;
|
||||||
c->old_master_inner_per = 1.0f;
|
c->old_master_inner_per = 0.0f;
|
||||||
c->old_master_mfact_per = 1.0f;
|
c->old_master_mfact_per = 0.0f;
|
||||||
c->isterm = 0;
|
c->isterm = 0;
|
||||||
c->allow_csd = 0;
|
c->allow_csd = 0;
|
||||||
c->force_maximize = 0;
|
c->force_fakemaximize = 0;
|
||||||
c->force_tiled_state = 1;
|
c->force_tiled_state = 1;
|
||||||
c->force_tearing = 0;
|
c->force_tearing = 0;
|
||||||
c->allow_shortcuts_inhibit = SHORTCUTS_INHIBIT_ENABLE;
|
c->allow_shortcuts_inhibit = SHORTCUTS_INHIBIT_ENABLE;
|
||||||
|
|
@ -4205,7 +4253,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) {
|
||||||
c->isminimized = 0;
|
client_pending_minimized_state(c, 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;
|
||||||
|
|
@ -4233,13 +4281,12 @@ 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;
|
||||||
c->isminimized = 1;
|
client_pending_minimized_state(c, 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); // 插入尾部
|
||||||
}
|
}
|
||||||
|
|
@ -5015,12 +5062,12 @@ setfloating(Client *c, int32_t floating) {
|
||||||
|
|
||||||
if (floating == 1 && c != grabc) {
|
if (floating == 1 && c != grabc) {
|
||||||
|
|
||||||
if (c->isfullscreen || c->ismaximizescreen) {
|
if (c->isfullscreen) {
|
||||||
c->isfullscreen = 0; // 清除窗口全屏标志
|
client_pending_fullscreen_state(c, 0);
|
||||||
c->ismaximizescreen = 0;
|
client_set_fullscreen(c, 0);
|
||||||
c->bw = c->isnoborder ? 0 : config.borderpx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
client_pending_maximized_state(c, 0);
|
||||||
exit_scroller_stack(c);
|
exit_scroller_stack(c);
|
||||||
|
|
||||||
// 重新计算居中的坐标
|
// 重新计算居中的坐标
|
||||||
|
|
@ -5062,7 +5109,8 @@ setfloating(Client *c, int32_t floating) {
|
||||||
// 让当前tag中的全屏窗口退出全屏参与平铺
|
// 让当前tag中的全屏窗口退出全屏参与平铺
|
||||||
wl_list_for_each(fc, &clients,
|
wl_list_for_each(fc, &clients,
|
||||||
link) if (fc && fc != c && VISIBLEON(fc, c->mon) &&
|
link) if (fc && fc != c && VISIBLEON(fc, c->mon) &&
|
||||||
c->tags & fc->tags && ISFULLSCREEN(fc)) {
|
c->tags & fc->tags && ISFULLSCREEN(fc) &&
|
||||||
|
old_floating_state) {
|
||||||
clear_fullscreen_flag(fc);
|
clear_fullscreen_flag(fc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -5076,7 +5124,8 @@ setfloating(Client *c, int32_t floating) {
|
||||||
layers[c->isfloating ? LyrTop : LyrTile]);
|
layers[c->isfloating ? LyrTop : LyrTile]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!c->isfloating && old_floating_state) {
|
if (!c->isfloating && old_floating_state &&
|
||||||
|
(c->old_stack_inner_per > 0.0f || c->old_master_inner_per > 0.0f)) {
|
||||||
restore_size_per(c->mon, c);
|
restore_size_per(c->mon, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -5084,7 +5133,7 @@ setfloating(Client *c, int32_t floating) {
|
||||||
save_old_size_per(c->mon);
|
save_old_size_per(c->mon);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!c->force_maximize)
|
if (!c->force_fakemaximize)
|
||||||
client_set_maximized(c, false);
|
client_set_maximized(c, false);
|
||||||
|
|
||||||
if (!c->isfloating || c->force_tiled_state) {
|
if (!c->isfloating || c->force_tiled_state) {
|
||||||
|
|
@ -5095,6 +5144,12 @@ setfloating(Client *c, int32_t floating) {
|
||||||
}
|
}
|
||||||
|
|
||||||
arrange(c->mon, false, false);
|
arrange(c->mon, false, false);
|
||||||
|
|
||||||
|
if (!c->isfloating) {
|
||||||
|
c->old_master_inner_per = c->master_inner_per;
|
||||||
|
c->old_stack_inner_per = c->stack_inner_per;
|
||||||
|
}
|
||||||
|
|
||||||
setborder_color(c);
|
setborder_color(c);
|
||||||
printstatus();
|
printstatus();
|
||||||
}
|
}
|
||||||
|
|
@ -5137,18 +5192,17 @@ void setmaximizescreen(Client *c, int32_t maximizescreen) {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int32_t old_maximizescreen_state = c->ismaximizescreen;
|
int32_t old_maximizescreen_state = c->ismaximizescreen;
|
||||||
c->ismaximizescreen = maximizescreen;
|
client_pending_maximized_state(c, maximizescreen);
|
||||||
|
|
||||||
if (maximizescreen) {
|
if (maximizescreen) {
|
||||||
|
|
||||||
if (c->isfullscreen)
|
if (c->isfullscreen) {
|
||||||
setfullscreen(c, 0);
|
client_pending_fullscreen_state(c, 0);
|
||||||
|
client_set_fullscreen(c, 0);
|
||||||
|
}
|
||||||
|
|
||||||
exit_scroller_stack(c);
|
exit_scroller_stack(c);
|
||||||
|
|
||||||
if (c->isfloating)
|
|
||||||
c->float_geom = c->geom;
|
|
||||||
|
|
||||||
maximizescreen_box.x = c->mon->w.x + config.gappoh;
|
maximizescreen_box.x = c->mon->w.x + config.gappoh;
|
||||||
maximizescreen_box.y = c->mon->w.y + config.gappov;
|
maximizescreen_box.y = c->mon->w.y + config.gappov;
|
||||||
maximizescreen_box.width = c->mon->w.width - 2 * config.gappoh;
|
maximizescreen_box.width = c->mon->w.width - 2 * config.gappoh;
|
||||||
|
|
@ -5156,10 +5210,8 @@ 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);
|
||||||
}
|
}
|
||||||
|
|
@ -5174,9 +5226,9 @@ void setmaximizescreen(Client *c, int32_t maximizescreen) {
|
||||||
save_old_size_per(c->mon);
|
save_old_size_per(c->mon);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!c->force_maximize && !c->ismaximizescreen) {
|
if (!c->force_fakemaximize && !c->ismaximizescreen) {
|
||||||
client_set_maximized(c, false);
|
client_set_maximized(c, false);
|
||||||
} else if (!c->force_maximize && c->ismaximizescreen) {
|
} else if (!c->force_fakemaximize && c->ismaximizescreen) {
|
||||||
client_set_maximized(c, true);
|
client_set_maximized(c, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -5207,26 +5259,25 @@ 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) {
|
||||||
if (c->ismaximizescreen)
|
|
||||||
setmaximizescreen(c, 0);
|
if (c->ismaximizescreen && !c->force_fakemaximize) {
|
||||||
|
client_set_maximized(c, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
client_pending_maximized_state(c, 0);
|
||||||
|
|
||||||
exit_scroller_stack(c);
|
exit_scroller_stack(c);
|
||||||
|
|
||||||
if (c->isfloating)
|
|
||||||
c->float_geom = c->geom;
|
|
||||||
|
|
||||||
c->isfakefullscreen = 0;
|
c->isfakefullscreen = 0;
|
||||||
|
|
||||||
c->bw = 0;
|
c->bw = 0;
|
||||||
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);
|
||||||
}
|
}
|
||||||
|
|
@ -5375,15 +5426,8 @@ void setmon(Client *c, Monitor *m, uint32_t newtags, bool focus) {
|
||||||
/* Make sure window actually overlaps with the monitor */
|
/* Make sure window actually overlaps with the monitor */
|
||||||
reset_foreign_tolevel(c);
|
reset_foreign_tolevel(c);
|
||||||
resize(c, c->geom, 0);
|
resize(c, c->geom, 0);
|
||||||
if (!newtags && !m->isoverview) {
|
client_reset_mon_tags(c, m, newtags);
|
||||||
c->tags = m->tagset[m->seltags];
|
check_match_tag_floating_rule(c, m);
|
||||||
} else if (!newtags && m->isoverview) {
|
|
||||||
c->tags = m->ovbk_current_tagset;
|
|
||||||
} else if (newtags) {
|
|
||||||
c->tags = newtags;
|
|
||||||
} else {
|
|
||||||
c->tags = m->tagset[m->seltags];
|
|
||||||
}
|
|
||||||
setfloating(c, c->isfloating);
|
setfloating(c, c->isfloating);
|
||||||
setfullscreen(c, c->isfullscreen); /* This will call arrange(c->mon) */
|
setfullscreen(c, c->isfullscreen); /* This will call arrange(c->mon) */
|
||||||
}
|
}
|
||||||
|
|
@ -5425,8 +5469,7 @@ void show_hide_client(Client *c) {
|
||||||
c->tags = c->oldtags;
|
c->tags = c->oldtags;
|
||||||
arrange(c->mon, false, false);
|
arrange(c->mon, false, false);
|
||||||
}
|
}
|
||||||
c->isminimized = 0;
|
client_pending_minimized_state(c, 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);
|
||||||
}
|
}
|
||||||
|
|
@ -5850,8 +5893,8 @@ void overview_backup(Client *c) {
|
||||||
c->isfloating = 0;
|
c->isfloating = 0;
|
||||||
}
|
}
|
||||||
if (c->isfullscreen || c->ismaximizescreen) {
|
if (c->isfullscreen || c->ismaximizescreen) {
|
||||||
c->isfullscreen = 0; // 清除窗口全屏标志
|
client_pending_fullscreen_state(c, 0); // 清除窗口全屏标志
|
||||||
c->ismaximizescreen = 0;
|
client_pending_maximized_state(c, 0);
|
||||||
}
|
}
|
||||||
c->bw = c->isnoborder ? 0 : config.borderpx;
|
c->bw = c->isnoborder ? 0 : config.borderpx;
|
||||||
|
|
||||||
|
|
@ -5881,8 +5924,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 {
|
||||||
c->isfullscreen = 0;
|
client_pending_fullscreen_state(c, 0);
|
||||||
c->ismaximizescreen = 0;
|
client_pending_maximized_state(c, 0);
|
||||||
setfullscreen(c, false);
|
setfullscreen(c, false);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -6455,13 +6498,11 @@ void activatex11(struct wl_listener *listener, void *data) {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (c->isminimized) {
|
if (c->isminimized) {
|
||||||
c->isminimized = 0;
|
client_pending_minimized_state(c, 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;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue