Merge branch 'mangowm:main' into main

This commit is contained in:
Sqooky 2026-03-16 07:48:18 -04:00 committed by GitHub
commit e3309c7e1b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
46 changed files with 3533 additions and 1014 deletions

61
.github/scripts/sync-wiki.py vendored Normal file
View file

@ -0,0 +1,61 @@
#!/usr/bin/env python3
import json
import re
from pathlib import Path
DOCS_DIR = Path("docs")
WIKI_DIR = Path("wiki-temp")
FRONTMATTER_RE = re.compile(r"\A---\s*\n.*?^---\s*\n", re.DOTALL | re.MULTILINE)
DOCS_LINK_RE = re.compile(r"\[([^\]]+)\]\(/docs/(?:[^/)]+/)*([^/)#]+)(#[^)]+)?\)")
def collect_all_files() -> list[tuple[Path, str]]:
files = []
def from_dir(directory: Path) -> list[Path]:
meta = directory / "meta.json"
if meta.exists():
data = json.loads(meta.read_text())
return [directory / f"{p}.md" for p in data.get("pages", []) if (directory / f"{p}.md").exists()]
return sorted(directory.glob("*.md"))
for src in from_dir(DOCS_DIR):
files.append((src, "Home" if src.stem == "index" else src.stem))
for subdir in sorted(DOCS_DIR.iterdir()):
if subdir.is_dir():
for src in from_dir(subdir):
files.append((src, src.stem))
return files
def main() -> None:
files = collect_all_files()
contents = {src: src.read_text() for src, _ in files}
for src, dest_name in files:
text = FRONTMATTER_RE.sub("", contents[src], count=1).lstrip("\n")
text = DOCS_LINK_RE.sub(lambda m: f"[{m.group(1)}]({m.group(2)}{m.group(3) or ''})", text)
(WIKI_DIR / f"{dest_name}.md").write_text(text)
lines: list[str] = []
current_section = None
for src, dest_name in files:
section = "General" if src.parent == DOCS_DIR else src.parent.name.replace("-", " ").title()
if section != current_section:
if current_section is not None:
lines.append("")
lines.append(f"## {section}\n")
current_section = section
if dest_name != "Home":
title = dest_name.replace("-", " ").replace("_", " ").title()
lines.append(f"- [[{dest_name}|{title}]]")
(WIKI_DIR / "_Sidebar.md").write_text("\n".join(lines))
if __name__ == "__main__":
main()

44
.github/workflows/sync-website.yml vendored Normal file
View file

@ -0,0 +1,44 @@
name: Sync website
on:
push:
branches: [main]
paths:
- docs/**
concurrency:
group: sync-website
cancel-in-progress: true
jobs:
sync-website:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 1
token: ${{ github.token }}
- name: Checkout website
uses: actions/checkout@v4
with:
repository: mangowm/mangowm.github.io
path: website
token: ${{ secrets.WEBSITE_SYNC_TOKEN }}
fetch-depth: 1
- name: Sync docs
run: |
rm -rf website/apps/web/content/docs
cp -r docs website/apps/web/content/docs
- name: Commit and push
working-directory: website
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add apps/web/content/docs
git diff --staged --quiet || git commit \
-m "docs: content update from mangowm/mango" \
-m "${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }}"
git push

40
.github/workflows/sync-wiki.yml vendored Normal file
View file

@ -0,0 +1,40 @@
name: Sync wiki
on:
push:
branches: [main]
paths:
- docs/**
concurrency:
group: sync-wiki
cancel-in-progress: true
permissions:
contents: write
jobs:
sync-wiki:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Clone wiki
run: |
git clone --depth 1 \
https://x-access-token:${{ github.token }}@github.com/${{ github.repository }}.wiki.git \
wiki-temp
- name: Sync docs to wiki
run: |
find wiki-temp -not -path 'wiki-temp/.git*' -type f -delete
python3 .github/scripts/sync-wiki.py
- name: Commit and push
working-directory: wiki-temp
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add -A
git diff --staged --quiet || git commit -m "sync from ${{ github.sha }}"
git push

15
docs/bindings/index.mdx Normal file
View file

@ -0,0 +1,15 @@
---
title: Bindings & Input
description: Keybindings, mouse gestures, and input devices.
icon: Keyboard
---
Configure how you interact with mangowm using flexible keybindings and input options.
<Cards>
<Card href="/docs/bindings/keys" title="Key Bindings" description="Keyboard shortcuts and modes" />
<Card href="/docs/bindings/mouse-gestures" title="Mouse Gestures" description="Touchpad and mouse gestures" />
</Cards>

204
docs/bindings/keys.md Normal file
View file

@ -0,0 +1,204 @@
---
title: Key Bindings
description: Define keyboard shortcuts and modes.
---
## Syntax
Key bindings follow this format:
```ini
bind[flags]=MODIFIERS,KEY,COMMAND,PARAMETERS
```
- **Modifiers**: `SUPER`, `CTRL`, `ALT`, `SHIFT`, `NONE` (combine with `+`, e.g. `SUPER+CTRL+ALT`).
- **Key**: Key name (from `xev` or `wev`) or keycode (e.g., `code:24` for `q`).
> **Info:** `bind` automatically converts keysym to keycode for comparison. This makes it compatible with all keyboard layouts, but the matching may not always be precise. If a key combination doesn't work on your keyboard layout, use a keycode instead (e.g., `code:24` instead of `q`).
### Flags
- `l`: Works even when screen is locked.
- `s`: Uses keysym instead of keycode to bind.
- `r`: Triggers on key release instead of press.
- `p`: Pass key event to client.
**Examples:**
```ini
bind=SUPER,Q,killclient
bindl=SUPER,L,spawn,swaylock
# Using keycode instead of key name
bind=ALT,code:24,killclient
# Combining keycodes for modifiers and keys
bind=code:64,code:24,killclient
bind=code:64+code:133,code:24,killclient
# Bind with no modifier
bind=NONE,XF86MonBrightnessUp,spawn,brightnessctl set +5%
# Bind a modifier key itself as the trigger key
bind=alt,shift_l,switch_keyboard_layout
```
## Key Modes (Submaps)
You can divide key bindings into named modes. Rules:
1. Set `keymode=<name>` before a group of `bind` lines — those binds only apply in that mode.
2. If no `keymode` is set before a bind, it belongs to the `default` mode.
3. The special `common` keymode applies its binds **across all modes**.
Use `setkeymode` to switch modes, and `mmsg -b` to query the current mode.
```ini
# Binds in 'common' apply in every mode
keymode=common
bind=SUPER,r,reload_config
# Default mode bindings
keymode=default
bind=ALT,Return,spawn,foot
bind=SUPER,F,setkeymode,resize
# 'resize' mode bindings
keymode=resize
bind=NONE,Left,resizewin,-10,0
bind=NONE,Right,resizewin,+10,0
bind=NONE,Escape,setkeymode,default
```
### Single Modifier Key Binding
When binding a modifier key itself, use `NONE` for press and the modifier name for release:
```ini
# Trigger on press of Super key
bind=none,Super_L,spawn,rofi -show run
# Trigger on release of Super key
bindr=Super,Super_L,spawn,rofi -show run
```
## Dispatchers List
### Window Management
| Command | Param | Description |
| :--- | :--- | :--- |
| `killclient` | - | Close the focused window. |
| `togglefloating` | - | Toggle floating state. |
| `togglefullscreen` | - | Toggle fullscreen. |
| `togglefakefullscreen` | - | Toggle "fake" fullscreen (remains constrained). |
| `togglemaximizescreen` | - | Maximize window (keep decoration/bar). |
| `toggleglobal` | - | Pin window to all tags. |
| `toggle_render_border` | - | Toggle border rendering. |
| `centerwin` | - | Center the floating window. |
| `minimized` | - | Minimize window to scratchpad. |
| `restore_minimized` | - | Restore window from scratchpad. |
| `toggle_scratchpad` | - | Toggle scratchpad. |
| `toggle_named_scratchpad` | `appid,title,cmd` | Toggle named scratchpad. Launches app if not running, otherwise shows/hides it. |
### Focus & Movement
| Command | Param | Description |
| :--- | :--- | :--- |
| `focusdir` | `left/right/up/down` | Focus window in direction. |
| `focusstack` | `next/prev` | Cycle focus within the stack. |
| `focuslast` | - | Focus the previously active window. |
| `exchange_client` | `left/right/up/down` | Swap window with neighbor in direction. |
| `exchange_stack_client` | `next/prev` | Exchange window position in stack. |
| `zoom` | - | Swap focused window with Master. |
### Tags & Monitors
| Command | Param | Description |
| :--- | :--- | :--- |
| `view` | `-1/0/1-9` or `mask [,synctag]` | View tag. `-1` = previous tagset, `0` = all tags, `1-9` = specific tag, mask e.g. `1\|3\|5`. Optional `synctag` (0/1) syncs the action to all monitors. |
| `viewtoleft` | `[synctag]` | View previous tag. Optional `synctag` (0/1) syncs to all monitors. |
| `viewtoright` | `[synctag]` | View next tag. Optional `synctag` (0/1) syncs to all monitors. |
| `viewtoleft_have_client` | `[synctag]` | View left tag and focus client if present. Optional `synctag` (0/1). |
| `viewtoright_have_client` | `[synctag]` | View right tag and focus client if present. Optional `synctag` (0/1). |
| `viewcrossmon` | `tag,monitor_spec` | View specified tag on specified monitor. |
| `tag` | `1-9 [,synctag]` | Move window to tag. Optional `synctag` (0/1) syncs to all monitors. |
| `tagsilent` | `1-9` | Move window to tag without focusing it. |
| `tagtoleft` | `[synctag]` | Move window to left tag. Optional `synctag` (0/1). |
| `tagtoright` | `[synctag]` | Move window to right tag. Optional `synctag` (0/1). |
| `tagcrossmon` | `tag,monitor_spec` | Move window to specified tag on specified monitor. |
| `toggletag` | `0-9` | Toggle tag on window (0 means all tags). |
| `toggleview` | `1-9` | Toggle tag view. |
| `comboview` | `1-9` | View multi tags pressed simultaneously. |
| `focusmon` | `left/right/up/down/monitor_spec` | Focus monitor by direction or [monitor spec](/docs/configuration/monitors#monitor-spec-format). |
| `tagmon` | `left/right/up/down/monitor_spec,[keeptag]` | Move window to monitor by direction or [monitor spec](/docs/configuration/monitors#monitor-spec-format). `keeptag` is 0 or 1. |
### Layouts
| Command | Param | Description |
| :--- | :--- | :--- |
| `setlayout` | `name` | Switch to layout (e.g., `scroller`, `tile`). |
| `switch_layout` | - | Cycle through available layouts. |
| `incnmaster` | `+1/-1` | Increase/Decrease number of master windows. |
| `setmfact` | `+0.05` | Increase/Decrease master area size. |
| `set_proportion` | `float` | Set scroller window proportion (0.01.0). |
| `switch_proportion_preset` | - | Cycle proportion presets of scroller window. |
| `scroller_stack` | `left/right/up/down` | Move window inside/outside scroller stack by direction. |
| `incgaps` | `+/-value` | Adjust gap size. |
| `togglegaps` | - | Toggle gaps. |
### System
| Command | Param | Description |
| :--- | :--- | :--- |
| `spawn` | `cmd` | Execute a command. |
| `spawn_shell` | `cmd` | Execute shell command (supports pipes `\|`). |
| `spawn_on_empty` | `cmd,tagnumber` | Open command on empty tag. |
| `reload_config` | - | Hot-reload configuration. |
| `quit` | - | Exit mangowm. |
| `toggleoverview` | - | Toggle overview mode. |
| `create_virtual_output` | - | Create a headless monitor (for VNC/Sunshine). |
| `destroy_all_virtual_output` | - | Destroy all virtual monitors. |
| `toggleoverlay` | - | Toggle overlay state for the focused window. |
| `toggle_trackpad_enable` | - | Toggle trackpad enable. |
| `setkeymode` | `mode` | Set keymode. |
| `switch_keyboard_layout` | `[index]` | Switch keyboard layout. Optional index (0, 1, 2...) to switch to specific layout. |
| `setoption` | `key,value` | Set config option temporarily. |
| `disable_monitor` | `monitor_spec` | Shutdown monitor. Accepts a [monitor spec](/docs/configuration/monitors#monitor-spec-format). |
| `enable_monitor` | `monitor_spec` | Power on monitor. Accepts a [monitor spec](/docs/configuration/monitors#monitor-spec-format). |
| `toggle_monitor` | `monitor_spec` | Toggle monitor power. Accepts a [monitor spec](/docs/configuration/monitors#monitor-spec-format). |
### Media Controls
> **Warning:** Some keyboards don't send standard media keys. Run `wev` and press your key to check the exact key name.
#### Brightness
Requires: `brightnessctl`
```ini
bind=NONE,XF86MonBrightnessUp,spawn,brightnessctl s +2%
bind=SHIFT,XF86MonBrightnessUp,spawn,brightnessctl s 100%
bind=NONE,XF86MonBrightnessDown,spawn,brightnessctl s 2%-
bind=SHIFT,XF86MonBrightnessDown,spawn,brightnessctl s 1%
```
#### Volume
Requires: `wpctl` (WirePlumber)
```ini
bind=NONE,XF86AudioRaiseVolume,spawn,wpctl set-volume @DEFAULT_SINK@ 5%+
bind=NONE,XF86AudioLowerVolume,spawn,wpctl set-volume @DEFAULT_SINK@ 5%-
bind=NONE,XF86AudioMute,spawn,wpctl set-mute @DEFAULT_SINK@ toggle
bind=SHIFT,XF86AudioMute,spawn,wpctl set-mute @DEFAULT_SOURCE@ toggle
```
### Floating Window Movement
| Command | Param | Description |
| :--- | :--- | :--- |
| `smartmovewin` | `left/right/up/down` | Move floating window by snap distance. |
| `smartresizewin` | `left/right/up/down` | Resize floating window by snap distance. |
| `movewin` | `(x,y)` | Move floating window. |
| `resizewin` | `(width,height)` | Resize window. |

4
docs/bindings/meta.json Normal file
View file

@ -0,0 +1,4 @@
{
"title": "Bindings & Input",
"pages": ["keys", "mouse-gestures"]
}

View file

@ -0,0 +1,116 @@
---
title: Mouse & Gestures
description: Configure mouse buttons, scrolling, gestures, and lid switches.
---
## Mouse Bindings
Assign actions to mouse button presses with optional modifier keys.
### Syntax
```ini
mousebind=MODIFIERS,BUTTON,COMMAND,PARAMETERS
```
- **Modifiers**: `SUPER`, `CTRL`, `ALT`, `SHIFT`, `NONE`. Combine with `+` (e.g., `SUPER+CTRL`)
- **Buttons**: `btn_left`, `btn_right`, `btn_middle`, `btn_side`, `btn_extra`, `btn_forward`, `btn_back`, `btn_task`
> **Warning:** When modifiers are set to `NONE`, only `btn_middle` works in normal mode. `btn_left` and `btn_right` only work in overview mode.
### Examples
```ini
# Window manipulation
mousebind=SUPER,btn_left,moveresize,curmove
mousebind=SUPER,btn_right,moveresize,curresize
mousebind=SUPER+CTRL,btn_right,killclient
# Overview mode (requires NONE modifier)
mousebind=NONE,btn_left,toggleoverview,-1
mousebind=NONE,btn_right,killclient,0
mousebind=NONE,btn_middle,togglemaximizescreen,0
```
---
## Axis Bindings
Map scroll wheel movements to actions for workspace and window navigation.
### Syntax
```ini
axisbind=MODIFIERS,DIRECTION,COMMAND,PARAMETERS
```
- **Direction**: `UP`, `DOWN`, `LEFT`, `RIGHT`
### Examples
```ini
axisbind=SUPER,UP,viewtoleft_have_client
axisbind=SUPER,DOWN,viewtoright_have_client
```
---
## Gesture Bindings
Enable touchpad swipe gestures for navigation and window management.
### Syntax
```ini
gesturebind=MODIFIERS,DIRECTION,FINGERS,COMMAND,PARAMETERS
```
- **Direction**: `up`, `down`, `left`, `right`
- **Fingers**: `3` or `4`
> **Info:** Gestures require proper touchpad configuration. See [Input Devices](/docs/configuration/input) for touchpad settings like `tap_to_click` and `disable_while_typing`.
### Examples
```ini
# 3-finger: Window focus
gesturebind=none,left,3,focusdir,left
gesturebind=none,right,3,focusdir,right
gesturebind=none,up,3,focusdir,up
gesturebind=none,down,3,focusdir,down
# 4-finger: Workspace navigation
gesturebind=none,left,4,viewtoleft_have_client
gesturebind=none,right,4,viewtoright_have_client
gesturebind=none,up,4,toggleoverview
gesturebind=none,down,4,toggleoverview
```
---
## Switch Bindings
Trigger actions on hardware events like laptop lid open/close.
### Syntax
```ini
switchbind=FOLD_STATE,COMMAND,PARAMETERS
```
- **Fold State**: `fold` (lid closed), `unfold` (lid opened)
> **Warning:** Disable system lid handling in `/etc/systemd/logind.conf`:
>
> ```ini
> HandleLidSwitch=ignore
> HandleLidSwitchExternalPower=ignore
> HandleLidSwitchDocked=ignore
> ```
### Examples
```ini
switchbind=fold,spawn,swaylock -f -c 000000
switchbind=unfold,spawn,wlr-dpms on
```

View file

@ -0,0 +1,87 @@
---
title: Basic Configuration
description: Learn how to configure mangowm files, environment variables, and autostart scripts.
---
## Configuration File
mangowm uses a simple configuration file format. By default, it looks for a configuration file in `~/.config/mango/`.
1. **Locate Default Config**
A fallback configuration is provided at `/etc/mango/config.conf`. You can use this as a reference.
2. **Create User Config**
Copy the default config to your local config directory to start customizing.
```bash
mkdir -p ~/.config/mango
cp /etc/mango/config.conf ~/.config/mango/config.conf
```
3. **Launch with Custom Config (Optional)**
If you prefer to keep your config elsewhere, you can launch mango with the `-c` flag.
```bash
mango -c /path/to/your_config.conf
```
### Sub-Configuration
To keep your configuration organized, you can split it into multiple files and include them using the `source` keyword.
```ini
# Import keybindings from a separate file
source=~/.config/mango/bind.conf
# Relative paths work too
source=./theme.conf
# Optional: ignore if file doesn't exist (useful for shared configs)
source-optional=~/.config/mango/optional.conf
```
### Validate Configuration
You can check your configuration for errors without starting mangowm:
```bash
mango -c /path/to/config.conf -p
```
Use with `source-optional` for shared configs across different setups.
## Environment Variables
You can define environment variables directly within your config file. These are set before the window manager fully initializes.
> **Warning:** Environment variables defined here will be **reset** every time you reload the configuration.
```ini
env=QT_IM_MODULES,wayland;fcitx
env=XMODIFIERS,@im=fcitx
```
## Autostart
mangowm can automatically run commands or scripts upon startup. There are two modes for execution:
| Command | Behavior | Usage Case |
| :--- | :--- | :--- |
| `exec-once` | Runs **only once** when mangowm starts. | Status bars, Wallpapers, Notification daemons |
| `exec` | Runs **every time** the config is reloaded. | Scripts that need to refresh settings |
### Example Setup
```ini
# Start the status bar once
exec-once=waybar
# Set wallpaper
exec-once=swaybg -i ~/.config/mango/wallpaper/room.png
# Reload a custom script on config change
exec=bash ~/.config/mango/reload-settings.sh
```

View file

@ -0,0 +1,21 @@
---
title: Configuration
description: Configure mangowm with config files, environment variables, and autostart.
icon: Settings
---
Configure mangowm through config files, environment variables, and autostart.
<Cards>
<Card href="/docs/configuration/basics" title="Basics" description="Config files, env vars, exec-once, exec" />
<Card href="/docs/configuration/monitors" title="Monitors" description="Monitor settings and resolution" />
<Card href="/docs/configuration/input" title="Input" description="Keyboard, mouse, and touchpad" />
<Card href="/docs/configuration/xdg-portals" title="XDG Portals" description="File pickers and notifications" />
<Card href="/docs/configuration/miscellaneous" title="Miscellaneous" description="Additional options" />
</Cards>

151
docs/configuration/input.md Normal file
View file

@ -0,0 +1,151 @@
---
title: Input Devices
description: Configure keyboard layouts, mouse sensitivity, and touchpad gestures.
---
## Device Configuration
mangowm provides granular control over different input devices.
### Keyboard Settings
Control key repeat rates and layout rules.
| Setting | Type | Default | Description |
| :--- | :--- | :--- | :--- |
| `repeat_rate` | `int` | `25` | How many times a key repeats per second. |
| `repeat_delay` | `int` | `600` | Delay (ms) before a held key starts repeating. |
| `numlockon` | `0` or `1` | `0` | Enable NumLock on startup. |
| `xkb_rules_rules` | `string` | - | XKB rules file (e.g., `evdev`, `base`). Usually auto-detected. |
| `xkb_rules_model` | `string` | - | Keyboard model (e.g., `pc104`, `macbook`). |
| `xkb_rules_layout` | `string` | - | Keyboard layout code (e.g., `us`, `de`, `us,de`). |
| `xkb_rules_variant` | `string` | - | Layout variant (e.g., `dvorak`, `colemak`, `intl`). |
| `xkb_rules_options` | `string` | - | XKB options (e.g., `caps:escape`, `ctrl:nocaps`). |
**Example:**
```ini
repeat_rate=40
repeat_delay=300
numlockon=1
xkb_rules_layout=us,de
xkb_rules_variant=dvorak
xkb_rules_options=caps:escape,ctrl:nocaps
```
---
### Trackpad Settings
Specific settings for laptop touchpads. Some settings may require a relogin to take effect.
| Setting | Default | Description |
| :--- | :--- | :--- |
| `disable_trackpad` | `0` | Set to `1` to disable the trackpad entirely. |
| `tap_to_click` | `1` | Tap to trigger a left click. |
| `tap_and_drag` | `1` | Tap and hold to drag items. |
| `trackpad_natural_scrolling` | `0` | Invert scrolling direction (natural scrolling). |
| `scroll_method` | `1` | `1` (Two-finger), `2` (Edge), `4` (Button). |
| `click_method` | `1` | `1` (Button areas), `2` (Clickfinger). |
| `drag_lock` | `1` | Lock dragging after tapping. |
| `disable_while_typing` | `1` | Disable trackpad while typing. |
| `left_handed` | `0` | Swap left/right buttons. |
| `middle_button_emulation` | `0` | Emulate middle button. |
| `swipe_min_threshold` | `1` | Minimum swipe threshold. |
---
**Detailed descriptions:**
- `scroll_method` values:
- `0` — Never send scroll events (no scrolling).
- `1` — Two-finger scrolling: send scroll events when two fingers are logically down on the device.
- `2` — Edge scrolling: send scroll events when a finger moves along the bottom or right edge.
- `4` — Button scrolling: send scroll events when a button is held and the device moves along a scroll axis.
- `click_method` values:
- `0` — No software click emulation.
- `1` — Button areas: use software-defined areas on the touchpad to generate button events.
- `2` — Clickfinger: the number of fingers determines which button is pressed.
- `accel_profile` values:
- `0` — No acceleration.
- `1` — Flat: no dynamic acceleration. Pointer speed = original input speed × (1 + `accel_speed`).
- `2` — Adaptive: slow movement results in less acceleration, fast movement results in more.
- `button_map` values:
- `0` — 1/2/3 finger tap maps to left / right / middle.
- `1` — 1/2/3 finger tap maps to left / middle / right.
- `send_events_mode` values:
- `0` — Send events from this device normally.
- `1` — Do not send events from this device.
- `2` — Disable this device when an external pointer device is plugged in.
---
### Mouse Settings
Configuration for external mice.
| Setting | Default | Description |
| :--- | :--- | :--- |
| `mouse_natural_scrolling` | `0` | Invert scrolling direction. |
| `accel_profile` | `2` | `0` (None), `1` (Flat), `2` (Adaptive). |
| `accel_speed` | `0.0` | Speed adjustment (-1.0 to 1.0). |
| `left_handed` | `0` | Swap left and right buttons. |
| `middle_button_emulation` | `0` | Emulate middle button. |
| `swipe_min_threshold` | `1` | Minimum swipe threshold. |
| `send_events_mode` | `0` | `0` (Enabled), `1` (Disabled), `2` (Disabled on external mouse). |
| `button_map` | `0` | `0` (Left/right/middle), `1` (Left/middle/right). |
---
---
## Keyboard Layout Switching
To bind multiple layouts and toggle between them, define the layouts in `xkb_rules_layout` and use `xkb_rules_options` to set a toggle key combination. Then bind `switch_keyboard_layout` to trigger a switch.
```ini
# Define two layouts: US QWERTY and US Dvorak
xkb_rules_layout=us,us
xkb_rules_variant=,dvorak
xkb_rules_options=grp:lalt_lshift_toggle
```
Or bind it manually to a key:
```ini
# Bind Alt+Shift_L to cycle keyboard layout
bind=alt,shift_l,switch_keyboard_layout
```
Use `mmsg -g -k` to query the current keyboard layout at any time.
---
## Input Method Editor (IME)
To use Fcitx5 or IBus, set these environment variables in your config file.
> **Info:** These settings require a restart of the window manager to take effect.
**For Fcitx5:**
```ini
env=GTK_IM_MODULE,fcitx
env=QT_IM_MODULE,fcitx
env=QT_IM_MODULES,wayland;fcitx
env=SDL_IM_MODULE,fcitx
env=XMODIFIERS,@im=fcitx
env=GLFW_IM_MODULE,ibus
```
**For IBus:**
```ini
env=GTK_IM_MODULE,ibus
env=QT_IM_MODULE,ibus
env=XMODIFIERS,@im=ibus
```

View file

@ -0,0 +1,4 @@
{
"title": "Configuration",
"pages": ["basics", "monitors", "input", "xdg-portals", "miscellaneous"]
}

View file

@ -0,0 +1,51 @@
---
title: Miscellaneous
description: Advanced settings for XWayland, focus behavior, and system integration.
---
## System & Hardware
| Setting | Default | Description |
| :--- | :--- | :--- |
| `xwayland_persistence` | `1` | Keep XWayland running even when no X11 apps are open (reduces startup lag). |
| `syncobj_enable` | `0` | Enable `drm_syncobj` timeline support (helps with gaming stutter/lag). **Requires restart.** |
| `allow_lock_transparent` | `0` | Allow the lock screen to be transparent. |
| `allow_shortcuts_inhibit` | `1` | Allow shortcuts to be inhibited by clients. |
| `vrr` | - | Set via [monitor rule](/docs/configuration/monitors#monitor-rules). |
## Focus & Input
| Setting | Default | Description |
| :--- | :--- | :--- |
| `focus_on_activate` | `1` | Automatically focus windows when they request activation. |
| `sloppyfocus` | `1` | Focus follows the mouse cursor. |
| `warpcursor` | `1` | Warp the cursor to the center of the window when focus changes via keyboard. |
| `cursor_hide_timeout` | `0` | Hide the cursor after `N` seconds of inactivity (`0` to disable). |
| `drag_tile_to_tile` | `0` | Allow dragging a tiled window onto another to swap their positions. |
| `drag_corner` | `3` | Corner for drag-to-tile detection (0: none, 13: corners, 4: auto-detect). |
| `drag_warp_cursor` | `1` | Warp cursor when dragging windows to tile. |
| `axis_bind_apply_timeout` | `100` | Timeout (ms) for detecting consecutive scroll events for axis bindings. |
| `axis_scroll_factor` | `1.0` | Scroll factor for axis scroll speed (0.110.0). |
## Multi-Monitor & Tags
| Setting | Default | Description |
| :--- | :--- | :--- |
| `focus_cross_monitor` | `0` | Allow directional focus to cross monitor boundaries. |
| `exchange_cross_monitor` | `0` | Allow exchanging clients across monitor boundaries. |
| `focus_cross_tag` | `0` | Allow directional focus to cross into other tags. |
| `view_current_to_back` | `0` | Toggling the current tag switches back to the previously viewed tag. |
| `scratchpad_cross_monitor` | `0` | Share the scratchpad pool across all monitors. |
| `single_scratchpad` | `1` | Only allow one scratchpad (named or standard) to be visible at a time. |
| `circle_layout` | - | A comma-separated list of layouts `switch_layout` cycles through,the value sample:`tile,scroller`. |
## Window Behavior
| Setting | Default | Description |
| :--- | :--- | :--- |
| `enable_floating_snap` | `0` | Snap floating windows to edges or other windows. |
| `snap_distance` | `30` | Max distance (pixels) to trigger floating snap. |
| `no_border_when_single` | `0` | Remove window borders when only one window is visible on the tag. |
| `idleinhibit_ignore_visible` | `0` | Allow invisible clients (e.g., background audio players) to inhibit idle. |
| `drag_tile_refresh_interval` | `8.0` | Interval (1.016.0) to refresh tiled window resize during drag. Too small may cause application lag. |
| `drag_floating_refresh_interval` | `8.0` | Interval (1.016.0) to refresh floating window resize during drag. Too small may cause application lag. |

View file

@ -0,0 +1,276 @@
---
title: Monitors
description: Manage display outputs, resolution, scaling, and tearing.
---
## Monitor Rules
You can configure each display output individually using the `monitorrule` keyword.
**Syntax:**
```ini
monitorrule=name:Values,Parameter:Values,Parameter:Values
```
> **Info:** If any of the matching fields (`name`, `make`, `model`, `serial`) are set, **all** of the set ones must match to be considered a match. Use `wlr-randr` to get your monitor's name, make, model, and serial.
### Parameters
| Parameter | Type | Values | Description |
| :--- | :--- | :--- | :--- |
| `name` | string | Any | Match by monitor name (supports regex) |
| `make` | string | Any | Match by monitor manufacturer |
| `model` | string | Any | Match by monitor model |
| `serial` | string | Any | Match by monitor serial number |
| `width` | integer | 0-9999 | Monitor width |
| `height` | integer | 0-9999 | Monitor height |
| `refresh` | float | 0.001-9999.0 | Monitor refresh rate |
| `x` | integer | 0-99999 | X position |
| `y` | integer | 0-99999 | Y position |
| `scale` | float | 0.01-100.0 | Monitor scale |
| `vrr` | integer | 0, 1 | Enable variable refresh rate |
| `rr` | integer | 0-7 | Monitor transform |
| `custom` | integer | 0, 1 | Enable custom mode (not supported on all displays — may cause black screen) |
### Transform Values
| Value | Rotation |
| :--- | :--- |
| `0` | No transform |
| `1` | 90° counter-clockwise |
| `2` | 180° counter-clockwise |
| `3` | 270° counter-clockwise |
| `4` | 180° vertical flip |
| `5` | Flip + 90° counter-clockwise |
| `6` | Flip + 180° counter-clockwise |
| `7` | Flip + 270° counter-clockwise |
> **Critical:** If you use XWayland applications, **never use negative coordinates** for your monitor positions. This is a known XWayland bug that causes click events to malfunction. Always arrange your monitors starting from `0,0` and extend into positive coordinates.
> **Note:** that "name" is a regular expression. If you want an exact match, you need to add `^` and `$` to the beginning and end of the expression, for example, `^eDP-1$` matches exactly the string `eDP-1`.
### Examples
```ini
# Laptop display: 1080p, 60Hz, positioned at origin
monitorrule=name:^eDP-1$,width:1920,height:1080,refresh:60,x:0,y:10
# Match by make and model instead of name
monitorrule=make:Chimei Innolux Corporation,model:0x15F5,width:1920,height:1080,refresh:60,x:0,y:0
# Virtual monitor with pattern matching
monitorrule=name:HEADLESS-.*,width:1920,height:1080,refresh:60,x:1926,y:0,scale:1,rr:0,vrr:0
```
---
## Monitor Spec Format
Several commands (`focusmon`, `tagmon`, `disable_monitor`, `enable_monitor`, `toggle_monitor`, `viewcrossmon`, `tagcrossmon`) accept a **monitor_spec** string to identify a monitor.
**Format:**
```text
name:xxx&&make:xxx&&model:xxx&&serial:xxx
```
- Any field can be omitted and there is no order requirement.
- If all fields are omitted, the string is treated as the monitor name directly (e.g., `eDP-1`).
- Use `wlr-randr` to find your monitor's name, make, model, and serial.
**Examples:**
```bash
# By name (shorthand)
mmsg -d toggle_monitor,eDP-1
# By make and model
mmsg -d toggle_monitor,make:Chimei Innolux Corporation&&model:0x15F5
# By serial
mmsg -d toggle_monitor,serial:12345678
```
---
## Tearing (Game Mode)
Tearing allows games to bypass the compositor's VSync for lower latency.
| Setting | Default | Description |
| :--- | :--- | :--- |
| `allow_tearing` | `0` | Global tearing control: `0` (Disable), `1` (Enable), `2` (Fullscreen only). |
### Configuration
**Enable Globally:**
```ini
allow_tearing=1
```
**Enable per Window:**
Use a window rule to force tearing for specific games.
```ini
windowrule=force_tearing:1,title:vkcube
```
### Tearing Behavior Matrix
| `force_tearing` \ `allow_tearing` | DISABLED (0) | ENABLED (1) | FULLSCREEN_ONLY (2) |
| :--- | :--- | :--- | :--- |
| **UNSPECIFIED** (0) | Not Allowed | Follows tearing_hint | Only fullscreen follows tearing_hint |
| **ENABLED** (1) | Not Allowed | Allowed | Only fullscreen allowed |
| **DISABLED** (2) | Not Allowed | Not Allowed | Not Allowed |
### Graphics Card Compatibility
> **Warning:** Some graphics cards require setting the `WLR_DRM_NO_ATOMIC` environment variable before mango starts to successfully enable tearing.
Add this to `/etc/environment` and reboot:
```bash
WLR_DRM_NO_ATOMIC=1
```
Or run mango with the environment variable:
```bash
WLR_DRM_NO_ATOMIC=1 mango
```
---
## GPU Compatibility
If mango cannot display correctly or shows a black screen, try selecting a specific GPU:
```bash
# Use a single GPU
WLR_DRM_DEVICES=/dev/dri/card1 mango
# Use multiple GPUs
WLR_DRM_DEVICES=/dev/dri/card0:/dev/dri/card1 mango
```
Some GPUs have compatibility issues with `syncobj_enable=1` — it may crash apps like `kitty` that use syncobj. Set `WLR_DRM_NO_ATOMIC=1` in `/etc/environment` and reboot to resolve this.
---
## Power Management
You can control monitor power using the `mmsg` IPC tool.
```bash
# Turn off
mmsg -d disable_monitor,eDP-1
# Turn on
mmsg -d enable_monitor,eDP-1
# Toggle
mmsg -d toggle_monitor,eDP-1
```
You can also use `wlr-randr` for monitor management:
```bash
# Turn off monitor
wlr-randr --output eDP-1 --off
# Turn on monitor
wlr-randr --output eDP-1 --on
# Show all monitors
wlr-randr
```
---
## Screen Scale
### Without Global Scale (Recommended)
- If you do not use XWayland apps, you can use monitor rules or `wlr-randr` to set a global monitor scale.
- If you are using XWayland apps, it is not recommended to set a global monitor scale.
You can set scale like this, for example with a 1.4 factor.
**Dependencies:**
```bash
yay -S xorg-xrdb
yay -S xwayland-satellite
```
**In config file:**
```ini
env=QT_AUTO_SCREEN_SCALE_FACTOR,1
env=QT_WAYLAND_FORCE_DPI,140
```
**In autostart:**
```bash
echo "Xft.dpi: 140" | xrdb -merge
gsettings set org.gnome.desktop.interface text-scaling-factor 1.4
```
**Edit autostart for XWayland:**
```bash
# Start xwayland
/usr/sbin/xwayland-satellite :11 &
# Apply scale 1.4 for xwayland
sleep 0.5s && echo "Xft.dpi: 140" | xrdb -merge
```
### Using xwayland-satellite to Prevent Blurry XWayland Apps
If you use fractional scaling, you can use `xwayland-satellite` to automatically scale XWayland apps to prevent blurriness, for example with a scale of 1.4.
**Dependencies:**
```bash
yay -S xwayland-satellite
```
**In config file:**
```ini
env=DISPLAY,:2
exec-once=xwayland-satellite :2
monitorrule=name:eDP-1,width:1920,height:1080,refresh:60,x:0,y:0,scale:1.4,vrr:0,rr:0
```
> **Warning:** Use a `DISPLAY` value other than `:1` to avoid conflicting with mangowm.
---
## Virtual Monitors
You can create and manage virtual displays through IPC commands:
```bash
# Create virtual output
mmsg -d create_virtual_output
# Destroy all virtual outputs
mmsg -d destroy_all_virtual_output
```
You can configure virtual monitors using `wlr-randr`:
```bash
# Show all monitors
wlr-randr
# Configure virtual monitor
wlr-randr --output HEADLESS-1 --pos 1921,0 --scale 1 --custom-mode 1920x1080@60Hz
```
Virtual monitors can be used for screen sharing with tools like [Sunshine](https://github.com/LizardByte/Sunshine) and [Moonlight](https://github.com/moonlight-stream/moonlight-android), allowing other devices to act as extended monitors.

View file

@ -0,0 +1,76 @@
---
title: XDG Portals
description: Set up screen sharing, clipboard, keyring, and file pickers using XDG portals.
---
## Portal Configuration
You can customize portal settings via the following paths:
- **User Configuration (Priority):** `~/.config/xdg-desktop-portal/mango-portals.conf`
- **System Fallback:** `/usr/share/xdg-desktop-portal/mango-portals.conf`
> **Warning:** If you previously added `dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP=wlroots` to your config, remove it. Mango now handles this automatically.
## Screen Sharing
To enable screen sharing (OBS, Discord, WebRTC), you need `xdg-desktop-portal-wlr`.
1. **Install Dependencies**
`pipewire`, `pipewire-pulse`, `xdg-desktop-portal-wlr`
2. **Optional: Add to autostart**
In some situations the portal may not start automatically. You can add this to your autostart script to ensure it launches:
```bash
/usr/lib/xdg-desktop-portal-wlr &
```
3. **Restart your computer** to apply changes.
### Known Issues
- **Window screen sharing:** Some applications may have issues sharing individual windows. See [#184](https://github.com/mangowm/mango/pull/184) for workarounds.
- **Screen recording lag:** If you experience stuttering during screen recording, see [xdg-desktop-portal-wlr#351](https://github.com/emersion/xdg-desktop-portal-wlr/issues/351).
## Clipboard Manager
Use `cliphist` to manage clipboard history.
**Dependencies:** `wl-clipboard`, `cliphist`, `wl-clip-persist`
**Autostart Config:**
```bash
# Keep clipboard content after app closes
wl-clip-persist --clipboard regular --reconnect-tries 0 &
# Watch clipboard and store history
wl-paste --type text --watch cliphist store &
```
## GNOME Keyring
If you need to store passwords or secrets (e.g., for VS Code or Minecraft launchers), install `gnome-keyring`.
**Configuration:**
Add the following to `~/.config/xdg-desktop-portal/mango-portals.conf`:
```ini
[preferred]
default=gtk
org.freedesktop.impl.portal.ScreenCast=wlr
org.freedesktop.impl.portal.Screenshot=wlr
org.freedesktop.impl.portal.Secret=gnome-keyring
org.freedesktop.impl.portal.Inhibit=none
```
## File Picker (File Selector)
**Dependencies:** `xdg-desktop-portal`, `xdg-desktop-portal-gtk`
Reboot your computer once to apply.

101
docs/faq.md Normal file
View file

@ -0,0 +1,101 @@
---
title: FAQ
description: Frequently asked questions and troubleshooting.
---
### How do I arrange tiled windows with my mouse?
You can enable the `drag_tile_to_tile` option in your config. This allows you to drag a tiled window onto another to swap them.
```ini
drag_tile_to_tile=1
```
---
### Why is my background blurry or why does blur look wrong?
Blur applies to the transparent areas of windows. To disable it entirely, set `blur=0`.
If you are experiencing **performance issues with blur**, make sure `blur_optimized=1` (the default). This caches the wallpaper as the blur background, which is much cheaper on the GPU:
```ini
blur_optimized=1
```
---
### Blur shows my wallpaper instead of the real background content
This is expected behavior when `blur_optimized=1` (the default). The optimizer caches the wallpaper to reduce GPU load — windows will blur against the wallpaper rather than the actual content stacked beneath them.
If you want blur to composite against the true background (i.e., show whatever is actually behind the window), set:
```ini
blur_optimized=0
```
> **Warning:** Disabling `blur_optimized` significantly increases GPU consumption and may cause rendering lag, especially on lower-end hardware.
---
### My games are lagging or stuttering
Try enabling **SyncObj** timeline support and **Adaptive Sync** (VRR) if your monitor supports it.
```ini
syncobj_enable=1
adaptive_sync=1
```
---
### My games have high input latency
You can enable **Tearing** (similar to VSync off).
First, enable it globally:
```ini
allow_tearing=1
```
Then force it for your specific game:
```ini
windowrule=force_tearing:1,title:Counter-Strike 2
```
> **Warning:** Some graphics cards require setting `WLR_DRM_NO_ATOMIC=1` before mango starts for tearing to work. Add it to `/etc/environment` and reboot, or launch mango with `WLR_DRM_NO_ATOMIC=1 mango`. See [Monitors — Tearing](/docs/configuration/monitors#tearing-game-mode) for details.
---
### How do I use pipes `|` in spawn commands?
The standard `spawn` command does not support shell pipes directly. You must use `spawn_shell` instead.
```ini
bind=SUPER,P,spawn_shell,echo "hello" | rofi -dmenu
```
---
### Certain key combinations do not work on my keyboard layout.
`bind` automatically converts keysym to keycode, which is compatible with most layouts but can sometimes be imprecise. If a key combination is not triggering, use the **keycode** directly instead of the key name.
Run `wev` and press the key to find its keycode, then use it in your bind:
```ini
# Instead of:
bind=ALT,q,killclient
# Use the keycode (e.g., code:24 = q on most layouts):
bind=ALT,code:24,killclient
```
You can also use `binds` (the `s` flag) to match by keysym instead of keycode:
```ini
binds=ALT,q,killclient
```

42
docs/index.md Normal file
View file

@ -0,0 +1,42 @@
---
title: Introduction
description: A lightweight and feature-rich Wayland compositor based on dwl.
---
**mango** is a Wayland compositor based on [dwl](https://codeberg.org/dwl/dwl/). It aims to be as lightweight as `dwl` and can be built completely within a few seconds, without compromising on functionality.
> **Philosophy:** **Lightweight & Fast**: mango is designed to be minimal yet functional. It compiles in seconds and offers a robust set of features out of the box.
## Feature Highlights
Beyond basic window management, mangowm provides a rich set of features designed for a modern Wayland experience.
- **[Animations](/docs/visuals/animations)** — Smooth, customizable animations for opening, moving, closing windows and tag switching.
- **[Layouts](/docs/window-management/layouts)** — Supports Scroller, Master-Stack, Monocle, Grid, Deck, and more, with per-tag layouts.
- **[Visual Effects](/docs/visuals/effects)** — Built-in blur, shadows, corner radius, and opacity effects powered by scenefx.
- **[IPC & Scripting](/docs/ipc)** — Control the compositor externally with robust IPC support for custom scripts and widgets.
## Additional Features
- **XWayland Support** — Excellent compatibility for legacy X11 applications.
- **Tag System** — Uses tags instead of workspaces, allowing separate window layouts for each tag.
- **Input Methods** — Great support for text input v2/v3 (Fcitx5, IBus).
- **Window States** — Rich states including swallow, minimize, maximize, fullscreen, and overlay.
- **Hot-Reload Config** — Simple external configuration that supports hot-reloading without restarting.
- **Scratchpads** — Support for both Sway-like and named scratchpads.
## Community
- **[Join the mangowm Discord](https://discord.gg/CPjbDxesh5)** — Chat with the community, get support, share your setup, and stay updated with the latest mangowm news.
- **[Join the GitHub Discussions](https://github.com/mangowm/mango/discussions)** — Ask questions, request features, report issues, or share ideas directly with contributors and other users.
## Acknowledgements
This project is built upon the hard work of several open-source projects:
- **[wlroots](https://gitlab.freedesktop.org/wlroots/wlroots)** — Implementation of the Wayland protocol.
- **[mwc](https://github.com/nikoloc/mwc)** — Basal window animation reference.
- **[dwl](https://codeberg.org/dwl/dwl)** — Basal dwl features.
- **[sway](https://github.com/swaywm/sway)** — Sample implementation of the Wayland protocol.
- **[scenefx](https://github.com/wlrfx/scenefx)** — Library to simplify adding window effects.

239
docs/installation.md Normal file
View file

@ -0,0 +1,239 @@
---
title: Installation
description: Install mangowm on AerynOS, Arch, Fedora, Gentoo, Guix System, NixOS, PikaOS, or build from source.
---
## Package Installation
mangowm is available as a pre-built package on several distributions. Choose your distribution below.
---
### AerynOS
mangowm is available in the **AerynOS package repository**.
You can install it using the `moss` package manager:
```bash
sudo moss install mangowm
```
---
### Arch Linux
mangowm is available in the **Arch User Repository (AUR)**.
You can install it using an AUR helper like `yay` or `paru`:
```bash
yay -S mangowm-git
```
> **Tip:** This package pulls the latest git version, ensuring you have the newest features and fixes.
---
### Fedora
The package is in the third-party **Terra repository**. First, add the Terra Repository.
> **Warning:** Both commands require root privileges. Use `sudo` if needed.
```bash
dnf install --nogpgcheck --repofrompath 'terra,https://repos.fyralabs.com/terra$releasever' terra-release
```
Then, install the package:
```bash
dnf install mangowm
```
---
### Gentoo
The package is hosted in the community-maintained **GURU** repository.
1. **Add the GURU repository**
```bash
emerge --ask --verbose eselect-repository
eselect repository enable guru
emerge --sync guru
```
2. **Unmask packages**
Add the required packages to your `package.accept_keywords` file:
- `gui-libs/scenefx`
- `gui-wm/mangowm`
3. **Install mango**
```bash
emerge --ask --verbose gui-wm/mangowm
```
---
### Guix System
The package definition is described in the source repository.
1. **Add mango channel**
Add to `$HOME/.config/guix/channels.scm`:
```scheme
(cons (channel
(name 'mangowm)
(url "https://github.com/mangowm/mango.git")
(branch "main"))
%default-channels)
```
2. **Install**
After running `guix pull`, you can install mangowm:
```bash
guix install mangowm
```
Or add it to your system configuration using the mangowm module:
```scheme
(use-modules (mangowm))
(packages (cons*
mangowm-git
... ;; Other packages
%base-packages))
```
> **Tip:** For more information, see the [Guix System documentation](https://guix.gnu.org/manual/devel/en/html_node/Channels.html).
---
### NixOS
The repository provides a Flake with a NixOS module.
1. **Add flake input**
```nix
# flake.nix
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
mangowm = {
url = "github:mangowm/mango";
inputs.nixpkgs.follows = "nixpkgs";
};
# other inputs ...
};
}
```
2. **Import the NixOS module**
**Option A — Import in `configuration.nix`:**
```nix
# configuration.nix (or any other file that you import)
{inputs, ...}: {
imports = [
inputs.mangowm.nixosModules.mango
# .. other imports ...
];
# ...
}
```
**Option B — Import directly in flake:**
```nix
# flake.nix
{
# ...
outputs = { self, nixpkgs, mangowm, ...}@inputs: let
inherit (nixpkgs) lib;
# ...
in {
nixosConfigurations.YourHostName = lib.nixosSystem {
modules = [
mangowm.nixosModules.mango # or inputs.mangowm.nixosModules.mango
# other imports ...
];
};
}
}
```
3. **Enable the module**
```nix
# configuration.nix (or any other file that you import)
{
programs.mango.enable = true;
}
```
4. **Extra options**
- `programs.mango.package` — the mango package to use, allows usage of custom mango drvs
- `programs.mango.addLoginEntry` (default: `true`) — adds login entry to the display manager
---
### PikaOS
mangowm is available in the **PikaOS package repository**.
You can install it using the `pikman` package manager:
```bash
pikman install mangowc
```
---
## Building from Source
If your distribution isn't listed above, or you want the latest unreleased changes, you can build mangowm from source.
> **Info:** Ensure the following dependencies are installed before proceeding:
> - `wayland`
> - `wayland-protocols`
> - `libinput`
> - `libdrm`
> - `libxkbcommon`
> - `pixman`
> - `libdisplay-info`
> - `libliftoff`
> - `hwdata`
> - `seatd`
> - `pcre2`
> - `xorg-xwayland`
> - `libxcb`
You will need to build `wlroots` and `scenefx` manually as well.
1. **Build wlroots**
Clone and install the specific version required (check README for latest version).
```bash
git clone -b 0.19.2 https://gitlab.freedesktop.org/wlroots/wlroots.git
cd wlroots
meson build -Dprefix=/usr
sudo ninja -C build install
```
2. **Build scenefx**
This library handles the visual effects.
```bash
git clone -b 0.4.1 https://github.com/wlrfx/scenefx.git
cd scenefx
meson build -Dprefix=/usr
sudo ninja -C build install
```
3. **Build mangowm**
Finally, compile the compositor itself.
```bash
git clone https://github.com/mangowm/mango.git
cd mango
meson build -Dprefix=/usr
sudo ninja -C build install
```

154
docs/ipc.md Normal file
View file

@ -0,0 +1,154 @@
---
title: IPC
description: Control mangowm programmatically using mmsg.
---
## Introduction
mangowm includes a powerful IPC (Inter-Process Communication) tool called `mmsg`. This allows you to query the window manager's state, watch for events, and execute commands from external scripts.
## Basic Usage
The general syntax for `mmsg` is:
```bash
mmsg [-OTLq]
mmsg [-o <output>] -s [-t <tags>] [-l <layout>] [-c <tags>] [-d <cmd>,<arg1>,<arg2>,<arg3>,<arg4>,<arg5>]
mmsg [-o <output>] (-g | -w) [-OotlcvmfxekbA]
```
### Options
| Flag | Description |
| :--- | :--- |
| `-q` | Quit mangowm. |
| `-g` | **Get** values (tags, layout, focused client). |
| `-s` | **Set** values (switch tags, layouts). |
| `-w` | **Watch** mode (streams events). |
| `-O` | Get all output (monitor) information. |
| `-T` | Get number of tags. |
| `-L` | Get all available layouts. |
| `-o` | Select output (monitor). |
| `-t` | Get/set selected tags (set with `[+-^.]`). |
| `-l` | Get/set current layout. |
| `-c` | Get title and appid of focused client. |
| `-v` | Get visibility of statusbar. |
| `-m` | Get fullscreen status. |
| `-f` | Get floating status. |
| `-d` | **Dispatch** an internal command. |
| `-x` | Get focused client geometry. |
| `-e` | Get the name of the last focused layer. |
| `-k` | Get current keyboard layout. |
| `-b` | Get current keybind mode. |
| `-A` | Get scale factor of monitor. |
## Examples
### Tag Management
You can perform arithmetic on tags using the `-t` flag with `-s` (set).
```bash
# Switch to Tag 1
mmsg -t 1
# Add Tag 2 to current view (Multiview)
mmsg -s -t 2+
# Remove Tag 2 from current view
mmsg -s -t 2-
# Toggle Tag 2
mmsg -s -t 2^
```
### Layouts
Switch layouts programmatically. Layout codes: `S` (Scroller), `T` (Tile), `G` (Grid), `M` (Monocle), `K` (Deck), `CT` (Center Tile), `RT` (Right Tile), `VS` (Vertical Scroller), `VT` (Vertical Tile), `VG` (Vertical Grid), `VK` (Vertical Deck), `TG` (TGMix).
```bash
# Switch to Scroller
mmsg -l "S"
# Switch to Tile
mmsg -l "T"
```
### Dispatching Commands
Any command available in `config.conf` keybindings can be run via IPC.
```bash
# Close the focused window
mmsg -d killclient
# Resize window by +10 width
mmsg -d resizewin,+10,0
# Toggle fullscreen
mmsg -d togglefullscreen
# Disable a monitor power
mmsg -d disable_monitor,eDP-1
```
### Monitoring & Status
Use `-g` or `-w` to build custom status bars or automation scripts.
```bash
# Watch for all message changes
mmsg -w
# Get all messages without watch
mmsg -g
# Watch focused client appid and title
mmsg -w -c
# Get all available outputs
mmsg -O
# Get all tags message
mmsg -g -t
# Get current focused client message
mmsg -g -c
# Get current keyboard layout
mmsg -g -k
# Get current keybind mode
mmsg -g -b
# Get scale factor of current monitor
mmsg -g -A
```
#### Tag Message Format
- State: 0 → none, 1 → active, 2 → urgent
Example output:
| Monitor | Tag Number | Tag State | Clients in Tag | Focused Client |
|---------|------------|-----------|----------------|----------------|
| eDP-1 | tag 2 | 0 | 1 | 0 |
| Monitor | occupied tags mask | active tags mask | urgent tags mask |
|---------|--------------------|------------------|------------------|
| eDP-1 | 14 | 6 | 0 |
## Virtual Monitors
You can create headless outputs for screen mirroring or remote desktop access (e.g., Sunshine/Moonlight).
```bash
# Create a virtual output
mmsg -d create_virtual_output
# Configure it (set resolution)
wlr-randr --output HEADLESS-1 --pos 1920,0 --mode 1920x1080@60Hz
# Destroy all virtual outputs
mmsg -d destroy_all_virtual_output

17
docs/meta.json Normal file
View file

@ -0,0 +1,17 @@
{
"title": "mangowm",
"pages": [
"---Getting Started---",
"index",
"installation",
"quick-start",
"---Configuration---",
"configuration",
"visuals",
"window-management",
"bindings",
"---Reference---",
"ipc",
"faq"
]
}

88
docs/quick-start.md Normal file
View file

@ -0,0 +1,88 @@
---
title: Quick Start
description: Basic configuration and first steps with mangowm.
---
Now that you have mangowm installed, let's get your environment set up.
## Initial Setup
1. **Create Configuration Directory**
mangowm looks for configuration files in `~/.config/mango/`.
```bash
mkdir -p ~/.config/mango
```
2. **Copy Default Config**
A default configuration file is provided at `/etc/mango/config.conf`. Copy it to your local directory to start customizing.
```bash
cp /etc/mango/config.conf ~/.config/mango/config.conf
```
3. **Launch mangowm**
You can now start the compositor from your TTY.
```bash
mango
```
Optional: To specify a custom config file path:
```bash
mango -c /path/to/your/config.conf
```
## Essential Keybindings
mangowm uses the following keybinds by default:
| Key Combination | Action |
| :--- | :--- |
| `Alt` + `Return` | Open Terminal (defaults to `foot`) |
| `Alt` + `Space` | Open Launcher (defaults to `rofi`) |
| `Alt` + `Q` | Close (Kill) the active window |
| `Super` + `M` | Quit mangowm |
| `Super` + `F` | Toggle Fullscreen |
| `Alt` + `Arrow Keys` | Move focus (Left, Right, Up, Down) |
| `Ctrl` + `1-9` | Switch to Tag 1-9 |
| `Alt` + `1-9` | Move window to Tag 1-9 |
> **Warning:** Some default bindings rely on specific tools like `foot` (terminal) and `rofi` (launcher). Ensure you have them installed or update your `config.conf` to use your preferred alternatives.
## Recommended Tools
To get a fully functional desktop experience, we recommend installing the following components:
| Category | Recommended Tools |
| :--- | :--- |
| Application Launcher | rofi, bemenu, wmenu, fuzzel |
| Terminal Emulator | foot, wezterm, alacritty, kitty, ghostty |
| Status Bar | waybar, eww, quickshell, ags |
| Desktop Shell | Noctalia, DankMaterialShell |
| Wallpaper Setup | swww, swaybg |
| Notification Daemon | swaync, dunst, mako |
| Desktop Portal | xdg-desktop-portal, xdg-desktop-portal-wlr, xdg-desktop-portal-gtk |
| Clipboard | wl-clipboard, wl-clip-persist, cliphist |
| Gamma Control / Night Light | wlsunset, gammastep |
| Miscellaneous | xfce-polkit, wlogout |
## Example Configuration
Check out the [example configuration](https://github.com/DreamMaoMao/mango-config) by the creator of mangowm, including complete setups for mangowm, Waybar, Rofi, and more.
```bash
git clone https://github.com/DreamMaoMao/mango-config.git ~/.config/mango
```
## Next Steps
Now that you are up and running, dive deeper into customizing mangowm:
- [Configure Monitors](/docs/configuration/monitors) — Set up resolution, scaling, and multi-monitor layouts.
- [Window Rules](/docs/window-management/rules#window-rules) — Define how specific applications should behave.
- [Appearance](/docs/visuals/theming) — Customize colors, borders, gaps, and effects.

108
docs/visuals/animations.md Normal file
View file

@ -0,0 +1,108 @@
---
title: Animations
description: Configure smooth transitions for windows and layers.
---
## Enabling Animations
mangowm supports animations for both standard windows and layer shell surfaces (like bars and notifications).
```ini
animations=1
layer_animations=1
```
## Animation Types
You can define different animation styles for opening and closing windows and layer surfaces.
Available types: `slide`, `zoom`, `fade`, `none`.
```ini
animation_type_open=zoom
animation_type_close=slide
layer_animation_type_open=slide
layer_animation_type_close=slide
```
## Fade Settings
Control the fade-in and fade-out effects for animations.
```ini
animation_fade_in=1
animation_fade_out=1
fadein_begin_opacity=0.5
fadeout_begin_opacity=0.5
```
- `animation_fade_in` — Enable fade-in effect (0: disable, 1: enable)
- `animation_fade_out` — Enable fade-out effect (0: disable, 1: enable)
- `fadein_begin_opacity` — Starting opacity for fade-in animations (0.01.0)
- `fadeout_begin_opacity` — Starting opacity for fade-out animations (0.01.0)
## Zoom Settings
Adjust the zoom ratios for zoom animations.
```ini
zoom_initial_ratio=0.3
zoom_end_ratio=0.8
```
- `zoom_initial_ratio` — Initial zoom ratio
- `zoom_end_ratio` — End zoom ratio
## Durations
Control the speed of animations (in milliseconds).
| Setting | Type | Default | Description |
| :--- | :--- | :--- | :--- |
| `animation_duration_move` | integer | `500` | Move animation duration (ms) |
| `animation_duration_open` | integer | `400` | Open animation duration (ms) |
| `animation_duration_tag` | integer | `300` | Tag animation duration (ms) |
| `animation_duration_close` | integer | `300` | Close animation duration (ms) |
| `animation_duration_focus` | integer | `0` | Focus change (opacity transition) animation duration (ms) |
```ini
animation_duration_move=500
animation_duration_open=400
animation_duration_tag=300
animation_duration_close=300
animation_duration_focus=0
```
## Custom Bezier Curves
Bezier curves determine the "feel" of an animation (e.g., linear vs. bouncy). The format is `x1,y1,x2,y2`.
You can visualize and generate curve values using online tools like [cssportal.com](https://www.cssportal.com/css-cubic-bezier-generator/) or [easings.net](https://easings.net).
| Setting | Type | Default | Description |
| :--- | :--- | :--- | :--- |
| `animation_curve_open` | string | `0.46,1.0,0.29,0.99` | Open animation bezier curve |
| `animation_curve_move` | string | `0.46,1.0,0.29,0.99` | Move animation bezier curve |
| `animation_curve_tag` | string | `0.46,1.0,0.29,0.99` | Tag animation bezier curve |
| `animation_curve_close` | string | `0.46,1.0,0.29,0.99` | Close animation bezier curve |
| `animation_curve_focus` | string | `0.46,1.0,0.29,0.99` | Focus change (opacity transition) animation bezier curve |
| `animation_curve_opafadein` | string | `0.46,1.0,0.29,0.99` | Open opacity animation bezier curve |
| `animation_curve_opafadeout` | string | `0.5,0.5,0.5,0.5` | Close opacity animation bezier curve |
```ini
animation_curve_open=0.46,1.0,0.29,0.99
animation_curve_move=0.46,1.0,0.29,0.99
animation_curve_tag=0.46,1.0,0.29,0.99
animation_curve_close=0.46,1.0,0.29,0.99
animation_curve_focus=0.46,1.0,0.29,0.99
animation_curve_opafadein=0.46,1.0,0.29,0.99
animation_curve_opafadeout=0.5,0.5,0.5,0.5
```
## Tag Animation Direction
Control the direction of tag switch animations.
| Setting | Default | Description |
| :--- | :--- | :--- |
| `tag_animation_direction` | `1` | Tag animation direction (1: horizontal, 0: vertical) |

82
docs/visuals/effects.md Normal file
View file

@ -0,0 +1,82 @@
---
title: Window Effects
description: Add visual polish with blur, shadows, and opacity.
---
## Blur
Blur creates a frosted glass effect for transparent windows.
| Setting | Default | Description |
| :--- | :--- | :--- |
| `blur` | `0` | Enable blur for windows. |
| `blur_layer` | `0` | Enable blur for layer surfaces (like bars/docks). |
| `blur_optimized` | `1` | Caches the wallpaper and blur background, significantly reducing GPU usage. Disabling it will significantly increase GPU consumption and may cause rendering lag. **Highly recommended.** |
| `blur_params_radius` | `5` | The strength (radius) of the blur. |
| `blur_params_num_passes` | `1` | Number of passes. Higher = smoother but more expensive. |
| `blur_params_noise` | `0.02` | Blur noise level. |
| `blur_params_brightness` | `0.9` | Blur brightness adjustment. |
| `blur_params_contrast` | `0.9` | Blur contrast adjustment. |
| `blur_params_saturation` | `1.2` | Blur saturation adjustment. |
> **Warning:** Blur has a relatively high impact on performance. If your hardware is limited, it is not recommended to enable it. If you experience lag with blur on, ensure `blur_optimized=1` — disabling it will significantly increase GPU consumption and may cause rendering lag. To disable blur entirely, set `blur=0`.
---
## Shadows
Drop shadows help distinguish floating windows from the background.
| Setting | Default | Description |
| :--- | :--- | :--- |
| `shadows` | `0` | Enable shadows. |
| `layer_shadows` | `0` | Enable shadows for layer surfaces. |
| `shadow_only_floating` | `1` | Only draw shadows for floating windows (saves performance). |
| `shadows_size` | `10` | Size of the shadow. |
| `shadows_blur` | `15` | Shadow blur amount. |
| `shadows_position_x` | `0` | Shadow X offset. |
| `shadows_position_y` | `0` | Shadow Y offset. |
| `shadowscolor` | `0x000000ff` | Color of the shadow. |
```ini
# Example shadows configuration
shadows=1
layer_shadows=1
shadow_only_floating=1
shadows_size=12
shadows_blur=15
shadows_position_x=0
shadows_position_y=0
shadowscolor=0x000000ff
```
---
## Opacity & Corner Radius
Control the transparency and roundness of your windows.
| Setting | Default | Description |
| :--- | :--- | :--- |
| `border_radius` | `0` | Window corner radius in pixels. |
| `border_radius_location_default` | `0` | Corner radius location: `0` (all), `1` (top-left), `2` (top-right), `3` (bottom-left), `4` (bottom-right), `5` (closest corner). |
| `no_radius_when_single` | `0` | Disable radius if only one window is visible. |
| `focused_opacity` | `1.0` | Opacity for the active window (0.0 - 1.0). |
| `unfocused_opacity` | `1.0` | Opacity for inactive windows (0.0 - 1.0). |
```ini
# Window corner radius in pixels
border_radius=0
# Corner radius location (0=all, 1=top-left, 2=top-right, 3=bottom-left, 4=bottom-right)
border_radius_location_default=0
# Disable radius if only one window is visible
no_radius_when_single=0
# Opacity for the active window (0.0 - 1.0)
focused_opacity=1.0
# Opacity for inactive windows
unfocused_opacity=1.0
```

19
docs/visuals/index.mdx Normal file
View file

@ -0,0 +1,19 @@
---
title: Visuals
description: Customize borders, colors, effects, and animations.
icon: Palette
---
Customize the look of your desktop.
<Cards>
<Card href="/docs/visuals/theming" title="Theming" description="Borders, colors, and cursor" />
<Card href="/docs/visuals/status-bar" title="Status Bar" description="Built-in status bar" />
<Card href="/docs/visuals/effects" title="Effects" description="Blur, shadows, rounded corners" />
<Card href="/docs/visuals/animations" title="Animations" description="Window and tag animations" />
</Cards>

4
docs/visuals/meta.json Normal file
View file

@ -0,0 +1,4 @@
{
"title": "Visuals",
"pages": ["theming", "status-bar", "effects", "animations"]
}

141
docs/visuals/status-bar.md Normal file
View file

@ -0,0 +1,141 @@
---
title: Status Bar
description: Configure Waybar for mangowm.
---
## Module Configuration
mangowm is compatible with Waybar's `ext/workspaces` module (Wayland standard) or the `dwl/tags` module. We recommend `ext/workspaces` for the best experience.
> **Tip:** You can also use the `dwl/tags` module, but `ext/workspaces` provides better integration with mangowm's features. The `ext/workspaces` module requires **Waybar > 0.14.0**.
### `config.jsonc`
Add the following to your Waybar configuration:
```jsonc
{
"modules-left": [
"ext/workspaces",
"dwl/window"
],
"ext/workspaces": {
"format": "{icon}",
"ignore-hidden": true,
"on-click": "activate",
"on-click-right": "deactivate",
"sort-by-id": true
},
"dwl/window": {
"format": "[{layout}] {title}"
}
}
```
## Styling
You can style the tags using standard CSS in `style.css`.
### `style.css`
```css
#workspaces {
border-radius: 4px;
border-width: 2px;
border-style: solid;
border-color: #c9b890;
margin-left: 4px;
padding-left: 10px;
padding-right: 6px;
background: rgba(40, 40, 40, 0.76);
}
#workspaces button {
border: none;
background: none;
box-shadow: inherit;
text-shadow: inherit;
color: #ddca9e;
padding: 1px;
padding-left: 1px;
padding-right: 1px;
margin-right: 2px;
margin-left: 2px;
}
#workspaces button.hidden {
color: #9e906f;
background-color: transparent;
}
#workspaces button.visible {
color: #ddca9e;
}
#workspaces button:hover {
color: #d79921;
}
#workspaces button.active {
background-color: #ddca9e;
color: #282828;
margin-top: 5px;
margin-bottom: 5px;
padding-top: 1px;
padding-bottom: 0px;
border-radius: 3px;
}
#workspaces button.urgent {
background-color: #ef5e5e;
color: #282828;
margin-top: 5px;
margin-bottom: 5px;
padding-top: 1px;
padding-bottom: 0px;
border-radius: 3px;
}
#tags {
background-color: transparent;
}
#tags button {
background-color: #fff;
color: #a585cd;
}
#tags button:not(.occupied):not(.focused) {
font-size: 0;
min-width: 0;
min-height: 0;
margin: -17px;
padding: 0;
color: transparent;
background-color: transparent;
}
#tags button.occupied {
background-color: #fff;
color: #cdc885;
}
#tags button.focused {
background-color: rgb(186, 142, 213);
color: #fff;
}
#tags button.urgent {
background: rgb(171, 101, 101);
color: #fff;
}
#window {
background-color: rgb(237, 196, 147);
color: rgb(63, 37, 5);
}
```
## Complete Configuration Example
> **Tip:** You can find a complete Waybar configuration for mangowm at [waybar-config](https://github.com/DreamMaoMao/waybar-config).

56
docs/visuals/theming.md Normal file
View file

@ -0,0 +1,56 @@
---
title: Theming
description: Customize the visual appearance of borders, colors, and the cursor.
---
## Dimensions
Control the sizing of window borders and gaps.
| Setting | Default | Description |
| :--- | :--- | :--- |
| `borderpx` | `4` | Border width in pixels. |
| `gappih` | `5` | Horizontal inner gap (between windows). |
| `gappiv` | `5` | Vertical inner gap. |
| `gappoh` | `10` | Horizontal outer gap (between windows and screen edges). |
| `gappov` | `10` | Vertical outer gap. |
## Colors
Colors are defined in `0xRRGGBBAA` hex format.
```ini
# Background color of the root window
rootcolor=0x323232ff
# Inactive window border
bordercolor=0x444444ff
# Active window border
focuscolor=0xc66b25ff
# Urgent window border (alerts)
urgentcolor=0xad401fff
```
### State-Specific Colors
You can also color-code windows based on their state:
| State | Config Key | Default Color |
| :--- | :--- | :--- |
| Maximized | `maximizescreencolor` | `0x89aa61ff` |
| Scratchpad | `scratchpadcolor` | `0x516c93ff` |
| Global | `globalcolor` | `0xb153a7ff` |
| Overlay | `overlaycolor` | `0x14a57cff` |
> **Tip:** For scratchpad window sizing, see [Scratchpad](/docs/window-management/scratchpad) configuration.
## Cursor Theme
Set the size and theme of your mouse cursor.
```ini
cursor_size=24
cursor_theme=Adwaita
```

View file

@ -0,0 +1,19 @@
---
title: Window Management
description: Layouts, rules, and window behavior.
icon: LayoutGrid
---
Window management with layouts, rules, and scratchpad support.
<Cards>
<Card href="/docs/window-management/layouts" title="Layouts" description="Tile, scroller, monocle, grid, deck" />
<Card href="/docs/window-management/rules" title="Rules" description="Window rules and conditions" />
<Card href="/docs/window-management/overview" title="Overview" description="Window states and properties" />
<Card href="/docs/window-management/scratchpad" title="Scratchpad" description="Quick access to applications" />
</Cards>

View file

@ -0,0 +1,99 @@
---
title: Layouts
description: Configure and switch between different window layouts.
---
## Supported Layouts
mangowm supports a variety of layouts that can be assigned per tag.
- `tile`
- `scroller`
- `monocle`
- `grid`
- `deck`
- `center_tile`
- `vertical_tile`
- `right_tile`
- `vertical_scroller`
- `vertical_grid`
- `vertical_deck`
- `tgmix`
---
## Scroller Layout
The Scroller layout positions windows in a scrollable strip, similar to PaperWM.
### Configuration
| Setting | Default | Description |
| :--- | :--- | :--- |
| `scroller_structs` | `20` | Width reserved on sides when window ratio is 1. |
| `scroller_default_proportion` | `0.9` | Default width proportion for new windows. |
| `scroller_focus_center` | `0` | Always center the focused window (1 = enable). |
| `scroller_prefer_center` | `0` | Center focused window only if it was outside the view. |
| `scroller_prefer_overspread` | `1` | Allow windows to overspread when there's extra space. |
| `edge_scroller_pointer_focus` | `1` | Focus windows even if partially off-screen. |
| `scroller_proportion_preset` | `0.5,0.8,1.0` | Presets for cycling window widths. |
| `scroller_ignore_proportion_single` | `1` | Ignore proportion adjustments for single windows. |
| `scroller_default_proportion_single` | `1.0` | Default proportion for single windows in scroller. **Requires `scroller_ignore_proportion_single=0` to take effect.** |
> **Warning:** `scroller_prefer_overspread`, `scroller_focus_center`, and `scroller_prefer_center` interact with each other. Their priority order is:
>
> **scroller_prefer_overspread > scroller_focus_center > scroller_prefer_center**
>
> To ensure a lower-priority setting takes effect, you must set all higher-priority options to `0`.
```ini
# Example scroller configuration
scroller_structs=20
scroller_default_proportion=0.9
scroller_focus_center=0
scroller_prefer_center=0
scroller_prefer_overspread=1
edge_scroller_pointer_focus=1
scroller_default_proportion_single=1.0
scroller_proportion_preset=0.5,0.8,1.0
```
---
## Master-Stack Layouts
These settings apply to layouts like `tile` and `center_tile`.
| Setting | Default | Description |
| :--- | :--- | :--- |
| `new_is_master` | `1` | New windows become the master window. |
| `default_mfact` | `0.55` | The split ratio between master and stack areas. |
| `default_nmaster` | `1` | Number of allowed master windows. |
| `smartgaps` | `0` | Disable gaps when only one window is present. |
| `center_master_overspread` | `0` | (Center Tile) Master spreads across screen if no stack exists. |
| `center_when_single_stack` | `1` | (Center Tile) Center master when only one stack window exists. |
```ini
# Example master-stack configuration
new_is_master=1
smartgaps=0
default_mfact=0.55
default_nmaster=1
```
---
## Switching Layouts
You can switch layouts dynamically or set a default for specific tags using [Tag Rules](/docs/window-management/rules#tag-rules).
**Keybinding Examples:**
```ini
# Cycle through layouts
bind=SUPER,n,switch_layout
# Set specific layout
bind=SUPER,t,setlayout,tile
bind=SUPER,s,setlayout,scroller
```

View file

@ -0,0 +1,4 @@
{
"title": "Window Management",
"pages": ["layouts", "rules", "overview", "scratchpad"]
}

View file

@ -0,0 +1,29 @@
---
title: Overview
description: Configure the overview mode for window navigation.
---
## Overview Settings
| Setting | Type | Default | Description |
| :--- | :--- | :--- | :--- |
| `hotarea_size` | integer | `10` | Hot area size in pixels. |
| `enable_hotarea` | integer | `1` | Enable hot areas (0: disable, 1: enable). |
| `hotarea_corner` | integer | `2` | Hot area corner (0: top-left, 1: top-right, 2: bottom-left, 3: bottom-right). |
| `ov_tab_mode` | integer | `0` | Overview tab mode (0: disable, 1: enable). |
| `overviewgappi` | integer | `5` | Inner gap in overview mode. |
| `overviewgappo` | integer | `30` | Outer gap in overview mode. |
### Setting Descriptions
- `enable_hotarea` — Toggles overview when the cursor enters the configured corner.
- `hotarea_size` — Size of the hot area trigger zone in pixels.
- `hotarea_corner` — Corner that triggers the hot area (0: top-left, 1: top-right, 2: bottom-left, 3: bottom-right).
- `ov_tab_mode` — Circles focus through windows in overview; releasing the mod key exits overview.
### Mouse Interaction in Overview
When in overview mode:
- **Left mouse button** — Jump to (focus) a window.
- **Right mouse button** — Close a window.

View file

@ -0,0 +1,249 @@
---
title: Rules
description: Define behavior for specific windows, tags, and layers.
---
## Window Rules
Window rules allow you to set specific properties (floating, opacity, size, animations, etc.) for applications based on their `appid` or `title`. You can set all parameters in one line, and if you both set appid and title, the window will only follow the rules when appid and title both match.
**Format:**
```ini
windowrule=Parameter:Values,title:Values
windowrule=Parameter:Values,Parameter:Values,appid:Values,title:Values
```
### State & Behavior Parameters
| Parameter | Type | Values | Description |
| :--- | :--- | :--- | :--- |
| `appid` | string | Any | Match by application ID, supports regex |
| `title` | string | Any | Match by window title, supports regex |
| `isfloating` | integer | `0` / `1` | Force floating state |
| `isfullscreen` | integer | `0` / `1` | Force fullscreen state |
| `isfakefullscreen` | integer | `0` / `1` | Force fake-fullscreen state (window stays constrained) |
| `isglobal` | integer | `0` / `1` | Open as global window (sticky across tags) |
| `isoverlay` | integer | `0` / `1` | Make it always in top layer |
| `isopensilent` | integer | `0` / `1` | Open without focus |
| `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 |
| `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 |
| `force_tiled_state` | integer | `0` / `1` | Deceive the window into thinking it is tiling, so it better adheres to assigned dimensions |
| `noopenmaximized` | integer | `0` / `1` | Window does not open as maximized mode |
| `single_scratchpad` | integer | `0` / `1` (default 1) | Only show one out of named scratchpads or the normal scratchpad |
| `allow_shortcuts_inhibit` | integer | `0` / `1` (default 1) | Allow shortcuts to be inhibited by clients |
| `indleinhibit_when_focus` | integer | `0` / `1` (default 0) | Automatically keep idle inhibit active when this window is focused |
### Geometry & Position
| Parameter | Type | Values | Description |
| :--- | :--- | :--- | :--- |
| `width` | integer | 0-9999 | Window width when it becomes a floating window |
| `height` | integer | 0-9999 | Window height when it becomes a floating window |
| `offsetx` | integer | -999-999 | X offset from center (%), 100 is the edge of screen with outer gap |
| `offsety` | integer | -999-999 | Y offset from center (%), 100 is the edge of screen with outer gap |
| `monitor` | string | Any | Assign to monitor by [monitor spec](/docs/configuration/monitors#monitor-spec-format) (name, make, model, or serial) |
| `tags` | integer | 1-9 | Assign to specific tag |
| `no_force_center` | integer | `0` / `1` | Window does not force center |
| `isnosizehint` | integer | `0` / `1` | Don't use min size and max size for size hints |
### Visuals & Decoration
| Parameter | Type | Values | Description |
| :--- | :--- | :--- | :--- |
| `noblur` | integer | `0` / `1` | Window does not have blur effect |
| `isnoborder` | integer | `0` / `1` | Remove window border |
| `isnoshadow` | integer | `0` / `1` | Not apply shadow |
| `isnoradius` | integer | `0` / `1` | Not apply corner radius |
| `isnoanimation` | integer | `0` / `1` | Not apply animation |
| `focused_opacity` | integer | `0` / `1` | Window focused opacity |
| `unfocused_opacity` | integer | `0` / `1` | Window unfocused opacity |
| `allow_csd` | integer | `0` / `1` | Allow client side decoration |
> **Tip:** For detailed visual effects configuration, see the [Window Effects](/docs/visuals/effects) page for blur, shadows, and opacity settings.
### Layout & Scroller
| Parameter | Type | Values | Description |
| :--- | :--- | :--- | :--- |
| `scroller_proportion` | float | 0.1-1.0 | Set scroller proportion |
| `scroller_proportion_single` | float | 0.1-1.0 | Set scroller auto adjust proportion when it is single window |
> **Tip:** For comprehensive layout configuration, see the [Layouts](/docs/window-management/layouts) page for all layout options and detailed settings.
### Animation
| Parameter | Type | Values | Description |
| :--- | :--- | :--- | :--- |
| `animation_type_open` | string | zoom, slide, fade, none | Set open animation |
| `animation_type_close` | string | zoom, slide, fade, none | Set close animation |
| `nofadein` | integer | `0` / `1` | Window ignores fade-in animation |
| `nofadeout` | integer | `0` / `1` | Window ignores fade-out animation |
> **Tip:** For detailed animation configuration, see the [Animations](/docs/visuals/animations) page for available types and settings.
### Terminal & Swallowing
| Parameter | Type | Values | Description |
| :--- | :--- | :--- | :--- |
| `isterm` | integer | `0` / `1` | A new GUI window will replace the isterm window when it is opened |
| `noswallow` | integer | `0` / `1` | The window will not replace the isterm window |
### Global & Special Windows
| Parameter | Type | Values | Description |
| :--- | :--- | :--- | :--- |
| `globalkeybinding` | string | `[mod combination][-][key]` | Global keybinding (only works for Wayland apps) |
| `isunglobal` | integer | `0` / `1` | Open as unmanaged global window (for desktop pets or camera windows) |
| `isnamedscratchpad` | integer | `0` / `1` | 0: disable, 1: named scratchpad |
> **Tip:** For scratchpad usage, see the [Scratchpad](/docs/window-management/scratchpad) page for detailed configuration examples.
### Performance & Tearing
| Parameter | Type | Values | Description |
| :--- | :--- | :--- | :--- |
| `force_tearing` | integer | `0` / `1` | Set window to tearing state, refer to [Tearing](/docs/configuration/monitors#tearing-game-mode) |
### Examples
```ini
# Set specific window size and position
windowrule=width:1000,height:900,appid:yesplaymusic,title:Demons
# Global keybindings for OBS Studio
windowrule=globalkeybinding:ctrl+alt-o,appid:com.obsproject.Studio
windowrule=globalkeybinding:ctrl+alt+n,appid:com.obsproject.Studio
windowrule=isopensilent:1,appid:com.obsproject.Studio
# Force tearing for games
windowrule=force_tearing:1,title:vkcube
windowrule=force_tearing:1,title:Counter-Strike 2
# Named scratchpad for file manager
windowrule=isnamedscratchpad:1,width:1280,height:800,appid:st-yazi
# Custom opacity for specific apps
windowrule=focused_opacity:0.8,appid:firefox
windowrule=unfocused_opacity:0.6,appid:foot
# Disable blur for selection tools
windowrule=noblur:1,appid:slurp
# Position windows relative to screen center
windowrule=offsetx:20,offsety:-30,width:800,height:600,appid:alacritty
# Send to specific tag and monitor
windowrule=tags:9,monitor:HDMI-A-1,appid:discord
# Terminal swallowing setup
windowrule=isterm:1,appid:st
windowrule=noswallow:1,appid:foot
# Disable client-side decorations
windowrule=allow_csd:1,appid:firefox
# Unmanaged global window (desktop pets, camera)
windowrule=isunglobal:1,appid:cheese
# Named scratchpad toggle
bind=alt,h,toggle_named_scratchpad,st-yazi,none,st -c st-yazi -e yazi
```
---
## Tag Rules
You can set all parameters in one line. If only `id` is set, the rule is followed when the id matches. If any of `monitor_name`, `monitor_make`, `monitor_model`, or `monitor_serial` are set, the rule is followed only if **all** of the set monitor fields match.
> **Warning:** Layouts set in tag rules have a higher priority than monitor rule layouts.
**Format:**
```ini
tagrule=id:Values,Parameter:Values,Parameter:Values
tagrule=id:Values,monitor_name:eDP-1,Parameter:Values,Parameter:Values
tagrule=id:Values,monitor_make:xxx,monitor_model:xxx,Parameter:Values
```
> **Tip:** See [Layouts](/docs/window-management/layouts#supported-layouts) for detailed descriptions of each layout type.
| Parameter | Type | Values | Description |
| :--- | :--- | :--- | :--- |
| `id` | integer | 0-9 | Match by tag id, 0 means the ~0 tag |
| `monitor_name` | string | monitor name | Match by monitor name |
| `monitor_make` | string | monitor make | Match by monitor manufacturer |
| `monitor_model` | string | monitor model | Match by monitor model |
| `monitor_serial` | string | monitor serial | Match by monitor serial number |
| `layout_name` | string | layout name | Layout name to set |
| `no_render_border` | integer | `0` / `1` | Disable render border |
| `no_hide` | integer | `0` / `1` | Not hide even if the tag is empty |
| `nmaster` | integer | 0, 99 | Number of master windows |
| `mfact` | float | 0.10.9 | Master area factor |
### Examples
```ini
# Set layout for specific tags
tagrule=id:1,layout_name:scroller
tagrule=id:2,layout_name:scroller
# Limit to specific monitor
tagrule=id:1,monitor_name:eDP-1,layout_name:scroller
tagrule=id:2,monitor_name:eDP-1,layout_name:scroller
# Persistent tags (1-4) with layout assignment
tagrule=id:1,no_hide:1,layout_name:scroller
tagrule=id:2,no_hide:1,layout_name:scroller
tagrule=id:3,monitor_name:eDP-1,no_hide:1,layout_name:scroller
tagrule=id:4,monitor_name:eDP-1,no_hide:1,layout_name:scroller
# Advanced tag configuration with master layout settings
tagrule=id:5,layout_name:tile,nmaster:2,mfact:0.6
tagrule=id:6,monitor_name:HDMI-A-1,layout_name:monocle,no_render_border:1
```
> **Tip:** For Waybar configuration with persistent tags, see [Status Bar](/docs/visuals/status-bar) documentation.
---
## Layer Rules
You can set all parameters in one line. Target "layer shell" surfaces like status bars (`waybar`), launchers (`rofi`), or notification daemons.
**Format:**
```ini
layerrule=layer_name:Values,Parameter:Values,Parameter:Values
```
> **Tip:** You can use `mmsg -e` to get the last open layer name for debugging.
| Parameter | Type | Values | Description |
| :--- | :--- | :--- | :--- |
| `layer_name` | string | layer name | Match name of layer, supports regex |
| `animation_type_open` | string | slide, zoom, fade, none | Set open animation |
| `animation_type_close` | string | slide, zoom, fade, none | Set close animation |
| `noblur` | integer | `0` / `1` | Disable blur |
| `noanim` | integer | `0` / `1` | Disable layer animation |
| `noshadow` | integer | `0` / `1` | Disable layer shadow |
> **Tip:** For animation types, see [Animations](/docs/visuals/animations#animation-types). For visual effects, see [Window Effects](/docs/visuals/effects).
### Examples
```ini
# No blur or animation for slurp selection layer (avoids occlusion and ghosting in screenshots)
layerrule=noanim:1,noblur:1,layer_name:selection
# Zoom animation for Rofi with multiple parameters
layerrule=animation_type_open:zoom,noanim:0,layer_name:rofi
# Disable animations and shadows for notification daemon
layerrule=noanim:1,noshadow:1,layer_name:swaync
# Multiple effects for launcher
layerrule=animation_type_open:slide,animation_type_close:fade,noblur:1,layer_name:wofi
```

View file

@ -0,0 +1,73 @@
---
title: Scratchpad
description: Manage hidden "scratchpad" windows for quick access.
---
mangowm supports two types of scratchpads: the standard pool (Sway-like) and named scratchpads.
## Standard Scratchpad
Any window can be sent to the "scratchpad" pile, which hides it. You can then cycle through them.
**Keybindings:**
```ini
# Send current window to scratchpad
bind=SUPER,i,minimized
# Toggle (show/hide) the scratchpad
bind=ALT,z,toggle_scratchpad
# Retrieve window from scratchpad (restore)
bind=SUPER+SHIFT,i,restore_minimized
```
---
## Named Scratchpad
Named scratchpads are bound to specific keys and applications. When triggered, mangowm will either launch the app (if not running) or toggle its visibility.
**1. Define the Window Rule**
You must identify the app using a unique `appid` or `title` and mark it as a named scratchpad. The application must support setting a custom appid or title at launch. Common examples:
- `st -c my-appid` — sets the appid
- `kitty -T my-title` — sets the window title
- `foot --app-id my-appid` — sets the appid
Use `none` as a placeholder when you only want to match by one field.
```ini
# Match by appid
windowrule=isnamedscratchpad:1,width:1280,height:800,appid:st-yazi
# Match by title
windowrule=isnamedscratchpad:1,width:1000,height:700,title:kitty-scratch
```
**2. Bind the Toggle Key**
Format: `bind=MOD,KEY,toggle_named_scratchpad,appid,title,command`
Use `none` for whichever field you are not matching on.
```ini
# Match by appid: launch 'st' with class 'st-yazi' running 'yazi'
bind=alt,h,toggle_named_scratchpad,st-yazi,none,st -c st-yazi -e yazi
# Match by title: launch 'kitty' with window title 'kitty-scratch'
bind=alt,k,toggle_named_scratchpad,none,kitty-scratch,kitty -T kitty-scratch
```
---
## Appearance
You can customize the size of scratchpad windows relative to the screen.
```ini
scratchpad_width_ratio=0.8
scratchpad_height_ratio=0.9
scratchpadcolor=0x516c93ff
```

View file

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

View file

@ -10,20 +10,21 @@ void set_rect_size(struct wlr_scene_rect *rect, int32_t width, int32_t height) {
enum corner_location set_client_corner_location(Client *c) {
enum corner_location current_corner_location = CORNER_LOCATION_ALL;
struct wlr_box target_geom = animations ? c->animation.current : c->geom;
if (target_geom.x + border_radius <= c->mon->m.x) {
current_corner_location &= ~CORNER_LOCATION_LEFT; // 清除左标志位
struct wlr_box target_geom =
config.animations ? c->animation.current : c->geom;
if (target_geom.x + config.border_radius <= c->mon->m.x) {
current_corner_location &= ~CORNER_LOCATION_LEFT;
}
if (target_geom.x + target_geom.width - border_radius >=
if (target_geom.x + target_geom.width - config.border_radius >=
c->mon->m.x + c->mon->m.width) {
current_corner_location &= ~CORNER_LOCATION_RIGHT; // 清除右标志位
current_corner_location &= ~CORNER_LOCATION_RIGHT;
}
if (target_geom.y + border_radius <= c->mon->m.y) {
current_corner_location &= ~CORNER_LOCATION_TOP; // 清除上标志位
if (target_geom.y + config.border_radius <= c->mon->m.y) {
current_corner_location &= ~CORNER_LOCATION_TOP;
}
if (target_geom.y + target_geom.height - border_radius >=
if (target_geom.y + target_geom.height - config.border_radius >=
c->mon->m.y + c->mon->m.height) {
current_corner_location &= ~CORNER_LOCATION_BOTTOM; // 清除下标志位
current_corner_location &= ~CORNER_LOCATION_BOTTOM;
}
return current_corner_location;
}
@ -54,15 +55,16 @@ int32_t is_special_animation_rule(Client *c) {
} else if (c->mon->visible_tiling_clients == 1 && !c->isfloating) {
return DOWN;
} else if (c->mon->visible_tiling_clients == 2 && !c->isfloating &&
!new_is_master && is_horizontal_stack_layout(c->mon)) {
!config.new_is_master && is_horizontal_stack_layout(c->mon)) {
return RIGHT;
} else if (!c->isfloating && new_is_master &&
} else if (!c->isfloating && config.new_is_master &&
is_horizontal_stack_layout(c->mon)) {
return LEFT;
} else if (c->mon->visible_tiling_clients == 2 && !c->isfloating &&
!new_is_master && is_horizontal_right_stack_layout(c->mon)) {
!config.new_is_master &&
is_horizontal_right_stack_layout(c->mon)) {
return LEFT;
} else if (!c->isfloating && new_is_master &&
} else if (!c->isfloating && config.new_is_master &&
is_horizontal_right_stack_layout(c->mon)) {
return RIGHT;
} else {
@ -77,7 +79,8 @@ void set_client_open_animation(Client *c, struct wlr_box geo) {
int32_t special_direction;
int32_t center_x, center_y;
if ((!c->animation_type_open && strcmp(animation_type_open, "fade") == 0) ||
if ((!c->animation_type_open &&
strcmp(config.animation_type_open, "fade") == 0) ||
(c->animation_type_open &&
strcmp(c->animation_type_open, "fade") == 0)) {
c->animainit_geom.width = geo.width;
@ -86,11 +89,11 @@ void set_client_open_animation(Client *c, struct wlr_box geo) {
c->animainit_geom.y = geo.y;
return;
} else if ((!c->animation_type_open &&
strcmp(animation_type_open, "zoom") == 0) ||
strcmp(config.animation_type_open, "zoom") == 0) ||
(c->animation_type_open &&
strcmp(c->animation_type_open, "zoom") == 0)) {
c->animainit_geom.width = geo.width * zoom_initial_ratio;
c->animainit_geom.height = geo.height * zoom_initial_ratio;
c->animainit_geom.width = geo.width * config.zoom_initial_ratio;
c->animainit_geom.height = geo.height * config.zoom_initial_ratio;
c->animainit_geom.x = geo.x + (geo.width - c->animainit_geom.width) / 2;
c->animainit_geom.y =
geo.y + (geo.height - c->animainit_geom.height) / 2;
@ -223,7 +226,7 @@ void scene_buffer_apply_effect(struct wlr_scene_buffer *buffer, int32_t sx,
if (wlr_xdg_popup_try_from_wlr_surface(surface) != NULL)
return;
wlr_scene_buffer_set_corner_radius(buffer, border_radius,
wlr_scene_buffer_set_corner_radius(buffer, config.border_radius,
buffer_data->corner_location);
}
@ -241,7 +244,7 @@ void buffer_set_effect(Client *c, BufferData data) {
data.should_scale = false;
if (c->isnoradius || c->isfullscreen ||
(no_radius_when_single && c->mon &&
(config.no_radius_when_single && c->mon &&
c->mon->visible_tiling_clients == 1)) {
data.corner_location = CORNER_LOCATION_NONE;
}
@ -255,7 +258,7 @@ void client_draw_shadow(Client *c) {
if (c->iskilling || !client_surface(c)->mapped || c->isnoshadow)
return;
if (!shadows || (!c->isfloating && shadow_only_floating)) {
if (!config.shadows || (!c->isfloating && config.shadow_only_floating)) {
if (c->shadow->node.enabled)
wlr_scene_node_set_enabled(&c->shadow->node, false);
return;
@ -266,7 +269,7 @@ void client_draw_shadow(Client *c) {
bool hit_no_border = check_hit_no_border(c);
enum corner_location current_corner_location =
c->isfullscreen || (no_radius_when_single && c->mon &&
c->isfullscreen || (config.no_radius_when_single && c->mon &&
c->mon->visible_tiling_clients == 1)
? CORNER_LOCATION_NONE
: CORNER_LOCATION_ALL;
@ -276,9 +279,8 @@ void client_draw_shadow(Client *c) {
int32_t width, height;
client_actual_size(c, &width, &height);
int32_t delta = shadows_size + (int32_t)c->bw - bwoffset;
int32_t delta = config.shadows_size + (int32_t)c->bw - bwoffset;
/* we calculate where to clip the shadow */
struct wlr_box client_box = {
.x = bwoffset,
.y = bwoffset,
@ -287,22 +289,20 @@ void client_draw_shadow(Client *c) {
};
struct wlr_box shadow_box = {
.x = shadows_position_x + bwoffset,
.y = shadows_position_y + bwoffset,
.x = config.shadows_position_x + bwoffset,
.y = config.shadows_position_y + bwoffset,
.width = width + 2 * delta,
.height = height + 2 * delta,
};
struct wlr_box intersection_box;
wlr_box_intersection(&intersection_box, &client_box, &shadow_box);
/* clipped region takes shadow relative coords, so we translate everything
* by its position */
intersection_box.x -= shadows_position_x + bwoffset;
intersection_box.y -= shadows_position_y + bwoffset;
intersection_box.x -= config.shadows_position_x + bwoffset;
intersection_box.y -= config.shadows_position_y + bwoffset;
struct clipped_region clipped_region = {
.area = intersection_box,
.corner_radius = border_radius,
.corner_radius = config.border_radius,
.corners = current_corner_location,
};
@ -356,23 +356,23 @@ void apply_border(Client *c) {
bool hit_no_border = check_hit_no_border(c);
enum corner_location current_corner_location;
if (c->isfullscreen || (no_radius_when_single && c->mon &&
if (c->isfullscreen || (config.no_radius_when_single && c->mon &&
c->mon->visible_tiling_clients == 1)) {
current_corner_location = CORNER_LOCATION_NONE;
} else {
current_corner_location = set_client_corner_location(c);
}
if (hit_no_border && smartgaps) {
if (hit_no_border && config.smartgaps) {
c->bw = 0;
c->fake_no_border = true;
} else if (hit_no_border && !smartgaps) {
} else if (hit_no_border && !config.smartgaps) {
wlr_scene_rect_set_size(c->border, 0, 0);
wlr_scene_node_set_position(&c->scene_surface->node, c->bw, c->bw);
c->fake_no_border = true;
return;
} else if (!c->isfullscreen && VISIBLEON(c, c->mon)) {
c->bw = c->isnoborder ? 0 : borderpx;
c->bw = c->isnoborder ? 0 : config.borderpx;
c->fake_no_border = false;
}
@ -434,14 +434,14 @@ void apply_border(Client *c) {
struct clipped_region clipped_region = {
.area = {inner_surface_x, inner_surface_y, inner_surface_width,
inner_surface_height},
.corner_radius = border_radius,
.corner_radius = config.border_radius,
.corners = current_corner_location,
};
wlr_scene_node_set_position(&c->scene_surface->node, c->bw, c->bw);
wlr_scene_rect_set_size(c->border, rect_width, rect_height);
wlr_scene_node_set_position(&c->border->node, rect_x, rect_y);
wlr_scene_rect_set_corner_radius(c->border, border_radius,
wlr_scene_rect_set_corner_radius(c->border, config.border_radius,
current_corner_location);
wlr_scene_rect_set_clipped_region(c->border, clipped_region);
}
@ -523,7 +523,7 @@ void client_apply_clip(Client *c, float factor) {
enum corner_location current_corner_location =
set_client_corner_location(c);
if (!animations) {
if (!config.animations) {
c->animation.running = false;
c->need_output_flush = false;
c->animainit_geom = c->current = c->pending = c->animation.current =
@ -655,19 +655,19 @@ void fadeout_client_animation_next_tick(Client *c) {
double opacity_eased_progress =
find_animation_curve_at(animation_passed, OPAFADEOUT);
double percent = fadeout_begin_opacity -
(opacity_eased_progress * fadeout_begin_opacity);
double percent = config.fadeout_begin_opacity -
(opacity_eased_progress * config.fadeout_begin_opacity);
double opacity = MAX(percent, 0);
if (animation_fade_out && !c->nofadeout)
if (config.animation_fade_out && !c->nofadeout)
wlr_scene_node_for_each_buffer(&c->scene->node,
scene_buffer_apply_opacity, &opacity);
if ((c->animation_type_close &&
strcmp(c->animation_type_close, "zoom") == 0) ||
(!c->animation_type_close &&
strcmp(animation_type_close, "zoom") == 0)) {
strcmp(config.animation_type_close, "zoom") == 0)) {
buffer_data.width = width;
buffer_data.height = height;
@ -768,14 +768,14 @@ void init_fadeout_client(Client *c) {
if ((c->animation_type_close &&
strcmp(c->animation_type_close, "none") == 0) ||
(!c->animation_type_close &&
strcmp(animation_type_close, "none") == 0)) {
strcmp(config.animation_type_close, "none") == 0)) {
return;
}
Client *fadeout_client = ecalloc(1, sizeof(*fadeout_client));
wlr_scene_node_set_enabled(&c->scene->node, true);
client_set_border_color(c, bordercolor);
client_set_border_color(c, config.bordercolor);
fadeout_client->scene =
wlr_scene_tree_snapshot(&c->scene->node, layers[LyrFadeOut]);
wlr_scene_node_set_enabled(&c->scene->node, false);
@ -785,7 +785,7 @@ void init_fadeout_client(Client *c) {
return;
}
fadeout_client->animation.duration = animation_duration_close;
fadeout_client->animation.duration = config.animation_duration_close;
fadeout_client->geom = fadeout_client->current =
fadeout_client->animainit_geom = fadeout_client->animation.initial =
c->animation.current;
@ -802,7 +802,7 @@ void init_fadeout_client(Client *c) {
fadeout_client->animation.initial.y = 0;
if ((!c->animation_type_close &&
strcmp(animation_type_close, "fade") == 0) ||
strcmp(config.animation_type_close, "fade") == 0) ||
(c->animation_type_close &&
strcmp(c->animation_type_close, "fade") == 0)) {
fadeout_client->current.x = 0;
@ -812,7 +812,7 @@ void init_fadeout_client(Client *c) {
} else if ((c->animation_type_close &&
strcmp(c->animation_type_close, "slide") == 0) ||
(!c->animation_type_close &&
strcmp(animation_type_close, "slide") == 0)) {
strcmp(config.animation_type_close, "slide") == 0)) {
fadeout_client->current.y =
c->geom.y + c->geom.height / 2 > c->mon->m.y + c->mon->m.height / 2
? c->mon->m.height -
@ -822,16 +822,16 @@ void init_fadeout_client(Client *c) {
} else {
fadeout_client->current.y =
(fadeout_client->geom.height -
fadeout_client->geom.height * zoom_end_ratio) /
fadeout_client->geom.height * config.zoom_end_ratio) /
2;
fadeout_client->current.x =
(fadeout_client->geom.width -
fadeout_client->geom.width * zoom_end_ratio) /
fadeout_client->geom.width * config.zoom_end_ratio) /
2;
fadeout_client->current.width =
fadeout_client->geom.width * zoom_end_ratio;
fadeout_client->geom.width * config.zoom_end_ratio;
fadeout_client->current.height =
fadeout_client->geom.height * zoom_end_ratio;
fadeout_client->geom.height * config.zoom_end_ratio;
}
fadeout_client->animation.time_started = get_now_in_ms();
@ -866,12 +866,11 @@ void client_set_pending_state(Client *c) {
if (!c || c->iskilling)
return;
// 判断是否需要动画
if (!animations) {
if (!config.animations) {
c->animation.should_animate = false;
} else if (animations && c->animation.tagining) {
} else if (config.animations && c->animation.tagining) {
c->animation.should_animate = true;
} else if (!animations || c == grabc ||
} else if (!config.animations || c == grabc ||
(!c->is_pending_open_animation &&
wlr_box_equal(&c->current, &c->pending))) {
c->animation.should_animate = false;
@ -882,7 +881,7 @@ void client_set_pending_state(Client *c) {
if (((c->animation_type_open &&
strcmp(c->animation_type_open, "none") == 0) ||
(!c->animation_type_open &&
strcmp(animation_type_open, "none") == 0)) &&
strcmp(config.animation_type_open, "none") == 0)) &&
c->animation.action == OPEN) {
c->animation.duration = 0;
}
@ -951,16 +950,16 @@ void resize(Client *c, struct wlr_box geo, int32_t interact) {
!c->animation.tagouting && wlr_box_equal(&c->geom, &c->current)) {
c->animation.action = c->animation.action;
} else if (c->animation.tagouting) {
c->animation.duration = animation_duration_tag;
c->animation.duration = config.animation_duration_tag;
c->animation.action = TAG;
} else if (c->animation.tagining) {
c->animation.duration = animation_duration_tag;
c->animation.duration = config.animation_duration_tag;
c->animation.action = TAG;
} else if (c->is_pending_open_animation) {
c->animation.duration = animation_duration_open;
c->animation.duration = config.animation_duration_open;
c->animation.action = OPEN;
} else {
c->animation.duration = animation_duration_move;
c->animation.duration = config.animation_duration_move;
c->animation.action = MOVE;
}
@ -981,7 +980,7 @@ void resize(Client *c, struct wlr_box geo, int32_t interact) {
}
bool hit_no_border = check_hit_no_border(c);
if (hit_no_border && smartgaps) {
if (hit_no_border && config.smartgaps) {
c->bw = 0;
c->fake_no_border = true;
}
@ -1048,12 +1047,12 @@ bool client_draw_fadeout_frame(Client *c) {
void client_set_focused_opacity_animation(Client *c) {
float *border_color = get_border_color(c);
if (!animations) {
if (!config.animations) {
setborder_color(c);
return;
}
c->opacity_animation.duration = animation_duration_focus;
c->opacity_animation.duration = config.animation_duration_focus;
memcpy(c->opacity_animation.target_border_color, border_color,
sizeof(c->opacity_animation.target_border_color));
c->opacity_animation.target_opacity = c->focused_opacity;
@ -1067,15 +1066,14 @@ void client_set_focused_opacity_animation(Client *c) {
}
void client_set_unfocused_opacity_animation(Client *c) {
// Start border color animation to unfocused
float *border_color = get_border_color(c);
if (!animations) {
if (!config.animations) {
setborder_color(c);
return;
}
c->opacity_animation.duration = animation_duration_focus;
c->opacity_animation.duration = config.animation_duration_focus;
memcpy(c->opacity_animation.target_border_color, border_color,
sizeof(c->opacity_animation.target_border_color));
// Start opacity animation to unfocused
@ -1110,13 +1108,14 @@ bool client_apply_focus_opacity(Client *c) {
double opacity_eased_progress =
find_animation_curve_at(linear_progress, OPAFADEIN);
float percent =
animation_fade_in && !c->nofadein ? opacity_eased_progress : 1.0;
float percent = config.animation_fade_in && !c->nofadein
? opacity_eased_progress
: 1.0;
float opacity =
c == selmon->sel ? c->focused_opacity : c->unfocused_opacity;
float target_opacity =
percent * (1.0 - fadein_begin_opacity) + fadein_begin_opacity;
float target_opacity = percent * (1.0 - config.fadein_begin_opacity) +
config.fadein_begin_opacity;
if (target_opacity > opacity) {
target_opacity = opacity;
}
@ -1126,7 +1125,7 @@ bool client_apply_focus_opacity(Client *c) {
c->opacity_animation.current_opacity = target_opacity;
client_set_opacity(c, target_opacity);
client_set_border_color(c, c->opacity_animation.target_border_color);
} else if (animations && c->opacity_animation.running) {
} else if (config.animations && c->opacity_animation.running) {
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
@ -1187,7 +1186,7 @@ bool client_draw_frame(Client *c) {
return client_apply_focus_opacity(c);
}
if (animations && c->animation.running) {
if (config.animations && c->animation.running) {
client_animation_next_tick(c);
} else {
wlr_scene_node_set_position(&c->scene->node, c->pending.x,

View file

@ -2,21 +2,21 @@ struct dvec2 calculate_animation_curve_at(double t, int32_t type) {
struct dvec2 point;
double *animation_curve;
if (type == MOVE) {
animation_curve = animation_curve_move;
animation_curve = config.animation_curve_move;
} else if (type == OPEN) {
animation_curve = animation_curve_open;
animation_curve = config.animation_curve_open;
} else if (type == TAG) {
animation_curve = animation_curve_tag;
animation_curve = config.animation_curve_tag;
} else if (type == CLOSE) {
animation_curve = animation_curve_close;
animation_curve = config.animation_curve_close;
} else if (type == FOCUS) {
animation_curve = animation_curve_focus;
animation_curve = config.animation_curve_focus;
} else if (type == OPAFADEIN) {
animation_curve = animation_curve_opafadein;
animation_curve = config.animation_curve_opafadein;
} else if (type == OPAFADEOUT) {
animation_curve = animation_curve_opafadeout;
animation_curve = config.animation_curve_opafadeout;
} else {
animation_curve = animation_curve_move;
animation_curve = config.animation_curve_move;
}
point.x = 3 * t * (1 - t) * (1 - t) * animation_curve[0] +

View file

@ -156,7 +156,7 @@ void layer_draw_shadow(LayerSurface *l) {
if (!l->mapped || !l->shadow)
return;
if (!shadows || !layer_shadows || l->noshadow) {
if (!config.shadows || !config.layer_shadows || l->noshadow) {
wlr_scene_shadow_set_size(l->shadow, 0, 0);
return;
}
@ -164,9 +164,8 @@ void layer_draw_shadow(LayerSurface *l) {
int32_t width, height;
layer_actual_size(l, &width, &height);
int32_t delta = shadows_size;
int32_t delta = config.shadows_size;
/* we calculate where to clip the shadow */
struct wlr_box layer_box = {
.x = 0,
.y = 0,
@ -175,23 +174,21 @@ void layer_draw_shadow(LayerSurface *l) {
};
struct wlr_box shadow_box = {
.x = shadows_position_x,
.y = shadows_position_y,
.x = config.shadows_position_x,
.y = config.shadows_position_y,
.width = width + 2 * delta,
.height = height + 2 * delta,
};
struct wlr_box intersection_box;
wlr_box_intersection(&intersection_box, &layer_box, &shadow_box);
/* clipped region takes shadow relative coords, so we translate everything
* by its position */
intersection_box.x -= shadows_position_x;
intersection_box.y -= shadows_position_y;
intersection_box.x -= config.shadows_position_x;
intersection_box.y -= config.shadows_position_y;
struct clipped_region clipped_region = {
.area = intersection_box,
.corner_radius = border_radius,
.corners = border_radius_location_default,
.corner_radius = config.border_radius,
.corners = config.border_radius_location_default,
};
wlr_scene_node_set_position(&l->shadow->node, shadow_box.x, shadow_box.y);
@ -261,7 +258,7 @@ void fadeout_layer_animation_next_tick(LayerSurface *l) {
buffer_data.height = height;
if ((!l->animation_type_close &&
strcmp(layer_animation_type_close, "zoom") == 0) ||
strcmp(config.layer_animation_type_close, "zoom") == 0) ||
(l->animation_type_close &&
strcmp(l->animation_type_close, "zoom") == 0)) {
wlr_scene_node_for_each_buffer(&l->scene->node,
@ -279,12 +276,12 @@ void fadeout_layer_animation_next_tick(LayerSurface *l) {
double opacity_eased_progress =
find_animation_curve_at(animation_passed, OPAFADEOUT);
double percent = fadeout_begin_opacity -
(opacity_eased_progress * fadeout_begin_opacity);
double percent = config.fadeout_begin_opacity -
(opacity_eased_progress * config.fadeout_begin_opacity);
double opacity = MAX(percent, 0.0f);
if (animation_fade_out)
if (config.animation_fade_out)
wlr_scene_node_for_each_buffer(&l->scene->node,
scene_buffer_apply_opacity, &opacity);
@ -327,11 +324,11 @@ void layer_animation_next_tick(LayerSurface *l) {
find_animation_curve_at(animation_passed, OPAFADEIN);
double opacity =
MIN(fadein_begin_opacity +
opacity_eased_progress * (1.0 - fadein_begin_opacity),
MIN(config.fadein_begin_opacity +
opacity_eased_progress * (1.0 - config.fadein_begin_opacity),
1.0f);
if (animation_fade_in)
if (config.animation_fade_in)
wlr_scene_node_for_each_buffer(&l->scene->node,
scene_buffer_apply_opacity, &opacity);
@ -347,7 +344,7 @@ void layer_animation_next_tick(LayerSurface *l) {
}
if ((!l->animation_type_open &&
strcmp(layer_animation_type_open, "zoom") == 0) ||
strcmp(config.layer_animation_type_open, "zoom") == 0) ||
(l->animation_type_open &&
strcmp(l->animation_type_open, "zoom") == 0)) {
wlr_scene_node_for_each_buffer(
@ -370,7 +367,7 @@ void layer_animation_next_tick(LayerSurface *l) {
void init_fadeout_layers(LayerSurface *l) {
if (!animations || !layer_animations || l->noanim) {
if (!config.animations || !config.layer_animations || l->noanim) {
return;
}
@ -380,7 +377,7 @@ void init_fadeout_layers(LayerSurface *l) {
if ((l->animation_type_close &&
strcmp(l->animation_type_close, "none") == 0) ||
(!l->animation_type_close &&
strcmp(layer_animation_type_close, "none") == 0)) {
strcmp(config.layer_animation_type_close, "none") == 0)) {
return;
}
@ -403,7 +400,7 @@ void init_fadeout_layers(LayerSurface *l) {
return;
}
fadeout_layer->animation.duration = animation_duration_close;
fadeout_layer->animation.duration = config.animation_duration_close;
fadeout_layer->geom = fadeout_layer->current =
fadeout_layer->animainit_geom = fadeout_layer->animation.initial =
l->animation.current;
@ -419,14 +416,14 @@ void init_fadeout_layers(LayerSurface *l) {
fadeout_layer->animation.initial.y = 0;
if ((!l->animation_type_close &&
strcmp(layer_animation_type_close, "zoom") == 0) ||
strcmp(config.layer_animation_type_close, "zoom") == 0) ||
(l->animation_type_close &&
strcmp(l->animation_type_close, "zoom") == 0)) {
// 算出要设置的绝对坐标和大小
fadeout_layer->current.width =
(float)l->animation.current.width * zoom_end_ratio;
(float)l->animation.current.width * config.zoom_end_ratio;
fadeout_layer->current.height =
(float)l->animation.current.height * zoom_end_ratio;
(float)l->animation.current.height * config.zoom_end_ratio;
fadeout_layer->current.x = usable_area.x + usable_area.width / 2 -
fadeout_layer->current.width / 2;
fadeout_layer->current.y = usable_area.y + usable_area.height / 2 -
@ -438,7 +435,7 @@ void init_fadeout_layers(LayerSurface *l) {
fadeout_layer->current.y - l->animation.current.y;
} else if ((!l->animation_type_close &&
strcmp(layer_animation_type_close, "slide") == 0) ||
strcmp(config.layer_animation_type_close, "slide") == 0) ||
(l->animation_type_close &&
strcmp(l->animation_type_close, "slide") == 0)) {
// 获取slide动画的结束绝对坐标和大小
@ -483,17 +480,18 @@ void layer_set_pending_state(LayerSurface *l) {
if (l->animation.action == OPEN && !l->animation.running) {
if ((!l->animation_type_open &&
strcmp(layer_animation_type_open, "zoom") == 0) ||
strcmp(config.layer_animation_type_open, "zoom") == 0) ||
(l->animation_type_open &&
strcmp(l->animation_type_open, "zoom") == 0)) {
l->animainit_geom.width = l->geom.width * zoom_initial_ratio;
l->animainit_geom.height = l->geom.height * zoom_initial_ratio;
l->animainit_geom.width = l->geom.width * config.zoom_initial_ratio;
l->animainit_geom.height =
l->geom.height * config.zoom_initial_ratio;
l->animainit_geom.x = usable_area.x + usable_area.width / 2 -
l->animainit_geom.width / 2;
l->animainit_geom.y = usable_area.y + usable_area.height / 2 -
l->animainit_geom.height / 2;
} else if ((!l->animation_type_open &&
strcmp(layer_animation_type_open, "slide") == 0) ||
strcmp(config.layer_animation_type_open, "slide") == 0) ||
(l->animation_type_open &&
strcmp(l->animation_type_open, "slide") == 0)) {
@ -507,8 +505,7 @@ void layer_set_pending_state(LayerSurface *l) {
} else {
l->animainit_geom = l->animation.current;
}
// 判断是否需要动画
if (!animations || !layer_animations || l->noanim ||
if (!config.animations || !config.layer_animations || l->noanim ||
l->layer_surface->current.layer ==
ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND ||
l->layer_surface->current.layer == ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM) {
@ -520,7 +517,7 @@ void layer_set_pending_state(LayerSurface *l) {
if (((l->animation_type_open &&
strcmp(l->animation_type_open, "none") == 0) ||
(!l->animation_type_open &&
strcmp(layer_animation_type_open, "none") == 0)) &&
strcmp(config.layer_animation_type_open, "none") == 0)) &&
l->animation.action == OPEN) {
l->animation.should_animate = false;
}
@ -567,7 +564,8 @@ bool layer_draw_frame(LayerSurface *l) {
return false;
}
if (animations && layer_animations && l->animation.running && !l->noanim) {
if (config.animations && config.layer_animations && l->animation.running &&
!l->noanim) {
layer_animation_next_tick(l);
layer_draw_shadow(l);
} else {

View file

@ -7,11 +7,11 @@ void set_tagin_animation(Monitor *m, Client *c) {
if (m->pertag->curtag > m->pertag->prevtag) {
c->animainit_geom.x = tag_animation_direction == VERTICAL
c->animainit_geom.x = config.tag_animation_direction == VERTICAL
? c->animation.current.x
: MAX(c->mon->m.x + c->mon->m.width,
c->geom.x + c->mon->m.width);
c->animainit_geom.y = tag_animation_direction == VERTICAL
c->animainit_geom.y = config.tag_animation_direction == VERTICAL
? MAX(c->mon->m.y + c->mon->m.height,
c->geom.y + c->mon->m.height)
: c->animation.current.y;
@ -19,11 +19,11 @@ void set_tagin_animation(Monitor *m, Client *c) {
} else {
c->animainit_geom.x =
tag_animation_direction == VERTICAL
config.tag_animation_direction == VERTICAL
? c->animation.current.x
: MIN(m->m.x - c->geom.width, c->geom.x - c->mon->m.width);
c->animainit_geom.y =
tag_animation_direction == VERTICAL
config.tag_animation_direction == VERTICAL
? MIN(m->m.y - c->geom.height, c->geom.y - c->mon->m.height)
: c->animation.current.y;
}
@ -39,7 +39,8 @@ void set_arrange_visible(Monitor *m, Client *c, bool want_animation) {
client_set_suspended(c, false);
if (!c->animation.tag_from_rule && want_animation &&
m->pertag->prevtag != 0 && m->pertag->curtag != 0 && animations) {
m->pertag->prevtag != 0 && m->pertag->curtag != 0 &&
config.animations) {
c->animation.tagining = true;
set_tagin_animation(m, c);
} else {
@ -57,10 +58,10 @@ void set_tagout_animation(Monitor *m, Client *c) {
if (m->pertag->curtag > m->pertag->prevtag) {
c->pending = c->geom;
c->pending.x =
tag_animation_direction == VERTICAL
config.tag_animation_direction == VERTICAL
? c->animation.current.x
: MIN(c->mon->m.x - c->geom.width, c->geom.x - c->mon->m.width);
c->pending.y = tag_animation_direction == VERTICAL
c->pending.y = config.tag_animation_direction == VERTICAL
? MIN(c->mon->m.y - c->geom.height,
c->geom.y - c->mon->m.height)
: c->animation.current.y;
@ -68,11 +69,11 @@ void set_tagout_animation(Monitor *m, Client *c) {
resize(c, c->geom, 0);
} else {
c->pending = c->geom;
c->pending.x = tag_animation_direction == VERTICAL
c->pending.x = config.tag_animation_direction == VERTICAL
? c->animation.current.x
: MAX(c->mon->m.x + c->mon->m.width,
c->geom.x + c->mon->m.width);
c->pending.y = tag_animation_direction == VERTICAL
c->pending.y = config.tag_animation_direction == VERTICAL
? MAX(c->mon->m.y + c->mon->m.height,
c->geom.y + c->mon->m.height)
: c->animation.current.y;
@ -82,7 +83,8 @@ void set_tagout_animation(Monitor *m, Client *c) {
void set_arrange_hidden(Monitor *m, Client *c, bool want_animation) {
if ((c->tags & (1 << (m->pertag->prevtag - 1))) &&
m->pertag->prevtag != 0 && m->pertag->curtag != 0 && animations) {
m->pertag->prevtag != 0 && m->pertag->curtag != 0 &&
config.animations) {
c->animation.tagouting = true;
c->animation.tagining = false;
set_tagout_animation(m, c);

View file

@ -285,6 +285,7 @@ typedef struct {
int32_t blur_layer;
int32_t blur_optimized;
int32_t border_radius;
int32_t border_radius_location_default;
struct blur_data blur_params;
int32_t shadows;
int32_t shadow_only_floating;
@ -312,7 +313,8 @@ typedef struct {
float globalcolor[4];
float overlaycolor[4];
char autostart[3][256];
int32_t log_level;
uint32_t capslock;
ConfigTagRule *tag_rules; // 动态数组
int32_t tag_rules_count; // 数量
@ -363,6 +365,11 @@ typedef struct {
int32_t allow_lock_transparent;
struct xkb_rule_names xkb_rules;
char xkb_rules_rules[128];
char xkb_rules_model[128];
char xkb_rules_layout[128];
char xkb_rules_variant[128];
char xkb_rules_options[128];
char keymode[28];
@ -1428,25 +1435,25 @@ bool parse_option(Config *config, char *key, char *value) {
} else if (strcmp(key, "unfocused_opacity") == 0) {
config->unfocused_opacity = atof(value);
} else if (strcmp(key, "xkb_rules_rules") == 0) {
strncpy(xkb_rules_rules, value, sizeof(xkb_rules_rules) - 1);
xkb_rules_rules[sizeof(xkb_rules_rules) - 1] =
'\0'; // 确保字符串以 null 结尾
strncpy(config->xkb_rules_rules, value,
sizeof(config->xkb_rules_rules) - 1);
config->xkb_rules_rules[sizeof(config->xkb_rules_rules) - 1] = '\0';
} else if (strcmp(key, "xkb_rules_model") == 0) {
strncpy(xkb_rules_model, value, sizeof(xkb_rules_model) - 1);
xkb_rules_model[sizeof(xkb_rules_model) - 1] =
'\0'; // 确保字符串以 null 结尾
strncpy(config->xkb_rules_model, value,
sizeof(config->xkb_rules_model) - 1);
config->xkb_rules_model[sizeof(config->xkb_rules_model) - 1] = '\0';
} else if (strcmp(key, "xkb_rules_layout") == 0) {
strncpy(xkb_rules_layout, value, sizeof(xkb_rules_layout) - 1);
xkb_rules_layout[sizeof(xkb_rules_layout) - 1] =
'\0'; // 确保字符串以 null 结尾
strncpy(config->xkb_rules_layout, value,
sizeof(config->xkb_rules_layout) - 1);
config->xkb_rules_layout[sizeof(config->xkb_rules_layout) - 1] = '\0';
} else if (strcmp(key, "xkb_rules_variant") == 0) {
strncpy(xkb_rules_variant, value, sizeof(xkb_rules_variant) - 1);
xkb_rules_variant[sizeof(xkb_rules_variant) - 1] =
'\0'; // 确保字符串以 null 结尾
strncpy(config->xkb_rules_variant, value,
sizeof(config->xkb_rules_variant) - 1);
config->xkb_rules_variant[sizeof(config->xkb_rules_variant) - 1] = '\0';
} else if (strcmp(key, "xkb_rules_options") == 0) {
strncpy(xkb_rules_options, value, sizeof(xkb_rules_options) - 1);
xkb_rules_options[sizeof(xkb_rules_options) - 1] =
'\0'; // 确保字符串以 null 结尾
strncpy(config->xkb_rules_options, value,
sizeof(config->xkb_rules_options) - 1);
config->xkb_rules_options[sizeof(config->xkb_rules_options) - 1] = '\0';
} else if (strcmp(key, "scroller_proportion_preset") == 0) {
// 1. 统计 value 中有多少个逗号,确定需要解析的浮点数个数
int32_t count = 0; // 初始化为 0
@ -3087,363 +3094,347 @@ void free_config(void) {
}
void override_config(void) {
// 动画启用
animations = CLAMP_INT(config.animations, 0, 1);
layer_animations = CLAMP_INT(config.layer_animations, 0, 1);
// 标签动画方向
tag_animation_direction = CLAMP_INT(config.tag_animation_direction, 0, 1);
// 动画淡入淡出设置
animation_fade_in = CLAMP_INT(config.animation_fade_in, 0, 1);
animation_fade_out = CLAMP_INT(config.animation_fade_out, 0, 1);
zoom_initial_ratio = CLAMP_FLOAT(config.zoom_initial_ratio, 0.1f, 1.0f);
zoom_end_ratio = CLAMP_FLOAT(config.zoom_end_ratio, 0.1f, 1.0f);
fadein_begin_opacity = CLAMP_FLOAT(config.fadein_begin_opacity, 0.0f, 1.0f);
fadeout_begin_opacity =
config.animations = CLAMP_INT(config.animations, 0, 1);
config.layer_animations = CLAMP_INT(config.layer_animations, 0, 1);
config.tag_animation_direction =
CLAMP_INT(config.tag_animation_direction, 0, 1);
config.animation_fade_in = CLAMP_INT(config.animation_fade_in, 0, 1);
config.animation_fade_out = CLAMP_INT(config.animation_fade_out, 0, 1);
config.zoom_initial_ratio =
CLAMP_FLOAT(config.zoom_initial_ratio, 0.1f, 1.0f);
config.zoom_end_ratio = CLAMP_FLOAT(config.zoom_end_ratio, 0.1f, 1.0f);
config.fadein_begin_opacity =
CLAMP_FLOAT(config.fadein_begin_opacity, 0.0f, 1.0f);
config.fadeout_begin_opacity =
CLAMP_FLOAT(config.fadeout_begin_opacity, 0.0f, 1.0f);
// 打开关闭动画类型
animation_type_open = config.animation_type_open;
animation_type_close = config.animation_type_close;
// layer打开关闭动画类型
layer_animation_type_open = config.layer_animation_type_open;
layer_animation_type_close = config.layer_animation_type_close;
// 动画时间限制在合理范围(1-50000ms)
animation_duration_move =
config.animation_duration_move =
CLAMP_INT(config.animation_duration_move, 1, 50000);
animation_duration_open =
config.animation_duration_open =
CLAMP_INT(config.animation_duration_open, 1, 50000);
animation_duration_tag = CLAMP_INT(config.animation_duration_tag, 1, 50000);
animation_duration_close =
config.animation_duration_tag =
CLAMP_INT(config.animation_duration_tag, 1, 50000);
config.animation_duration_close =
CLAMP_INT(config.animation_duration_close, 1, 50000);
animation_duration_focus =
config.animation_duration_focus =
CLAMP_INT(config.animation_duration_focus, 1, 50000);
// 滚动布局设置
scroller_default_proportion =
config.scroller_default_proportion =
CLAMP_FLOAT(config.scroller_default_proportion, 0.1f, 1.0f);
scroller_default_proportion_single =
config.scroller_default_proportion_single =
CLAMP_FLOAT(config.scroller_default_proportion_single, 0.1f, 1.0f);
scroller_ignore_proportion_single =
config.scroller_ignore_proportion_single =
CLAMP_INT(config.scroller_ignore_proportion_single, 0, 1);
scroller_focus_center = CLAMP_INT(config.scroller_focus_center, 0, 1);
scroller_prefer_center = CLAMP_INT(config.scroller_prefer_center, 0, 1);
scroller_prefer_overspread =
config.scroller_focus_center =
CLAMP_INT(config.scroller_focus_center, 0, 1);
config.scroller_prefer_center =
CLAMP_INT(config.scroller_prefer_center, 0, 1);
config.scroller_prefer_overspread =
CLAMP_INT(config.scroller_prefer_overspread, 0, 1);
edge_scroller_pointer_focus =
config.edge_scroller_pointer_focus =
CLAMP_INT(config.edge_scroller_pointer_focus, 0, 1);
scroller_structs = CLAMP_INT(config.scroller_structs, 0, 1000);
// 主从布局设置
default_mfact = CLAMP_FLOAT(config.default_mfact, 0.1f, 0.9f);
default_nmaster = CLAMP_INT(config.default_nmaster, 1, 1000);
center_master_overspread = CLAMP_INT(config.center_master_overspread, 0, 1);
center_when_single_stack = CLAMP_INT(config.center_when_single_stack, 0, 1);
new_is_master = CLAMP_INT(config.new_is_master, 0, 1);
// 概述模式设置
hotarea_size = CLAMP_INT(config.hotarea_size, 1, 1000);
hotarea_corner = CLAMP_INT(config.hotarea_corner, 0, 3);
enable_hotarea = CLAMP_INT(config.enable_hotarea, 0, 1);
ov_tab_mode = CLAMP_INT(config.ov_tab_mode, 0, 1);
overviewgappi = CLAMP_INT(config.overviewgappi, 0, 1000);
overviewgappo = CLAMP_INT(config.overviewgappo, 0, 1000);
// 杂项设置
xwayland_persistence = CLAMP_INT(config.xwayland_persistence, 0, 1);
syncobj_enable = CLAMP_INT(config.syncobj_enable, 0, 1);
drag_tile_refresh_interval =
config.scroller_structs = CLAMP_INT(config.scroller_structs, 0, 1000);
config.default_mfact = CLAMP_FLOAT(config.default_mfact, 0.1f, 0.9f);
config.default_nmaster = CLAMP_INT(config.default_nmaster, 1, 1000);
config.center_master_overspread =
CLAMP_INT(config.center_master_overspread, 0, 1);
config.center_when_single_stack =
CLAMP_INT(config.center_when_single_stack, 0, 1);
config.new_is_master = CLAMP_INT(config.new_is_master, 0, 1);
config.hotarea_size = CLAMP_INT(config.hotarea_size, 1, 1000);
config.hotarea_corner = CLAMP_INT(config.hotarea_corner, 0, 3);
config.enable_hotarea = CLAMP_INT(config.enable_hotarea, 0, 1);
config.ov_tab_mode = CLAMP_INT(config.ov_tab_mode, 0, 1);
config.overviewgappi = CLAMP_INT(config.overviewgappi, 0, 1000);
config.overviewgappo = CLAMP_INT(config.overviewgappo, 0, 1000);
config.xwayland_persistence = CLAMP_INT(config.xwayland_persistence, 0, 1);
config.syncobj_enable = CLAMP_INT(config.syncobj_enable, 0, 1);
config.drag_tile_refresh_interval =
CLAMP_FLOAT(config.drag_tile_refresh_interval, 1.0f, 16.0f);
drag_floating_refresh_interval =
CLAMP_FLOAT(config.drag_floating_refresh_interval, 1.0f, 16.0f);
drag_tile_to_tile = CLAMP_INT(config.drag_tile_to_tile, 0, 1);
drag_floating_refresh_interval =
config.drag_floating_refresh_interval =
CLAMP_FLOAT(config.drag_floating_refresh_interval, 0.0f, 1000.0f);
allow_tearing = CLAMP_INT(config.allow_tearing, 0, 2);
allow_shortcuts_inhibit = CLAMP_INT(config.allow_shortcuts_inhibit, 0, 1);
allow_lock_transparent = CLAMP_INT(config.allow_lock_transparent, 0, 1);
axis_bind_apply_timeout =
config.drag_tile_to_tile = CLAMP_INT(config.drag_tile_to_tile, 0, 1);
config.allow_tearing = CLAMP_INT(config.allow_tearing, 0, 2);
config.allow_shortcuts_inhibit =
CLAMP_INT(config.allow_shortcuts_inhibit, 0, 1);
config.allow_lock_transparent =
CLAMP_INT(config.allow_lock_transparent, 0, 1);
config.axis_bind_apply_timeout =
CLAMP_INT(config.axis_bind_apply_timeout, 0, 1000);
focus_on_activate = CLAMP_INT(config.focus_on_activate, 0, 1);
idleinhibit_ignore_visible =
config.focus_on_activate = CLAMP_INT(config.focus_on_activate, 0, 1);
config.idleinhibit_ignore_visible =
CLAMP_INT(config.idleinhibit_ignore_visible, 0, 1);
sloppyfocus = CLAMP_INT(config.sloppyfocus, 0, 1);
warpcursor = CLAMP_INT(config.warpcursor, 0, 1);
drag_corner = CLAMP_INT(config.drag_corner, 0, 4);
drag_warp_cursor = CLAMP_INT(config.drag_warp_cursor, 0, 1);
focus_cross_monitor = CLAMP_INT(config.focus_cross_monitor, 0, 1);
exchange_cross_monitor = CLAMP_INT(config.exchange_cross_monitor, 0, 1);
scratchpad_cross_monitor = CLAMP_INT(config.scratchpad_cross_monitor, 0, 1);
focus_cross_tag = CLAMP_INT(config.focus_cross_tag, 0, 1);
view_current_to_back = CLAMP_INT(config.view_current_to_back, 0, 1);
enable_floating_snap = CLAMP_INT(config.enable_floating_snap, 0, 1);
snap_distance = CLAMP_INT(config.snap_distance, 0, 99999);
cursor_size = CLAMP_INT(config.cursor_size, 4, 512);
no_border_when_single = CLAMP_INT(config.no_border_when_single, 0, 1);
no_radius_when_single = CLAMP_INT(config.no_radius_when_single, 0, 1);
cursor_hide_timeout =
CLAMP_INT(config.cursor_hide_timeout, 0, 36000); // 0-10小时
drag_tile_to_tile = CLAMP_INT(config.drag_tile_to_tile, 0, 1);
single_scratchpad = CLAMP_INT(config.single_scratchpad, 0, 1);
// 键盘设置
repeat_rate = CLAMP_INT(config.repeat_rate, 1, 1000);
repeat_delay = CLAMP_INT(config.repeat_delay, 1, 20000);
numlockon = CLAMP_INT(config.numlockon, 0, 1);
// 触控板设置
disable_trackpad = CLAMP_INT(config.disable_trackpad, 0, 1);
tap_to_click = CLAMP_INT(config.tap_to_click, 0, 1);
tap_and_drag = CLAMP_INT(config.tap_and_drag, 0, 1);
drag_lock = CLAMP_INT(config.drag_lock, 0, 1);
trackpad_natural_scrolling =
config.sloppyfocus = CLAMP_INT(config.sloppyfocus, 0, 1);
config.warpcursor = CLAMP_INT(config.warpcursor, 0, 1);
config.drag_corner = CLAMP_INT(config.drag_corner, 0, 4);
config.drag_warp_cursor = CLAMP_INT(config.drag_warp_cursor, 0, 1);
config.focus_cross_monitor = CLAMP_INT(config.focus_cross_monitor, 0, 1);
config.exchange_cross_monitor =
CLAMP_INT(config.exchange_cross_monitor, 0, 1);
config.scratchpad_cross_monitor =
CLAMP_INT(config.scratchpad_cross_monitor, 0, 1);
config.focus_cross_tag = CLAMP_INT(config.focus_cross_tag, 0, 1);
config.view_current_to_back = CLAMP_INT(config.view_current_to_back, 0, 1);
config.enable_floating_snap = CLAMP_INT(config.enable_floating_snap, 0, 1);
config.snap_distance = CLAMP_INT(config.snap_distance, 0, 99999);
config.cursor_size = CLAMP_INT(config.cursor_size, 4, 512);
config.no_border_when_single =
CLAMP_INT(config.no_border_when_single, 0, 1);
config.no_radius_when_single =
CLAMP_INT(config.no_radius_when_single, 0, 1);
config.cursor_hide_timeout =
CLAMP_INT(config.cursor_hide_timeout, 0, 36000);
config.single_scratchpad = CLAMP_INT(config.single_scratchpad, 0, 1);
config.repeat_rate = CLAMP_INT(config.repeat_rate, 1, 1000);
config.repeat_delay = CLAMP_INT(config.repeat_delay, 1, 20000);
config.numlockon = CLAMP_INT(config.numlockon, 0, 1);
config.disable_trackpad = CLAMP_INT(config.disable_trackpad, 0, 1);
config.tap_to_click = CLAMP_INT(config.tap_to_click, 0, 1);
config.tap_and_drag = CLAMP_INT(config.tap_and_drag, 0, 1);
config.drag_lock = CLAMP_INT(config.drag_lock, 0, 1);
config.trackpad_natural_scrolling =
CLAMP_INT(config.trackpad_natural_scrolling, 0, 1);
disable_while_typing = CLAMP_INT(config.disable_while_typing, 0, 1);
left_handed = CLAMP_INT(config.left_handed, 0, 1);
middle_button_emulation = CLAMP_INT(config.middle_button_emulation, 0, 1);
swipe_min_threshold = CLAMP_INT(config.swipe_min_threshold, 1, 1000);
// 鼠标设置
mouse_natural_scrolling = CLAMP_INT(config.mouse_natural_scrolling, 0, 1);
accel_profile = CLAMP_INT(config.accel_profile, 0, 2);
accel_speed = CLAMP_FLOAT(config.accel_speed, -1.0f, 1.0f);
scroll_method = CLAMP_INT(config.scroll_method, 0, 4);
scroll_button = CLAMP_INT(config.scroll_button, 272, 276);
click_method = CLAMP_INT(config.click_method, 0, 2);
send_events_mode = CLAMP_INT(config.send_events_mode, 0, 2);
button_map = CLAMP_INT(config.button_map, 0, 1);
axis_scroll_factor = CLAMP_FLOAT(config.axis_scroll_factor, 0.1f, 10.0f);
// 外观设置
gappih = CLAMP_INT(config.gappih, 0, 1000);
gappiv = CLAMP_INT(config.gappiv, 0, 1000);
gappoh = CLAMP_INT(config.gappoh, 0, 1000);
gappov = CLAMP_INT(config.gappov, 0, 1000);
scratchpad_width_ratio =
config.disable_while_typing = CLAMP_INT(config.disable_while_typing, 0, 1);
config.left_handed = CLAMP_INT(config.left_handed, 0, 1);
config.middle_button_emulation =
CLAMP_INT(config.middle_button_emulation, 0, 1);
config.swipe_min_threshold = CLAMP_INT(config.swipe_min_threshold, 1, 1000);
config.mouse_natural_scrolling =
CLAMP_INT(config.mouse_natural_scrolling, 0, 1);
config.accel_profile = CLAMP_INT(config.accel_profile, 0, 2);
config.accel_speed = CLAMP_FLOAT(config.accel_speed, -1.0f, 1.0f);
config.scroll_method = CLAMP_INT(config.scroll_method, 0, 4);
config.scroll_button = CLAMP_INT(config.scroll_button, 272, 276);
config.click_method = CLAMP_INT(config.click_method, 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.axis_scroll_factor =
CLAMP_FLOAT(config.axis_scroll_factor, 0.1f, 10.0f);
config.gappih = CLAMP_INT(config.gappih, 0, 1000);
config.gappiv = CLAMP_INT(config.gappiv, 0, 1000);
config.gappoh = CLAMP_INT(config.gappoh, 0, 1000);
config.gappov = CLAMP_INT(config.gappov, 0, 1000);
config.scratchpad_width_ratio =
CLAMP_FLOAT(config.scratchpad_width_ratio, 0.1f, 1.0f);
scratchpad_height_ratio =
config.scratchpad_height_ratio =
CLAMP_FLOAT(config.scratchpad_height_ratio, 0.1f, 1.0f);
borderpx = CLAMP_INT(config.borderpx, 0, 200);
smartgaps = CLAMP_INT(config.smartgaps, 0, 1);
blur = CLAMP_INT(config.blur, 0, 1);
blur_layer = CLAMP_INT(config.blur_layer, 0, 1);
blur_optimized = CLAMP_INT(config.blur_optimized, 0, 1);
border_radius = CLAMP_INT(config.border_radius, 0, 100);
blur_params.num_passes = CLAMP_INT(config.blur_params.num_passes, 0, 10);
blur_params.radius = CLAMP_INT(config.blur_params.radius, 0, 100);
blur_params.noise = CLAMP_FLOAT(config.blur_params.noise, 0, 1);
blur_params.brightness = CLAMP_FLOAT(config.blur_params.brightness, 0, 1);
blur_params.contrast = CLAMP_FLOAT(config.blur_params.contrast, 0, 1);
blur_params.saturation = CLAMP_FLOAT(config.blur_params.saturation, 0, 1);
shadows = CLAMP_INT(config.shadows, 0, 1);
shadow_only_floating = CLAMP_INT(config.shadow_only_floating, 0, 1);
layer_shadows = CLAMP_INT(config.layer_shadows, 0, 1);
shadows_size = CLAMP_INT(config.shadows_size, 0, 100);
shadows_blur = CLAMP_INT(config.shadows_blur, 0, 100);
shadows_position_x = CLAMP_INT(config.shadows_position_x, -1000, 1000);
shadows_position_y = CLAMP_INT(config.shadows_position_y, -1000, 1000);
focused_opacity = CLAMP_FLOAT(config.focused_opacity, 0.0f, 1.0f);
unfocused_opacity = CLAMP_FLOAT(config.unfocused_opacity, 0.0f, 1.0f);
memcpy(shadowscolor, config.shadowscolor, sizeof(shadowscolor));
// 复制颜色数组
memcpy(rootcolor, config.rootcolor, sizeof(rootcolor));
memcpy(bordercolor, config.bordercolor, sizeof(bordercolor));
memcpy(focuscolor, config.focuscolor, sizeof(focuscolor));
memcpy(maximizescreencolor, config.maximizescreencolor,
sizeof(maximizescreencolor));
memcpy(urgentcolor, config.urgentcolor, sizeof(urgentcolor));
memcpy(scratchpadcolor, config.scratchpadcolor, sizeof(scratchpadcolor));
memcpy(globalcolor, config.globalcolor, sizeof(globalcolor));
memcpy(overlaycolor, config.overlaycolor, sizeof(overlaycolor));
// 复制动画曲线
memcpy(animation_curve_move, config.animation_curve_move,
sizeof(animation_curve_move));
memcpy(animation_curve_open, config.animation_curve_open,
sizeof(animation_curve_open));
memcpy(animation_curve_tag, config.animation_curve_tag,
sizeof(animation_curve_tag));
memcpy(animation_curve_close, config.animation_curve_close,
sizeof(animation_curve_close));
memcpy(animation_curve_focus, config.animation_curve_focus,
sizeof(animation_curve_focus));
memcpy(animation_curve_opafadein, config.animation_curve_opafadein,
sizeof(animation_curve_opafadein));
memcpy(animation_curve_opafadeout, config.animation_curve_opafadeout,
sizeof(animation_curve_opafadeout));
config.borderpx = CLAMP_INT(config.borderpx, 0, 200);
config.smartgaps = CLAMP_INT(config.smartgaps, 0, 1);
config.blur = CLAMP_INT(config.blur, 0, 1);
config.blur_layer = CLAMP_INT(config.blur_layer, 0, 1);
config.blur_optimized = CLAMP_INT(config.blur_optimized, 0, 1);
config.border_radius = CLAMP_INT(config.border_radius, 0, 100);
config.blur_params.num_passes =
CLAMP_INT(config.blur_params.num_passes, 0, 10);
config.blur_params.radius = CLAMP_INT(config.blur_params.radius, 0, 100);
config.blur_params.noise = CLAMP_FLOAT(config.blur_params.noise, 0, 1);
config.blur_params.brightness =
CLAMP_FLOAT(config.blur_params.brightness, 0, 1);
config.blur_params.contrast =
CLAMP_FLOAT(config.blur_params.contrast, 0, 1);
config.blur_params.saturation =
CLAMP_FLOAT(config.blur_params.saturation, 0, 1);
config.shadows = CLAMP_INT(config.shadows, 0, 1);
config.shadow_only_floating = CLAMP_INT(config.shadow_only_floating, 0, 1);
config.layer_shadows = CLAMP_INT(config.layer_shadows, 0, 1);
config.shadows_size = CLAMP_INT(config.shadows_size, 0, 100);
config.shadows_blur = CLAMP_INT(config.shadows_blur, 0, 100);
config.shadows_position_x =
CLAMP_INT(config.shadows_position_x, -1000, 1000);
config.shadows_position_y =
CLAMP_INT(config.shadows_position_y, -1000, 1000);
config.focused_opacity = CLAMP_FLOAT(config.focused_opacity, 0.0f, 1.0f);
config.unfocused_opacity =
CLAMP_FLOAT(config.unfocused_opacity, 0.0f, 1.0f);
}
void set_value_default() {
/* animaion */
config.animations = animations; // 是否启用动画
config.layer_animations = layer_animations; // 是否启用layer动画
config.animation_fade_in = animation_fade_in; // Enable animation fade in
config.animation_fade_out = animation_fade_out; // Enable animation fade out
config.tag_animation_direction = tag_animation_direction; // 标签动画方向
config.zoom_initial_ratio = zoom_initial_ratio; // 动画起始窗口比例
config.zoom_end_ratio = zoom_end_ratio; // 动画结束窗口比例
config.fadein_begin_opacity =
fadein_begin_opacity; // Begin opac window ratio for animations
config.fadeout_begin_opacity = fadeout_begin_opacity;
config.animation_duration_move =
animation_duration_move; // Animation move speed
config.animation_duration_open =
animation_duration_open; // Animation open speed
config.animation_duration_tag =
animation_duration_tag; // Animation tag speed
config.animation_duration_close =
animation_duration_close; // Animation tag speed
config.animation_duration_focus =
animation_duration_focus; // Animation focus opacity speed
config.animations = 1;
config.layer_animations = 0;
config.animation_fade_in = 1;
config.animation_fade_out = 1;
config.tag_animation_direction = HORIZONTAL;
config.zoom_initial_ratio = 0.3f;
config.zoom_end_ratio = 0.8f;
config.fadein_begin_opacity = 0.5f;
config.fadeout_begin_opacity = 0.5f;
config.animation_duration_move = 500;
config.animation_duration_open = 400;
config.animation_duration_tag = 300;
config.animation_duration_close = 300;
config.animation_duration_focus = 0;
/* appearance */
config.axis_bind_apply_timeout =
axis_bind_apply_timeout; // 滚轮绑定动作的触发的时间间隔
config.focus_on_activate =
focus_on_activate; // 收到窗口激活请求是否自动跳转聚焦
config.new_is_master = new_is_master; // 新窗口是否插在头部
config.default_mfact = default_mfact; // master 窗口比例
config.default_nmaster = default_nmaster; // 默认master数量
config.center_master_overspread =
center_master_overspread; // 中心master时是否铺满
config.center_when_single_stack =
center_when_single_stack; // 单个stack时是否居中
config.axis_bind_apply_timeout = 100;
config.focus_on_activate = 1;
config.new_is_master = 1;
config.default_mfact = 0.55f;
config.default_nmaster = 1;
config.center_master_overspread = 0;
config.center_when_single_stack = 1;
config.numlockon = numlockon; // 是否打开右边小键盘
config.log_level = WLR_ERROR;
config.numlockon = 0;
config.capslock = 0;
config.ov_tab_mode = ov_tab_mode; // alt tab切换模式
config.hotarea_size = hotarea_size; // 热区大小,10x10
config.hotarea_corner = hotarea_corner;
config.enable_hotarea = enable_hotarea; // 是否启用鼠标热区
config.smartgaps = smartgaps; /* 1 means no outer gap when there is
only one window */
config.sloppyfocus = sloppyfocus; /* focus follows mouse */
config.gappih = gappih; /* horiz inner gap between windows */
config.gappiv = gappiv; /* vert inner gap between windows */
config.gappoh =
gappoh; /* horiz outer gap between windows and screen edge */
config.gappov = gappov; /* vert outer gap between windows and screen edge */
config.scratchpad_width_ratio = scratchpad_width_ratio;
config.scratchpad_height_ratio = scratchpad_height_ratio;
config.ov_tab_mode = 0;
config.hotarea_size = 10;
config.hotarea_corner = BOTTOM_LEFT;
config.enable_hotarea = 1;
config.smartgaps = 0;
config.sloppyfocus = 1;
config.gappih = 5;
config.gappiv = 5;
config.gappoh = 10;
config.gappov = 10;
config.scratchpad_width_ratio = 0.8f;
config.scratchpad_height_ratio = 0.9f;
config.scroller_structs = scroller_structs;
config.scroller_default_proportion = scroller_default_proportion;
config.scroller_default_proportion_single =
scroller_default_proportion_single;
config.scroller_ignore_proportion_single =
scroller_ignore_proportion_single;
config.scroller_focus_center = scroller_focus_center;
config.scroller_prefer_center = scroller_prefer_center;
config.scroller_prefer_overspread = scroller_prefer_overspread;
config.edge_scroller_pointer_focus = edge_scroller_pointer_focus;
config.focus_cross_monitor = focus_cross_monitor;
config.exchange_cross_monitor = exchange_cross_monitor;
config.scratchpad_cross_monitor = scratchpad_cross_monitor;
config.focus_cross_tag = focus_cross_tag;
config.axis_scroll_factor = axis_scroll_factor;
config.view_current_to_back = view_current_to_back;
config.single_scratchpad = single_scratchpad;
config.xwayland_persistence = xwayland_persistence;
config.syncobj_enable = syncobj_enable;
config.drag_tile_refresh_interval = drag_tile_refresh_interval;
config.drag_floating_refresh_interval = drag_floating_refresh_interval;
config.allow_tearing = allow_tearing;
config.allow_shortcuts_inhibit = allow_shortcuts_inhibit;
config.allow_lock_transparent = allow_lock_transparent;
config.no_border_when_single = no_border_when_single;
config.no_radius_when_single = no_radius_when_single;
config.snap_distance = snap_distance;
config.drag_tile_to_tile = drag_tile_to_tile;
config.enable_floating_snap = enable_floating_snap;
config.swipe_min_threshold = swipe_min_threshold;
config.scroller_structs = 20;
config.scroller_default_proportion = 0.9f;
config.scroller_default_proportion_single = 1.0f;
config.scroller_ignore_proportion_single = 1;
config.scroller_focus_center = 0;
config.scroller_prefer_center = 0;
config.scroller_prefer_overspread = 1;
config.edge_scroller_pointer_focus = 1;
config.focus_cross_monitor = 0;
config.exchange_cross_monitor = 0;
config.scratchpad_cross_monitor = 0;
config.focus_cross_tag = 0;
config.axis_scroll_factor = 1.0;
config.view_current_to_back = 0;
config.single_scratchpad = 1;
config.xwayland_persistence = 1;
config.syncobj_enable = 0;
config.drag_tile_refresh_interval = 8.0f;
config.drag_floating_refresh_interval = 8.0f;
config.allow_tearing = TEARING_DISABLED;
config.allow_shortcuts_inhibit = SHORTCUTS_INHIBIT_ENABLE;
config.allow_lock_transparent = 0;
config.no_border_when_single = 0;
config.no_radius_when_single = 0;
config.snap_distance = 30;
config.drag_tile_to_tile = 0;
config.enable_floating_snap = 0;
config.swipe_min_threshold = 1;
config.idleinhibit_ignore_visible =
idleinhibit_ignore_visible; /* 1 means idle inhibitors will
disable idle tracking even if it's
surface isn't visible
*/
config.idleinhibit_ignore_visible = 0;
config.borderpx = borderpx;
config.overviewgappi = overviewgappi; /* overview时 窗口与边缘 缝隙大小 */
config.overviewgappo = overviewgappo; /* overview时 窗口与窗口 缝隙大小 */
config.cursor_hide_timeout = cursor_hide_timeout;
config.borderpx = 4;
config.overviewgappi = 5;
config.overviewgappo = 30;
config.cursor_hide_timeout = 0;
config.warpcursor = warpcursor; /* Warp cursor to focused client */
config.drag_corner = drag_corner;
config.drag_warp_cursor = drag_warp_cursor;
config.warpcursor = 1;
config.drag_corner = 3;
config.drag_warp_cursor = 1;
config.repeat_rate = repeat_rate;
config.repeat_delay = repeat_delay;
config.repeat_rate = 25;
config.repeat_delay = 600;
/* Trackpad */
config.disable_trackpad = disable_trackpad;
config.tap_to_click = tap_to_click;
config.tap_and_drag = tap_and_drag;
config.drag_lock = drag_lock;
config.mouse_natural_scrolling = mouse_natural_scrolling;
config.cursor_size = cursor_size;
config.trackpad_natural_scrolling = trackpad_natural_scrolling;
config.disable_while_typing = disable_while_typing;
config.left_handed = left_handed;
config.middle_button_emulation = middle_button_emulation;
config.accel_profile = accel_profile;
config.accel_speed = accel_speed;
config.scroll_method = scroll_method;
config.scroll_button = scroll_button;
config.click_method = click_method;
config.send_events_mode = send_events_mode;
config.button_map = button_map;
config.disable_trackpad = 0;
config.tap_to_click = 1;
config.tap_and_drag = 1;
config.drag_lock = 1;
config.mouse_natural_scrolling = 0;
config.cursor_size = 24;
config.trackpad_natural_scrolling = 0;
config.disable_while_typing = 1;
config.left_handed = 0;
config.middle_button_emulation = 0;
config.accel_profile = LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE;
config.accel_speed = 0.0;
config.scroll_method = LIBINPUT_CONFIG_SCROLL_2FG;
config.scroll_button = 274;
config.click_method = LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS;
config.send_events_mode = LIBINPUT_CONFIG_SEND_EVENTS_ENABLED;
config.button_map = LIBINPUT_CONFIG_TAP_MAP_LRM;
config.blur = blur;
config.blur_layer = blur_layer;
config.blur_optimized = blur_optimized;
config.border_radius = border_radius;
config.blur_params.num_passes = blur_params_num_passes;
config.blur_params.radius = blur_params_radius;
config.blur_params.noise = blur_params_noise;
config.blur_params.brightness = blur_params_brightness;
config.blur_params.contrast = blur_params_contrast;
config.blur_params.saturation = blur_params_saturation;
config.shadows = shadows;
config.shadow_only_floating = shadow_only_floating;
config.layer_shadows = layer_shadows;
config.shadows_size = shadows_size;
config.shadows_blur = shadows_blur;
config.shadows_position_x = shadows_position_x;
config.shadows_position_y = shadows_position_y;
config.focused_opacity = focused_opacity;
config.unfocused_opacity = unfocused_opacity;
memcpy(config.shadowscolor, shadowscolor, sizeof(shadowscolor));
config.blur = 0;
config.blur_layer = 0;
config.blur_optimized = 1;
config.border_radius = 0;
config.border_radius_location_default = CORNER_LOCATION_ALL;
config.blur_params.num_passes = 1;
config.blur_params.radius = 5;
config.blur_params.noise = 0.02f;
config.blur_params.brightness = 0.9f;
config.blur_params.contrast = 0.9f;
config.blur_params.saturation = 1.2f;
config.shadows = 0;
config.shadow_only_floating = 1;
config.layer_shadows = 0;
config.shadows_size = 10;
config.shadows_blur = 15.0f;
config.shadows_position_x = 0;
config.shadows_position_y = 0;
config.focused_opacity = 1.0f;
config.unfocused_opacity = 1.0f;
memcpy(config.animation_curve_move, animation_curve_move,
sizeof(animation_curve_move));
memcpy(config.animation_curve_open, animation_curve_open,
sizeof(animation_curve_open));
memcpy(config.animation_curve_tag, animation_curve_tag,
sizeof(animation_curve_tag));
memcpy(config.animation_curve_close, animation_curve_close,
sizeof(animation_curve_close));
memcpy(config.animation_curve_focus, animation_curve_focus,
sizeof(animation_curve_focus));
memcpy(config.animation_curve_opafadein, animation_curve_opafadein,
sizeof(animation_curve_opafadein));
memcpy(config.animation_curve_opafadeout, animation_curve_opafadeout,
sizeof(animation_curve_opafadeout));
config.shadowscolor[0] = 0.0f;
config.shadowscolor[1] = 0.0f;
config.shadowscolor[2] = 0.0f;
config.shadowscolor[3] = 1.0f;
memcpy(config.rootcolor, rootcolor, sizeof(rootcolor));
memcpy(config.bordercolor, bordercolor, sizeof(bordercolor));
memcpy(config.focuscolor, focuscolor, sizeof(focuscolor));
memcpy(config.maximizescreencolor, maximizescreencolor,
sizeof(maximizescreencolor));
memcpy(config.urgentcolor, urgentcolor, sizeof(urgentcolor));
memcpy(config.scratchpadcolor, scratchpadcolor, sizeof(scratchpadcolor));
memcpy(config.globalcolor, globalcolor, sizeof(globalcolor));
memcpy(config.overlaycolor, overlaycolor, sizeof(overlaycolor));
config.animation_curve_move[0] = 0.46;
config.animation_curve_move[1] = 1.0;
config.animation_curve_move[2] = 0.29;
config.animation_curve_move[3] = 0.99;
config.animation_curve_open[0] = 0.46;
config.animation_curve_open[1] = 1.0;
config.animation_curve_open[2] = 0.29;
config.animation_curve_open[3] = 0.99;
config.animation_curve_tag[0] = 0.46;
config.animation_curve_tag[1] = 1.0;
config.animation_curve_tag[2] = 0.29;
config.animation_curve_tag[3] = 0.99;
config.animation_curve_close[0] = 0.46;
config.animation_curve_close[1] = 1.0;
config.animation_curve_close[2] = 0.29;
config.animation_curve_close[3] = 0.99;
config.animation_curve_focus[0] = 0.46;
config.animation_curve_focus[1] = 1.0;
config.animation_curve_focus[2] = 0.29;
config.animation_curve_focus[3] = 0.99;
config.animation_curve_opafadein[0] = 0.46;
config.animation_curve_opafadein[1] = 1.0;
config.animation_curve_opafadein[2] = 0.29;
config.animation_curve_opafadein[3] = 0.99;
config.animation_curve_opafadeout[0] = 0.5;
config.animation_curve_opafadeout[1] = 0.5;
config.animation_curve_opafadeout[2] = 0.5;
config.animation_curve_opafadeout[3] = 0.5;
config.rootcolor[0] = 0x32 / 255.0f;
config.rootcolor[1] = 0x32 / 255.0f;
config.rootcolor[2] = 0x32 / 255.0f;
config.rootcolor[3] = 1.0f;
config.bordercolor[0] = 0x44 / 255.0f;
config.bordercolor[1] = 0x44 / 255.0f;
config.bordercolor[2] = 0x44 / 255.0f;
config.bordercolor[3] = 1.0f;
config.focuscolor[0] = 0xc6 / 255.0f;
config.focuscolor[1] = 0x6b / 255.0f;
config.focuscolor[2] = 0x25 / 255.0f;
config.focuscolor[3] = 1.0f;
config.maximizescreencolor[0] = 0x89 / 255.0f;
config.maximizescreencolor[1] = 0xaa / 255.0f;
config.maximizescreencolor[2] = 0x61 / 255.0f;
config.maximizescreencolor[3] = 1.0f;
config.urgentcolor[0] = 0xad / 255.0f;
config.urgentcolor[1] = 0x40 / 255.0f;
config.urgentcolor[2] = 0x1f / 255.0f;
config.urgentcolor[3] = 1.0f;
config.scratchpadcolor[0] = 0x51 / 255.0f;
config.scratchpadcolor[1] = 0x6c / 255.0f;
config.scratchpadcolor[2] = 0x93 / 255.0f;
config.scratchpadcolor[3] = 1.0f;
config.globalcolor[0] = 0xb1 / 255.0f;
config.globalcolor[1] = 0x53 / 255.0f;
config.globalcolor[2] = 0xa7 / 255.0f;
config.globalcolor[3] = 1.0f;
config.overlaycolor[0] = 0x14 / 255.0f;
config.overlaycolor[1] = 0xa5 / 255.0f;
config.overlaycolor[2] = 0x7c / 255.0f;
config.overlaycolor[3] = 1.0f;
}
void set_default_key_bindings(Config *config) {
@ -3479,13 +3470,14 @@ bool parse_config(void) {
free_config();
// 重置config结构体确保所有指针初始化为NULL
memset(&config, 0, sizeof(config));
memset(&xkb_rules_rules, 0, sizeof(xkb_rules_rules));
memset(&xkb_rules_model, 0, sizeof(xkb_rules_model));
memset(&xkb_rules_layout, 0, sizeof(xkb_rules_layout));
memset(&xkb_rules_variant, 0, sizeof(xkb_rules_variant));
memset(&xkb_rules_options, 0, sizeof(xkb_rules_options));
// 重新将xkb_rules指针指向静态数组
config.xkb_rules.layout = config.xkb_rules_layout;
config.xkb_rules.variant = config.xkb_rules_variant;
config.xkb_rules.options = config.xkb_rules_options;
config.xkb_rules.rules = config.xkb_rules_rules;
config.xkb_rules.model = config.xkb_rules_model;
// 初始化动态数组的指针为NULL避免野指针
config.window_rules = NULL;
@ -3549,7 +3541,7 @@ bool parse_config(void) {
}
void reset_blur_params(void) {
if (blur) {
if (config.blur) {
Monitor *m = NULL;
wl_list_for_each(m, &mons, link) {
if (m->blur != NULL) {
@ -3559,9 +3551,9 @@ void reset_blur_params(void) {
wlr_scene_node_reparent(&m->blur->node, layers[LyrBlur]);
wlr_scene_optimized_blur_set_size(m->blur, m->m.width, m->m.height);
wlr_scene_set_blur_data(
scene, blur_params.num_passes, blur_params.radius,
blur_params.noise, blur_params.brightness, blur_params.contrast,
blur_params.saturation);
scene, config.blur_params.num_passes, config.blur_params.radius,
config.blur_params.noise, config.blur_params.brightness,
config.blur_params.contrast, config.blur_params.saturation);
}
} else {
Monitor *m = NULL;
@ -3612,6 +3604,20 @@ void reapply_monitor_rules(void) {
updatemons(NULL, NULL);
}
void set_xcursor_env() {
if (config.cursor_size > 0) {
char size_str[16];
snprintf(size_str, sizeof(size_str), "%d", config.cursor_size);
setenv("XCURSOR_SIZE", size_str, 1);
} else {
setenv("XCURSOR_SIZE", "24", 1);
}
if (config.cursor_theme) {
setenv("XCURSOR_THEME", config.cursor_theme, 1);
}
}
void reapply_cursor_style(void) {
if (hide_cursor_source) {
wl_event_source_timer_update(hide_cursor_source, 0);
@ -3628,17 +3634,10 @@ void reapply_cursor_style(void) {
cursor_mgr = NULL;
}
cursor_mgr = wlr_xcursor_manager_create(config.cursor_theme, cursor_size);
set_xcursor_env();
if (cursor_size > 0) {
char size_str[16];
snprintf(size_str, sizeof(size_str), "%d", cursor_size);
setenv("XCURSOR_SIZE", size_str, 1);
}
if (config.cursor_theme) {
setenv("XCURSOR_THEME", config.cursor_theme, 1);
}
cursor_mgr =
wlr_xcursor_manager_create(config.cursor_theme, config.cursor_size);
Monitor *m = NULL;
wl_list_for_each(m, &mons, link) {
@ -3653,11 +3652,13 @@ void reapply_cursor_style(void) {
wlr_cursor_unset_image(cursor);
} else {
wl_event_source_timer_update(hide_cursor_source,
cursor_hide_timeout * 1000);
config.cursor_hide_timeout * 1000);
}
}
void reapply_rootbg(void) { wlr_scene_rect_set_color(root_bg, rootcolor); }
void reapply_rootbg(void) {
wlr_scene_rect_set_color(root_bg, config.rootcolor);
}
void reapply_border(void) {
Client *c = NULL;
@ -3666,7 +3667,7 @@ void reapply_border(void) {
wl_list_for_each(c, &clients, link) {
if (c && !c->iskilling) {
if (!c->isnoborder && !c->isfullscreen) {
c->bw = borderpx;
c->bw = config.borderpx;
}
}
}
@ -3679,7 +3680,7 @@ void reapply_keyboard(void) {
continue;
}
wlr_keyboard_set_repeat_info((struct wlr_keyboard *)id->device_data,
repeat_rate, repeat_delay);
config.repeat_rate, config.repeat_delay);
}
}
@ -3708,12 +3709,12 @@ void reapply_master(void) {
if (!m->wlr_output->enabled) {
continue;
}
m->pertag->nmasters[i] = default_nmaster;
m->pertag->mfacts[i] = default_mfact;
m->gappih = gappih;
m->gappiv = gappiv;
m->gappoh = gappoh;
m->gappov = gappov;
m->pertag->nmasters[i] = config.default_nmaster;
m->pertag->mfacts[i] = config.default_mfact;
m->gappih = config.gappih;
m->gappiv = config.gappiv;
m->gappoh = config.gappoh;
m->gappov = config.gappov;
}
}
}
@ -3725,8 +3726,8 @@ void parse_tagrule(Monitor *m) {
bool match_rule = false;
for (i = 0; i <= LENGTH(tags); i++) {
m->pertag->nmasters[i] = default_nmaster;
m->pertag->mfacts[i] = default_mfact;
m->pertag->nmasters[i] = config.default_nmaster;
m->pertag->mfacts[i] = config.default_mfact;
}
for (i = 0; i < config.tag_rules_count; i++) {

View file

@ -1,132 +1,9 @@
// TODO: remove this file in the future, replace all global variables with
// config.xxx
#define MODKEY WLR_MODIFIER_ALT
/* speedie's mango config */
static const char *tags[] = {
"1", "2", "3", "4", "5", "6", "7", "8", "9",
};
#define COLOR(hex) \
{((hex >> 24) & 0xFF) / 255.0f, ((hex >> 16) & 0xFF) / 255.0f, \
((hex >> 8) & 0xFF) / 255.0f, (hex & 0xFF) / 255.0f}
/* animaion */
char *animation_type_open = "slide"; // 是否启用动画 //slide,zoom
char *animation_type_close = "slide"; // 是否启用动画 //slide,zoom
char *layer_animation_type_open = "slide"; // 是否启用layer动画 //slide,zoom
char *layer_animation_type_close = "slide"; // 是否启用layer动画 //slide,zoom
int32_t animations = 1; // 是否启用动画
int32_t layer_animations = 0; // 是否启用layer动画
int32_t tag_animation_direction = HORIZONTAL; // 标签动画方向
int32_t animation_fade_in = 1; // Enable animation fade in
int32_t animation_fade_out = 1; // Enable animation fade out
float zoom_initial_ratio = 0.3; // 动画起始窗口比例
float zoom_end_ratio = 0.8; // 动画结束窗口比例
float fadein_begin_opacity = 0.5; // Begin opac window ratio for animations
float fadeout_begin_opacity = 0.5; // Begin opac window ratio for animations
uint32_t animation_duration_move = 500; // Animation move speed
uint32_t animation_duration_open = 400; // Animation open speed
uint32_t animation_duration_tag = 300; // Animation tag speed
uint32_t animation_duration_close = 300; // Animation close speed
uint32_t animation_duration_focus = 0; // Animation focus opacity speed
double animation_curve_move[4] = {0.46, 1.0, 0.29, 0.99}; // 动画曲线
double animation_curve_open[4] = {0.46, 1.0, 0.29, 0.99}; // 动画曲线
double animation_curve_tag[4] = {0.46, 1.0, 0.29, 0.99}; // 动画曲线
double animation_curve_close[4] = {0.46, 1.0, 0.29, 0.99}; // 动画曲线
double animation_curve_focus[4] = {0.46, 1.0, 0.29, 0.99}; // 动画曲线
double animation_curve_opafadein[4] = {0.46, 1.0, 0.29, 0.99}; // 动画曲线
double animation_curve_opafadeout[4] = {0.5, 0.5, 0.5, 0.5}; // 动画曲线
/* appearance */
uint32_t axis_bind_apply_timeout = 100; // 滚轮绑定动作的触发的时间间隔
uint32_t focus_on_activate = 1; // 收到窗口激活请求是否自动跳转聚焦
uint32_t new_is_master = 1; // 新窗口是否插在头部
double default_mfact = 0.55f; // master 窗口比例
uint32_t default_nmaster = 1; // 默认master数量
int32_t center_master_overspread = 0; // 中心master时是否铺满
int32_t center_when_single_stack = 1; // 单个stack时是否居中
/* logging */
int32_t log_level = WLR_ERROR;
uint32_t numlockon = 0; // 是否打开右边小键盘
uint32_t capslock = 0; // 是否启用快捷键
uint32_t ov_tab_mode = 0; // alt tab切换模式
uint32_t hotarea_size = 10; // 热区大小,10x10
uint32_t hotarea_corner = BOTTOM_LEFT;
uint32_t enable_hotarea = 1; // 是否启用鼠标热区
int32_t smartgaps = 0; /* 1 means no outer gap when there is only one window */
int32_t sloppyfocus = 1; /* focus follows mouse */
uint32_t gappih = 5; /* horiz inner gap between windows */
uint32_t gappiv = 5; /* vert inner gap between windows */
uint32_t gappoh = 10; /* horiz outer gap between windows and screen edge */
uint32_t gappov = 10; /* vert outer gap between windows and screen edge */
float scratchpad_width_ratio = 0.8;
float scratchpad_height_ratio = 0.9;
int32_t scroller_structs = 20;
float scroller_default_proportion = 0.9;
float scroller_default_proportion_single = 1.0;
int32_t scroller_ignore_proportion_single = 1;
int32_t scroller_focus_center = 0;
int32_t scroller_prefer_center = 0;
int32_t scroller_prefer_overspread = 1;
int32_t focus_cross_monitor = 0;
int32_t focus_cross_tag = 0;
int32_t exchange_cross_monitor = 0;
int32_t scratchpad_cross_monitor = 0;
int32_t view_current_to_back = 0;
int32_t no_border_when_single = 0;
int32_t no_radius_when_single = 0;
int32_t snap_distance = 30;
int32_t enable_floating_snap = 0;
int32_t drag_tile_to_tile = 0;
uint32_t cursor_size = 24;
uint32_t cursor_hide_timeout = 0;
uint32_t swipe_min_threshold = 1;
int32_t idleinhibit_ignore_visible =
0; /* 1 means idle inhibitors will disable idle tracking even if it's
surface isn't visible */
uint32_t borderpx = 4; /* border pixel of windows */
float rootcolor[] = COLOR(0x323232ff);
float bordercolor[] = COLOR(0x444444ff);
float focuscolor[] = COLOR(0xc66b25ff);
float maximizescreencolor[] = COLOR(0x89aa61ff);
float urgentcolor[] = COLOR(0xad401fff);
float scratchpadcolor[] = COLOR(0x516c93ff);
float globalcolor[] = COLOR(0xb153a7ff);
float overlaycolor[] = COLOR(0x14a57cff);
// char *cursor_theme = "Bibata-Modern-Ice";
int32_t overviewgappi = 5; /* overview时 窗口与边缘 缝隙大小 */
int32_t overviewgappo = 30; /* overview时 窗口与窗口 缝隙大小 */
/* To conform the xdg-protocol, set the alpha to zero to restore the old
* behavior */
float fullscreen_bg[] = {0.1, 0.1, 0.1, 1.0};
int32_t warpcursor = 1;
int32_t drag_corner = 3;
int32_t drag_warp_cursor = 1;
int32_t xwayland_persistence = 1; /* xwayland persistence */
int32_t syncobj_enable = 0;
int32_t allow_lock_transparent = 0;
double drag_tile_refresh_interval = 8.0;
double drag_floating_refresh_interval = 8.0;
int32_t allow_tearing = TEARING_DISABLED;
int32_t allow_shortcuts_inhibit = SHORTCUTS_INHIBIT_ENABLE;
/* keyboard */
/*
only layout can modify after fisrt init
other fields change will be ignored.
*/
char xkb_rules_rules[256];
char xkb_rules_model[256];
char xkb_rules_layout[256];
char xkb_rules_variant[256];
char xkb_rules_options[256];
/* keyboard */
static const struct xkb_rule_names xkb_fallback_rules = {
.layout = "us",
.variant = NULL,
@ -134,106 +11,3 @@ static const struct xkb_rule_names xkb_fallback_rules = {
.rules = NULL,
.options = NULL,
};
static const struct xkb_rule_names xkb_default_rules = {
.options = NULL,
};
struct xkb_rule_names xkb_rules = {
/* can specify fields: rules, model, layout, variant, options */
/* example:
.options = "ctrl:nocaps",
*/
.rules = xkb_rules_rules, .model = xkb_rules_model,
.layout = xkb_rules_layout, .variant = xkb_rules_variant,
.options = xkb_rules_options,
};
int32_t repeat_rate = 25;
int32_t repeat_delay = 600;
/* Trackpad */
int32_t disable_trackpad = 0;
int32_t tap_to_click = 1;
int32_t tap_and_drag = 1;
int32_t drag_lock = 1;
int32_t mouse_natural_scrolling = 0;
int32_t trackpad_natural_scrolling = 0;
int32_t disable_while_typing = 1;
int32_t left_handed = 0;
int32_t middle_button_emulation = 0;
int32_t single_scratchpad = 1;
int32_t edge_scroller_pointer_focus = 1;
/* You can choose between:
LIBINPUT_CONFIG_SCROLL_NO_SCROLL
LIBINPUT_CONFIG_SCROLL_2FG
LIBINPUT_CONFIG_SCROLL_EDGE
LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN
*/
enum libinput_config_scroll_method scroll_method = LIBINPUT_CONFIG_SCROLL_2FG;
uint32_t scroll_button = 274;
/* You can choose between:
LIBINPUT_CONFIG_CLICK_METHOD_NONE
LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS
LIBINPUT_CONFIG_CLICK_METHOD_CLICKFINGER
*/
enum libinput_config_click_method click_method =
LIBINPUT_CONFIG_CLICK_METHOD_BUTTON_AREAS;
double axis_scroll_factor = 1.0;
/* You can choose between:
LIBINPUT_CONFIG_SEND_EVENTS_ENABLED
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED
LIBINPUT_CONFIG_SEND_EVENTS_DISABLED_ON_EXTERNAL_MOUSE
*/
uint32_t send_events_mode = LIBINPUT_CONFIG_SEND_EVENTS_ENABLED;
/* You can choose between:
LIBINPUT_CONFIG_ACCEL_PROFILE_FLAT
LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE
*/
enum libinput_config_accel_profile accel_profile =
LIBINPUT_CONFIG_ACCEL_PROFILE_ADAPTIVE;
double accel_speed = 0.0;
/* You can choose between:
LIBINPUT_CONFIG_TAP_MAP_LRM -- 1/2/3 finger tap maps to left/right/middle
LIBINPUT_CONFIG_TAP_MAP_LMR -- 1/2/3 finger tap maps to left/middle/right
*/
enum libinput_config_tap_button_map button_map = LIBINPUT_CONFIG_TAP_MAP_LRM;
/* If you want to use the windows key for MODKEY, use WLR_MODIFIER_LOGO */
#define MODKEY WLR_MODIFIER_ALT
static const char *tags[] = {
"1", "2", "3", "4", "5", "6", "7", "8", "9",
};
float focused_opacity = 1.0;
float unfocused_opacity = 1.0;
int32_t border_radius = 0;
int32_t border_radius_location_default = CORNER_LOCATION_ALL;
int32_t blur = 0;
int32_t blur_layer = 0;
int32_t blur_optimized = 1;
struct blur_data blur_params;
int32_t blur_params_num_passes = 1;
int32_t blur_params_radius = 5;
float blur_params_noise = 0.02;
float blur_params_brightness = 0.9;
float blur_params_contrast = 0.9;
float blur_params_saturation = 1.2;
int32_t shadows = 0;
int32_t shadow_only_floating = 1;
int32_t layer_shadows = 0;
uint32_t shadows_size = 10;
double shadows_blur = 15;
int32_t shadows_position_x = 0;
int32_t shadows_position_y = 0;
float shadowscolor[] = COLOR(0x000000ff);

View file

@ -3,7 +3,7 @@ int32_t bind_to_view(const Arg *arg) {
return 0;
uint32_t target = arg->ui;
if (view_current_to_back && selmon->pertag->curtag &&
if (config.view_current_to_back && selmon->pertag->curtag &&
(target & TAGMASK) == (selmon->tagset[selmon->seltags])) {
if (selmon->pertag->prevtag)
target = 1 << (selmon->pertag->prevtag - 1);
@ -11,13 +11,13 @@ int32_t bind_to_view(const Arg *arg) {
target = 0;
}
if (!view_current_to_back &&
if (!config.view_current_to_back &&
(target & TAGMASK) == (selmon->tagset[selmon->seltags])) {
return 0;
}
if ((int32_t)target == INT_MIN && selmon->pertag->curtag == 0) {
if (view_current_to_back && selmon->pertag->prevtag)
if (config.view_current_to_back && selmon->pertag->prevtag)
target = 1 << (selmon->pertag->prevtag - 1);
else
target = 0;
@ -96,7 +96,7 @@ int32_t destroy_all_virtual_output(const Arg *arg) {
}
int32_t defaultgaps(const Arg *arg) {
setgaps(gappoh, gappov, gappih, gappiv);
setgaps(config.gappoh, config.gappov, config.gappih, config.gappiv);
return 0;
}
@ -140,7 +140,7 @@ int32_t focusdir(const Arg *arg) {
c = get_focused_stack_client(c);
if (c) {
focusclient(c, 1);
if (warpcursor)
if (config.warpcursor)
warp_cursor(c);
} else {
if (config.focus_cross_tag) {
@ -196,7 +196,7 @@ int32_t focuslast(const Arg *arg) {
}
int32_t toggle_trackpad_enable(const Arg *arg) {
disable_trackpad = !disable_trackpad;
config.disable_trackpad = !config.disable_trackpad;
return 0;
}
@ -225,7 +225,7 @@ int32_t focusmon(const Arg *arg) {
return 0;
selmon = tm;
if (warpcursor) {
if (config.warpcursor) {
warp_cursor_to_selmon(selmon);
}
c = focustop(selmon);
@ -258,7 +258,7 @@ int32_t focusstack(const Arg *arg) {
return 0;
focusclient(tc, 1);
if (warpcursor)
if (config.warpcursor)
warp_cursor(tc);
return 0;
}
@ -390,7 +390,7 @@ int32_t moveresize(const Arg *arg) {
/* Doesn't work for X11 output - the next absolute motion event
* returns the cursor to where it started */
if (grabc->isfloating) {
rzcorner = drag_corner;
rzcorner = config.drag_corner;
grabcx = (int)round(cursor->x);
grabcy = (int)round(cursor->y);
if (rzcorner == 4)
@ -404,7 +404,7 @@ int32_t moveresize(const Arg *arg) {
? 0
: 2);
if (drag_warp_cursor) {
if (config.drag_warp_cursor) {
grabcx = rzcorner & 1 ? grabc->geom.x + grabc->geom.width
: grabc->geom.x;
grabcy = rzcorner & 2 ? grabc->geom.y + grabc->geom.height
@ -476,9 +476,9 @@ int32_t resizewin(const Arg *arg) {
if (!c || c->isfullscreen || c->ismaximizescreen)
return 0;
int32_t animations_state_backup = animations;
int32_t animations_state_backup = config.animations;
if (!c->isfloating)
animations = 0;
config.animations = 0;
if (ISTILED(c)) {
switch (arg->ui) {
@ -505,7 +505,7 @@ int32_t resizewin(const Arg *arg) {
break;
}
resize_tile_client(c, false, offsetx, offsety, 0);
animations = animations_state_backup;
config.animations = animations_state_backup;
return 0;
}
@ -536,7 +536,7 @@ int32_t resizewin(const Arg *arg) {
c->iscustomsize = 1;
c->float_geom = c->geom;
resize(c, c->geom, 0);
animations = animations_state_backup;
config.animations = animations_state_backup;
return 0;
}
@ -608,7 +608,7 @@ int32_t set_proportion(const Arg *arg) {
return 0;
if (selmon->visible_tiling_clients == 1 &&
!scroller_ignore_proportion_single)
!config.scroller_ignore_proportion_single)
return 0;
Client *tc = selmon->sel;
@ -616,7 +616,7 @@ int32_t set_proportion(const Arg *arg) {
if (tc) {
tc = get_scroll_stack_head(tc);
uint32_t max_client_width =
selmon->w.width - 2 * scroller_structs - gappih;
selmon->w.width - 2 * config.scroller_structs - config.gappih;
tc->scroller_proportion = arg->f;
tc->geom.width = max_client_width * arg->f;
arrange(selmon, false, false);
@ -650,7 +650,7 @@ int32_t smartmovewin(const Arg *arg) {
if (c->geom.x + c->geom.width < tc->geom.x ||
c->geom.x > tc->geom.x + tc->geom.width)
continue;
buttom = tc->geom.y + tc->geom.height + gappiv;
buttom = tc->geom.y + tc->geom.height + config.gappiv;
if (top > buttom && ny < buttom) {
tar = MAX(tar, buttom);
};
@ -670,7 +670,7 @@ int32_t smartmovewin(const Arg *arg) {
if (c->geom.x + c->geom.width < tc->geom.x ||
c->geom.x > tc->geom.x + tc->geom.width)
continue;
top = tc->geom.y - gappiv;
top = tc->geom.y - config.gappiv;
if (buttom < top && (ny + c->geom.height) > top) {
tar = MIN(tar, top - c->geom.height);
};
@ -690,7 +690,7 @@ int32_t smartmovewin(const Arg *arg) {
if (c->geom.y + c->geom.height < tc->geom.y ||
c->geom.y > tc->geom.y + tc->geom.height)
continue;
right = tc->geom.x + tc->geom.width + gappih;
right = tc->geom.x + tc->geom.width + config.gappih;
if (left > right && nx < right) {
tar = MAX(tar, right);
};
@ -709,7 +709,7 @@ int32_t smartmovewin(const Arg *arg) {
if (c->geom.y + c->geom.height < tc->geom.y ||
c->geom.y > tc->geom.y + tc->geom.height)
continue;
left = tc->geom.x - gappih;
left = tc->geom.x - config.gappih;
if (right < left && (nx + c->geom.width) > left) {
tar = MIN(tar, left - c->geom.width);
};
@ -757,14 +757,14 @@ int32_t smartresizewin(const Arg *arg) {
if (c->geom.x + c->geom.width < tc->geom.x ||
c->geom.x > tc->geom.x + tc->geom.width)
continue;
top = tc->geom.y - gappiv;
top = tc->geom.y - config.gappiv;
if (buttom < top && (nh + c->geom.y) > top) {
tar = MAX(tar, top - c->geom.y);
};
}
nh = tar == -99999 ? nh : tar;
if (c->geom.y + nh + gappov > selmon->w.y + selmon->w.height)
nh = selmon->w.y + selmon->w.height - c->geom.y - gappov;
if (c->geom.y + nh + config.gappov > selmon->w.y + selmon->w.height)
nh = selmon->w.y + selmon->w.height - c->geom.y - config.gappov;
break;
case LEFT:
nw -= selmon->w.width / 16;
@ -780,15 +780,15 @@ int32_t smartresizewin(const Arg *arg) {
if (c->geom.y + c->geom.height < tc->geom.y ||
c->geom.y > tc->geom.y + tc->geom.height)
continue;
left = tc->geom.x - gappih;
left = tc->geom.x - config.gappih;
if (right < left && (nw + c->geom.x) > left) {
tar = MIN(tar, left - c->geom.x);
};
}
nw = tar == 99999 ? nw : tar;
if (c->geom.x + nw + gappoh > selmon->w.x + selmon->w.width)
nw = selmon->w.x + selmon->w.width - c->geom.x - gappoh;
if (c->geom.x + nw + config.gappoh > selmon->w.x + selmon->w.width)
nw = selmon->w.x + selmon->w.width - c->geom.x - config.gappoh;
break;
}
@ -1046,7 +1046,7 @@ int32_t switch_proportion_preset(const Arg *arg) {
return 0;
if (selmon->visible_tiling_clients == 1 &&
!scroller_ignore_proportion_single)
!config.scroller_ignore_proportion_single)
return 0;
Client *tc = selmon->sel;
@ -1087,7 +1087,7 @@ int32_t switch_proportion_preset(const Arg *arg) {
}
uint32_t max_client_width =
selmon->w.width - 2 * scroller_structs - gappih;
selmon->w.width - 2 * config.scroller_structs - config.gappih;
tc->scroller_proportion = target_proportion;
tc->geom.width = max_client_width * target_proportion;
arrange(selmon, false, false);
@ -1170,7 +1170,7 @@ int32_t tagmon(const Arg *arg) {
focusclient(c, 1);
arrange(selmon, false, false);
}
if (warpcursor) {
if (config.warpcursor) {
warp_cursor_to_selmon(c->mon);
}
return 0;
@ -1257,11 +1257,12 @@ int32_t toggle_scratchpad(const Arg *arg) {
return 0;
wl_list_for_each_safe(c, tmp, &clients, link) {
if (!scratchpad_cross_monitor && c->mon != selmon) {
if (!config.scratchpad_cross_monitor && c->mon != selmon) {
continue;
}
if (single_scratchpad && c->isnamedscratchpad && !c->isminimized) {
if (config.single_scratchpad && c->isnamedscratchpad &&
!c->isminimized) {
set_minimized(c);
continue;
}
@ -1662,7 +1663,8 @@ int32_t toggleoverview(const Arg *arg) {
if (!selmon)
return 0;
if (selmon->isoverview && ov_tab_mode && arg->i != 1 && selmon->sel) {
if (selmon->isoverview && config.ov_tab_mode && arg->i != 1 &&
selmon->sel) {
focusstack(&(Arg){.i = 1});
return 0;
}

View file

@ -60,7 +60,7 @@ void handle_tearing_new_object(struct wl_listener *listener, void *data) {
bool check_tearing_frame_allow(Monitor *m) {
/* never allow tearing when disabled */
if (!allow_tearing) {
if (!config.allow_tearing) {
return false;
}
@ -72,7 +72,7 @@ bool check_tearing_frame_allow(Monitor *m) {
}
/* allow tearing for any window when requested or forced */
if (allow_tearing == TEARING_ENABLED) {
if (config.allow_tearing == TEARING_ENABLED) {
if (c->force_tearing == STATE_UNSPECIFIED) {
return c->tearing_hint;
} else {
@ -87,7 +87,8 @@ bool check_tearing_frame_allow(Monitor *m) {
if (c->force_tearing == STATE_UNSPECIFIED) {
/* honor the tearing hint or the fullscreen-force preference */
return c->tearing_hint || allow_tearing == TEARING_FULLSCREEN_ONLY;
return c->tearing_hint ||
config.allow_tearing == TEARING_FULLSCREEN_ONLY;
}
/* honor tearing as requested by action */

View file

@ -12,7 +12,7 @@ bool check_hit_no_border(Client *c) {
}
}
if (no_border_when_single && c && c->mon &&
if (config.no_border_when_single && c && c->mon &&
((ISSCROLLTILED(c) && c->mon->visible_scroll_tiling_clients == 1) ||
c->mon->visible_clients == 1)) {
hit_no_border = true;
@ -39,7 +39,7 @@ Client *get_client_by_id_or_title(const char *arg_id, const char *arg_title) {
const char *appid, *title;
Client *c = NULL;
wl_list_for_each(c, &clients, link) {
if (!scratchpad_cross_monitor && c->mon != selmon) {
if (!config.scratchpad_cross_monitor && c->mon != selmon) {
continue;
}
@ -167,7 +167,7 @@ Client *find_client_by_direction(Client *tc, const Arg *arg, bool findfloating,
// 第一次遍历,计算客户端数量
wl_list_for_each(c, &clients, link) {
if (c && (findfloating || !c->isfloating) && !c->isunglobal &&
(focus_cross_monitor || c->mon == tc->mon) &&
(config.focus_cross_monitor || c->mon == tc->mon) &&
(c->tags & c->mon->tagset[c->mon->seltags])) {
last++;
}
@ -188,7 +188,7 @@ Client *find_client_by_direction(Client *tc, const Arg *arg, bool findfloating,
last = -1;
wl_list_for_each(c, &clients, link) {
if (c && (findfloating || !c->isfloating) && !c->isunglobal &&
(focus_cross_monitor || c->mon == tc->mon) &&
(config.focus_cross_monitor || c->mon == tc->mon) &&
(c->tags & c->mon->tagset[c->mon->seltags])) {
last++;
tempClients[last] = c;
@ -511,21 +511,21 @@ Client *get_next_stack_client(Client *c, bool reverse) {
float *get_border_color(Client *c) {
if (c->mon != selmon) {
return bordercolor;
return config.bordercolor;
} else if (c->isurgent) {
return urgentcolor;
return config.urgentcolor;
} else if (c->is_in_scratchpad && selmon && c == selmon->sel) {
return scratchpadcolor;
return config.scratchpadcolor;
} else if (c->isglobal && selmon && c == selmon->sel) {
return globalcolor;
return config.globalcolor;
} else if (c->isoverlay && selmon && c == selmon->sel) {
return overlaycolor;
return config.overlaycolor;
} else if (c->ismaximizescreen && selmon && c == selmon->sel) {
return maximizescreencolor;
return config.maximizescreencolor;
} else if (selmon && c == selmon->sel) {
return focuscolor;
return config.focuscolor;
} else {
return bordercolor;
return config.bordercolor;
}
}

View file

@ -15,6 +15,9 @@ void restore_size_per(Monitor *m, Client *c) {
if (!m || !c)
return;
if (!m->wlr_output->enabled)
return;
wl_list_for_each(fc, &clients, link) {
if (VISIBLEON(fc, m) && ISTILED(fc)) {
fc->old_ismaster = fc->ismaster;
@ -309,7 +312,7 @@ void resize_tile_master_horizontal(Client *grabc, bool isdrag, int32_t offsetx,
}
if (last_apply_drap_time == 0 ||
time - last_apply_drap_time > drag_tile_refresh_interval) {
time - last_apply_drap_time > config.drag_tile_refresh_interval) {
arrange(grabc->mon, false, false);
last_apply_drap_time = time;
}
@ -478,7 +481,7 @@ void resize_tile_master_vertical(Client *grabc, bool isdrag, int32_t offsetx,
}
if (last_apply_drap_time == 0 ||
time - last_apply_drap_time > drag_tile_refresh_interval) {
time - last_apply_drap_time > config.drag_tile_refresh_interval) {
arrange(grabc->mon, false, false);
last_apply_drap_time = time;
}
@ -494,7 +497,7 @@ void resize_tile_scroller(Client *grabc, bool isdrag, int32_t offsetx,
Client *stack_head = get_scroll_stack_head(grabc);
if (grabc && grabc->mon->visible_tiling_clients == 1 &&
!scroller_ignore_proportion_single)
!config.scroller_ignore_proportion_single)
return;
if (!start_drag_window && isdrag) {
@ -670,7 +673,7 @@ void resize_tile_scroller(Client *grabc, bool isdrag, int32_t offsetx,
}
if (last_apply_drap_time == 0 ||
time - last_apply_drap_time > drag_tile_refresh_interval) {
time - last_apply_drap_time > config.drag_tile_refresh_interval) {
arrange(grabc->mon, false, false);
last_apply_drap_time = time;
}
@ -811,11 +814,6 @@ void pre_caculate_before_arrange(Monitor *m, bool want_animation,
int32_t master_num = 0;
int32_t stack_num = 0;
if (!m)
return;
if (!m->wlr_output->enabled)
return;
m->visible_clients = 0;
m->visible_tiling_clients = 0;
m->visible_scroll_tiling_clients = 0;
@ -912,6 +910,12 @@ void pre_caculate_before_arrange(Monitor *m, bool want_animation,
void // 17
arrange(Monitor *m, bool want_animation, bool from_view) {
if (!m)
return;
if (!m->wlr_output->enabled)
return;
pre_caculate_before_arrange(m, want_animation, from_view, false);
if (m->isoverview) {

View file

@ -7,9 +7,9 @@ void grid(Monitor *m) {
Client *c = NULL;
n = 0;
int32_t target_gappo =
enablegaps ? m->isoverview ? overviewgappo : gappoh : 0;
enablegaps ? m->isoverview ? config.overviewgappo : config.gappoh : 0;
int32_t target_gappi =
enablegaps ? m->isoverview ? overviewgappi : gappih : 0;
enablegaps ? m->isoverview ? config.overviewgappi : config.gappih : 0;
float single_width_ratio = m->isoverview ? 0.7 : 0.9;
float single_height_ratio = m->isoverview ? 0.8 : 0.9;
@ -123,9 +123,12 @@ void deck(Monitor *m) {
int32_t cur_gappoh = enablegaps ? m->gappoh : 0;
int32_t cur_gappov = enablegaps ? m->gappov : 0;
cur_gappih = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappih;
cur_gappoh = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappoh;
cur_gappov = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappov;
cur_gappih =
config.smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappih;
cur_gappoh =
config.smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappoh;
cur_gappov =
config.smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappov;
n = m->visible_tiling_clients;
@ -188,12 +191,15 @@ void horizontal_scroll_adjust_fullandmax(Client *c,
int32_t cur_gappoh = enablegaps ? m->gappoh : 0;
int32_t cur_gappov = enablegaps ? m->gappov : 0;
cur_gappih =
smartgaps && m->visible_scroll_tiling_clients == 1 ? 0 : cur_gappih;
cur_gappoh =
smartgaps && m->visible_scroll_tiling_clients == 1 ? 0 : cur_gappoh;
cur_gappov =
smartgaps && m->visible_scroll_tiling_clients == 1 ? 0 : cur_gappov;
cur_gappih = config.smartgaps && m->visible_scroll_tiling_clients == 1
? 0
: cur_gappih;
cur_gappoh = config.smartgaps && m->visible_scroll_tiling_clients == 1
? 0
: cur_gappoh;
cur_gappov = config.smartgaps && m->visible_scroll_tiling_clients == 1
? 0
: cur_gappov;
if (c->isfullscreen) {
target_geom->height = m->m.height;
@ -289,14 +295,18 @@ void scroller(Monitor *m) {
int32_t cur_gappov = enablegaps ? m->gappov : 0;
int32_t cur_gappiv = enablegaps ? m->gappiv : 0;
cur_gappih =
smartgaps && m->visible_scroll_tiling_clients == 1 ? 0 : cur_gappih;
cur_gappoh =
smartgaps && m->visible_scroll_tiling_clients == 1 ? 0 : cur_gappoh;
cur_gappov =
smartgaps && m->visible_scroll_tiling_clients == 1 ? 0 : cur_gappov;
cur_gappih = config.smartgaps && m->visible_scroll_tiling_clients == 1
? 0
: cur_gappih;
cur_gappoh = config.smartgaps && m->visible_scroll_tiling_clients == 1
? 0
: cur_gappoh;
cur_gappov = config.smartgaps && m->visible_scroll_tiling_clients == 1
? 0
: cur_gappov;
int32_t max_client_width = m->w.width - 2 * scroller_structs - cur_gappih;
int32_t max_client_width =
m->w.width - 2 * config.scroller_structs - cur_gappih;
n = m->visible_scroll_tiling_clients;
@ -320,13 +330,13 @@ void scroller(Monitor *m) {
}
}
if (n == 1 && !scroller_ignore_proportion_single &&
if (n == 1 && !config.scroller_ignore_proportion_single &&
!tempClients[0]->isfullscreen && !tempClients[0]->ismaximizescreen) {
c = tempClients[0];
single_proportion = c->scroller_proportion_single > 0.0f
? c->scroller_proportion_single
: scroller_default_proportion_single;
: config.scroller_default_proportion_single;
target_geom.height = m->w.height - 2 * cur_gappov;
target_geom.width = (m->w.width - 2 * cur_gappoh) * single_proportion;
@ -360,9 +370,9 @@ void scroller(Monitor *m) {
for (i = 0; i < n; i++) {
c = tempClients[i];
if (root_client == c) {
if (c->geom.x >= m->w.x + scroller_structs &&
if (c->geom.x >= m->w.x + config.scroller_structs &&
c->geom.x + c->geom.width <=
m->w.x + m->w.width - scroller_structs) {
m->w.x + m->w.width - config.scroller_structs) {
need_scroller = false;
} else {
need_scroller = true;
@ -373,7 +383,8 @@ void scroller(Monitor *m) {
}
bool need_apply_overspread =
scroller_prefer_overspread && m->visible_scroll_tiling_clients > 1 &&
config.scroller_prefer_overspread &&
m->visible_scroll_tiling_clients > 1 &&
(focus_client_index == 0 || focus_client_index == n - 1) &&
tempClients[focus_client_index]->scroller_proportion < 1.0f;
@ -403,16 +414,16 @@ void scroller(Monitor *m) {
}
bool need_apply_center =
scroller_focus_center || m->visible_scroll_tiling_clients == 1 ||
(scroller_prefer_center && !need_apply_overspread &&
config.scroller_focus_center || m->visible_scroll_tiling_clients == 1 ||
(config.scroller_prefer_center && !need_apply_overspread &&
(!m->prevsel ||
(ISSCROLLTILED(m->prevsel) &&
(m->prevsel->scroller_proportion * max_client_width) +
(tempClients[focus_client_index]->scroller_proportion *
max_client_width) >
m->w.width - 2 * scroller_structs - cur_gappih)));
m->w.width - 2 * config.scroller_structs - cur_gappih)));
if (n == 1 && scroller_ignore_proportion_single) {
if (n == 1 && config.scroller_ignore_proportion_single) {
need_scroller = true;
}
@ -439,14 +450,14 @@ void scroller(Monitor *m) {
target_geom.x = m->w.x + (m->w.width - target_geom.width) / 2;
} else if (need_apply_overspread) {
if (over_overspread_to_left) {
target_geom.x = m->w.x + scroller_structs;
target_geom.x = m->w.x + config.scroller_structs;
} else {
target_geom.x =
m->w.x +
(m->w.width -
tempClients[focus_client_index]->scroller_proportion *
max_client_width -
scroller_structs);
config.scroller_structs);
}
} else {
@ -456,8 +467,8 @@ void scroller(Monitor *m) {
tempClients[focus_client_index]
->scroller_proportion *
max_client_width -
scroller_structs)
: m->w.x + scroller_structs;
config.scroller_structs)
: m->w.x + config.scroller_structs;
}
horizontal_check_scroller_root_inside_mon(
tempClients[focus_client_index], &target_geom);
@ -522,10 +533,14 @@ void center_tile(Monitor *m) {
int32_t cur_gappoh = enablegaps ? m->gappoh : 0; // 外部水平间隙
// 智能间隙处理
cur_gappiv = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappiv;
cur_gappih = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappih;
cur_gappov = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappov;
cur_gappoh = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappoh;
cur_gappiv =
config.smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappiv;
cur_gappih =
config.smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappih;
cur_gappov =
config.smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappov;
cur_gappoh =
config.smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappoh;
int32_t nmasters = m->pertag->nmasters[m->pertag->curtag];
mfact = fc->master_mfact_per > 0.0f ? fc->master_mfact_per
@ -538,7 +553,8 @@ void center_tile(Monitor *m) {
tw = mw;
// 判断是否需要主区域铺满
int32_t should_overspread = center_master_overspread && (n <= nmasters);
int32_t should_overspread =
config.center_master_overspread && (n <= nmasters);
int32_t master_surplus_height =
(m->w.height - 2 * cur_gappov - cur_gappiv * ie * (master_num - 1));
@ -564,7 +580,7 @@ void center_tile(Monitor *m) {
mx = cur_gappoh + tw + cur_gappih * ie;
} else if (n - nmasters == 1) {
// 单个堆叠窗口的处理
if (center_when_single_stack) {
if (config.center_when_single_stack) {
// stack在右边master居中左边空着
tw = (m->w.width - mw) / 2 - cur_gappoh - cur_gappih * ie;
mx = cur_gappoh + tw + cur_gappih * ie; // master居中
@ -641,7 +657,7 @@ void center_tile(Monitor *m) {
}
int32_t stack_x;
if (center_when_single_stack) {
if (config.center_when_single_stack) {
// 放在右侧master居中时stack在右边
stack_x = m->w.x + mx + mw + cur_gappih * ie;
} else {
@ -745,10 +761,14 @@ void tile(Monitor *m) {
int32_t cur_gappov = enablegaps ? m->gappov : 0;
int32_t cur_gappoh = enablegaps ? m->gappoh : 0;
cur_gappiv = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappiv;
cur_gappih = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappih;
cur_gappov = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappov;
cur_gappoh = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappoh;
cur_gappiv =
config.smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappiv;
cur_gappih =
config.smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappih;
cur_gappov =
config.smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappov;
cur_gappoh =
config.smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappoh;
wl_list_for_each(fc, &clients, link) {
@ -855,10 +875,14 @@ void right_tile(Monitor *m) {
int32_t cur_gappov = enablegaps ? m->gappov : 0;
int32_t cur_gappoh = enablegaps ? m->gappoh : 0;
cur_gappiv = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappiv;
cur_gappih = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappih;
cur_gappov = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappov;
cur_gappoh = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappoh;
cur_gappiv =
config.smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappiv;
cur_gappih =
config.smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappih;
cur_gappov =
config.smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappov;
cur_gappoh =
config.smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappoh;
wl_list_for_each(fc, &clients, link) {
@ -953,8 +977,10 @@ monocle(Monitor *m) {
int32_t cur_gappov = enablegaps ? m->gappov : 0;
int32_t cur_gappoh = enablegaps ? m->gappoh : 0;
cur_gappoh = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappoh;
cur_gappov = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappov;
cur_gappoh =
config.smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappoh;
cur_gappov =
config.smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappov;
wl_list_for_each(c, &clients, link) {
if (!VISIBLEON(c, m) || !ISTILED(c))

View file

@ -19,10 +19,14 @@ void vertical_tile(Monitor *m) {
int32_t cur_gapoh = enablegaps ? m->gappoh : 0;
int32_t cur_gapov = enablegaps ? m->gappov : 0;
cur_gapih = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gapih;
cur_gapiv = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gapiv;
cur_gapoh = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gapoh;
cur_gapov = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gapov;
cur_gapih =
config.smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gapih;
cur_gapiv =
config.smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gapiv;
cur_gapoh =
config.smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gapoh;
cur_gapov =
config.smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gapov;
wl_list_for_each(fc, &clients, link) {
if (VISIBLEON(fc, m) && ISTILED(fc))
@ -116,9 +120,12 @@ void vertical_deck(Monitor *m) {
int32_t cur_gappoh = enablegaps ? m->gappoh : 0;
int32_t cur_gappov = enablegaps ? m->gappov : 0;
cur_gappiv = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappiv;
cur_gappoh = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappoh;
cur_gappov = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappov;
cur_gappiv =
config.smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappiv;
cur_gappoh =
config.smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappoh;
cur_gappov =
config.smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappov;
n = m->visible_tiling_clients;
@ -175,12 +182,15 @@ void vertical_scroll_adjust_fullandmax(Client *c, struct wlr_box *target_geom) {
int32_t cur_gappov = enablegaps ? m->gappov : 0;
int32_t cur_gappoh = enablegaps ? m->gappoh : 0;
cur_gappiv =
smartgaps && m->visible_scroll_tiling_clients == 1 ? 0 : cur_gappiv;
cur_gappov =
smartgaps && m->visible_scroll_tiling_clients == 1 ? 0 : cur_gappov;
cur_gappoh =
smartgaps && m->visible_scroll_tiling_clients == 1 ? 0 : cur_gappoh;
cur_gappiv = config.smartgaps && m->visible_scroll_tiling_clients == 1
? 0
: cur_gappiv;
cur_gappov = config.smartgaps && m->visible_scroll_tiling_clients == 1
? 0
: cur_gappov;
cur_gappoh = config.smartgaps && m->visible_scroll_tiling_clients == 1
? 0
: cur_gappoh;
if (c->isfullscreen) {
target_geom->width = m->m.width;
@ -276,14 +286,18 @@ void vertical_scroller(Monitor *m) {
int32_t cur_gappoh = enablegaps ? m->gappoh : 0;
int32_t cur_gappih = enablegaps ? m->gappih : 0;
cur_gappiv =
smartgaps && m->visible_scroll_tiling_clients == 1 ? 0 : cur_gappiv;
cur_gappov =
smartgaps && m->visible_scroll_tiling_clients == 1 ? 0 : cur_gappov;
cur_gappoh =
smartgaps && m->visible_scroll_tiling_clients == 1 ? 0 : cur_gappoh;
cur_gappiv = config.smartgaps && m->visible_scroll_tiling_clients == 1
? 0
: cur_gappiv;
cur_gappov = config.smartgaps && m->visible_scroll_tiling_clients == 1
? 0
: cur_gappov;
cur_gappoh = config.smartgaps && m->visible_scroll_tiling_clients == 1
? 0
: cur_gappoh;
int32_t max_client_height = m->w.height - 2 * scroller_structs - cur_gappiv;
int32_t max_client_height =
m->w.height - 2 * config.scroller_structs - cur_gappiv;
n = m->visible_scroll_tiling_clients;
@ -304,13 +318,13 @@ void vertical_scroller(Monitor *m) {
}
}
if (n == 1 && !scroller_ignore_proportion_single &&
if (n == 1 && !config.scroller_ignore_proportion_single &&
!tempClients[0]->isfullscreen && !tempClients[0]->ismaximizescreen) {
c = tempClients[0];
single_proportion = c->scroller_proportion_single > 0.0f
? c->scroller_proportion_single
: scroller_default_proportion_single;
: config.scroller_default_proportion_single;
target_geom.width = m->w.width - 2 * cur_gappoh;
target_geom.height = (m->w.height - 2 * cur_gappov) * single_proportion;
@ -344,9 +358,9 @@ void vertical_scroller(Monitor *m) {
for (i = 0; i < n; i++) {
c = tempClients[i];
if (root_client == c) {
if (c->geom.y >= m->w.y + scroller_structs &&
if (c->geom.y >= m->w.y + config.scroller_structs &&
c->geom.y + c->geom.height <=
m->w.y + m->w.height - scroller_structs) {
m->w.y + m->w.height - config.scroller_structs) {
need_scroller = false;
} else {
need_scroller = true;
@ -357,7 +371,8 @@ void vertical_scroller(Monitor *m) {
}
bool need_apply_overspread =
scroller_prefer_overspread && m->visible_scroll_tiling_clients > 1 &&
config.scroller_prefer_overspread &&
m->visible_scroll_tiling_clients > 1 &&
(focus_client_index == 0 || focus_client_index == n - 1) &&
tempClients[focus_client_index]->scroller_proportion < 1.0f;
@ -387,16 +402,16 @@ void vertical_scroller(Monitor *m) {
}
bool need_apply_center =
scroller_focus_center || m->visible_scroll_tiling_clients == 1 ||
(scroller_prefer_center && !need_apply_overspread &&
config.scroller_focus_center || m->visible_scroll_tiling_clients == 1 ||
(config.scroller_prefer_center && !need_apply_overspread &&
(!m->prevsel ||
(ISSCROLLTILED(m->prevsel) &&
(m->prevsel->scroller_proportion * max_client_height) +
(tempClients[focus_client_index]->scroller_proportion *
max_client_height) >
m->w.height - 2 * scroller_structs - cur_gappiv)));
m->w.height - 2 * config.scroller_structs - cur_gappiv)));
if (n == 1 && scroller_ignore_proportion_single) {
if (n == 1 && config.scroller_ignore_proportion_single) {
need_scroller = true;
}
@ -426,14 +441,14 @@ void vertical_scroller(Monitor *m) {
target_geom.y = m->w.y + (m->w.height - target_geom.height) / 2;
} else if (need_apply_overspread) {
if (over_overspread_to_up) {
target_geom.y = m->w.y + scroller_structs;
target_geom.y = m->w.y + config.scroller_structs;
} else {
target_geom.y =
m->w.y +
(m->w.height -
tempClients[focus_client_index]->scroller_proportion *
max_client_height -
scroller_structs);
config.scroller_structs);
}
} else {
target_geom.y = root_client->geom.y > m->w.y + (m->w.height) / 2
@ -441,8 +456,8 @@ void vertical_scroller(Monitor *m) {
tempClients[focus_client_index]
->scroller_proportion *
max_client_height -
scroller_structs)
: m->w.y + scroller_structs;
config.scroller_structs)
: m->w.y + config.scroller_structs;
}
vertical_check_scroller_root_inside_mon(tempClients[focus_client_index],
&target_geom);
@ -486,9 +501,9 @@ void vertical_grid(Monitor *m) {
int32_t rows, cols, overrows;
Client *c = NULL;
int32_t target_gappo =
enablegaps ? m->isoverview ? overviewgappo : gappov : 0;
enablegaps ? m->isoverview ? config.overviewgappo : config.gappov : 0;
int32_t target_gappi =
enablegaps ? m->isoverview ? overviewgappi : gappiv : 0;
enablegaps ? m->isoverview ? config.overviewgappi : config.gappiv : 0;
float single_width_ratio = m->isoverview ? 0.7 : 0.9;
float single_height_ratio = m->isoverview ? 0.8 : 0.9;

View file

@ -910,13 +910,19 @@ static struct wl_event_source *keep_idle_inhibit_source;
static bool cursor_hidden = false;
static bool tag_combo = false;
static const char *cli_config_path = NULL;
static bool cli_debug_log = false;
static KeyMode keymode = {
.mode = {'d', 'e', 'f', 'a', 'u', 'l', 't', '\0'},
.isdefault = true,
};
static char *env_vars[] = {"DISPLAY", "WAYLAND_DISPLAY", "XDG_CURRENT_DESKTOP",
"XDG_SESSION_TYPE", NULL};
static char *env_vars[] = {"DISPLAY",
"WAYLAND_DISPLAY",
"XDG_CURRENT_DESKTOP",
"XDG_SESSION_TYPE",
"XCURSOR_THEME",
"XCURSOR_SIZE",
NULL};
static struct {
enum wp_cursor_shape_device_v1_shape shape;
struct wlr_surface *surface;
@ -937,6 +943,8 @@ struct Pertag {
*ltidxs[LENGTH(tags) + 1]; /* matrix of tags and layouts indexes */
};
#include "config/parse_config.h"
static struct wl_signal mango_print_status;
static struct wl_listener print_status_listener = {.notify =
@ -999,7 +1007,6 @@ static struct wl_event_source *sync_keymap;
#include "animation/common.h"
#include "animation/layer.h"
#include "animation/tag.h"
#include "config/parse_config.h"
#include "dispatch/bind_define.h"
#include "ext-protocol/all.h"
#include "fetch/fetch.h"
@ -1064,7 +1071,7 @@ void show_scratchpad(Client *c) {
if (c->isfullscreen || c->ismaximizescreen) {
c->isfullscreen = 0; // 清除窗口全屏标志
c->ismaximizescreen = 0;
c->bw = c->isnoborder ? 0 : borderpx;
c->bw = c->isnoborder ? 0 : config.borderpx;
}
/* return if fullscreen */
@ -1072,10 +1079,10 @@ void show_scratchpad(Client *c) {
setfloating(c, 1);
c->geom.width = c->iscustomsize
? c->float_geom.width
: c->mon->w.width * scratchpad_width_ratio;
c->geom.height = c->iscustomsize
? c->float_geom.height
: c->mon->w.height * scratchpad_height_ratio;
: c->mon->w.width * config.scratchpad_width_ratio;
c->geom.height =
c->iscustomsize ? c->float_geom.height
: c->mon->w.height * config.scratchpad_height_ratio;
// 重新计算居中的坐标
c->float_geom = c->geom = c->animainit_geom = c->animation.current =
setclient_coordinate_center(c, c->mon, c->geom, 0, 0);
@ -1143,7 +1150,7 @@ void swallow(Client *c, Client *w) {
bool switch_scratchpad_client_state(Client *c) {
if (scratchpad_cross_monitor && selmon && c->mon != selmon &&
if (config.scratchpad_cross_monitor && selmon && c->mon != selmon &&
c->is_in_scratchpad) {
// 保存原始monitor用于尺寸计算
Monitor *oldmon = c->mon;
@ -1197,12 +1204,12 @@ void apply_named_scratchpad(Client *target_client) {
Client *c = NULL;
wl_list_for_each(c, &clients, link) {
if (!scratchpad_cross_monitor && c->mon != selmon) {
if (!config.scratchpad_cross_monitor && c->mon != selmon) {
continue;
}
if (single_scratchpad && c->is_in_scratchpad && c->is_scratchpad_show &&
c != target_client) {
if (config.single_scratchpad && c->is_in_scratchpad &&
c->is_scratchpad_show && c != target_client) {
set_minimized(c);
}
}
@ -1263,30 +1270,30 @@ void toggle_hotarea(int32_t x_root, int32_t y_root) {
// 根据热角位置计算不同的热区坐标
unsigned hx, hy;
switch (hotarea_corner) {
switch (config.hotarea_corner) {
case BOTTOM_RIGHT: // 右下角
hx = selmon->m.x + selmon->m.width - hotarea_size;
hy = selmon->m.y + selmon->m.height - hotarea_size;
hx = selmon->m.x + selmon->m.width - config.hotarea_size;
hy = selmon->m.y + selmon->m.height - config.hotarea_size;
break;
case TOP_LEFT: // 左上角
hx = selmon->m.x + hotarea_size;
hy = selmon->m.y + hotarea_size;
hx = selmon->m.x + config.hotarea_size;
hy = selmon->m.y + config.hotarea_size;
break;
case TOP_RIGHT: // 右上角
hx = selmon->m.x + selmon->m.width - hotarea_size;
hy = selmon->m.y + hotarea_size;
hx = selmon->m.x + selmon->m.width - config.hotarea_size;
hy = selmon->m.y + config.hotarea_size;
break;
case BOTTOM_LEFT: // 左下角(默认)
default:
hx = selmon->m.x + hotarea_size;
hy = selmon->m.y + selmon->m.height - hotarea_size;
hx = selmon->m.x + config.hotarea_size;
hy = selmon->m.y + selmon->m.height - config.hotarea_size;
break;
}
// 判断鼠标是否在热区内
int in_hotarea = 0;
switch (hotarea_corner) {
switch (config.hotarea_corner) {
case BOTTOM_RIGHT: // 右下角
in_hotarea = (y_root > hy && x_root > hx &&
x_root <= (selmon->m.x + selmon->m.width) &&
@ -1308,10 +1315,11 @@ void toggle_hotarea(int32_t x_root, int32_t y_root) {
break;
}
if (enable_hotarea == 1 && selmon->is_in_hotarea == 0 && in_hotarea) {
if (config.enable_hotarea == 1 && selmon->is_in_hotarea == 0 &&
in_hotarea) {
toggleoverview(&arg);
selmon->is_in_hotarea = 1;
} else if (enable_hotarea == 1 && selmon->is_in_hotarea == 1 &&
} else if (config.enable_hotarea == 1 && selmon->is_in_hotarea == 1 &&
!in_hotarea) {
selmon->is_in_hotarea = 0;
}
@ -1604,7 +1612,7 @@ void apply_window_snap(Client *c) {
int32_t snap_up_mon = 0, snap_down_mon = 0, snap_left_mon = 0,
snap_right_mon = 0;
uint32_t cbw = !render_border || c->fake_no_border ? borderpx : 0;
uint32_t cbw = !render_border || c->fake_no_border ? config.borderpx : 0;
uint32_t tcbw;
uint32_t cx, cy, cw, ch, tcx, tcy, tcw, tch;
cx = c->geom.x + cbw;
@ -1616,14 +1624,14 @@ void apply_window_snap(Client *c) {
if (!c || !c->mon || !client_surface(c)->mapped || c->iskilling)
return;
if (!c->isfloating || !enable_floating_snap)
if (!c->isfloating || !config.enable_floating_snap)
return;
wl_list_for_each(tc, &clients, link) {
if (tc && tc->isfloating && !tc->iskilling &&
client_surface(tc)->mapped && VISIBLEON(tc, c->mon)) {
tcbw = !render_border || tc->fake_no_border ? borderpx : 0;
tcbw = !render_border || tc->fake_no_border ? config.borderpx : 0;
tcx = tc->geom.x + tcbw;
tcy = tc->geom.y + tcbw;
tcw = tc->geom.width - 2 * tcbw;
@ -1677,19 +1685,19 @@ void apply_window_snap(Client *c) {
if (snap_right_screen >= 0 && snap_right_screen < snap_right)
snap_right = snap_right_screen;
if (snap_left < snap_right && snap_left < snap_distance) {
if (snap_left < snap_right && snap_left < config.snap_distance) {
c->geom.x = c->geom.x - snap_left;
}
if (snap_right <= snap_left && snap_right < snap_distance) {
if (snap_right <= snap_left && snap_right < config.snap_distance) {
c->geom.x = c->geom.x + snap_right;
}
if (snap_up < snap_down && snap_up < snap_distance) {
if (snap_up < snap_down && snap_up < config.snap_distance) {
c->geom.y = c->geom.y - snap_up;
}
if (snap_down <= snap_up && snap_down < snap_distance) {
if (snap_down <= snap_up && snap_down < config.snap_distance) {
c->geom.y = c->geom.y + snap_down;
}
@ -1819,7 +1827,8 @@ axisnotify(struct wl_listener *listener, void *data) {
a = &config.axis_bindings[ji];
if (CLEANMASK(mods) == CLEANMASK(a->mod) && // 按键一致
adir == a->dir && a->func) { // 滚轮方向判断一致且处理函数存在
if (event->time_msec - axis_apply_time > axis_bind_apply_timeout ||
if (event->time_msec - axis_apply_time >
config.axis_bind_apply_timeout ||
axis_apply_dir * event->delta < 0) {
a->func(&a->arg);
axis_apply_time = event->time_msec;
@ -1839,9 +1848,10 @@ axisnotify(struct wl_listener *listener, void *data) {
/* Notify the client with pointer focus of the axis event. */
wlr_seat_pointer_notify_axis(
seat, // 滚轮事件发送给客户端也就是窗口
event->time_msec, event->orientation, event->delta * axis_scroll_factor,
roundf(event->delta_discrete * axis_scroll_factor), event->source,
event->relative_direction);
event->time_msec, event->orientation,
event->delta * config.axis_scroll_factor,
roundf(event->delta_discrete * config.axis_scroll_factor),
event->source, event->relative_direction);
}
int32_t ongesture(struct wlr_pointer_swipe_end_event *event) {
@ -1859,7 +1869,8 @@ int32_t ongesture(struct wlr_pointer_swipe_end_event *event) {
}
// Require absolute distance movement beyond a small thresh-hold
if (adx * adx + ady * ady < swipe_min_threshold * swipe_min_threshold) {
if (adx * adx + ady * ady <
config.swipe_min_threshold * config.swipe_min_threshold) {
return handled;
}
@ -1996,7 +2007,7 @@ void place_drag_tile_client(Client *c) {
bool check_trackpad_disabled(struct wlr_pointer *pointer) {
struct libinput_device *device;
if (!disable_trackpad)
if (!config.disable_trackpad)
return false;
if (wlr_input_device_is_libinput(&pointer->base) &&
@ -2122,7 +2133,7 @@ bool handle_buttonpress(struct wlr_pointer_button_event *event) {
grabc = NULL;
start_drag_window = false;
last_apply_drap_time = 0;
if (tmpc->drag_to_tile && drag_tile_to_tile) {
if (tmpc->drag_to_tile && config.drag_tile_to_tile) {
place_drag_tile_client(tmpc);
} else {
apply_window_snap(tmpc);
@ -2153,7 +2164,7 @@ void checkidleinhibitor(struct wlr_surface *exclude) {
toplevel_from_wlr_surface(inhibitor->surface, &c, NULL);
if (idleinhibit_ignore_visible) {
if (config.idleinhibit_ignore_visible) {
inhibited = 1;
break;
}
@ -2351,7 +2362,7 @@ static void iter_layer_scene_buffers(struct wlr_scene_buffer *buffer,
wlr_scene_buffer_set_backdrop_blur(buffer, true);
wlr_scene_buffer_set_backdrop_blur_ignore_transparent(buffer, true);
if (blur_optimized) {
if (config.blur_optimized) {
wlr_scene_buffer_set_backdrop_blur_optimized(buffer, true);
} else {
wlr_scene_buffer_set_backdrop_blur_optimized(buffer, false);
@ -2359,7 +2370,7 @@ static void iter_layer_scene_buffers(struct wlr_scene_buffer *buffer,
}
void layer_flush_blur_background(LayerSurface *l) {
if (!blur)
if (!config.blur)
return;
// 如果背景层发生变化,标记优化的模糊背景缓存需要更新
@ -2415,15 +2426,16 @@ void maplayersurfacenotify(struct wl_listener *listener, void *data) {
if (layer_surface->current.exclusive_zone == 0 &&
layer_surface->current.layer != ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM &&
layer_surface->current.layer != ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND) {
l->shadow = wlr_scene_shadow_create(l->scene, 0, 0, border_radius,
shadows_blur, shadowscolor);
l->shadow =
wlr_scene_shadow_create(l->scene, 0, 0, config.border_radius,
config.shadows_blur, config.shadowscolor);
wlr_scene_node_lower_to_bottom(&l->shadow->node);
wlr_scene_node_set_enabled(&l->shadow->node, true);
}
// 初始化动画
if (animations && layer_animations && !l->noanim) {
l->animation.duration = animation_duration_open;
if (config.animations && config.layer_animations && !l->noanim) {
l->animation.duration = config.animation_duration_open;
l->animation.action = OPEN;
layer_set_pending_state(l);
}
@ -2469,7 +2481,8 @@ void commitlayersurfacenotify(struct wl_listener *listener, void *data) {
get_layer_target_geometry(l, &box);
if (animations && layer_animations && !l->noanim && l->mapped &&
if (config.animations && config.layer_animations && !l->noanim &&
l->mapped &&
layer_surface->current.layer != ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM &&
layer_surface->current.layer != ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND &&
!wlr_box_equal(&box, &l->geom)) {
@ -2479,13 +2492,12 @@ void commitlayersurfacenotify(struct wl_listener *listener, void *data) {
l->geom.width = box.width;
l->geom.height = box.height;
l->animation.action = MOVE;
l->animation.duration = animation_duration_move;
l->animation.duration = config.animation_duration_move;
l->need_output_flush = true;
layer_set_pending_state(l);
}
if (blur && blur_layer) {
// 设置非背景layer模糊
if (config.blur && config.blur_layer) {
if (!l->noblur &&
layer_surface->current.layer != ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM &&
@ -2763,22 +2775,21 @@ KeyboardGroup *createkeyboardgroup(void) {
group->wlr_group = wlr_keyboard_group_create();
group->wlr_group->data = group;
/* Prepare an XKB keymap and assign it to the keyboard group. */
context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
if (!(keymap = xkb_keymap_new_from_names(context, &xkb_rules,
if (!(keymap = xkb_keymap_new_from_names(context, &config.xkb_rules,
XKB_KEYMAP_COMPILE_NO_FLAGS)))
die("failed to compile keymap");
wlr_keyboard_set_keymap(&group->wlr_group->keyboard, keymap);
if (numlockon) {
if (config.numlockon) {
xkb_mod_index_t mod_index =
xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_NUM);
if (mod_index != XKB_MOD_INVALID)
locked_mods |= (uint32_t)1 << mod_index;
}
if (capslock) {
if (config.capslock) {
xkb_mod_index_t mod_index =
xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CAPS);
if (mod_index != XKB_MOD_INVALID)
@ -2792,8 +2803,8 @@ KeyboardGroup *createkeyboardgroup(void) {
xkb_keymap_unref(keymap);
xkb_context_unref(context);
wlr_keyboard_set_repeat_info(&group->wlr_group->keyboard, repeat_rate,
repeat_delay);
wlr_keyboard_set_repeat_info(&group->wlr_group->keyboard,
config.repeat_rate, config.repeat_delay);
/* Set up listeners for keyboard events */
LISTEN(&group->wlr_group->keyboard.events.key, &group->key, keypress);
@ -2983,11 +2994,10 @@ void createmon(struct wl_listener *listener, void *data) {
for (i = 0; i < LENGTH(m->layers); i++)
wl_list_init(&m->layers[i]);
/* Initialize monitor state using configured rules */
m->gappih = gappih;
m->gappiv = gappiv;
m->gappoh = gappoh;
m->gappov = gappov;
m->gappih = config.gappih;
m->gappiv = config.gappiv;
m->gappoh = config.gappoh;
m->gappov = config.gappov;
m->isoverview = 0;
m->sel = NULL;
m->is_in_hotarea = 0;
@ -3049,8 +3059,8 @@ void createmon(struct wl_listener *listener, void *data) {
}
for (i = 0; i <= LENGTH(tags); i++) {
m->pertag->nmasters[i] = default_nmaster;
m->pertag->mfacts[i] = default_mfact;
m->pertag->nmasters[i] = config.default_nmaster;
m->pertag->mfacts[i] = config.default_mfact;
m->pertag->ltidxs[i] = &layouts[0];
}
@ -3078,12 +3088,11 @@ void createmon(struct wl_listener *listener, void *data) {
else
wlr_output_layout_add(output_layout, wlr_output, m->m.x, m->m.y);
if (blur) {
if (config.blur) {
m->blur = wlr_scene_optimized_blur_create(&scene->tree, 0, 0);
wlr_scene_node_set_position(&m->blur->node, m->m.x, m->m.y);
wlr_scene_node_reparent(&m->blur->node, layers[LyrBlur]);
wlr_scene_optimized_blur_set_size(m->blur, m->m.width, m->m.height);
// wlr_scene_node_set_enabled(&m->blur->node, 1);
}
m->ext_group = wlr_ext_workspace_group_handle_v1_create(
ext_manager, EXT_WORKSPACE_ENABLE_CAPS);
@ -3109,7 +3118,7 @@ createnotify(struct wl_listener *listener, void *data) {
/* Allocate a Client for this surface */
c = toplevel->base->data = ecalloc(1, sizeof(*c));
c->surface.xdg = toplevel->base;
c->bw = borderpx;
c->bw = config.borderpx;
LISTEN(&toplevel->base->surface->events.commit, &c->commit, commitnotify);
LISTEN(&toplevel->base->surface->events.map, &c->map, mapnotify);
@ -3155,44 +3164,49 @@ void destroyinputdevice(struct wl_listener *listener, void *data) {
void configure_pointer(struct libinput_device *device) {
if (libinput_device_config_tap_get_finger_count(device)) {
libinput_device_config_tap_set_enabled(device, tap_to_click);
libinput_device_config_tap_set_drag_enabled(device, tap_and_drag);
libinput_device_config_tap_set_drag_lock_enabled(device, drag_lock);
libinput_device_config_tap_set_button_map(device, button_map);
libinput_device_config_tap_set_enabled(device, config.tap_to_click);
libinput_device_config_tap_set_drag_enabled(device,
config.tap_and_drag);
libinput_device_config_tap_set_drag_lock_enabled(device,
config.drag_lock);
libinput_device_config_tap_set_button_map(device, config.button_map);
libinput_device_config_scroll_set_natural_scroll_enabled(
device, trackpad_natural_scrolling);
device, config.trackpad_natural_scrolling);
} else {
libinput_device_config_scroll_set_natural_scroll_enabled(
device, mouse_natural_scrolling);
device, config.mouse_natural_scrolling);
}
if (libinput_device_config_dwt_is_available(device))
libinput_device_config_dwt_set_enabled(device, disable_while_typing);
libinput_device_config_dwt_set_enabled(device,
config.disable_while_typing);
if (libinput_device_config_left_handed_is_available(device))
libinput_device_config_left_handed_set(device, left_handed);
libinput_device_config_left_handed_set(device, config.left_handed);
if (libinput_device_config_middle_emulation_is_available(device))
libinput_device_config_middle_emulation_set_enabled(
device, middle_button_emulation);
device, config.middle_button_emulation);
if (libinput_device_config_scroll_get_methods(device) !=
LIBINPUT_CONFIG_SCROLL_NO_SCROLL)
libinput_device_config_scroll_set_method(device, scroll_method);
libinput_device_config_scroll_set_method(device, config.scroll_method);
if (libinput_device_config_scroll_get_methods(device) ==
LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN)
libinput_device_config_scroll_set_button(device, scroll_button);
libinput_device_config_scroll_set_button(device, config.scroll_button);
if (libinput_device_config_click_get_methods(device) !=
LIBINPUT_CONFIG_CLICK_METHOD_NONE)
libinput_device_config_click_set_method(device, click_method);
libinput_device_config_click_set_method(device, config.click_method);
if (libinput_device_config_send_events_get_modes(device))
libinput_device_config_send_events_set_mode(device, send_events_mode);
libinput_device_config_send_events_set_mode(device,
config.send_events_mode);
if (accel_profile && libinput_device_config_accel_is_available(device)) {
libinput_device_config_accel_set_profile(device, accel_profile);
libinput_device_config_accel_set_speed(device, accel_speed);
if (config.accel_profile &&
libinput_device_config_accel_is_available(device)) {
libinput_device_config_accel_set_profile(device, config.accel_profile);
libinput_device_config_accel_set_speed(device, config.accel_speed);
} else {
// profile cannot be directly applied to 0, need to set to 1 first
libinput_device_config_accel_set_profile(device, 1);
@ -3850,7 +3864,7 @@ void keypress(struct wl_listener *listener, void *data) {
wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
// ov tab mode detect moe key release
if (ov_tab_mode && !locked && group == kb_group &&
if (config.ov_tab_mode && !locked && group == kb_group &&
event->state == WL_KEYBOARD_KEY_STATE_RELEASED &&
(keycode == 133 || keycode == 37 || keycode == 64 || keycode == 50 ||
keycode == 134 || keycode == 105 || keycode == 108 || keycode == 62) &&
@ -3934,7 +3948,7 @@ void pending_kill_client(Client *c) {
void locksession(struct wl_listener *listener, void *data) {
struct wlr_session_lock_v1 *session_lock = data;
SessionLock *lock;
if (!allow_lock_transparent) {
if (!config.allow_lock_transparent) {
wlr_scene_node_set_enabled(&locked_bg->node, true);
}
if (cur_lock) {
@ -3971,10 +3985,10 @@ static void iter_xdg_scene_buffers(struct wlr_scene_buffer *buffer, int32_t sx,
if (wlr_subsurface_try_from_wlr_surface(surface) != NULL)
return;
if (blur && c && !c->noblur) {
if (config.blur && c && !c->noblur) {
wlr_scene_buffer_set_backdrop_blur(buffer, true);
wlr_scene_buffer_set_backdrop_blur_ignore_transparent(buffer, false);
if (blur_optimized) {
if (config.blur_optimized) {
wlr_scene_buffer_set_backdrop_blur_optimized(buffer, true);
} else {
wlr_scene_buffer_set_backdrop_blur_optimized(buffer, false);
@ -4021,13 +4035,13 @@ void init_client_properties(Client *c) {
c->is_restoring_from_ov = 0;
c->isurgent = 0;
c->need_output_flush = 0;
c->scroller_proportion = scroller_default_proportion;
c->scroller_proportion = config.scroller_default_proportion;
c->is_pending_open_animation = true;
c->drag_to_tile = false;
c->scratchpad_switching_mon = false;
c->fake_no_border = false;
c->focused_opacity = focused_opacity;
c->unfocused_opacity = unfocused_opacity;
c->focused_opacity = config.focused_opacity;
c->unfocused_opacity = config.unfocused_opacity;
c->nofocus = 0;
c->nofadein = 0;
c->nofadeout = 0;
@ -4062,9 +4076,9 @@ void init_client_properties(Client *c) {
c->next_in_stack = NULL;
c->prev_in_stack = NULL;
memset(c->oldmonname, 0, sizeof(c->oldmonname));
memcpy(c->opacity_animation.initial_border_color, bordercolor,
memcpy(c->opacity_animation.initial_border_color, config.bordercolor,
sizeof(c->opacity_animation.initial_border_color));
memcpy(c->opacity_animation.current_border_color, bordercolor,
memcpy(c->opacity_animation.current_border_color, config.bordercolor,
sizeof(c->opacity_animation.current_border_color));
c->opacity_animation.initial_opacity = c->unfocused_opacity;
c->opacity_animation.current_opacity = c->unfocused_opacity;
@ -4094,7 +4108,7 @@ mapnotify(struct wl_listener *listener, void *data) {
c->bw = 0;
c->isnoborder = 1;
} else {
c->bw = borderpx;
c->bw = config.borderpx;
}
if (client_should_global(c)) {
@ -4126,21 +4140,22 @@ mapnotify(struct wl_listener *listener, void *data) {
}
// extra node
c->border = wlr_scene_rect_create(c->scene, 0, 0,
c->isurgent ? urgentcolor : bordercolor);
c->border = wlr_scene_rect_create(
c->scene, 0, 0, c->isurgent ? config.urgentcolor : config.bordercolor);
wlr_scene_node_lower_to_bottom(&c->border->node);
wlr_scene_node_set_position(&c->border->node, 0, 0);
wlr_scene_rect_set_corner_radius(c->border, border_radius,
border_radius_location_default);
wlr_scene_rect_set_corner_radius(c->border, config.border_radius,
config.border_radius_location_default);
wlr_scene_node_set_enabled(&c->border->node, true);
c->shadow = wlr_scene_shadow_create(c->scene, 0, 0, border_radius,
shadows_blur, shadowscolor);
c->shadow =
wlr_scene_shadow_create(c->scene, 0, 0, config.border_radius,
config.shadows_blur, config.shadowscolor);
wlr_scene_node_lower_to_bottom(&c->shadow->node);
wlr_scene_node_set_enabled(&c->shadow->node, true);
if (new_is_master && selmon && !is_scroller_layout(selmon))
if (config.new_is_master && selmon && !is_scroller_layout(selmon))
// tile at the top
wl_list_insert(&clients, &c->link); // 新窗口是master,头部入栈
else if (selmon && is_scroller_layout(selmon) &&
@ -4353,7 +4368,7 @@ void motionnotify(uint32_t time, struct wlr_input_device *device, double dx,
wlr_idle_notifier_v1_notify_activity(idle_notifier, seat);
/* Update selmon (even while dragging a window) */
if (sloppyfocus)
if (config.sloppyfocus)
selmon = xytomon(cursor->x, cursor->y);
}
@ -4389,7 +4404,8 @@ void motionnotify(uint32_t time, struct wlr_input_device *device, double dx,
if (grabc->isfloating) {
grabc->iscustomsize = 1;
if (last_apply_drap_time == 0 ||
time - last_apply_drap_time > drag_floating_refresh_interval) {
time - last_apply_drap_time >
config.drag_floating_refresh_interval) {
resize_floating_window(grabc);
last_apply_drap_time = time;
}
@ -4415,7 +4431,7 @@ void motionnotify(uint32_t time, struct wlr_input_device *device, double dx,
should_lock = true;
}
if (!(!edge_scroller_pointer_focus && c && c->mon &&
if (!(!config.edge_scroller_pointer_focus && c && c->mon &&
is_scroller_layout(c->mon) && !INSIDEMON(c)))
pointerfocus(c, surface, sx, sy, time);
@ -4521,7 +4537,7 @@ void pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy,
uint32_t time) {
struct timespec now;
if (sloppyfocus && !start_drag_window && c && time && c->scene &&
if (config.sloppyfocus && !start_drag_window && c && time && c->scene &&
c->scene->node.enabled && !c->animation.tagining &&
(surface != seat->pointer_state.focused_surface) &&
!client_is_unmanaged(c) && VISIBLEON(c, c->mon))
@ -4647,7 +4663,7 @@ void rendermon(struct wl_listener *listener, void *data) {
// 绘制客户端
wl_list_for_each(c, &clients, link) {
need_more_frames = client_draw_frame(c) || need_more_frames;
if (!animations && !grabc && c->configure_serial &&
if (!config.animations && !grabc && c->configure_serial &&
client_is_rendered_on_mon(c, m)) {
monitor_check_skip_frame_timeout(m);
goto skip;
@ -4659,7 +4675,7 @@ void rendermon(struct wl_listener *listener, void *data) {
}
// 只有在需要帧时才构建和提交状态
if (allow_tearing && frame_allow_tearing) {
if (config.allow_tearing && frame_allow_tearing) {
apply_tear_state(m);
} else {
wlr_scene_output_commit(m->scene_output, NULL);
@ -4735,7 +4751,7 @@ void exchange_two_client(Client *c1, Client *c2) {
float stack_proportion = 0.0f;
if (c1 == NULL || c2 == NULL ||
(!exchange_cross_monitor && c1->mon != c2->mon)) {
(!config.exchange_cross_monitor && c1->mon != c2->mon)) {
return;
}
@ -4837,7 +4853,7 @@ void exchange_two_client(Client *c1, Client *c2) {
}
// 处理跨监视器交换
if (exchange_cross_monitor) {
if (config.exchange_cross_monitor) {
tmp_mon = c2->mon;
tmp_tags = c2->tags;
setmon(c2, c1->mon, c1->tags, false);
@ -5017,7 +5033,7 @@ setfloating(Client *c, int32_t floating) {
if (c->isfullscreen || c->ismaximizescreen) {
c->isfullscreen = 0; // 清除窗口全屏标志
c->ismaximizescreen = 0;
c->bw = c->isnoborder ? 0 : borderpx;
c->bw = c->isnoborder ? 0 : config.borderpx;
}
exit_scroller_stack(c);
@ -5031,11 +5047,13 @@ setfloating(Client *c, int32_t floating) {
// restore to the memeroy geom
if (c->float_geom.width > 0 && c->float_geom.height > 0) {
if (c->mon && c->float_geom.width >= c->mon->w.width - gappoh) {
if (c->mon &&
c->float_geom.width >= c->mon->w.width - config.gappoh) {
c->float_geom.width = c->mon->w.width * 0.9;
window_size_outofrange = true;
}
if (c->mon && c->float_geom.height >= c->mon->w.height - gappov) {
if (c->mon &&
c->float_geom.height >= c->mon->w.height - config.gappov) {
c->float_geom.height = c->mon->w.height * 0.9;
window_size_outofrange = true;
}
@ -5097,10 +5115,10 @@ setfloating(Client *c, int32_t floating) {
}
void reset_maximizescreen_size(Client *c) {
c->geom.x = c->mon->w.x + gappoh;
c->geom.y = c->mon->w.y + gappov;
c->geom.width = c->mon->w.width - 2 * gappoh;
c->geom.height = c->mon->w.height - 2 * gappov;
c->geom.x = c->mon->w.x + config.gappoh;
c->geom.y = c->mon->w.y + config.gappov;
c->geom.width = c->mon->w.width - 2 * config.gappoh;
c->geom.height = c->mon->w.height - 2 * config.gappov;
resize(c, c->geom, 0);
}
@ -5146,16 +5164,16 @@ void setmaximizescreen(Client *c, int32_t maximizescreen) {
if (c->isfloating)
c->float_geom = c->geom;
maximizescreen_box.x = c->mon->w.x + gappoh;
maximizescreen_box.y = c->mon->w.y + gappov;
maximizescreen_box.width = c->mon->w.width - 2 * gappoh;
maximizescreen_box.height = c->mon->w.height - 2 * gappov;
wlr_scene_node_raise_to_top(&c->scene->node); // 将视图提升到顶层
maximizescreen_box.x = c->mon->w.x + config.gappoh;
maximizescreen_box.y = c->mon->w.y + config.gappov;
maximizescreen_box.width = c->mon->w.width - 2 * config.gappoh;
maximizescreen_box.height = c->mon->w.height - 2 * config.gappov;
wlr_scene_node_raise_to_top(&c->scene->node);
if (!is_scroller_layout(c->mon) || c->isfloating)
resize(c, maximizescreen_box, 0);
c->ismaximizescreen = 1;
} else {
c->bw = c->isnoborder ? 0 : borderpx;
c->bw = c->isnoborder ? 0 : config.borderpx;
c->ismaximizescreen = 0;
if (c->isfloating)
setfloating(c, 1);
@ -5222,7 +5240,7 @@ void setfullscreen(Client *c, int32_t fullscreen) // 用自定义全屏代理自
resize(c, c->mon->m, 1);
c->isfullscreen = 1;
} else {
c->bw = c->isnoborder ? 0 : borderpx;
c->bw = c->isnoborder ? 0 : config.borderpx;
c->isfullscreen = 0;
if (c->isfloating)
setfloating(c, 1);
@ -5285,9 +5303,8 @@ void reset_keyboard_layout(void) {
return;
}
// 现在安全地创建真正的keymap
struct xkb_keymap *new_keymap = xkb_keymap_new_from_names(
context, &xkb_rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
context, &config.xkb_rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
if (!new_keymap) {
// 理论上这里不应该失败,因为前面已经验证过了
wlr_log(WLR_ERROR,
@ -5466,10 +5483,13 @@ void handle_print_status(struct wl_listener *listener, void *data) {
void setup(void) {
setenv("XCURSOR_SIZE", "24", 1);
setenv("XDG_CURRENT_DESKTOP", "mango", 1);
setenv("_JAVA_AWT_WM_NONREPARENTING", "1", 1);
parse_config();
if (cli_debug_log) {
config.log_level = WLR_DEBUG;
}
init_baked_points();
int32_t drm_fd, i, sig[] = {SIGCHLD, SIGINT, SIGTERM, SIGPIPE};
@ -5479,7 +5499,7 @@ void setup(void) {
for (i = 0; i < LENGTH(sig); i++)
sigaction(sig[i], &sa, NULL);
wlr_log_init(log_level, NULL);
wlr_log_init(config.log_level, NULL);
/* The Wayland display is managed by libwayland. It handles accepting
* clients from the Unix socket, manging Wayland globals, and so on. */
@ -5515,7 +5535,7 @@ void setup(void) {
/* Initialize the scene graph used to lay out windows */
scene = wlr_scene_create();
root_bg = wlr_scene_rect_create(&scene->tree, 0, 0, rootcolor);
root_bg = wlr_scene_rect_create(&scene->tree, 0, 0, config.rootcolor);
for (i = 0; i < NUM_LAYERS; i++)
layers[i] = wlr_scene_tree_create(&scene->tree);
drag_icon = wlr_scene_tree_create(&scene->tree);
@ -5540,7 +5560,7 @@ void setup(void) {
scene, wlr_linux_dmabuf_v1_create_with_renderer(dpy, 4, drw));
}
if (syncobj_enable && (drm_fd = wlr_renderer_get_drm_fd(drw)) >= 0 &&
if (config.syncobj_enable && (drm_fd = wlr_renderer_get_drm_fd(drw)) >= 0 &&
drw->features.timeline && backend->features.timeline)
wlr_linux_drm_syncobj_manager_v1_create(dpy, 1, drm_fd);
@ -5659,9 +5679,11 @@ void setup(void) {
* cursor images are available at all scale factors on the screen
* (necessary for HiDPI support). Scaled cursors will be loaded with
* each output. */
// cursor_mgr = wlr_xcursor_manager_create(cursor_theme, 24);
cursor_mgr = wlr_xcursor_manager_create(config.cursor_theme, cursor_size);
set_xcursor_env();
cursor_mgr =
wlr_xcursor_manager_create(config.cursor_theme, config.cursor_size);
/*
* wlr_cursor *only* displays an image on screen. It does not move
* around when the pointer moves. However, we can attach input devices
@ -5739,10 +5761,10 @@ void setup(void) {
wl_signal_add(&output_mgr->events.apply, &output_mgr_apply);
wl_signal_add(&output_mgr->events.test, &output_mgr_test);
// blur
wlr_scene_set_blur_data(scene, blur_params.num_passes, blur_params.radius,
blur_params.noise, blur_params.brightness,
blur_params.contrast, blur_params.saturation);
wlr_scene_set_blur_data(
scene, config.blur_params.num_passes, config.blur_params.radius,
config.blur_params.noise, config.blur_params.brightness,
config.blur_params.contrast, config.blur_params.saturation);
/* create text_input-, and input_method-protocol relevant globals */
input_method_manager = wlr_input_method_manager_v2_create(dpy);
@ -5775,7 +5797,8 @@ void setup(void) {
* Initialise the XWayland X server.
* It will be started when the first X client is started.
*/
xwayland = wlr_xwayland_create(dpy, compositor, !xwayland_persistence);
xwayland =
wlr_xwayland_create(dpy, compositor, !config.xwayland_persistence);
if (xwayland) {
wl_signal_add(&xwayland->events.ready, &xwayland_ready);
wl_signal_add(&xwayland->events.new_surface, &new_xwayland_surface);
@ -5860,7 +5883,7 @@ void overview_backup(Client *c) {
c->isfullscreen = 0; // 清除窗口全屏标志
c->ismaximizescreen = 0;
}
c->bw = c->isnoborder ? 0 : borderpx;
c->bw = c->isnoborder ? 0 : config.borderpx;
client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT |
WLR_EDGE_RIGHT);
@ -5901,7 +5924,7 @@ void overview_restore(Client *c, const Arg *arg) {
if (c->bw == 0 &&
!c->isfullscreen) { // 如果是在ov模式中创建的窗口,没有bw记录
c->bw = c->isnoborder ? 0 : borderpx;
c->bw = c->isnoborder ? 0 : config.borderpx;
}
if (c->isfloating && !c->force_tiled_state) {
@ -5911,7 +5934,7 @@ void overview_restore(Client *c, const Arg *arg) {
void handlecursoractivity(void) {
wl_event_source_timer_update(hide_cursor_source,
cursor_hide_timeout * 1000);
config.cursor_hide_timeout * 1000);
if (!cursor_hidden)
return;
@ -6002,7 +6025,7 @@ void unmapnotify(struct wl_listener *listener, void *data) {
Client *prev_in_stack = c->prev_in_stack;
c->iskilling = 1;
if (animations && !c->is_clip_to_hide && !c->isminimized &&
if (config.animations && !c->is_clip_to_hide && !c->isminimized &&
(!c->mon || VISIBLEON(c, c->mon)))
init_fadeout_client(c);
@ -6103,7 +6126,7 @@ void updatemons(struct wl_listener *listener, void *data) {
* positions, focus, and the stored configuration in wlroots'
* output-manager implementation.
*/
struct wlr_output_configuration_v1 *config =
struct wlr_output_configuration_v1 *output_config =
wlr_output_configuration_v1_create();
Client *c = NULL;
struct wlr_output_configuration_head_v1 *config_head;
@ -6114,8 +6137,8 @@ void updatemons(struct wl_listener *listener, void *data) {
wl_list_for_each(m, &mons, link) {
if (m->wlr_output->enabled || m->asleep)
continue;
config_head =
wlr_output_configuration_head_v1_create(config, m->wlr_output);
config_head = wlr_output_configuration_head_v1_create(output_config,
m->wlr_output);
config_head->state.enabled = 0;
/* Remove this output from the layout to avoid cursor enter inside
* it */
@ -6143,8 +6166,8 @@ void updatemons(struct wl_listener *listener, void *data) {
wl_list_for_each(m, &mons, link) {
if (!m->wlr_output->enabled)
continue;
config_head =
wlr_output_configuration_head_v1_create(config, m->wlr_output);
config_head = wlr_output_configuration_head_v1_create(output_config,
m->wlr_output);
oldx = m->m.x;
oldy = m->m.y;
@ -6177,7 +6200,7 @@ void updatemons(struct wl_listener *listener, void *data) {
*/
wlr_scene_output_set_position(m->scene_output, m->m.x, m->m.y);
if (blur && m->blur) {
if (config.blur && m->blur) {
wlr_scene_node_set_position(&m->blur->node, m->m.x, m->m.y);
wlr_scene_optimized_blur_set_size(m->blur, m->m.width, m->m.height);
}
@ -6230,7 +6253,7 @@ void updatemons(struct wl_listener *listener, void *data) {
* it's at the wrong position after all. */
wlr_cursor_move(cursor, NULL, 0, 0);
wlr_output_manager_v1_set_configuration(output_mgr, config);
wlr_output_manager_v1_set_configuration(output_mgr, output_config);
}
void updatetitle(struct wl_listener *listener, void *data) {
@ -6256,7 +6279,7 @@ urgent(struct wl_listener *listener, void *data) {
if (!c || !c->foreign_toplevel)
return;
if (focus_on_activate && !c->istagsilent && c != selmon->sel) {
if (config.focus_on_activate && !c->istagsilent && c != selmon->sel) {
if (!(c->mon == selmon && c->tags & c->mon->tagset[c->mon->seltags]))
view_in_mon(&(Arg){.ui = c->tags}, true, c->mon, true);
focusclient(c, 1);
@ -6355,7 +6378,7 @@ void handle_keyboard_shortcuts_inhibit_new_inhibitor(
struct wlr_keyboard_shortcuts_inhibitor_v1 *inhibitor = data;
if (allow_shortcuts_inhibit == SHORTCUTS_INHIBIT_DISABLE) {
if (config.allow_shortcuts_inhibit == SHORTCUTS_INHIBIT_DISABLE) {
return;
}
@ -6475,7 +6498,7 @@ void activatex11(struct wl_listener *listener, void *data) {
}
}
if (focus_on_activate && !c->istagsilent && c != selmon->sel) {
if (config.focus_on_activate && !c->istagsilent && c != selmon->sel) {
if (!(c->mon == selmon && c->tags & c->mon->tagset[c->mon->seltags]))
view_in_mon(&(Arg){.ui = c->tags}, true, c->mon, true);
wlr_xwayland_surface_activate(c->surface.xwayland, 1);
@ -6621,7 +6644,7 @@ int32_t main(int32_t argc, char *argv[]) {
if (c == 's') {
startup_cmd = optarg;
} else if (c == 'd') {
log_level = WLR_DEBUG;
cli_debug_log = true;
} else if (c == 'v') {
printf("mango " VERSION "\n");
return EXIT_SUCCESS;