diff --git a/.github/scripts/sync-wiki.py b/.github/scripts/sync-wiki.py new file mode 100644 index 00000000..ebf543c7 --- /dev/null +++ b/.github/scripts/sync-wiki.py @@ -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() diff --git a/.github/workflows/sync-website.yml b/.github/workflows/sync-website.yml new file mode 100644 index 00000000..57c99e71 --- /dev/null +++ b/.github/workflows/sync-website.yml @@ -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 diff --git a/.github/workflows/sync-wiki.yml b/.github/workflows/sync-wiki.yml new file mode 100644 index 00000000..ef30fe77 --- /dev/null +++ b/.github/workflows/sync-wiki.yml @@ -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 diff --git a/docs/bindings/index.mdx b/docs/bindings/index.mdx new file mode 100644 index 00000000..4c3a5bda --- /dev/null +++ b/docs/bindings/index.mdx @@ -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. + + + + + + + + diff --git a/docs/bindings/keys.md b/docs/bindings/keys.md new file mode 100644 index 00000000..64ba64b7 --- /dev/null +++ b/docs/bindings/keys.md @@ -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=` 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.0–1.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. | \ No newline at end of file diff --git a/docs/bindings/meta.json b/docs/bindings/meta.json new file mode 100644 index 00000000..f1b629b6 --- /dev/null +++ b/docs/bindings/meta.json @@ -0,0 +1,4 @@ +{ + "title": "Bindings & Input", + "pages": ["keys", "mouse-gestures"] +} diff --git a/docs/bindings/mouse-gestures.md b/docs/bindings/mouse-gestures.md new file mode 100644 index 00000000..c4a36889 --- /dev/null +++ b/docs/bindings/mouse-gestures.md @@ -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 +``` diff --git a/docs/configuration/basics.md b/docs/configuration/basics.md new file mode 100644 index 00000000..7afa343b --- /dev/null +++ b/docs/configuration/basics.md @@ -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 +``` diff --git a/docs/configuration/index.mdx b/docs/configuration/index.mdx new file mode 100644 index 00000000..2bcd3a7e --- /dev/null +++ b/docs/configuration/index.mdx @@ -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. + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/configuration/input.md b/docs/configuration/input.md new file mode 100644 index 00000000..6d5eefdb --- /dev/null +++ b/docs/configuration/input.md @@ -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 +``` diff --git a/docs/configuration/meta.json b/docs/configuration/meta.json new file mode 100644 index 00000000..bc209b4e --- /dev/null +++ b/docs/configuration/meta.json @@ -0,0 +1,4 @@ +{ + "title": "Configuration", + "pages": ["basics", "monitors", "input", "xdg-portals", "miscellaneous"] +} diff --git a/docs/configuration/miscellaneous.md b/docs/configuration/miscellaneous.md new file mode 100644 index 00000000..2e5a1e92 --- /dev/null +++ b/docs/configuration/miscellaneous.md @@ -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, 1–3: 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.1–10.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.0–16.0) to refresh tiled window resize during drag. Too small may cause application lag. | +| `drag_floating_refresh_interval` | `8.0` | Interval (1.0–16.0) to refresh floating window resize during drag. Too small may cause application lag. | \ No newline at end of file diff --git a/docs/configuration/monitors.md b/docs/configuration/monitors.md new file mode 100644 index 00000000..28ef240b --- /dev/null +++ b/docs/configuration/monitors.md @@ -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. \ No newline at end of file diff --git a/docs/configuration/xdg-portals.md b/docs/configuration/xdg-portals.md new file mode 100644 index 00000000..27819ad8 --- /dev/null +++ b/docs/configuration/xdg-portals.md @@ -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. \ No newline at end of file diff --git a/docs/faq.md b/docs/faq.md new file mode 100644 index 00000000..13c6391b --- /dev/null +++ b/docs/faq.md @@ -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 +``` diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 00000000..d308370d --- /dev/null +++ b/docs/index.md @@ -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. diff --git a/docs/installation.md b/docs/installation.md new file mode 100644 index 00000000..10d2bd47 --- /dev/null +++ b/docs/installation.md @@ -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 + ``` diff --git a/docs/ipc.md b/docs/ipc.md new file mode 100644 index 00000000..72beefb5 --- /dev/null +++ b/docs/ipc.md @@ -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 ] -s [-t ] [-l ] [-c ] [-d ,,,,,] +mmsg [-o ] (-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 \ No newline at end of file diff --git a/docs/meta.json b/docs/meta.json new file mode 100644 index 00000000..74818a9d --- /dev/null +++ b/docs/meta.json @@ -0,0 +1,17 @@ +{ + "title": "mangowm", + "pages": [ + "---Getting Started---", + "index", + "installation", + "quick-start", + "---Configuration---", + "configuration", + "visuals", + "window-management", + "bindings", + "---Reference---", + "ipc", + "faq" + ] +} diff --git a/docs/quick-start.md b/docs/quick-start.md new file mode 100644 index 00000000..85f67cc2 --- /dev/null +++ b/docs/quick-start.md @@ -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. diff --git a/docs/visuals/animations.md b/docs/visuals/animations.md new file mode 100644 index 00000000..b4b88816 --- /dev/null +++ b/docs/visuals/animations.md @@ -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.0–1.0) +- `fadeout_begin_opacity` — Starting opacity for fade-out animations (0.0–1.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) | \ No newline at end of file diff --git a/docs/visuals/effects.md b/docs/visuals/effects.md new file mode 100644 index 00000000..23c1f206 --- /dev/null +++ b/docs/visuals/effects.md @@ -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 +``` diff --git a/docs/visuals/index.mdx b/docs/visuals/index.mdx new file mode 100644 index 00000000..f71ae2f8 --- /dev/null +++ b/docs/visuals/index.mdx @@ -0,0 +1,19 @@ +--- +title: Visuals +description: Customize borders, colors, effects, and animations. +icon: Palette +--- + +Customize the look of your desktop. + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/visuals/meta.json b/docs/visuals/meta.json new file mode 100644 index 00000000..58723c4e --- /dev/null +++ b/docs/visuals/meta.json @@ -0,0 +1,4 @@ +{ + "title": "Visuals", + "pages": ["theming", "status-bar", "effects", "animations"] +} diff --git a/docs/visuals/status-bar.md b/docs/visuals/status-bar.md new file mode 100644 index 00000000..f2924e83 --- /dev/null +++ b/docs/visuals/status-bar.md @@ -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). \ No newline at end of file diff --git a/docs/visuals/theming.md b/docs/visuals/theming.md new file mode 100644 index 00000000..8137eb4e --- /dev/null +++ b/docs/visuals/theming.md @@ -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 +``` diff --git a/docs/window-management/index.mdx b/docs/window-management/index.mdx new file mode 100644 index 00000000..b96c5891 --- /dev/null +++ b/docs/window-management/index.mdx @@ -0,0 +1,19 @@ +--- +title: Window Management +description: Layouts, rules, and window behavior. +icon: LayoutGrid +--- + +Window management with layouts, rules, and scratchpad support. + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/window-management/layouts.md b/docs/window-management/layouts.md new file mode 100644 index 00000000..26c05fe4 --- /dev/null +++ b/docs/window-management/layouts.md @@ -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 +``` diff --git a/docs/window-management/meta.json b/docs/window-management/meta.json new file mode 100644 index 00000000..e0937d14 --- /dev/null +++ b/docs/window-management/meta.json @@ -0,0 +1,4 @@ +{ + "title": "Window Management", + "pages": ["layouts", "rules", "overview", "scratchpad"] +} diff --git a/docs/window-management/overview.md b/docs/window-management/overview.md new file mode 100644 index 00000000..7da6e690 --- /dev/null +++ b/docs/window-management/overview.md @@ -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. \ No newline at end of file diff --git a/docs/window-management/rules.md b/docs/window-management/rules.md new file mode 100644 index 00000000..996c172f --- /dev/null +++ b/docs/window-management/rules.md @@ -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.1–0.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 +``` diff --git a/docs/window-management/scratchpad.md b/docs/window-management/scratchpad.md new file mode 100644 index 00000000..398182f9 --- /dev/null +++ b/docs/window-management/scratchpad.md @@ -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 +``` diff --git a/meson.build b/meson.build index c538c927..5d09d536 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('mango', ['c', 'cpp'], - version : '0.12.6', + version : '0.12.7', ) subdir('protocols') diff --git a/src/animation/client.h b/src/animation/client.h index b6683ecc..8c9c3915 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -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, diff --git a/src/animation/common.h b/src/animation/common.h index 9f022db2..10b66b91 100644 --- a/src/animation/common.h +++ b/src/animation/common.h @@ -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] + diff --git a/src/animation/layer.h b/src/animation/layer.h index 568d52b3..90f1b4ee 100644 --- a/src/animation/layer.h +++ b/src/animation/layer.h @@ -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 { diff --git a/src/animation/tag.h b/src/animation/tag.h index 8e65a93a..18eef56a 100644 --- a/src/animation/tag.h +++ b/src/animation/tag.h @@ -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); diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 3220b713..6ae97406 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -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++) { diff --git a/src/config/preset.h b/src/config/preset.h index f91da11a..6952518e 100644 --- a/src/config/preset.h +++ b/src/config/preset.h @@ -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); diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 4f808bdf..449adf3b 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -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; } diff --git a/src/ext-protocol/tearing.h b/src/ext-protocol/tearing.h index 8e02656a..5a9851e4 100644 --- a/src/ext-protocol/tearing.h +++ b/src/ext-protocol/tearing.h @@ -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 */ diff --git a/src/fetch/client.h b/src/fetch/client.h index 11edb76b..0b142847 100644 --- a/src/fetch/client.h +++ b/src/fetch/client.h @@ -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; } } diff --git a/src/layout/arrange.h b/src/layout/arrange.h index e164a0f6..04f4554b 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -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) { diff --git a/src/layout/horizontal.h b/src/layout/horizontal.h index 8140934a..eaa7b5c2 100644 --- a/src/layout/horizontal.h +++ b/src/layout/horizontal.h @@ -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)) diff --git a/src/layout/vertical.h b/src/layout/vertical.h index 4759e7a5..3d8863af 100644 --- a/src/layout/vertical.h +++ b/src/layout/vertical.h @@ -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; diff --git a/src/mango.c b/src/mango.c index 07656b8d..246a927c 100644 --- a/src/mango.c +++ b/src/mango.c @@ -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;