diff --git a/.github/scripts/sync-wiki.py b/.github/scripts/sync-wiki.py deleted file mode 100644 index ebf543c7..00000000 --- a/.github/scripts/sync-wiki.py +++ /dev/null @@ -1,61 +0,0 @@ -#!/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/stale.yml b/.github/workflows/stale.yml index d0b19c1e..43e8badc 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -16,7 +16,7 @@ jobs: days-before-issue-stale: -1 # 手动标记后,14 天后关闭 days-before-issue-close: 7 - # 使用的标签 + # 使用的标签(必须和你手动添加的标签一致) stale-issue-label: "stale" # 自动关闭时自动加上的标签 close-issue-label: "automatic-closing" diff --git a/.github/workflows/sync-website.yml b/.github/workflows/sync-website.yml deleted file mode 100644 index 57c99e71..00000000 --- a/.github/workflows/sync-website.yml +++ /dev/null @@ -1,44 +0,0 @@ -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 deleted file mode 100644 index ef30fe77..00000000 --- a/.github/workflows/sync-wiki.yml +++ /dev/null @@ -1,40 +0,0 @@ -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/README.md b/README.md index b927b920..d512f39f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Mango Wayland Compositor
- MangoWM Logo + MangoWC Logo
This project's development is based on [dwl](https://codeberg.org/dwl/dwl/). @@ -23,22 +23,25 @@ This project's development is based on [dwl](https://codeberg.org/dwl/dwl/). - Ipc support(get/send message from/to compositor by external program) - Hycov-like overview - Window effects from scenefx (blur, shadow, corner radius, opacity) - - Zero flickering - every frame is perfect. -https://github.com/user-attachments/assets/bb83004a-0563-4b48-ad89-6461a9b78b1f +Master-Stack Layout -# Mango's Vision +https://github.com/user-attachments/assets/a9d4776e-b50b-48fb-94ce-651d8a749b8a -**Mango's primary goal is stability**: After months of testing and development—and aside from a few lingering GPU compatibility issues—it should now be stable enough. I don't plan on making many breaking changes. +Scroller Layout -**Mango's preference is practicality**: I tend to add features that genuinely help with daily workflows—things that make our work more convenient. +https://github.com/user-attachments/assets/c9bf9415-fad1-4400-bcdc-3ad2d76de85a + +Layer animation + +https://github.com/user-attachments/assets/014c893f-115c-4ae9-8342-f9ae3e9a0df0 -**Mango won't cater to every user preference**: For niche feature requests, I'll take a wait-and-see approach. I'll only consider adding them if they get a significant number of upvotes. # Our discord -[mangowm](https://discord.gg/CPjbDxesh5) +[mangowc](https://discord.gg/CPjbDxesh5) # Supported layouts + - tile - scroller - monocle @@ -48,20 +51,21 @@ https://github.com/user-attachments/assets/bb83004a-0563-4b48-ad89-6461a9b78b1f - vertical_tile - vertical_grid - vertical_scroller -- tgmix # Installation -[![Packaging status](https://repology.org/badge/vertical-allrepos/mangowm.svg)](https://repology.org/project/mangowm/versions) - ## Dependencies +- glibc - wayland - wayland-protocols - libinput - libdrm - libxkbcommon - pixman +- git +- meson +- ninja - libdisplay-info - libliftoff - hwdata @@ -71,9 +75,9 @@ https://github.com/user-attachments/assets/bb83004a-0563-4b48-ad89-6461a9b78b1f - libxcb ## Arch Linux -The package is in the Arch User Repository and is available for manual download [here](https://aur.archlinux.org/packages/mangowm-git) or through a AUR helper like yay: +The package is in the Arch User Repository and is availble for manual download [here](https://aur.archlinux.org/packages/mangowc-git) or through a AUR helper like yay: ```bash -yay -S mangowm-git +yay -S mangowc-git ``` @@ -87,12 +91,12 @@ eselect repository enable guru emerge --sync guru ``` -Then, add `gui-libs/scenefx` and `gui-wm/mangowm` to the `package.accept_keywords`. +Then, add `gui-libs/scenefx` and `gui-wm/mangowc` to the `package.accept_keywords`. Finally, install the package: ```bash -emerge --ask --verbose gui-wm/mangowm +emerge --ask --verbose gui-wm/mangowc ``` ## Fedora Linux @@ -102,38 +106,9 @@ First, add the [Terra Repository](https://terra.fyralabs.com/). Then, install the package: ```bash -dnf install mangowm +dnf install mangowc ``` -## Guix System -The package definition is described in the source repository. -First, add `mangowm` channel to `channels.scm` file: - -```scheme -;; In $HOME/.config/guix/channels.scm -(cons (channel - (name 'mangowm) - (url "https://github.com/mangowm/mango.git") - (branch "main")) - ... ;; Your other channels - %default-channels) -``` - -Then, run `guix pull` and after update you can either run -`guix install mangowm` or add it to your configuration via: - -```scheme -(use-modules (mangowm)) ;; Add mangowm module - -;; Add mangowm to packages list -(packages (cons* - mangowm-git - ... ;; Other packages you specified - %base-packages)) -``` - -And then rebuild your system. - ## Other ```bash @@ -147,8 +122,8 @@ cd scenefx meson build -Dprefix=/usr sudo ninja -C build install -git clone https://github.com/mangowm/mango.git -cd mangowm +git clone https://github.com/DreamMaoMao/mangowc.git +cd mangowc meson build -Dprefix=/usr sudo ninja -C build install ``` @@ -206,9 +181,9 @@ git clone https://github.com/DreamMaoMao/mango-config.git ~/.config/mango ## Config Documentation -Refer to the repo wiki [wiki](https://github.com/mangowm/mango/wiki/) +Refer to the repo wiki [wiki](https://github.com/DreamMaoMao/mango/wiki/) -or the website docs [docs](https://mangowm.github.io/) +or the website docs [docs](https://mangowc.vercel.app/docs) # NixOS + Home-manager @@ -228,7 +203,7 @@ Here's an example of using the modules in a flake: }; flake-parts.url = "github:hercules-ci/flake-parts"; mango = { - url = "github:mangowm/mango"; + url = "github:DreamMaoMao/mango"; inputs.nixpkgs.follows = "nixpkgs"; }; }; @@ -290,9 +265,9 @@ Here's an example of using the modules in a flake: To package mango for other distributions, you can check the reference setup for: -- [nix](https://github.com/mangowm/mango/blob/main/nix/default.nix) -- [arch](https://aur.archlinux.org/cgit/aur.git/tree/PKGBUILD?h=mangowm-git). -- [gentoo](https://data.gpo.zugaina.org/guru/gui-wm/mangowm) +- [nix](https://github.com/DreamMaoMao/mangowc/blob/main/nix/default.nix) +- [arch](https://aur.archlinux.org/cgit/aur.git/tree/PKGBUILD?h=mangowc-git). +- [gentoo](https://data.gpo.zugaina.org/guru/gui-wm/mangowc) You might need to package `scenefx` for your distribution, check availability [here](https://github.com/wlrfx/scenefx.git). diff --git a/assets/mango-portals.conf b/assets/mango-portals.conf deleted file mode 100644 index aebea31a..00000000 --- a/assets/mango-portals.conf +++ /dev/null @@ -1,5 +0,0 @@ -[preferred] -default=gtk -org.freedesktop.impl.portal.ScreenCast=wlr -org.freedesktop.impl.portal.Screenshot=wlr -org.freedesktop.impl.portal.Inhibit=none diff --git a/assets/config.conf b/config.conf similarity index 98% rename from assets/config.conf rename to config.conf index 15b654c1..6cbb3a20 100644 --- a/assets/config.conf +++ b/config.conf @@ -240,11 +240,12 @@ bind=CTRL+ALT,Left,resizewin,-50,+0 bind=CTRL+ALT,Right,resizewin,+50,+0 # Mouse Button Bindings -# btn_left and btn_right can't bind none mod key +# NONE mode key only work in ov mode mousebind=SUPER,btn_left,moveresize,curmove mousebind=NONE,btn_middle,togglemaximizescreen,0 mousebind=SUPER,btn_right,moveresize,curresize - +mousebind=NONE,btn_left,toggleoverview,1 +mousebind=NONE,btn_right,killclient,0 # Axis Bindings axisbind=SUPER,UP,viewtoleft_have_client diff --git a/docs/bindings/index.mdx b/docs/bindings/index.mdx deleted file mode 100644 index 4c3a5bda..00000000 --- a/docs/bindings/index.mdx +++ /dev/null @@ -1,15 +0,0 @@ ---- -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 deleted file mode 100644 index 64ba64b7..00000000 --- a/docs/bindings/keys.md +++ /dev/null @@ -1,204 +0,0 @@ ---- -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 deleted file mode 100644 index f1b629b6..00000000 --- a/docs/bindings/meta.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "title": "Bindings & Input", - "pages": ["keys", "mouse-gestures"] -} diff --git a/docs/bindings/mouse-gestures.md b/docs/bindings/mouse-gestures.md deleted file mode 100644 index c4a36889..00000000 --- a/docs/bindings/mouse-gestures.md +++ /dev/null @@ -1,116 +0,0 @@ ---- -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 deleted file mode 100644 index 7afa343b..00000000 --- a/docs/configuration/basics.md +++ /dev/null @@ -1,87 +0,0 @@ ---- -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 deleted file mode 100644 index 2bcd3a7e..00000000 --- a/docs/configuration/index.mdx +++ /dev/null @@ -1,21 +0,0 @@ ---- -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 deleted file mode 100644 index 6d5eefdb..00000000 --- a/docs/configuration/input.md +++ /dev/null @@ -1,151 +0,0 @@ ---- -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 deleted file mode 100644 index bc209b4e..00000000 --- a/docs/configuration/meta.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "title": "Configuration", - "pages": ["basics", "monitors", "input", "xdg-portals", "miscellaneous"] -} diff --git a/docs/configuration/miscellaneous.md b/docs/configuration/miscellaneous.md deleted file mode 100644 index 2e5a1e92..00000000 --- a/docs/configuration/miscellaneous.md +++ /dev/null @@ -1,51 +0,0 @@ ---- -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 deleted file mode 100644 index 28ef240b..00000000 --- a/docs/configuration/monitors.md +++ /dev/null @@ -1,276 +0,0 @@ ---- -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 deleted file mode 100644 index 27819ad8..00000000 --- a/docs/configuration/xdg-portals.md +++ /dev/null @@ -1,76 +0,0 @@ ---- -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 deleted file mode 100644 index 13c6391b..00000000 --- a/docs/faq.md +++ /dev/null @@ -1,101 +0,0 @@ ---- -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 deleted file mode 100644 index d308370d..00000000 --- a/docs/index.md +++ /dev/null @@ -1,42 +0,0 @@ ---- -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 deleted file mode 100644 index 10d2bd47..00000000 --- a/docs/installation.md +++ /dev/null @@ -1,239 +0,0 @@ ---- -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 deleted file mode 100644 index 72beefb5..00000000 --- a/docs/ipc.md +++ /dev/null @@ -1,154 +0,0 @@ ---- -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 deleted file mode 100644 index 74818a9d..00000000 --- a/docs/meta.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "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 deleted file mode 100644 index 85f67cc2..00000000 --- a/docs/quick-start.md +++ /dev/null @@ -1,88 +0,0 @@ ---- -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 deleted file mode 100644 index b4b88816..00000000 --- a/docs/visuals/animations.md +++ /dev/null @@ -1,108 +0,0 @@ ---- -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 deleted file mode 100644 index 23c1f206..00000000 --- a/docs/visuals/effects.md +++ /dev/null @@ -1,82 +0,0 @@ ---- -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 deleted file mode 100644 index f71ae2f8..00000000 --- a/docs/visuals/index.mdx +++ /dev/null @@ -1,19 +0,0 @@ ---- -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 deleted file mode 100644 index 58723c4e..00000000 --- a/docs/visuals/meta.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "title": "Visuals", - "pages": ["theming", "status-bar", "effects", "animations"] -} diff --git a/docs/visuals/status-bar.md b/docs/visuals/status-bar.md deleted file mode 100644 index f2924e83..00000000 --- a/docs/visuals/status-bar.md +++ /dev/null @@ -1,141 +0,0 @@ ---- -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 deleted file mode 100644 index 8137eb4e..00000000 --- a/docs/visuals/theming.md +++ /dev/null @@ -1,56 +0,0 @@ ---- -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 deleted file mode 100644 index b96c5891..00000000 --- a/docs/window-management/index.mdx +++ /dev/null @@ -1,19 +0,0 @@ ---- -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 deleted file mode 100644 index 26c05fe4..00000000 --- a/docs/window-management/layouts.md +++ /dev/null @@ -1,99 +0,0 @@ ---- -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 deleted file mode 100644 index e0937d14..00000000 --- a/docs/window-management/meta.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "title": "Window Management", - "pages": ["layouts", "rules", "overview", "scratchpad"] -} diff --git a/docs/window-management/overview.md b/docs/window-management/overview.md deleted file mode 100644 index 7da6e690..00000000 --- a/docs/window-management/overview.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -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 deleted file mode 100644 index 996c172f..00000000 --- a/docs/window-management/rules.md +++ /dev/null @@ -1,249 +0,0 @@ ---- -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 deleted file mode 100644 index 398182f9..00000000 --- a/docs/window-management/scratchpad.md +++ /dev/null @@ -1,73 +0,0 @@ ---- -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/assets/mango.desktop b/mango.desktop similarity index 78% rename from assets/mango.desktop rename to mango.desktop index 37c4fad0..0c109cea 100644 --- a/assets/mango.desktop +++ b/mango.desktop @@ -1,7 +1,6 @@ [Desktop Entry] Encoding=UTF-8 Name=Mango -DesktopNames=mango;wlroots Comment=mango WM Exec=mango Icon=mango diff --git a/mangowm.scm b/mangowc.scm similarity index 89% rename from mangowm.scm rename to mangowc.scm index 7d94166d..9c55d43e 100644 --- a/mangowm.scm +++ b/mangowc.scm @@ -1,4 +1,4 @@ -(define-module (mangowm) +(define-module (mangowc) #:use-module (guix download) #:use-module (guix git-download) #:use-module (guix gexp) @@ -18,11 +18,11 @@ #:use-module (guix licenses)) -(define-public mangowm-git +(define-public mangowc-git (package - (name "mangowm") + (name "mangowc") (version "git") - (source (local-file "." "mangowm-checkout" + (source (local-file "." "mangowc-checkout" #:recursive? #t #:select? (or (git-predicate (current-source-directory)) (const #t)))) @@ -55,13 +55,10 @@ wlroots scenefx)) (native-inputs (list pkg-config wayland-protocols)) - (home-page "https://github.com/DreamMaoMao/mangowm") + (home-page "https://github.com/DreamMaoMao/mangowc") (synopsis "Wayland compositor based on wlroots and scenefx") (description "A Wayland compositor based on wlroots and scenefx, inspired by dwl but aiming to be more feature-rich.") (license gpl3))) -(define-deprecated-package mangowc - mangowm-git) - -mangowm-git +mangowc-git diff --git a/meson.build b/meson.build index 5d09d536..d71eb597 100644 --- a/meson.build +++ b/meson.build @@ -1,5 +1,5 @@ project('mango', ['c', 'cpp'], - version : '0.12.7', + version : '0.11.0', ) subdir('protocols') @@ -56,7 +56,7 @@ endif if is_git_repo # 如果是 Git 目录,获取 Commit Hash 和最新的 tag commit_hash = run_command(git, 'rev-parse', '--short', 'HEAD', check : false).stdout().strip() - latest_tag = meson.project_version() + latest_tag = run_command(git, 'describe', '--tags', '--abbrev=0', check : false).stdout().strip() version_with_hash = '@0@(@1@)'.format(latest_tag, commit_hash) else # 如果不是 Git 目录,使用项目版本号和 "release" 字符串 @@ -147,7 +147,5 @@ executable('mmsg', ) desktop_install_dir = join_paths(prefix, 'share/wayland-sessions') -portal_install_dir = join_paths(prefix, 'share/xdg-desktop-portal') -install_data('assets/mango.desktop', install_dir : desktop_install_dir) -install_data('assets/mango-portals.conf', install_dir : portal_install_dir) -install_data('assets/config.conf', install_dir : join_paths(sysconfdir, 'mango')) +install_data('mango.desktop', install_dir : desktop_install_dir) +install_data('config.conf', install_dir : join_paths(sysconfdir, 'mango')) diff --git a/mmsg/mmsg.c b/mmsg/mmsg.c index 4e0e1d8c..ba073aad 100644 --- a/mmsg/mmsg.c +++ b/mmsg/mmsg.c @@ -500,48 +500,12 @@ static const struct wl_registry_listener registry_listener = { static void usage(void) { fprintf(stderr, - "mmsg - MangoWM IPC\n" - "\n" - "SYNOPSIS:\n" - "\tmmsg [-OTLq]\n" - "\tmmsg [-o ] -s [-t ] [-l ] [-c ] [-d " + "usage:" + "\t%s [-OTLq]\n" + "\t%s [-o ] -s [-t ] [-l ] [-c ] [-d " ",,,,,]\n" - "\tmmsg [-o ] (-g | -w) [-OotlcvmfxekbA]\n" - "\n" - "OPERATION MODES:\n" - "\t-g Get values (tags, layout, focused client)\n" - "\t-s Set values (switch tags, layouts)\n" - "\t-w Watch mode (stream events)\n" - "\n" - "GENERAL OPTIONS:\n" - "\t-O Get all output (monitor) information\n" - "\t-T Get number of tags\n" - "\t-L Get all available layouts\n" - "\t-q Quit mango\n" - "\t-o Select output (monitor)\n" - "\n" - "GET OPTIONS (used with -g or -w):\n" - "\t-O Get output name\n" - "\t-o Get output (monitor) focus information\n" - "\t-t Get selected tags\n" - "\t-l Get current layout\n" - "\t-c Get title and appid of focused clients\n" - "\t-v Get visibility of statusbar\n" - "\t-m Get fullscreen status\n" - "\t-f Get floating status\n" - "\t-x Get focused client geometry\n" - "\t-e Get name of last focused layer\n" - "\t-k Get current keyboard layout\n" - "\t-b Get current keybind mode\n" - "\t-A Get scale factor of monitor\n" - "\n" - "SET OPTIONS (used with -s):\n" - "\t-o Select output (monitor)\n" - "\t-t Set selected tags (can be used with [+-^.] " - "modifiers)\n" - "\t-l Set current layout\n" - "\t-c Get title and appid of focused client\n" - "\t-d , Dispatch internal command (max 5 args)\n"); + "\t%s [-o ] (-g | -w) [-OotlcvmfxekbA]\n", + argv0, argv0, argv0); exit(2); } diff --git a/nix/default.nix b/nix/default.nix index cb6497b9..6085565e 100644 --- a/nix/default.nix +++ b/nix/default.nix @@ -11,7 +11,7 @@ wayland, wayland-protocols, wayland-scanner, - libxcb-wm, + xcbutilwm, xwayland, meson, ninja, @@ -57,7 +57,7 @@ stdenv.mkDerivation { ] ++ lib.optionals enableXWayland [ libX11 - libxcb-wm + xcbutilwm xwayland ]; @@ -67,8 +67,8 @@ stdenv.mkDerivation { meta = { mainProgram = "mango"; - description = "Practical and Powerful wayland compositor (dwm but wayland)"; - homepage = "https://github.com/mangowm/mango"; + description = "A streamlined but feature-rich Wayland compositor"; + homepage = "https://github.com/DreamMaoMao/mango"; license = lib.licenses.gpl3Plus; maintainers = []; platforms = lib.platforms.unix; diff --git a/protocols/meson.build b/protocols/meson.build index 922a76ed..cafab64a 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -1,6 +1,6 @@ wayland_scanner = find_program('wayland-scanner') wayland_protos_dep = dependency('wayland-protocols') -wl_protocol_dir = wayland_protos_dep.get_variable(pkgconfig:'pkgdatadir') +wl_protocol_dir = wayland_protos_dep.get_pkgconfig_variable('pkgdatadir') wayland_scanner_code = generator( wayland_scanner, output: '@BASENAME@-protocol.c', diff --git a/src/animation/client.h b/src/animation/client.h index 8c9c3915..849bc10e 100644 --- a/src/animation/client.h +++ b/src/animation/client.h @@ -10,21 +10,20 @@ 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 = - config.animations ? c->animation.current : c->geom; - if (target_geom.x + config.border_radius <= c->mon->m.x) { - current_corner_location &= ~CORNER_LOCATION_LEFT; + 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; // 清除左标志位 } - if (target_geom.x + target_geom.width - config.border_radius >= + if (target_geom.x + target_geom.width - 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 + config.border_radius <= c->mon->m.y) { - current_corner_location &= ~CORNER_LOCATION_TOP; + if (target_geom.y + border_radius <= c->mon->m.y) { + current_corner_location &= ~CORNER_LOCATION_TOP; // 清除上标志位 } - if (target_geom.y + target_geom.height - config.border_radius >= + if (target_geom.y + target_geom.height - 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; } @@ -48,23 +47,22 @@ bool is_horizontal_right_stack_layout(Monitor *m) { return false; } -int32_t is_special_animation_rule(Client *c) { +int32_t is_special_animaiton_rule(Client *c) { if (is_scroller_layout(c->mon) && !c->isfloating) { return DOWN; } else if (c->mon->visible_tiling_clients == 1 && !c->isfloating) { return DOWN; } else if (c->mon->visible_tiling_clients == 2 && !c->isfloating && - !config.new_is_master && is_horizontal_stack_layout(c->mon)) { + !new_is_master && is_horizontal_stack_layout(c->mon)) { return RIGHT; - } else if (!c->isfloating && config.new_is_master && + } else if (!c->isfloating && new_is_master && is_horizontal_stack_layout(c->mon)) { return LEFT; } else if (c->mon->visible_tiling_clients == 2 && !c->isfloating && - !config.new_is_master && - is_horizontal_right_stack_layout(c->mon)) { + !new_is_master && is_horizontal_right_stack_layout(c->mon)) { return LEFT; - } else if (!c->isfloating && config.new_is_master && + } else if (!c->isfloating && new_is_master && is_horizontal_right_stack_layout(c->mon)) { return RIGHT; } else { @@ -72,15 +70,14 @@ int32_t is_special_animation_rule(Client *c) { } } -void set_client_open_animation(Client *c, struct wlr_box geo) { +void set_client_open_animaiton(Client *c, struct wlr_box geo) { int32_t slide_direction; int32_t horizontal, horizontal_value; int32_t vertical, vertical_value; int32_t special_direction; int32_t center_x, center_y; - if ((!c->animation_type_open && - strcmp(config.animation_type_open, "fade") == 0) || + if ((!c->animation_type_open && strcmp(animation_type_open, "fade") == 0) || (c->animation_type_open && strcmp(c->animation_type_open, "fade") == 0)) { c->animainit_geom.width = geo.width; @@ -89,17 +86,17 @@ 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(config.animation_type_open, "zoom") == 0) || + strcmp(animation_type_open, "zoom") == 0) || (c->animation_type_open && strcmp(c->animation_type_open, "zoom") == 0)) { - c->animainit_geom.width = geo.width * config.zoom_initial_ratio; - c->animainit_geom.height = geo.height * config.zoom_initial_ratio; + c->animainit_geom.width = geo.width * zoom_initial_ratio; + c->animainit_geom.height = geo.height * 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; return; } else { - special_direction = is_special_animation_rule(c); + special_direction = is_special_animaiton_rule(c); center_x = c->geom.x + c->geom.width / 2; center_y = c->geom.y + c->geom.height / 2; if (special_direction == UNDIR) { @@ -226,7 +223,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, config.border_radius, + wlr_scene_buffer_set_corner_radius(buffer, border_radius, buffer_data->corner_location); } @@ -244,7 +241,7 @@ void buffer_set_effect(Client *c, BufferData data) { data.should_scale = false; if (c->isnoradius || c->isfullscreen || - (config.no_radius_when_single && c->mon && + (no_radius_when_single && c->mon && c->mon->visible_tiling_clients == 1)) { data.corner_location = CORNER_LOCATION_NONE; } @@ -258,7 +255,7 @@ void client_draw_shadow(Client *c) { if (c->iskilling || !client_surface(c)->mapped || c->isnoshadow) return; - if (!config.shadows || (!c->isfloating && config.shadow_only_floating)) { + if (!shadows || (!c->isfloating && shadow_only_floating)) { if (c->shadow->node.enabled) wlr_scene_node_set_enabled(&c->shadow->node, false); return; @@ -269,7 +266,7 @@ void client_draw_shadow(Client *c) { bool hit_no_border = check_hit_no_border(c); enum corner_location current_corner_location = - c->isfullscreen || (config.no_radius_when_single && c->mon && + c->isfullscreen || (no_radius_when_single && c->mon && c->mon->visible_tiling_clients == 1) ? CORNER_LOCATION_NONE : CORNER_LOCATION_ALL; @@ -279,8 +276,9 @@ void client_draw_shadow(Client *c) { int32_t width, height; client_actual_size(c, &width, &height); - int32_t delta = config.shadows_size + (int32_t)c->bw - bwoffset; + int32_t delta = shadows_size + (int32_t)c->bw - bwoffset; + /* we calculate where to clip the shadow */ struct wlr_box client_box = { .x = bwoffset, .y = bwoffset, @@ -289,20 +287,22 @@ void client_draw_shadow(Client *c) { }; struct wlr_box shadow_box = { - .x = config.shadows_position_x + bwoffset, - .y = config.shadows_position_y + bwoffset, + .x = shadows_position_x + bwoffset, + .y = 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); - intersection_box.x -= config.shadows_position_x + bwoffset; - intersection_box.y -= config.shadows_position_y + bwoffset; + /* 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; struct clipped_region clipped_region = { .area = intersection_box, - .corner_radius = config.border_radius, + .corner_radius = border_radius, .corners = current_corner_location, }; @@ -356,23 +356,24 @@ void apply_border(Client *c) { bool hit_no_border = check_hit_no_border(c); enum corner_location current_corner_location; - if (c->isfullscreen || (config.no_radius_when_single && c->mon && + if (c->isfullscreen || (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 && config.smartgaps) { + // Handle no-border cases + if (hit_no_border && smartgaps) { c->bw = 0; c->fake_no_border = true; - } else if (hit_no_border && !config.smartgaps) { + } else if (hit_no_border && !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 : config.borderpx; + c->bw = c->isnoborder ? 0 : borderpx; c->fake_no_border = false; } @@ -434,14 +435,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 = config.border_radius, + .corner_radius = 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, config.border_radius, + wlr_scene_rect_set_corner_radius(c->border, border_radius, current_corner_location); wlr_scene_rect_set_clipped_region(c->border, clipped_region); } @@ -523,7 +524,7 @@ void client_apply_clip(Client *c, float factor) { enum corner_location current_corner_location = set_client_corner_location(c); - if (!config.animations) { + if (!animations) { c->animation.running = false; c->need_output_flush = false; c->animainit_geom = c->current = c->pending = c->animation.current = @@ -655,19 +656,19 @@ void fadeout_client_animation_next_tick(Client *c) { double opacity_eased_progress = find_animation_curve_at(animation_passed, OPAFADEOUT); - double percent = config.fadeout_begin_opacity - - (opacity_eased_progress * config.fadeout_begin_opacity); + double percent = fadeout_begin_opacity - + (opacity_eased_progress * fadeout_begin_opacity); double opacity = MAX(percent, 0); - if (config.animation_fade_out && !c->nofadeout) + if (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(config.animation_type_close, "zoom") == 0)) { + strcmp(animation_type_close, "zoom") == 0)) { buffer_data.width = width; buffer_data.height = height; @@ -768,75 +769,75 @@ void init_fadeout_client(Client *c) { if ((c->animation_type_close && strcmp(c->animation_type_close, "none") == 0) || (!c->animation_type_close && - strcmp(config.animation_type_close, "none") == 0)) { + strcmp(animation_type_close, "none") == 0)) { return; } - Client *fadeout_client = ecalloc(1, sizeof(*fadeout_client)); + Client *fadeout_cient = ecalloc(1, sizeof(*fadeout_cient)); wlr_scene_node_set_enabled(&c->scene->node, true); - client_set_border_color(c, config.bordercolor); - fadeout_client->scene = + client_set_border_color(c, bordercolor); + fadeout_cient->scene = wlr_scene_tree_snapshot(&c->scene->node, layers[LyrFadeOut]); wlr_scene_node_set_enabled(&c->scene->node, false); - if (!fadeout_client->scene) { - free(fadeout_client); + if (!fadeout_cient->scene) { + free(fadeout_cient); return; } - fadeout_client->animation.duration = config.animation_duration_close; - fadeout_client->geom = fadeout_client->current = - fadeout_client->animainit_geom = fadeout_client->animation.initial = + fadeout_cient->animation.duration = animation_duration_close; + fadeout_cient->geom = fadeout_cient->current = + fadeout_cient->animainit_geom = fadeout_cient->animation.initial = c->animation.current; - fadeout_client->mon = c->mon; - fadeout_client->animation_type_close = c->animation_type_close; - fadeout_client->animation.action = CLOSE; - fadeout_client->bw = c->bw; - fadeout_client->nofadeout = c->nofadeout; + fadeout_cient->mon = c->mon; + fadeout_cient->animation_type_close = c->animation_type_close; + fadeout_cient->animation.action = CLOSE; + fadeout_cient->bw = c->bw; + fadeout_cient->nofadeout = c->nofadeout; // 这里snap节点的坐标设置是使用的相对坐标,所以不能加上原来坐标 // 这跟普通node有区别 - fadeout_client->animation.initial.x = 0; - fadeout_client->animation.initial.y = 0; + fadeout_cient->animation.initial.x = 0; + fadeout_cient->animation.initial.y = 0; if ((!c->animation_type_close && - strcmp(config.animation_type_close, "fade") == 0) || + strcmp(animation_type_close, "fade") == 0) || (c->animation_type_close && strcmp(c->animation_type_close, "fade") == 0)) { - fadeout_client->current.x = 0; - fadeout_client->current.y = 0; - fadeout_client->current.width = 0; - fadeout_client->current.height = 0; + fadeout_cient->current.x = 0; + fadeout_cient->current.y = 0; + fadeout_cient->current.width = 0; + fadeout_cient->current.height = 0; } else if ((c->animation_type_close && strcmp(c->animation_type_close, "slide") == 0) || (!c->animation_type_close && - strcmp(config.animation_type_close, "slide") == 0)) { - fadeout_client->current.y = + strcmp(animation_type_close, "slide") == 0)) { + fadeout_cient->current.y = c->geom.y + c->geom.height / 2 > c->mon->m.y + c->mon->m.height / 2 ? c->mon->m.height - (c->animation.current.y - c->mon->m.y) // down out : c->mon->m.y - c->geom.height; // up out - fadeout_client->current.x = 0; // x无偏差,垂直划出 + fadeout_cient->current.x = 0; // x无偏差,垂直划出 } else { - fadeout_client->current.y = - (fadeout_client->geom.height - - fadeout_client->geom.height * config.zoom_end_ratio) / + fadeout_cient->current.y = + (fadeout_cient->geom.height - + fadeout_cient->geom.height * zoom_end_ratio) / 2; - fadeout_client->current.x = - (fadeout_client->geom.width - - fadeout_client->geom.width * config.zoom_end_ratio) / + fadeout_cient->current.x = + (fadeout_cient->geom.width - + fadeout_cient->geom.width * zoom_end_ratio) / 2; - fadeout_client->current.width = - fadeout_client->geom.width * config.zoom_end_ratio; - fadeout_client->current.height = - fadeout_client->geom.height * config.zoom_end_ratio; + fadeout_cient->current.width = + fadeout_cient->geom.width * zoom_end_ratio; + fadeout_cient->current.height = + fadeout_cient->geom.height * zoom_end_ratio; } - fadeout_client->animation.time_started = get_now_in_ms(); - wlr_scene_node_set_enabled(&fadeout_client->scene->node, true); - wl_list_insert(&fadeout_clients, &fadeout_client->fadeout_link); + fadeout_cient->animation.time_started = get_now_in_ms(); + wlr_scene_node_set_enabled(&fadeout_cient->scene->node, true); + wl_list_insert(&fadeout_clients, &fadeout_cient->fadeout_link); // 请求刷新屏幕 request_fresh_all_monitors(); @@ -866,11 +867,12 @@ void client_set_pending_state(Client *c) { if (!c || c->iskilling) return; - if (!config.animations) { + // 判断是否需要动画 + if (!animations) { c->animation.should_animate = false; - } else if (config.animations && c->animation.tagining) { + } else if (animations && c->animation.tagining) { c->animation.should_animate = true; - } else if (!config.animations || c == grabc || + } else if (!animations || c == grabc || (!c->is_pending_open_animation && wlr_box_equal(&c->current, &c->pending))) { c->animation.should_animate = false; @@ -881,7 +883,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(config.animation_type_open, "none") == 0)) && + strcmp(animation_type_open, "none") == 0)) && c->animation.action == OPEN) { c->animation.duration = 0; } @@ -950,16 +952,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 = config.animation_duration_tag; + c->animation.duration = animation_duration_tag; c->animation.action = TAG; } else if (c->animation.tagining) { - c->animation.duration = config.animation_duration_tag; + c->animation.duration = animation_duration_tag; c->animation.action = TAG; } else if (c->is_pending_open_animation) { - c->animation.duration = config.animation_duration_open; + c->animation.duration = animation_duration_open; c->animation.action = OPEN; } else { - c->animation.duration = config.animation_duration_move; + c->animation.duration = animation_duration_move; c->animation.action = MOVE; } @@ -970,7 +972,7 @@ void resize(Client *c, struct wlr_box geo, int32_t interact) { c->animainit_geom.height = c->animation.current.height; c->animainit_geom.width = c->animation.current.width; } else if (c->is_pending_open_animation) { - set_client_open_animation(c, c->geom); + set_client_open_animaiton(c, c->geom); } else { c->animainit_geom = c->animation.current; } @@ -979,20 +981,10 @@ void resize(Client *c, struct wlr_box geo, int32_t interact) { c->bw = 0; } - bool hit_no_border = check_hit_no_border(c); - if (hit_no_border && config.smartgaps) { - c->bw = 0; - c->fake_no_border = true; - } - // c->geom 是真实的窗口大小和位置,跟过度的动画无关,用于计算布局 c->configure_serial = client_set_size(c, c->geom.width - 2 * c->bw, c->geom.height - 2 * c->bw); - if (c->configure_serial != 0) { - c->mon->resizing_count_pending++; - } - if (c == grabc) { c->animation.running = false; c->need_output_flush = false; @@ -1047,43 +1039,63 @@ bool client_draw_fadeout_frame(Client *c) { void client_set_focused_opacity_animation(Client *c) { float *border_color = get_border_color(c); - if (!config.animations) { + if (!animations) { setborder_color(c); return; } - c->opacity_animation.duration = config.animation_duration_focus; + c->opacity_animation.duration = 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; c->opacity_animation.time_started = get_now_in_ms(); - memcpy(c->opacity_animation.initial_border_color, - c->opacity_animation.current_border_color, - sizeof(c->opacity_animation.initial_border_color)); - c->opacity_animation.initial_opacity = c->opacity_animation.current_opacity; - + if (c->opacity_animation.running) { + memcpy(c->opacity_animation.initial_border_color, + c->opacity_animation.current_border_color, + sizeof(c->opacity_animation.initial_border_color)); + c->opacity_animation.initial_opacity = + c->opacity_animation.current_opacity; + } else { + memcpy(c->opacity_animation.initial_border_color, border_color, + sizeof(c->opacity_animation.initial_border_color)); + memcpy(c->opacity_animation.current_border_color, border_color, + sizeof(c->opacity_animation.current_border_color)); + c->opacity_animation.initial_opacity = c->unfocused_opacity; + c->opacity_animation.current_opacity = c->unfocused_opacity; + } c->opacity_animation.running = true; } void client_set_unfocused_opacity_animation(Client *c) { + // Start border color animation to unfocused float *border_color = get_border_color(c); - if (!config.animations) { + if (!animations) { setborder_color(c); return; } - c->opacity_animation.duration = config.animation_duration_focus; + c->opacity_animation.duration = animation_duration_focus; memcpy(c->opacity_animation.target_border_color, border_color, sizeof(c->opacity_animation.target_border_color)); // Start opacity animation to unfocused c->opacity_animation.target_opacity = c->unfocused_opacity; c->opacity_animation.time_started = get_now_in_ms(); - memcpy(c->opacity_animation.initial_border_color, - c->opacity_animation.current_border_color, - sizeof(c->opacity_animation.initial_border_color)); - c->opacity_animation.initial_opacity = c->opacity_animation.current_opacity; + if (c->opacity_animation.running) { + memcpy(c->opacity_animation.initial_border_color, + c->opacity_animation.current_border_color, + sizeof(c->opacity_animation.initial_border_color)); + c->opacity_animation.initial_opacity = + c->opacity_animation.current_opacity; + } else { + memcpy(c->opacity_animation.initial_border_color, border_color, + sizeof(c->opacity_animation.initial_border_color)); + memcpy(c->opacity_animation.current_border_color, border_color, + sizeof(c->opacity_animation.current_border_color)); + c->opacity_animation.initial_opacity = c->focused_opacity; + c->opacity_animation.current_opacity = c->focused_opacity; + } c->opacity_animation.running = true; } @@ -1108,24 +1120,18 @@ bool client_apply_focus_opacity(Client *c) { double opacity_eased_progress = find_animation_curve_at(linear_progress, OPAFADEIN); - float percent = config.animation_fade_in && !c->nofadein - ? opacity_eased_progress - : 1.0; + float percent = + 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 - config.fadein_begin_opacity) + - config.fadein_begin_opacity; + float target_opacity = + percent * (1.0 - fadein_begin_opacity) + fadein_begin_opacity; if (target_opacity > opacity) { target_opacity = opacity; } - memcpy(c->opacity_animation.current_border_color, - c->opacity_animation.target_border_color, - sizeof(c->opacity_animation.current_border_color)); - 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 (config.animations && c->opacity_animation.running) { + } else if (animations && c->opacity_animation.running) { struct timespec now; clock_gettime(CLOCK_MONOTONIC, &now); @@ -1155,7 +1161,7 @@ bool client_apply_focus_opacity(Client *c) { eased_progress; } client_set_border_color(c, c->opacity_animation.current_border_color); - if (linear_progress >= 1.0f) { + if (linear_progress == 1.0f) { c->opacity_animation.running = false; } else { return true; @@ -1186,7 +1192,7 @@ bool client_draw_frame(Client *c) { return client_apply_focus_opacity(c); } - if (config.animations && c->animation.running) { + if (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 10b66b91..9f022db2 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 = config.animation_curve_move; + animation_curve = animation_curve_move; } else if (type == OPEN) { - animation_curve = config.animation_curve_open; + animation_curve = animation_curve_open; } else if (type == TAG) { - animation_curve = config.animation_curve_tag; + animation_curve = animation_curve_tag; } else if (type == CLOSE) { - animation_curve = config.animation_curve_close; + animation_curve = animation_curve_close; } else if (type == FOCUS) { - animation_curve = config.animation_curve_focus; + animation_curve = animation_curve_focus; } else if (type == OPAFADEIN) { - animation_curve = config.animation_curve_opafadein; + animation_curve = animation_curve_opafadein; } else if (type == OPAFADEOUT) { - animation_curve = config.animation_curve_opafadeout; + animation_curve = animation_curve_opafadeout; } else { - animation_curve = config.animation_curve_move; + animation_curve = 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 90f1b4ee..568d52b3 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 (!config.shadows || !config.layer_shadows || l->noshadow) { + if (!shadows || !layer_shadows || l->noshadow) { wlr_scene_shadow_set_size(l->shadow, 0, 0); return; } @@ -164,8 +164,9 @@ void layer_draw_shadow(LayerSurface *l) { int32_t width, height; layer_actual_size(l, &width, &height); - int32_t delta = config.shadows_size; + int32_t delta = shadows_size; + /* we calculate where to clip the shadow */ struct wlr_box layer_box = { .x = 0, .y = 0, @@ -174,21 +175,23 @@ void layer_draw_shadow(LayerSurface *l) { }; struct wlr_box shadow_box = { - .x = config.shadows_position_x, - .y = config.shadows_position_y, + .x = shadows_position_x, + .y = 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); - intersection_box.x -= config.shadows_position_x; - intersection_box.y -= config.shadows_position_y; + /* 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; struct clipped_region clipped_region = { .area = intersection_box, - .corner_radius = config.border_radius, - .corners = config.border_radius_location_default, + .corner_radius = border_radius, + .corners = border_radius_location_default, }; wlr_scene_node_set_position(&l->shadow->node, shadow_box.x, shadow_box.y); @@ -258,7 +261,7 @@ void fadeout_layer_animation_next_tick(LayerSurface *l) { buffer_data.height = height; if ((!l->animation_type_close && - strcmp(config.layer_animation_type_close, "zoom") == 0) || + strcmp(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, @@ -276,12 +279,12 @@ void fadeout_layer_animation_next_tick(LayerSurface *l) { double opacity_eased_progress = find_animation_curve_at(animation_passed, OPAFADEOUT); - double percent = config.fadeout_begin_opacity - - (opacity_eased_progress * config.fadeout_begin_opacity); + double percent = fadeout_begin_opacity - + (opacity_eased_progress * fadeout_begin_opacity); double opacity = MAX(percent, 0.0f); - if (config.animation_fade_out) + if (animation_fade_out) wlr_scene_node_for_each_buffer(&l->scene->node, scene_buffer_apply_opacity, &opacity); @@ -324,11 +327,11 @@ void layer_animation_next_tick(LayerSurface *l) { find_animation_curve_at(animation_passed, OPAFADEIN); double opacity = - MIN(config.fadein_begin_opacity + - opacity_eased_progress * (1.0 - config.fadein_begin_opacity), + MIN(fadein_begin_opacity + + opacity_eased_progress * (1.0 - fadein_begin_opacity), 1.0f); - if (config.animation_fade_in) + if (animation_fade_in) wlr_scene_node_for_each_buffer(&l->scene->node, scene_buffer_apply_opacity, &opacity); @@ -344,7 +347,7 @@ void layer_animation_next_tick(LayerSurface *l) { } if ((!l->animation_type_open && - strcmp(config.layer_animation_type_open, "zoom") == 0) || + strcmp(layer_animation_type_open, "zoom") == 0) || (l->animation_type_open && strcmp(l->animation_type_open, "zoom") == 0)) { wlr_scene_node_for_each_buffer( @@ -367,7 +370,7 @@ void layer_animation_next_tick(LayerSurface *l) { void init_fadeout_layers(LayerSurface *l) { - if (!config.animations || !config.layer_animations || l->noanim) { + if (!animations || !layer_animations || l->noanim) { return; } @@ -377,7 +380,7 @@ void init_fadeout_layers(LayerSurface *l) { if ((l->animation_type_close && strcmp(l->animation_type_close, "none") == 0) || (!l->animation_type_close && - strcmp(config.layer_animation_type_close, "none") == 0)) { + strcmp(layer_animation_type_close, "none") == 0)) { return; } @@ -400,7 +403,7 @@ void init_fadeout_layers(LayerSurface *l) { return; } - fadeout_layer->animation.duration = config.animation_duration_close; + fadeout_layer->animation.duration = animation_duration_close; fadeout_layer->geom = fadeout_layer->current = fadeout_layer->animainit_geom = fadeout_layer->animation.initial = l->animation.current; @@ -416,14 +419,14 @@ void init_fadeout_layers(LayerSurface *l) { fadeout_layer->animation.initial.y = 0; if ((!l->animation_type_close && - strcmp(config.layer_animation_type_close, "zoom") == 0) || + strcmp(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 * config.zoom_end_ratio; + (float)l->animation.current.width * zoom_end_ratio; fadeout_layer->current.height = - (float)l->animation.current.height * config.zoom_end_ratio; + (float)l->animation.current.height * 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 - @@ -435,7 +438,7 @@ void init_fadeout_layers(LayerSurface *l) { fadeout_layer->current.y - l->animation.current.y; } else if ((!l->animation_type_close && - strcmp(config.layer_animation_type_close, "slide") == 0) || + strcmp(layer_animation_type_close, "slide") == 0) || (l->animation_type_close && strcmp(l->animation_type_close, "slide") == 0)) { // 获取slide动画的结束绝对坐标和大小 @@ -480,18 +483,17 @@ void layer_set_pending_state(LayerSurface *l) { if (l->animation.action == OPEN && !l->animation.running) { if ((!l->animation_type_open && - strcmp(config.layer_animation_type_open, "zoom") == 0) || + strcmp(layer_animation_type_open, "zoom") == 0) || (l->animation_type_open && strcmp(l->animation_type_open, "zoom") == 0)) { - 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.width = l->geom.width * zoom_initial_ratio; + l->animainit_geom.height = l->geom.height * 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(config.layer_animation_type_open, "slide") == 0) || + strcmp(layer_animation_type_open, "slide") == 0) || (l->animation_type_open && strcmp(l->animation_type_open, "slide") == 0)) { @@ -505,7 +507,8 @@ void layer_set_pending_state(LayerSurface *l) { } else { l->animainit_geom = l->animation.current; } - if (!config.animations || !config.layer_animations || l->noanim || + // 判断是否需要动画 + if (!animations || !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) { @@ -517,7 +520,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(config.layer_animation_type_open, "none") == 0)) && + strcmp(layer_animation_type_open, "none") == 0)) && l->animation.action == OPEN) { l->animation.should_animate = false; } @@ -564,8 +567,7 @@ bool layer_draw_frame(LayerSurface *l) { return false; } - if (config.animations && config.layer_animations && l->animation.running && - !l->noanim) { + if (animations && 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 18eef56a..8e65a93a 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 = config.tag_animation_direction == VERTICAL + c->animainit_geom.x = 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 = config.tag_animation_direction == VERTICAL + c->animainit_geom.y = 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 = - config.tag_animation_direction == VERTICAL + 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 = - config.tag_animation_direction == VERTICAL + tag_animation_direction == VERTICAL ? MIN(m->m.y - c->geom.height, c->geom.y - c->mon->m.height) : c->animation.current.y; } @@ -39,8 +39,7 @@ 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 && - config.animations) { + m->pertag->prevtag != 0 && m->pertag->curtag != 0 && animations) { c->animation.tagining = true; set_tagin_animation(m, c); } else { @@ -58,10 +57,10 @@ void set_tagout_animation(Monitor *m, Client *c) { if (m->pertag->curtag > m->pertag->prevtag) { c->pending = c->geom; c->pending.x = - config.tag_animation_direction == VERTICAL + 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 = config.tag_animation_direction == VERTICAL + c->pending.y = tag_animation_direction == VERTICAL ? MIN(c->mon->m.y - c->geom.height, c->geom.y - c->mon->m.height) : c->animation.current.y; @@ -69,11 +68,11 @@ void set_tagout_animation(Monitor *m, Client *c) { resize(c, c->geom, 0); } else { c->pending = c->geom; - c->pending.x = config.tag_animation_direction == VERTICAL + c->pending.x = 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 = config.tag_animation_direction == VERTICAL + c->pending.y = tag_animation_direction == VERTICAL ? MAX(c->mon->m.y + c->mon->m.height, c->geom.y + c->mon->m.height) : c->animation.current.y; @@ -83,8 +82,7 @@ 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 && - config.animations) { + m->pertag->prevtag != 0 && m->pertag->curtag != 0 && animations) { c->animation.tagouting = true; c->animation.tagining = false; set_tagout_animation(m, c); diff --git a/src/client/client.h b/src/client/client.h index 4788e448..8995a5d0 100644 --- a/src/client/client.h +++ b/src/client/client.h @@ -243,6 +243,31 @@ static inline int32_t client_is_rendered_on_mon(Client *c, Monitor *m) { return 0; } +static inline int32_t client_is_stopped(Client *c) { + int32_t pid; + siginfo_t in = {0}; +#ifdef XWAYLAND + if (client_is_x11(c)) + return 0; +#endif + + wl_client_get_credentials(c->surface.xdg->client->client, &pid, NULL, NULL); + if (waitid(P_PID, pid, &in, WNOHANG | WCONTINUED | WSTOPPED | WNOWAIT) < + 0) { + /* This process is not our child process, while is very unluckely that + * it is stopped, in order to do not skip frames assume that it is. */ + if (errno == ECHILD) + return 1; + } else if (in.si_pid) { + if (in.si_code == CLD_STOPPED || in.si_code == CLD_TRAPPED) + return 1; + if (in.si_code == CLD_CONTINUED) + return 0; + } + + return 0; +} + static inline int32_t client_is_unmanaged(Client *c) { #ifdef XWAYLAND if (client_is_x11(c)) @@ -294,24 +319,9 @@ static inline uint32_t client_set_size(Client *c, uint32_t width, uint32_t height) { #ifdef XWAYLAND if (client_is_x11(c)) { - - struct wlr_surface_state *state = - &c->surface.xwayland->surface->current; - - if ((int32_t)c->geom.width - 2 * (int32_t)c->bw == - (int32_t)state->width && - (int32_t)c->geom.height - 2 * (int32_t)c->bw == - (int32_t)state->height && - (int32_t)c->surface.xwayland->x == - (int32_t)c->geom.x + (int32_t)c->bw && - (int32_t)c->surface.xwayland->y == - (int32_t)c->geom.y + (int32_t)c->bw) { - return 0; - } - wlr_xwayland_surface_configure(c->surface.xwayland, c->geom.x + c->bw, c->geom.y + c->bw, width, height); - return 1; + return 0; } #endif if ((int32_t)width == c->surface.xdg->toplevel->current.width && @@ -537,4 +547,4 @@ static inline void client_set_size_bound(Client *c) { state.max_height > 0) { c->geom.height = state.max_height + 2 * c->bw; } -} +} \ No newline at end of file diff --git a/src/common/util.c b/src/common/util.c index 025aed6d..a15cca7c 100644 --- a/src/common/util.c +++ b/src/common/util.c @@ -92,85 +92,3 @@ uint32_t get_now_in_ms(void) { uint32_t timespec_to_ms(struct timespec *ts) { return (uint32_t)ts->tv_sec * 1000 + (uint32_t)ts->tv_nsec / 1000000; } - -char *join_strings(char *arr[], const char *sep) { - if (!arr || !arr[0]) { - char *empty = malloc(1); - if (empty) - empty[0] = '\0'; - return empty; - } - - size_t total_len = 0; - int count = 0; - for (int i = 0; arr[i] != NULL; i++) { - total_len += strlen(arr[i]); - count++; - } - if (count > 0) { - total_len += strlen(sep) * (count - 1); - } - - char *result = malloc(total_len + 1); - if (!result) - return NULL; - - result[0] = '\0'; - for (int i = 0; arr[i] != NULL; i++) { - if (i > 0) - strcat(result, sep); - strcat(result, arr[i]); - } - return result; -} - -char *join_strings_with_suffix(char *arr[], const char *suffix, - const char *sep) { - if (!arr || !arr[0]) { - char *empty = malloc(1); - if (empty) - empty[0] = '\0'; - return empty; - } - - size_t total_len = 0; - int count = 0; - for (int i = 0; arr[i] != NULL; i++) { - total_len += strlen(arr[i]) + strlen(suffix); - count++; - } - if (count > 0) { - total_len += strlen(sep) * (count - 1); - } - - char *result = malloc(total_len + 1); - if (!result) - return NULL; - - result[0] = '\0'; - for (int i = 0; arr[i] != NULL; i++) { - if (i > 0) - strcat(result, sep); - strcat(result, arr[i]); - strcat(result, suffix); - } - return result; -} - -char *string_printf(const char *fmt, ...) { - va_list args; - va_start(args, fmt); - int len = vsnprintf(NULL, 0, fmt, args); - va_end(args); - if (len < 0) - return NULL; - - char *str = malloc(len + 1); - if (!str) - return NULL; - - va_start(args, fmt); - vsnprintf(str, len + 1, fmt, args); - va_end(args); - return str; -} diff --git a/src/common/util.h b/src/common/util.h index cb232ac5..8fb60338 100644 --- a/src/common/util.h +++ b/src/common/util.h @@ -7,8 +7,4 @@ int32_t fd_set_nonblock(int32_t fd); int32_t regex_match(const char *pattern_mb, const char *str_mb); void wl_list_append(struct wl_list *list, struct wl_list *object); uint32_t get_now_in_ms(void); -uint32_t timespec_to_ms(struct timespec *ts); -char *join_strings(char *arr[], const char *sep); -char *join_strings_with_suffix(char *arr[], const char *suffix, - const char *sep); -char *string_printf(const char *fmt, ...); \ No newline at end of file +uint32_t timespec_to_ms(struct timespec *ts); \ No newline at end of file diff --git a/src/config/parse_config.h b/src/config/parse_config.h index 7816631e..b2535b15 100644 --- a/src/config/parse_config.h +++ b/src/config/parse_config.h @@ -58,7 +58,6 @@ typedef struct { uint32_t tags; int32_t isfloating; int32_t isfullscreen; - int32_t isfakefullscreen; float scroller_proportion; const char *animation_type_open; const char *animation_type_close; @@ -78,8 +77,7 @@ typedef struct { int32_t ignore_maximize; int32_t ignore_minimize; int32_t isnosizehint; - int32_t indleinhibit_when_focus; - char *monitor; + const char *monitor; int32_t offsetx; int32_t offsety; int32_t width; @@ -91,7 +89,6 @@ typedef struct { int32_t isterm; int32_t allow_csd; int32_t force_maximize; - int32_t force_tiled_state; int32_t force_tearing; int32_t noswallow; int32_t noblur; @@ -104,15 +101,15 @@ typedef struct { } ConfigWinRule; typedef struct { - const char *name; // Monitor name - char *make, *model, *serial; // may be NULL - int32_t rr; // Rotate and flip (assume integer) - float scale; // Monitor scale factor - int32_t x, y; // Monitor position - int32_t width, height; // Monitor resolution - float refresh; // Refresh rate - int32_t vrr; // variable refresh rate - int32_t custom; // enable custom mode + const char *name; // 显示器名称 + float mfact; // 主区域比例 + int32_t nmaster; // 主区域窗口数量 + const char *layout; // 布局名称(字符串) + int32_t rr; // 旋转和翻转(假设为整数) + float scale; // 显示器缩放比例 + int32_t x, y; // 显示器位置 + int32_t width, height; // 显示器分辨率 + float refresh; // 刷新率 } ConfigMonitorRule; // 修改后的宏定义 @@ -159,14 +156,9 @@ typedef struct { } GestureBinding; typedef struct { - int32_t id; - char *layout_name; + int32_t id; // 标签ID (1-9) + char *layout_name; // 布局名称 char *monitor_name; - char *monitor_make; - char *monitor_model; - char *monitor_serial; - float mfact; - int32_t nmaster; int32_t no_render_border; int32_t no_hide; } ConfigTagRule; @@ -213,7 +205,6 @@ typedef struct { int32_t scroller_ignore_proportion_single; int32_t scroller_focus_center; int32_t scroller_prefer_center; - int32_t scroller_prefer_overspread; int32_t edge_scroller_pointer_focus; int32_t focus_cross_monitor; int32_t exchange_cross_monitor; @@ -241,7 +232,6 @@ typedef struct { int32_t center_when_single_stack; uint32_t hotarea_size; - uint32_t hotarea_corner; uint32_t enable_hotarea; uint32_t ov_tab_mode; int32_t overviewgappi; @@ -253,8 +243,6 @@ typedef struct { int32_t idleinhibit_ignore_visible; int32_t sloppyfocus; int32_t warpcursor; - int32_t drag_corner; - int32_t drag_warp_cursor; /* keyboard */ int32_t repeat_rate; @@ -285,7 +273,6 @@ 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; @@ -313,8 +300,7 @@ typedef struct { float globalcolor[4]; float overlaycolor[4]; - int32_t log_level; - uint32_t capslock; + char autostart[3][256]; ConfigTagRule *tag_rules; // 动态数组 int32_t tag_rules_count; // 数量 @@ -358,18 +344,12 @@ typedef struct { int32_t single_scratchpad; int32_t xwayland_persistence; int32_t syncobj_enable; - float drag_tile_refresh_interval; - float drag_floating_refresh_interval; + int32_t adaptive_sync; int32_t allow_tearing; int32_t allow_shortcuts_inhibit; 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]; @@ -380,10 +360,7 @@ typedef struct { typedef int32_t (*FuncType)(const Arg *); Config config; -bool parse_config_file(Config *config, const char *file_path, bool must_exist); -bool apply_rule_to_state(Monitor *m, const ConfigMonitorRule *rule, - struct wlr_output_state *state, int vrr, int custom); -bool monitor_matches_rule(Monitor *m, const ConfigMonitorRule *rule); +void parse_config_file(Config *config, const char *file_path); // Helper function to trim whitespace from start and end of a string void trim_whitespace(char *str) { @@ -426,10 +403,7 @@ int32_t parse_double_array(const char *input, double *output, char *endptr; double val = strtod(token, &endptr); if (endptr == token || *endptr != '\0') { - fprintf( - stderr, - "\033[1m\033[31m[ERROR]:\033[33m Invalid number in array: %s\n", - token); + fprintf(stderr, "Error: Invalid number in array: %s\n", token); free(dup); return -1; } @@ -481,9 +455,7 @@ void parse_bind_flags(const char *str, KeyBinding *kb) { kb->ispassapply = true; break; default: - fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Unknown bind flag: %c\n", - suffix[i]); + // 忽略其他字符或可根据需要处理错误 break; } } @@ -571,58 +543,15 @@ static bool starts_with_ignore_case(const char *str, const char *prefix) { return true; } -static char *combine_args_until_empty(char *values[], int count) { - // find the first empty string - int first_empty = count; - for (int i = 0; i < count; i++) { - // check if it's empty: empty string or only contains "0" (initialized) - if (values[i][0] == '\0' || - (strlen(values[i]) == 1 && values[i][0] == '0')) { - first_empty = i; - break; - } - } - - // if there are no valid parameters, return an empty string - if (first_empty == 0) { - return strdup(""); - } - - // calculate the total length - size_t total_len = 0; - for (int i = 0; i < first_empty; i++) { - total_len += strlen(values[i]); - } - // plus the number of commas (first_empty-1 commas) - total_len += (first_empty - 1); - - // allocate memory and concatenate - char *combined = malloc(total_len + 1); - if (combined == NULL) { - return strdup(""); - } - - combined[0] = '\0'; - for (int i = 0; i < first_empty; i++) { - if (i > 0) { - strcat(combined, ","); - } - strcat(combined, values[i]); - } - - return combined; -} - uint32_t parse_mod(const char *mod_str) { if (!mod_str || !*mod_str) { - return UINT32_MAX; + return 0; } uint32_t mod = 0; char input_copy[256]; char *token; char *saveptr = NULL; - bool match_success = false; // 复制并转换为小写 strncpy(input_copy, mod_str, sizeof(input_copy) - 1); @@ -634,14 +563,9 @@ uint32_t parse_mod(const char *mod_str) { // 分割处理每个部分 token = strtok_r(input_copy, "+", &saveptr); while (token != NULL) { - // 去除前后空白 - trim_whitespace(token); - - // 如果 token 变成空字符串则跳过 - if (*token == '\0') { - token = strtok_r(NULL, "+", &saveptr); - continue; - } + // 去除空白 + while (*token == ' ' || *token == '\t') + token++; if (strncmp(token, "code:", 5) == 0) { // 处理 code: 形式 @@ -665,56 +589,35 @@ uint32_t parse_mod(const char *mod_str) { case 108: mod |= WLR_MODIFIER_ALT; break; - default: - fprintf(stderr, - "unknown modifier keycode: \033[1m\033[31m%s\n", - token); - break; } } } else { // 完整的 modifier 检查(保留原始所有检查项) - if (!strcmp(token, "super") || !strcmp(token, "super_l") || - !strcmp(token, "super_r")) { + if (strstr(token, "super") || strstr(token, "super_l") || + strstr(token, "super_r")) { mod |= WLR_MODIFIER_LOGO; - match_success = true; } - if (!strcmp(token, "ctrl") || !strcmp(token, "ctrl_l") || - !strcmp(token, "ctrl_r")) { + if (strstr(token, "ctrl") || strstr(token, "ctrl_l") || + strstr(token, "ctrl_r")) { mod |= WLR_MODIFIER_CTRL; - match_success = true; } - if (!strcmp(token, "shift") || !strcmp(token, "shift_l") || - !strcmp(token, "shift_r")) { + if (strstr(token, "shift") || strstr(token, "shift_l") || + strstr(token, "shift_r")) { mod |= WLR_MODIFIER_SHIFT; - match_success = true; } - if (!strcmp(token, "alt") || !strcmp(token, "alt_l") || - !strcmp(token, "alt_r")) { + if (strstr(token, "alt") || strstr(token, "alt_l") || + strstr(token, "alt_r")) { mod |= WLR_MODIFIER_ALT; - match_success = true; } - if (!strcmp(token, "hyper") || !strcmp(token, "hyper_l") || - !strcmp(token, "hyper_r")) { + if (strstr(token, "hyper") || strstr(token, "hyper_l") || + strstr(token, "hyper_r")) { mod |= WLR_MODIFIER_MOD3; - match_success = true; - } - if (!strcmp(token, "none")) { - match_success = true; } } token = strtok_r(NULL, "+", &saveptr); } - if (!match_success) { - mod = UINT32_MAX; - fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Unknown modifier: " - "\033[1m\033[31m%s\n", - mod_str); - } - return mod; } @@ -805,9 +708,8 @@ KeySymCode parse_key(const char *key_str, bool isbindsym) { return kc; } - // change key string to keysym, case insensitive - xkb_keysym_t sym = - xkb_keysym_from_name(key_str, XKB_KEYSYM_CASE_INSENSITIVE); + // 普通键名直接转换 + xkb_keysym_t sym = xkb_keysym_from_name(key_str, XKB_KEYSYM_NO_FLAGS); if (isbindsym) { kc.type = KEY_TYPE_SYM; @@ -831,17 +733,13 @@ KeySymCode parse_key(const char *key_str, bool isbindsym) { // 无法解析的键名 kc.type = KEY_TYPE_SYM; kc.keysym = XKB_KEY_NoSymbol; - fprintf( - stderr, - "\033[1m\033[31m[ERROR]:\033[33m Unknown key: \033[1m\033[31m%s\n", - key_str); // keycode 字段保持为0 } return kc; } -uint32_t parse_button(const char *str) { +int32_t parse_button(const char *str) { // 将输入字符串转换为小写 char lowerStr[20]; int32_t i = 0; @@ -869,11 +767,7 @@ uint32_t parse_button(const char *str) { } else if (strcmp(lowerStr, "btn_task") == 0) { return BTN_TASK; } else { - fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Unknown button: " - "\033[1m\033[31m%s\n", - str); - return UINT32_MAX; + return 0; } } @@ -924,12 +818,6 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value, char *arg_value5) { FuncType func = NULL; - (*arg).i = 0; - (*arg).i2 = 0; - (*arg).f = 0.0f; - (*arg).f2 = 0.0f; - (*arg).ui = 0; - (*arg).ui2 = 0; (*arg).v = NULL; (*arg).v2 = NULL; (*arg).v3 = NULL; @@ -964,7 +852,6 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value, (*arg).f = atof(arg_value); } else if (strcmp(func_name, "switch_proportion_preset") == 0) { func = switch_proportion_preset; - (*arg).i = parse_circle_direction(arg_value); } else if (strcmp(func_name, "viewtoleft") == 0) { func = viewtoleft; (*arg).i = atoi(arg_value); @@ -1037,7 +924,6 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value, (*arg).v = strdup(arg_value); } else if (strcmp(func_name, "switch_keyboard_layout") == 0) { func = switch_keyboard_layout; - (*arg).i = CLAMP_INT(atoi(arg_value), 0, 100); } else if (strcmp(func_name, "setlayout") == 0) { func = setlayout; (*arg).v = strdup(arg_value); @@ -1082,14 +968,10 @@ FuncType parse_func_name(char *func_name, Arg *arg, char *arg_value, (*arg).ui = atoi(arg_value); } else if (strcmp(func_name, "spawn") == 0) { func = spawn; - char *values[] = {arg_value, arg_value2, arg_value3, arg_value4, - arg_value5}; - (*arg).v = combine_args_until_empty(values, 5); + (*arg).v = strdup(arg_value); } else if (strcmp(func_name, "spawn_shell") == 0) { func = spawn_shell; - char *values[] = {arg_value, arg_value2, arg_value3, arg_value4, - arg_value5}; - (*arg).v = combine_args_until_empty(values, 5); + (*arg).v = strdup(arg_value); } else if (strcmp(func_name, "spawn_on_empty") == 0) { func = spawn_on_empty; (*arg).v = strdup(arg_value); // 注意:之后需要释放这个内存 @@ -1231,7 +1113,7 @@ void run_exec_once() { } } -bool parse_option(Config *config, char *key, char *value) { +void parse_option(Config *config, char *key, char *value) { if (strcmp(key, "keymode") == 0) { snprintf(config->keymode, sizeof(config->keymode), "%.27s", value); } else if (strcmp(key, "animations") == 0) { @@ -1282,70 +1164,53 @@ bool parse_option(Config *config, char *key, char *value) { int32_t num = parse_double_array(value, config->animation_curve_move, 4); if (num != 4) { - fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Failed to parse " - "animation_curve_move: %s\n", + fprintf(stderr, "Error: Failed to parse animation_curve_move: %s\n", value); - return false; } } else if (strcmp(key, "animation_curve_open") == 0) { int32_t num = parse_double_array(value, config->animation_curve_open, 4); if (num != 4) { - fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Failed to parse " - "animation_curve_open: %s\n", + fprintf(stderr, "Error: Failed to parse animation_curve_open: %s\n", value); - return false; } } else if (strcmp(key, "animation_curve_tag") == 0) { int32_t num = parse_double_array(value, config->animation_curve_tag, 4); if (num != 4) { - fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Failed to parse " - "animation_curve_tag: %s\n", + fprintf(stderr, "Error: Failed to parse animation_curve_tag: %s\n", value); - return false; } } else if (strcmp(key, "animation_curve_close") == 0) { int32_t num = parse_double_array(value, config->animation_curve_close, 4); if (num != 4) { fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Failed to parse " - "animation_curve_close: %s\n", + "Error: Failed to parse animation_curve_close: %s\n", value); - return false; } } else if (strcmp(key, "animation_curve_focus") == 0) { int32_t num = parse_double_array(value, config->animation_curve_focus, 4); if (num != 4) { fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Failed to parse " - "animation_curve_focus: %s\n", + "Error: Failed to parse animation_curve_focus: %s\n", value); - return false; } } else if (strcmp(key, "animation_curve_opafadein") == 0) { int32_t num = parse_double_array(value, config->animation_curve_opafadein, 4); if (num != 4) { fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Failed to parse " - "animation_curve_opafadein: %s\n", + "Error: Failed to parse animation_curve_opafadein: %s\n", value); - return false; } } else if (strcmp(key, "animation_curve_opafadeout") == 0) { int32_t num = parse_double_array(value, config->animation_curve_opafadeout, 4); if (num != 4) { fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Failed to parse " - "animation_curve_opafadeout: %s\n", + "Error: Failed to parse animation_curve_opafadeout: %s\n", value); - return false; } } else if (strcmp(key, "scroller_structs") == 0) { config->scroller_structs = atoi(value); @@ -1359,8 +1224,6 @@ bool parse_option(Config *config, char *key, char *value) { config->scroller_focus_center = atoi(value); } else if (strcmp(key, "scroller_prefer_center") == 0) { config->scroller_prefer_center = atoi(value); - } else if (strcmp(key, "scroller_prefer_overspread") == 0) { - config->scroller_prefer_overspread = atoi(value); } else if (strcmp(key, "edge_scroller_pointer_focus") == 0) { config->edge_scroller_pointer_focus = atoi(value); } else if (strcmp(key, "focus_cross_monitor") == 0) { @@ -1413,10 +1276,8 @@ bool parse_option(Config *config, char *key, char *value) { config->xwayland_persistence = atoi(value); } else if (strcmp(key, "syncobj_enable") == 0) { config->syncobj_enable = atoi(value); - } else if (strcmp(key, "drag_tile_refresh_interval") == 0) { - config->drag_tile_refresh_interval = atof(value); - } else if (strcmp(key, "drag_floating_refresh_interval") == 0) { - config->drag_floating_refresh_interval = atof(value); + } else if (strcmp(key, "adaptive_sync") == 0) { + config->adaptive_sync = atoi(value); } else if (strcmp(key, "allow_tearing") == 0) { config->allow_tearing = atoi(value); } else if (strcmp(key, "allow_shortcuts_inhibit") == 0) { @@ -1440,25 +1301,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(config->xkb_rules_rules, value, - sizeof(config->xkb_rules_rules) - 1); - config->xkb_rules_rules[sizeof(config->xkb_rules_rules) - 1] = '\0'; + strncpy(xkb_rules_rules, value, sizeof(xkb_rules_rules) - 1); + xkb_rules_rules[sizeof(xkb_rules_rules) - 1] = + '\0'; // 确保字符串以 null 结尾 } else if (strcmp(key, "xkb_rules_model") == 0) { - strncpy(config->xkb_rules_model, value, - sizeof(config->xkb_rules_model) - 1); - config->xkb_rules_model[sizeof(config->xkb_rules_model) - 1] = '\0'; + strncpy(xkb_rules_model, value, sizeof(xkb_rules_model) - 1); + xkb_rules_model[sizeof(xkb_rules_model) - 1] = + '\0'; // 确保字符串以 null 结尾 } else if (strcmp(key, "xkb_rules_layout") == 0) { - strncpy(config->xkb_rules_layout, value, - sizeof(config->xkb_rules_layout) - 1); - config->xkb_rules_layout[sizeof(config->xkb_rules_layout) - 1] = '\0'; + strncpy(xkb_rules_layout, value, sizeof(xkb_rules_layout) - 1); + xkb_rules_layout[sizeof(xkb_rules_layout) - 1] = + '\0'; // 确保字符串以 null 结尾 } else if (strcmp(key, "xkb_rules_variant") == 0) { - strncpy(config->xkb_rules_variant, value, - sizeof(config->xkb_rules_variant) - 1); - config->xkb_rules_variant[sizeof(config->xkb_rules_variant) - 1] = '\0'; + strncpy(xkb_rules_variant, value, sizeof(xkb_rules_variant) - 1); + xkb_rules_variant[sizeof(xkb_rules_variant) - 1] = + '\0'; // 确保字符串以 null 结尾 } else if (strcmp(key, "xkb_rules_options") == 0) { - strncpy(config->xkb_rules_options, value, - sizeof(config->xkb_rules_options) - 1); - config->xkb_rules_options[sizeof(config->xkb_rules_options) - 1] = '\0'; + strncpy(xkb_rules_options, value, sizeof(xkb_rules_options) - 1); + xkb_rules_options[sizeof(xkb_rules_options) - 1] = + '\0'; // 确保字符串以 null 结尾 } else if (strcmp(key, "scroller_proportion_preset") == 0) { // 1. 统计 value 中有多少个逗号,确定需要解析的浮点数个数 int32_t count = 0; // 初始化为 0 @@ -1472,9 +1333,8 @@ bool parse_option(Config *config, char *key, char *value) { config->scroller_proportion_preset = (float *)malloc(float_count * sizeof(float)); if (!config->scroller_proportion_preset) { - fprintf(stderr, "\033[1m\033[31m[ERROR]:\033[33m Memory " - "allocation failed\n"); - return false; + fprintf(stderr, "Error: Memory allocation failed\n"); + return; } // 3. 解析 value 中的浮点数 @@ -1487,18 +1347,16 @@ bool parse_option(Config *config, char *key, char *value) { while (token != NULL && i < float_count) { if (sscanf(token, "%f", &value_set) != 1) { fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Invalid float " - "value in " + "Error: Invalid float value in " "scroller_proportion_preset: %s\n", token); free(value_copy); free(config->scroller_proportion_preset); config->scroller_proportion_preset = NULL; - return false; + return; } - // Clamp the value between 0.0 and 1.0 (or your desired - // range) + // Clamp the value between 0.0 and 1.0 (or your desired range) config->scroller_proportion_preset[i] = CLAMP_FLOAT(value_set, 0.1f, 1.0f); @@ -1509,14 +1367,13 @@ bool parse_option(Config *config, char *key, char *value) { // 4. 检查解析的浮点数数量是否匹配 if (i != float_count) { fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Invalid " - "scroller_proportion_preset format: %s\n", + "Error: Invalid scroller_proportion_preset format: %s\n", value); free(value_copy); free(config->scroller_proportion_preset); // 释放已分配的内存 config->scroller_proportion_preset = NULL; // 防止野指针 config->scroller_proportion_preset_count = 0; - return false; + return; } config->scroller_proportion_preset_count = float_count; @@ -1535,9 +1392,8 @@ bool parse_option(Config *config, char *key, char *value) { config->circle_layout = (char **)malloc(string_count * sizeof(char *)); memset(config->circle_layout, 0, string_count * sizeof(char *)); if (!config->circle_layout) { - fprintf(stderr, "\033[1m\033[31m[ERROR]:\033[33m Memory " - "allocation failed\n"); - return false; + fprintf(stderr, "Error: Memory allocation failed\n"); + return; } // 3. 解析 value 中的字符串 @@ -1552,9 +1408,7 @@ bool parse_option(Config *config, char *key, char *value) { config->circle_layout[i] = strdup(cleaned_token); if (!config->circle_layout[i]) { fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Memory allocation " - "failed for " - "string: %s\n", + "Error: Memory allocation failed for string: %s\n", token); // 释放之前分配的内存 for (int32_t j = 0; j < i; j++) { @@ -1564,7 +1418,7 @@ bool parse_option(Config *config, char *key, char *value) { free(value_copy); config->circle_layout = NULL; // 防止野指针 config->circle_layout_count = 0; - return false; + return; } token = strtok(NULL, ","); i++; @@ -1572,10 +1426,7 @@ bool parse_option(Config *config, char *key, char *value) { // 4. 检查解析的字符串数量是否匹配 if (i != string_count) { - fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Invalid circle_layout " - "format: %s\n", - value); + fprintf(stderr, "Error: Invalid circle_layout format: %s\n", value); // 释放之前分配的内存 for (int32_t j = 0; j < i; j++) { free(config->circle_layout[j]); @@ -1584,7 +1435,7 @@ bool parse_option(Config *config, char *key, char *value) { free(value_copy); config->circle_layout = NULL; // 防止野指针 config->circle_layout_count = 0; - return false; + return; } config->circle_layout_count = string_count; @@ -1602,8 +1453,6 @@ bool parse_option(Config *config, char *key, char *value) { config->center_when_single_stack = atoi(value); } else if (strcmp(key, "hotarea_size") == 0) { config->hotarea_size = atoi(value); - } else if (strcmp(key, "hotarea_corner") == 0) { - config->hotarea_corner = atoi(value); } else if (strcmp(key, "enable_hotarea") == 0) { config->enable_hotarea = atoi(value); } else if (strcmp(key, "ov_tab_mode") == 0) { @@ -1626,10 +1475,6 @@ bool parse_option(Config *config, char *key, char *value) { config->sloppyfocus = atoi(value); } else if (strcmp(key, "warpcursor") == 0) { config->warpcursor = atoi(value); - } else if (strcmp(key, "drag_corner") == 0) { - config->drag_corner = atoi(value); - } else if (strcmp(key, "drag_warp_cursor") == 0) { - config->drag_warp_cursor = atoi(value); } else if (strcmp(key, "smartgaps") == 0) { config->smartgaps = atoi(value); } else if (strcmp(key, "repeat_rate") == 0) { @@ -1691,12 +1536,7 @@ bool parse_option(Config *config, char *key, char *value) { } else if (strcmp(key, "rootcolor") == 0) { int64_t color = parse_color(value); if (color == -1) { - fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Invalid rootcolor " - "format: " - "%s\n", - value); - return false; + fprintf(stderr, "Error: Invalid rootcolor format: %s\n", value); } else { convert_hex_to_rgba(config->rootcolor, color); } @@ -1704,191 +1544,68 @@ bool parse_option(Config *config, char *key, char *value) { } else if (strcmp(key, "shadowscolor") == 0) { int64_t color = parse_color(value); if (color == -1) { - fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Invalid shadowscolor " - "format: %s\n", - value); - return false; + fprintf(stderr, "Error: Invalid shadowscolor format: %s\n", value); } else { convert_hex_to_rgba(config->shadowscolor, color); } } else if (strcmp(key, "bordercolor") == 0) { int64_t color = parse_color(value); if (color == -1) { - fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Invalid bordercolor " - "format: %s\n", - value); - return false; + fprintf(stderr, "Error: Invalid bordercolor format: %s\n", value); } else { convert_hex_to_rgba(config->bordercolor, color); } } else if (strcmp(key, "focuscolor") == 0) { int64_t color = parse_color(value); if (color == -1) { - fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Invalid focuscolor " - "format: %s\n", - value); - return false; + fprintf(stderr, "Error: Invalid focuscolor format: %s\n", value); } else { convert_hex_to_rgba(config->focuscolor, color); } } else if (strcmp(key, "maximizescreencolor") == 0) { int64_t color = parse_color(value); if (color == -1) { - fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Invalid " - "maximizescreencolor " - "format: %s\n", + fprintf(stderr, "Error: Invalid maximizescreencolor format: %s\n", value); - return false; } else { convert_hex_to_rgba(config->maximizescreencolor, color); } } else if (strcmp(key, "urgentcolor") == 0) { int64_t color = parse_color(value); if (color == -1) { - fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Invalid urgentcolor " - "format: %s\n", - value); - return false; + fprintf(stderr, "Error: Invalid urgentcolor format: %s\n", value); } else { convert_hex_to_rgba(config->urgentcolor, color); } } else if (strcmp(key, "scratchpadcolor") == 0) { int64_t color = parse_color(value); if (color == -1) { - fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Invalid " - "scratchpadcolor " - "format: %s\n", + fprintf(stderr, "Error: Invalid scratchpadcolor format: %s\n", value); - return false; } else { convert_hex_to_rgba(config->scratchpadcolor, color); } } else if (strcmp(key, "globalcolor") == 0) { int64_t color = parse_color(value); if (color == -1) { - fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Invalid globalcolor " - "format: %s\n", - value); - return false; + fprintf(stderr, "Error: Invalid globalcolor format: %s\n", value); } else { convert_hex_to_rgba(config->globalcolor, color); } } else if (strcmp(key, "overlaycolor") == 0) { int64_t color = parse_color(value); if (color == -1) { - fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Invalid overlaycolor " - "format: %s\n", - value); - return false; + fprintf(stderr, "Error: Invalid overlaycolor format: %s\n", value); } else { convert_hex_to_rgba(config->overlaycolor, color); } - } else if (strcmp(key, "monitorrule") == 0) { - config->monitor_rules = - realloc(config->monitor_rules, (config->monitor_rules_count + 1) * - sizeof(ConfigMonitorRule)); - if (!config->monitor_rules) { - fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Failed to allocate " - "memory for monitor rules\n"); - return false; - } - - ConfigMonitorRule *rule = - &config->monitor_rules[config->monitor_rules_count]; - memset(rule, 0, sizeof(ConfigMonitorRule)); - - // 设置默认值 - rule->name = NULL; - rule->make = NULL; - rule->model = NULL; - rule->serial = NULL; - rule->rr = 0; - rule->scale = 1.0f; - rule->x = INT32_MAX; - rule->y = INT32_MAX; - rule->width = -1; - rule->height = -1; - rule->refresh = 0.0f; - rule->vrr = 0; - rule->custom = 0; - - bool parse_error = false; - char *token = strtok(value, ","); - while (token != NULL) { - char *colon = strchr(token, ':'); - if (colon != NULL) { - *colon = '\0'; - char *key = token; - char *val = colon + 1; - - trim_whitespace(key); - trim_whitespace(val); - - if (strcmp(key, "name") == 0) { - rule->name = strdup(val); - } else if (strcmp(key, "make") == 0) { - rule->make = strdup(val); - } else if (strcmp(key, "model") == 0) { - rule->model = strdup(val); - } else if (strcmp(key, "serial") == 0) { - rule->serial = strdup(val); - } else if (strcmp(key, "rr") == 0) { - rule->rr = CLAMP_INT(atoi(val), 0, 7); - } else if (strcmp(key, "scale") == 0) { - rule->scale = CLAMP_FLOAT(atof(val), 0.001f, 1000.0f); - } else if (strcmp(key, "x") == 0) { - rule->x = atoi(val); - } else if (strcmp(key, "y") == 0) { - rule->y = atoi(val); - } else if (strcmp(key, "width") == 0) { - rule->width = CLAMP_INT(atoi(val), 1, INT32_MAX); - } else if (strcmp(key, "height") == 0) { - rule->height = CLAMP_INT(atoi(val), 1, INT32_MAX); - } else if (strcmp(key, "refresh") == 0) { - rule->refresh = CLAMP_FLOAT(atof(val), 0.001f, 1000.0f); - } else if (strcmp(key, "vrr") == 0) { - rule->vrr = CLAMP_INT(atoi(val), 0, 1); - } else if (strcmp(key, "custom") == 0) { - rule->custom = CLAMP_INT(atoi(val), 0, 1); - } else { - fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Unknown " - "monitor rule " - "option:\033[1m\033[31m %s\n", - key); - parse_error = true; - } - } - token = strtok(NULL, ","); - } - - if (!rule->name && !rule->make && !rule->model && !rule->serial) { - fprintf(stderr, "\033[1m\033[31m[ERROR]:\033[33m Monitor rule " - "must have at least one of the following " - "options: name, make, model, serial\n"); - return false; - } - - config->monitor_rules_count++; - return !parse_error; } else if (strcmp(key, "tagrule") == 0) { config->tag_rules = realloc(config->tag_rules, (config->tag_rules_count + 1) * sizeof(ConfigTagRule)); if (!config->tag_rules) { - fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Failed to allocate " - "memory for tag rules\n"); - return false; + fprintf(stderr, "Error: Failed to allocate memory for tag rules\n"); + return; } ConfigTagRule *rule = &config->tag_rules[config->tag_rules_count]; @@ -1898,15 +1615,7 @@ bool parse_option(Config *config, char *key, char *value) { rule->id = 0; rule->layout_name = NULL; rule->monitor_name = NULL; - rule->monitor_make = NULL; - rule->monitor_model = NULL; - rule->monitor_serial = NULL; - rule->nmaster = 0; - rule->mfact = 0.0f; - rule->no_render_border = 0; - rule->no_hide = 0; - bool parse_error = false; char *token = strtok(value, ","); while (token != NULL) { char *colon = strchr(token, ':'); @@ -1924,43 +1633,24 @@ bool parse_option(Config *config, char *key, char *value) { rule->layout_name = strdup(val); } else if (strcmp(key, "monitor_name") == 0) { rule->monitor_name = strdup(val); - } else if (strcmp(key, "monitor_make") == 0) { - rule->monitor_make = strdup(val); - } else if (strcmp(key, "monitor_model") == 0) { - rule->monitor_model = strdup(val); - } else if (strcmp(key, "monitor_serial") == 0) { - rule->monitor_serial = strdup(val); } else if (strcmp(key, "no_render_border") == 0) { rule->no_render_border = CLAMP_INT(atoi(val), 0, 1); } else if (strcmp(key, "no_hide") == 0) { rule->no_hide = CLAMP_INT(atoi(val), 0, 1); - } else if (strcmp(key, "nmaster") == 0) { - rule->nmaster = CLAMP_INT(atoi(val), 1, 99); - } else if (strcmp(key, "mfact") == 0) { - rule->mfact = CLAMP_FLOAT(atof(val), 0.1f, 0.9f); - } else { - fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Unknown " - "tag rule " - "option:\033[1m\033[31m %s\n", - key); - parse_error = true; } } token = strtok(NULL, ","); } config->tag_rules_count++; - return !parse_error; } else if (strcmp(key, "layerrule") == 0) { config->layer_rules = realloc(config->layer_rules, (config->layer_rules_count + 1) * sizeof(ConfigLayerRule)); if (!config->layer_rules) { fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Failed to allocate " - "memory for layer rules\n"); - return false; + "Error: Failed to allocate memory for layer rules\n"); + return; } ConfigLayerRule *rule = &config->layer_rules[config->layer_rules_count]; @@ -1974,7 +1664,6 @@ bool parse_option(Config *config, char *key, char *value) { rule->noanim = 0; rule->noshadow = 0; - bool parse_error = false; char *token = strtok(value, ","); while (token != NULL) { char *colon = strchr(token, ':'); @@ -1998,13 +1687,6 @@ bool parse_option(Config *config, char *key, char *value) { rule->noanim = CLAMP_INT(atoi(val), 0, 1); } else if (strcmp(key, "noshadow") == 0) { rule->noshadow = CLAMP_INT(atoi(val), 0, 1); - } else { - fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Unknown " - "layer rule " - "option:\033[1m\033[31m %s\n", - key); - parse_error = true; } } token = strtok(NULL, ","); @@ -2016,16 +1698,14 @@ bool parse_option(Config *config, char *key, char *value) { } config->layer_rules_count++; - return !parse_error; } else if (strcmp(key, "windowrule") == 0) { config->window_rules = realloc(config->window_rules, (config->window_rules_count + 1) * sizeof(ConfigWinRule)); if (!config->window_rules) { fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Failed to allocate " - "memory for window rules\n"); - return false; + "Error: Failed to allocate memory for window rules\n"); + return; } ConfigWinRule *rule = &config->window_rules[config->window_rules_count]; @@ -2034,7 +1714,6 @@ bool parse_option(Config *config, char *key, char *value) { // int32_t rule value, relay to a client property rule->isfloating = -1; rule->isfullscreen = -1; - rule->isfakefullscreen = -1; rule->isnoborder = -1; rule->isnoshadow = -1; rule->isnoradius = -1; @@ -2049,11 +1728,9 @@ bool parse_option(Config *config, char *key, char *value) { rule->ignore_maximize = -1; rule->ignore_minimize = -1; rule->isnosizehint = -1; - rule->indleinhibit_when_focus = -1; rule->isterm = -1; rule->allow_csd = -1; rule->force_maximize = -1; - rule->force_tiled_state = -1; rule->force_tearing = -1; rule->noswallow = -1; rule->noblur = -1; @@ -2084,7 +1761,6 @@ bool parse_option(Config *config, char *key, char *value) { rule->globalkeybinding = (KeyBinding){0}; - bool parse_error = false; char *token = strtok(value, ","); while (token != NULL) { char *colon = strchr(token, ':'); @@ -2160,16 +1836,12 @@ bool parse_option(Config *config, char *key, char *value) { rule->ignore_minimize = atoi(val); } else if (strcmp(key, "isnosizehint") == 0) { rule->isnosizehint = atoi(val); - } else if (strcmp(key, "indleinhibit_when_focus") == 0) { - rule->indleinhibit_when_focus = atoi(val); } else if (strcmp(key, "isterm") == 0) { rule->isterm = atoi(val); } else if (strcmp(key, "allow_csd") == 0) { rule->allow_csd = atoi(val); } else if (strcmp(key, "force_maximize") == 0) { rule->force_maximize = atoi(val); - } else if (strcmp(key, "force_tiled_state") == 0) { - rule->force_tiled_state = atoi(val); } else if (strcmp(key, "force_tearing") == 0) { rule->force_tearing = atoi(val); } else if (strcmp(key, "noswallow") == 0) { @@ -2180,8 +1852,6 @@ bool parse_option(Config *config, char *key, char *value) { rule->scroller_proportion = atof(val); } else if (strcmp(key, "isfullscreen") == 0) { rule->isfullscreen = atoi(val); - } else if (strcmp(key, "isfakefullscreen") == 0) { - rule->isfakefullscreen = atoi(val); } else if (strcmp(key, "globalkeybinding") == 0) { char mod_str[256], keysym_str[256]; sscanf(val, "%255[^-]-%255[a-zA-Z]", mod_str, keysym_str); @@ -2190,37 +1860,86 @@ bool parse_option(Config *config, char *key, char *value) { rule->globalkeybinding.mod = parse_mod(mod_str); rule->globalkeybinding.keysymcode = parse_key(keysym_str, false); - if (rule->globalkeybinding.mod == UINT32_MAX) { - return false; - } - if (rule->globalkeybinding.keysymcode.type == - KEY_TYPE_SYM && - rule->globalkeybinding.keysymcode.keysym == - XKB_KEY_NoSymbol) { - return false; - } - } else { - fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Unknown " - "window rule " - "option:\033[1m\033[31m %s\n", - key); - parse_error = true; } } token = strtok(NULL, ","); } config->window_rules_count++; - return !parse_error; + } else if (strcmp(key, "monitorrule") == 0) { + config->monitor_rules = + realloc(config->monitor_rules, (config->monitor_rules_count + 1) * + sizeof(ConfigMonitorRule)); + if (!config->monitor_rules) { + fprintf(stderr, + "Error: Failed to allocate memory for monitor rules\n"); + return; + } + + ConfigMonitorRule *rule = + &config->monitor_rules[config->monitor_rules_count]; + memset(rule, 0, sizeof(ConfigMonitorRule)); + + // 临时存储每个字段的原始字符串 + char raw_name[256], raw_layout[256]; + char raw_mfact[256], raw_nmaster[256], raw_rr[256]; + char raw_scale[256], raw_x[256], raw_y[256], raw_width[256], + raw_height[256], raw_refresh[256]; + + // 先读取所有字段为字符串 + int32_t parsed = + sscanf(value, + "%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[" + "^,],%255[^,],%255[^,],%255[^,],%255[^,],%255s", + raw_name, raw_mfact, raw_nmaster, raw_layout, raw_rr, + raw_scale, raw_x, raw_y, raw_width, raw_height, raw_refresh); + + if (parsed == 11) { + // 修剪每个字段的空格 + trim_whitespace(raw_name); + trim_whitespace(raw_mfact); + trim_whitespace(raw_nmaster); + trim_whitespace(raw_layout); + trim_whitespace(raw_rr); + trim_whitespace(raw_scale); + trim_whitespace(raw_x); + trim_whitespace(raw_y); + trim_whitespace(raw_width); + trim_whitespace(raw_height); + trim_whitespace(raw_refresh); + + // 转换修剪后的字符串为特定类型 + rule->name = strdup(raw_name); + rule->layout = strdup(raw_layout); + rule->mfact = atof(raw_mfact); + rule->nmaster = atoi(raw_nmaster); + rule->rr = atoi(raw_rr); + rule->scale = atof(raw_scale); + rule->x = atoi(raw_x); + rule->y = atoi(raw_y); + rule->width = atoi(raw_width); + rule->height = atoi(raw_height); + rule->refresh = atof(raw_refresh); + + if (!rule->name || !rule->layout) { + if (rule->name) + free((void *)rule->name); + if (rule->layout) + free((void *)rule->layout); + fprintf(stderr, + "Error: Failed to allocate memory for monitor rule\n"); + return; + } + + config->monitor_rules_count++; + } else { + fprintf(stderr, "Error: Invalid monitorrule format: %s\n", value); + } } else if (strncmp(key, "env", 3) == 0) { char env_type[256], env_value[256]; if (sscanf(value, "%255[^,],%255[^\n]", env_type, env_value) < 2) { - fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Invalid bind format: " - "\033[1m\033[31m%s\n", - value); - return false; + fprintf(stderr, "Error: Invalid bind format: %s\n", value); + return; } trim_whitespace(env_type); trim_whitespace(env_value); @@ -2235,9 +1954,8 @@ bool parse_option(Config *config, char *key, char *value) { free(env->type); free(env->value); free(env); - fprintf(stderr, "\033[1m\033[31m[ERROR]:\033[33m Failed to " - "allocate memory for env\n"); - return false; + fprintf(stderr, "Error: Failed to allocate memory for env\n"); + return; } config->env[config->env_count] = env; @@ -2247,18 +1965,15 @@ bool parse_option(Config *config, char *key, char *value) { char **new_exec = realloc(config->exec, (config->exec_count + 1) * sizeof(char *)); if (!new_exec) { - fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Failed to allocate " - "memory for exec\n"); - return false; + fprintf(stderr, "Error: Failed to allocate memory for exec\n"); + return; } config->exec = new_exec; config->exec[config->exec_count] = strdup(value); if (!config->exec[config->exec_count]) { - fprintf(stderr, "\033[1m\033[31m[ERROR]:\033[33m Failed to " - "duplicate exec string\n"); - return false; + fprintf(stderr, "Error: Failed to duplicate exec string\n"); + return; } config->exec_count++; @@ -2268,19 +1983,15 @@ bool parse_option(Config *config, char *key, char *value) { char **new_exec_once = realloc( config->exec_once, (config->exec_once_count + 1) * sizeof(char *)); if (!new_exec_once) { - fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Failed to allocate " - "memory for exec_once\n"); - return false; + fprintf(stderr, "Error: Failed to allocate memory for exec_once\n"); + return; } config->exec_once = new_exec_once; config->exec_once[config->exec_once_count] = strdup(value); if (!config->exec_once[config->exec_once_count]) { - fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Failed to duplicate " - "exec_once string\n"); - return false; + fprintf(stderr, "Error: Failed to duplicate exec_once string\n"); + return; } config->exec_once_count++; @@ -2291,9 +2002,8 @@ bool parse_option(Config *config, char *key, char *value) { (config->key_bindings_count + 1) * sizeof(KeyBinding)); if (!config->key_bindings) { fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Failed to allocate " - "memory for key bindings\n"); - return false; + "Error: Failed to allocate memory for key bindings\n"); + return; } KeyBinding *binding = &config->key_bindings[config->key_bindings_count]; @@ -2304,16 +2014,12 @@ bool parse_option(Config *config, char *key, char *value) { arg_value3[256] = "0\0", arg_value4[256] = "0\0", arg_value5[256] = "0\0"; if (sscanf(value, - "%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^" - ",],%255[" + "%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[" "^,],%255[^\n]", mod_str, keysym_str, func_name, arg_value, arg_value2, arg_value3, arg_value4, arg_value5) < 3) { - fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Invalid bind format: " - "\033[1m\033[31m%s\n", - value); - return false; + fprintf(stderr, "Error: Invalid bind format: %s\n", value); + return; } trim_whitespace(mod_str); trim_whitespace(keysym_str); @@ -2340,21 +2046,13 @@ bool parse_option(Config *config, char *key, char *value) { binding->keysymcode = parse_key(keysym_str, binding->keysymcode.type == KEY_TYPE_SYM); binding->mod = parse_mod(mod_str); - binding->arg.i = 0; - binding->arg.i2 = 0; - binding->arg.f = 0.0f; - binding->arg.f2 = 0.0f; - binding->arg.ui = 0; - binding->arg.ui2 = 0; binding->arg.v = NULL; binding->arg.v2 = NULL; binding->arg.v3 = NULL; binding->func = parse_func_name(func_name, &binding->arg, arg_value, arg_value2, arg_value3, arg_value4, arg_value5); - if (!binding->func || binding->mod == UINT32_MAX || - (binding->keysymcode.type == KEY_TYPE_SYM && - binding->keysymcode.keysym == XKB_KEY_NoSymbol)) { + if (!binding->func) { if (binding->arg.v) { free(binding->arg.v); binding->arg.v = NULL; @@ -2367,13 +2065,7 @@ bool parse_option(Config *config, char *key, char *value) { free(binding->arg.v3); binding->arg.v3 = NULL; } - if (!binding->func) - fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Unknown " - "dispatch in bind: " - "\033[1m\033[31m%s\n", - func_name); - return false; + fprintf(stderr, "Error: Unknown function in bind: %s\n", func_name); } else { config->key_bindings_count++; } @@ -2384,9 +2076,8 @@ bool parse_option(Config *config, char *key, char *value) { (config->mouse_bindings_count + 1) * sizeof(MouseBinding)); if (!config->mouse_bindings) { fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Failed to allocate " - "memory for mouse bindings\n"); - return false; + "Error: Failed to allocate memory for mouse bindings\n"); + return; } MouseBinding *binding = @@ -2398,17 +2089,12 @@ bool parse_option(Config *config, char *key, char *value) { arg_value3[256] = "0\0", arg_value4[256] = "0\0", arg_value5[256] = "0\0"; if (sscanf(value, - "%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^" - ",],%255[" + "%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[" "^,],%255[^\n]", mod_str, button_str, func_name, arg_value, arg_value2, arg_value3, arg_value4, arg_value5) < 3) { - fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Invalid mousebind " - "format: " - "%s\n", - value); - return false; + fprintf(stderr, "Error: Invalid mousebind format: %s\n", value); + return; } trim_whitespace(mod_str); trim_whitespace(button_str); @@ -2421,31 +2107,13 @@ bool parse_option(Config *config, char *key, char *value) { binding->mod = parse_mod(mod_str); binding->button = parse_button(button_str); - binding->arg.i = 0; - binding->arg.i2 = 0; - binding->arg.f = 0.0f; - binding->arg.f2 = 0.0f; - binding->arg.ui = 0; - binding->arg.ui2 = 0; binding->arg.v = NULL; binding->arg.v2 = NULL; binding->arg.v3 = NULL; - - // TODO: remove this in next version - if (binding->mod == 0 && - (binding->button == BTN_LEFT || binding->button == BTN_RIGHT)) { - fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m \033[31m%s\033[33m can't " - "bind to \033[31m%s\033[33m mod key\n", - button_str, mod_str); - return false; - } - binding->func = parse_func_name(func_name, &binding->arg, arg_value, arg_value2, arg_value3, arg_value4, arg_value5); - if (!binding->func || binding->mod == UINT32_MAX || - binding->button == UINT32_MAX) { + if (!binding->func) { if (binding->arg.v) { free(binding->arg.v); binding->arg.v = NULL; @@ -2458,14 +2126,8 @@ bool parse_option(Config *config, char *key, char *value) { free(binding->arg.v3); binding->arg.v3 = NULL; } - - if (!binding->func) - fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Unknown " - "dispatch in " - "mousebind: \033[1m\033[31m%s\n", - func_name); - return false; + fprintf(stderr, "Error: Unknown function in mousebind: %s\n", + func_name); } else { config->mouse_bindings_count++; } @@ -2475,9 +2137,8 @@ bool parse_option(Config *config, char *key, char *value) { (config->axis_bindings_count + 1) * sizeof(AxisBinding)); if (!config->axis_bindings) { fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Failed to allocate " - "memory for axis bindings\n"); - return false; + "Error: Failed to allocate memory for axis bindings\n"); + return; } AxisBinding *binding = @@ -2489,16 +2150,12 @@ bool parse_option(Config *config, char *key, char *value) { arg_value3[256] = "0\0", arg_value4[256] = "0\0", arg_value5[256] = "0\0"; if (sscanf(value, - "%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^" - ",],%255[" + "%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[" "^,],%255[^\n]", mod_str, dir_str, func_name, arg_value, arg_value2, arg_value3, arg_value4, arg_value5) < 3) { - fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Invalid axisbind " - "format: %s\n", - value); - return false; + fprintf(stderr, "Error: Invalid axisbind format: %s\n", value); + return; } trim_whitespace(mod_str); @@ -2519,7 +2176,7 @@ bool parse_option(Config *config, char *key, char *value) { parse_func_name(func_name, &binding->arg, arg_value, arg_value2, arg_value3, arg_value4, arg_value5); - if (!binding->func || binding->mod == UINT32_MAX) { + if (!binding->func) { if (binding->arg.v) { free(binding->arg.v); binding->arg.v = NULL; @@ -2532,13 +2189,8 @@ bool parse_option(Config *config, char *key, char *value) { free(binding->arg.v3); binding->arg.v3 = NULL; } - if (!binding->func) - fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Unknown " - "dispatch in " - "axisbind: \033[1m\033[31m%s\n", - func_name); - return false; + fprintf(stderr, "Error: Unknown function in axisbind: %s\n", + func_name); } else { config->axis_bindings_count++; } @@ -2549,9 +2201,8 @@ bool parse_option(Config *config, char *key, char *value) { sizeof(SwitchBinding)); if (!config->switch_bindings) { fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Failed to allocate " - "memory for switch bindings\n"); - return false; + "Error: Failed to allocate memory for switch bindings\n"); + return; } SwitchBinding *binding = @@ -2563,16 +2214,12 @@ bool parse_option(Config *config, char *key, char *value) { arg_value3[256] = "0\0", arg_value4[256] = "0\0", arg_value5[256] = "0\0"; if (sscanf(value, - "%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^" - ",],%255[" + "%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[" "^\n]", fold_str, func_name, arg_value, arg_value2, arg_value3, arg_value4, arg_value5) < 3) { - fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Invalid switchbind " - "format: %s\n", - value); - return false; + fprintf(stderr, "Error: Invalid switchbind format: %s\n", value); + return; } trim_whitespace(fold_str); trim_whitespace(func_name); @@ -2600,13 +2247,8 @@ bool parse_option(Config *config, char *key, char *value) { free(binding->arg.v3); binding->arg.v3 = NULL; } - - fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Unknown dispatch in " - "switchbind: " - "\033[1m\033[31m%s\n", + fprintf(stderr, "Error: Unknown function in switchbind: %s\n", func_name); - return false; } else { config->switch_bindings_count++; } @@ -2617,9 +2259,8 @@ bool parse_option(Config *config, char *key, char *value) { (config->gesture_bindings_count + 1) * sizeof(GestureBinding)); if (!config->gesture_bindings) { fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Failed to allocate " - "memory for axis gesturebind\n"); - return false; + "Error: Failed to allocate memory for axis gesturebind\n"); + return; } GestureBinding *binding = @@ -2631,16 +2272,12 @@ bool parse_option(Config *config, char *key, char *value) { arg_value3[256] = "0\0", arg_value4[256] = "0\0", arg_value5[256] = "0\0"; if (sscanf(value, - "%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^" - ",],%255[" + "%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[^,],%255[" "^,],%255[^,],%255[^\n]", mod_str, motion_str, fingers_count_str, func_name, arg_value, arg_value2, arg_value3, arg_value4, arg_value5) < 4) { - fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Invalid gesturebind " - "format: %s\n", - value); - return false; + fprintf(stderr, "Error: Invalid gesturebind format: %s\n", value); + return; } trim_whitespace(mod_str); @@ -2656,12 +2293,6 @@ bool parse_option(Config *config, char *key, char *value) { binding->mod = parse_mod(mod_str); binding->motion = parse_direction(motion_str); binding->fingers_count = atoi(fingers_count_str); - binding->arg.i = 0; - binding->arg.i2 = 0; - binding->arg.f = 0.0f; - binding->arg.f2 = 0.0f; - binding->arg.ui = 0; - binding->arg.ui2 = 0; binding->arg.v = NULL; binding->arg.v2 = NULL; binding->arg.v3 = NULL; @@ -2669,7 +2300,7 @@ bool parse_option(Config *config, char *key, char *value) { parse_func_name(func_name, &binding->arg, arg_value, arg_value2, arg_value3, arg_value4, arg_value5); - if (!binding->func || binding->mod == UINT32_MAX) { + if (!binding->func) { if (binding->arg.v) { free(binding->arg.v); binding->arg.v = NULL; @@ -2682,49 +2313,34 @@ bool parse_option(Config *config, char *key, char *value) { free(binding->arg.v3); binding->arg.v3 = NULL; } - if (!binding->func) - fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Unknown " - "dispatch in " - "axisbind: \033[1m\033[31m%s\n", - func_name); - return false; + fprintf(stderr, "Error: Unknown function in axisbind: %s\n", + func_name); } else { config->gesture_bindings_count++; } - } else if (strncmp(key, "source-optional", 15) == 0) { - parse_config_file(config, value, false); } else if (strncmp(key, "source", 6) == 0) { - parse_config_file(config, value, true); + parse_config_file(config, value); } else { - fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Unknown keyword: " - "\033[1m\033[31m%s\n", - key); - return false; + fprintf(stderr, "Error: Unknown key: %s\n", key); } - - return true; } -bool parse_config_line(Config *config, const char *line) { +void parse_config_line(Config *config, const char *line) { char key[256], value[256]; if (sscanf(line, "%255[^=]=%255[^\n]", key, value) != 2) { - fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m Invalid line format: %s", - line); - return false; + // fprintf(stderr, "Error: Invalid line format: %s\n", line); + return; } // Then trim each part separately trim_whitespace(key); trim_whitespace(value); - return parse_option(config, key, value); + parse_option(config, key, value); } -bool parse_config_file(Config *config, const char *file_path, bool must_exist) { +void parse_config_file(Config *config, const char *file_path) { FILE *file; char full_path[1024]; @@ -2740,10 +2356,8 @@ bool parse_config_file(Config *config, const char *file_path, bool must_exist) { } else { const char *home = getenv("HOME"); if (!home) { - fprintf(stderr, - "\033[1m\033[31m[ERROR]:\033[33m HOME environment " - "variable not set.\n"); - return false; + fprintf(stderr, "Error: HOME environment variable not set.\n"); + return; } snprintf(full_path, sizeof(full_path), "%s/.config/mango/%s", home, file_path + 1); @@ -2756,9 +2370,8 @@ bool parse_config_file(Config *config, const char *file_path, bool must_exist) { const char *home = getenv("HOME"); if (!home) { - fprintf(stderr, "\033[1m\033[31m[ERROR]:\033[33m HOME environment " - "variable not set.\n"); - return false; + fprintf(stderr, "Error: HOME environment variable not set.\n"); + return; } snprintf(full_path, sizeof(full_path), "%s%s", home, file_path + 1); file = fopen(full_path, "r"); @@ -2769,39 +2382,19 @@ bool parse_config_file(Config *config, const char *file_path, bool must_exist) { } if (!file) { - if (must_exist) { - fprintf(stderr, - "\033[1;31m\033[1;33m[ERROR]:\033[0m Failed to open " - "config file: %s\n", - file_path); - return false; - } else { - return true; - } + perror("Error opening file"); + return; } char line[512]; - bool parse_correct = true; - bool parse_line_correct = true; - uint32_t line_count = 0; while (fgets(line, sizeof(line), file)) { - line_count++; if (line[0] == '#' || line[0] == '\n') { continue; } - parse_line_correct = parse_config_line(config, line); - if (!parse_line_correct) { - parse_correct = false; - fprintf(stderr, - "\033[1;31m╰─\033[1;33m[Index]\033[0m " - "\033[1;36m%s\033[0m:\033[1;35m%d\033[0m\n" - " \033[1;36m╰─\033[0;33m%s\033[0m\n\n", - file_path, line_count, line); - } + parse_config_line(config, line); } fclose(file); - return parse_correct; } void free_circle_layout(Config *config) { @@ -2884,6 +2477,18 @@ void free_config(void) { config.window_rules_count = 0; } + // 释放 monitor_rules + if (config.monitor_rules) { + for (int32_t i = 0; i < config.monitor_rules_count; i++) { + ConfigMonitorRule *rule = &config.monitor_rules[i]; + free((void *)rule->name); + free((void *)rule->layout); + } + free(config.monitor_rules); + config.monitor_rules = NULL; + config.monitor_rules_count = 0; + } + // 释放 key_bindings if (config.key_bindings) { for (i = 0; i < config.key_bindings_count; i++) { @@ -2996,35 +2601,12 @@ void free_config(void) { free((void *)config.tag_rules[i].layout_name); if (config.tag_rules[i].monitor_name) free((void *)config.tag_rules[i].monitor_name); - if (config.tag_rules[i].monitor_make) - free((void *)config.tag_rules[i].monitor_make); - if (config.tag_rules[i].monitor_model) - free((void *)config.tag_rules[i].monitor_model); - if (config.tag_rules[i].monitor_serial) - free((void *)config.tag_rules[i].monitor_serial); } free(config.tag_rules); config.tag_rules = NULL; config.tag_rules_count = 0; } - // 释放 monitor_rules - if (config.monitor_rules) { - for (int32_t i = 0; i < config.monitor_rules_count; i++) { - if (config.monitor_rules[i].name) - free((void *)config.monitor_rules[i].name); - if (config.monitor_rules[i].make) - free((void *)config.monitor_rules[i].make); - if (config.monitor_rules[i].model) - free((void *)config.monitor_rules[i].model); - if (config.monitor_rules[i].serial) - free((void *)config.monitor_rules[i].serial); - } - free(config.monitor_rules); - config.monitor_rules = NULL; - config.monitor_rules_count = 0; - } - // 释放 layer_rules if (config.layer_rules) { for (int32_t i = 0; i < config.layer_rules_count; i++) { @@ -3099,347 +2681,347 @@ void free_config(void) { } void override_config(void) { - 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 = + // 动画启用 + 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 = CLAMP_FLOAT(config.fadeout_begin_opacity, 0.0f, 1.0f); - config.animation_duration_move = + + // 打开关闭动画类型 + 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 = CLAMP_INT(config.animation_duration_move, 1, 50000); - config.animation_duration_open = + animation_duration_open = CLAMP_INT(config.animation_duration_open, 1, 50000); - config.animation_duration_tag = - CLAMP_INT(config.animation_duration_tag, 1, 50000); - config.animation_duration_close = + animation_duration_tag = CLAMP_INT(config.animation_duration_tag, 1, 50000); + animation_duration_close = CLAMP_INT(config.animation_duration_close, 1, 50000); - config.animation_duration_focus = + animation_duration_focus = CLAMP_INT(config.animation_duration_focus, 1, 50000); - config.scroller_default_proportion = + + // 滚动布局设置 + scroller_default_proportion = CLAMP_FLOAT(config.scroller_default_proportion, 0.1f, 1.0f); - config.scroller_default_proportion_single = + scroller_default_proportion_single = CLAMP_FLOAT(config.scroller_default_proportion_single, 0.1f, 1.0f); - config.scroller_ignore_proportion_single = + scroller_ignore_proportion_single = CLAMP_INT(config.scroller_ignore_proportion_single, 0, 1); - 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); - config.edge_scroller_pointer_focus = + scroller_focus_center = CLAMP_INT(config.scroller_focus_center, 0, 1); + scroller_prefer_center = CLAMP_INT(config.scroller_prefer_center, 0, 1); + edge_scroller_pointer_focus = CLAMP_INT(config.edge_scroller_pointer_focus, 0, 1); - 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); - config.drag_floating_refresh_interval = - CLAMP_FLOAT(config.drag_floating_refresh_interval, 0.0f, 1000.0f); - 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 = + 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); + 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); + adaptive_sync = CLAMP_INT(config.adaptive_sync, 0, 1); + 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 = CLAMP_INT(config.axis_bind_apply_timeout, 0, 1000); - config.focus_on_activate = CLAMP_INT(config.focus_on_activate, 0, 1); - config.idleinhibit_ignore_visible = + focus_on_activate = CLAMP_INT(config.focus_on_activate, 0, 1); + idleinhibit_ignore_visible = CLAMP_INT(config.idleinhibit_ignore_visible, 0, 1); - 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 = + sloppyfocus = CLAMP_INT(config.sloppyfocus, 0, 1); + warpcursor = CLAMP_INT(config.warpcursor, 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 = CLAMP_INT(config.trackpad_natural_scrolling, 0, 1); - 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 = + 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 = CLAMP_FLOAT(config.scratchpad_width_ratio, 0.1f, 1.0f); - config.scratchpad_height_ratio = + scratchpad_height_ratio = CLAMP_FLOAT(config.scratchpad_height_ratio, 0.1f, 1.0f); - 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); + 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)); } void set_value_default() { - 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; + /* 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.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; + /* 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.log_level = WLR_ERROR; - config.numlockon = 0; - config.capslock = 0; + config.numlockon = numlockon; // 是否打开右边小键盘 - 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.ov_tab_mode = ov_tab_mode; // alt tab切换模式 + config.hotarea_size = hotarea_size; // 热区大小,10x10 + 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.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.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.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.adaptive_sync = adaptive_sync; + 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.idleinhibit_ignore_visible = 0; + config.idleinhibit_ignore_visible = + idleinhibit_ignore_visible; /* 1 means idle inhibitors will + disable idle tracking even if it's + surface isn't visible + */ - config.borderpx = 4; - config.overviewgappi = 5; - config.overviewgappo = 30; - config.cursor_hide_timeout = 0; + config.borderpx = borderpx; + config.overviewgappi = overviewgappi; /* overview时 窗口与边缘 缝隙大小 */ + config.overviewgappo = overviewgappo; /* overview时 窗口与窗口 缝隙大小 */ + config.cursor_hide_timeout = cursor_hide_timeout; - config.warpcursor = 1; - config.drag_corner = 3; - config.drag_warp_cursor = 1; + config.warpcursor = warpcursor; /* Warp cursor to focused client */ - config.repeat_rate = 25; - config.repeat_delay = 600; + config.repeat_rate = repeat_rate; + config.repeat_delay = repeat_delay; - 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; + /* 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.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; + 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.shadowscolor[0] = 0.0f; - config.shadowscolor[1] = 0.0f; - config.shadowscolor[2] = 0.0f; - config.shadowscolor[3] = 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.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; + 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)); } void set_default_key_bindings(Config *config) { @@ -3469,20 +3051,19 @@ void set_default_key_bindings(Config *config) { config->key_bindings_count += default_key_bindings_count; } -bool parse_config(void) { +void parse_config(void) { char filename[1024]; free_config(); + // 重置config结构体,确保所有指针初始化为NULL memset(&config, 0, sizeof(config)); - - // 重新将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; + 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)); // 初始化动态数组的指针为NULL,避免野指针 config.window_rules = NULL; @@ -3523,7 +3104,7 @@ bool parse_config(void) { const char *homedir = getenv("HOME"); if (!homedir) { // 如果获取失败,则无法继续 - return false; + return; } // 构建日志文件路径 snprintf(filename, sizeof(filename), "%s/.config/mango/config.conf", @@ -3537,16 +3118,14 @@ bool parse_config(void) { } } - bool parse_correct = true; set_value_default(); - parse_correct = parse_config_file(&config, filename, true); + parse_config_file(&config, filename); set_default_key_bindings(&config); override_config(); - return parse_correct; } void reset_blur_params(void) { - if (config.blur) { + if (blur) { Monitor *m = NULL; wl_list_for_each(m, &mons, link) { if (m->blur != NULL) { @@ -3556,9 +3135,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, 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); + scene, blur_params.num_passes, blur_params.radius, + blur_params.noise, blur_params.brightness, blur_params.contrast, + blur_params.saturation); } } else { Monitor *m = NULL; @@ -3575,59 +3154,70 @@ void reset_blur_params(void) { void reapply_monitor_rules(void) { ConfigMonitorRule *mr; Monitor *m = NULL; - int32_t ji, vrr, custom; - int32_t mx, my; + int32_t ji, jk; struct wlr_output_state state; + struct wlr_output_mode *internal_mode = NULL; + wlr_output_state_init(&state); wl_list_for_each(m, &mons, link) { - if (!m->wlr_output->enabled) + if (!m->wlr_output->enabled) { continue; - - wlr_output_state_init(&state); + } for (ji = 0; ji < config.monitor_rules_count; ji++) { if (config.monitor_rules_count < 1) break; mr = &config.monitor_rules[ji]; + if (!mr->name || regex_match(mr->name, m->wlr_output->name)) { - if (monitor_matches_rule(m, mr)) { - mx = mr->x == INT32_MAX ? m->m.x : mr->x; - my = mr->y == INT32_MAX ? m->m.y : mr->y; - vrr = mr->vrr >= 0 ? mr->vrr : 0; - custom = mr->custom >= 0 ? mr->custom : 0; + m->mfact = mr->mfact; + m->nmaster = mr->nmaster; + m->m.x = mr->x; + m->m.y = mr->y; - (void)apply_rule_to_state(m, mr, &state, vrr, custom); - wlr_output_layout_add(output_layout, m->wlr_output, mx, my); - wlr_output_commit_state(m->wlr_output, &state); - break; + if (mr->layout) { + for (jk = 0; jk < LENGTH(layouts); jk++) { + if (strcmp(layouts[jk].name, mr->layout) == 0) { + m->lt = &layouts[jk]; + } + } + } + + if (mr->width > 0 && mr->height > 0 && mr->refresh > 0) { + internal_mode = get_nearest_output_mode( + m->wlr_output, mr->width, mr->height, mr->refresh); + if (internal_mode) { + wlr_output_state_set_mode(&state, internal_mode); + } else if (wlr_output_is_headless(m->wlr_output)) { + wlr_output_state_set_custom_mode( + &state, mr->width, mr->height, + (int32_t)roundf(mr->refresh * 1000)); + } + } + + wlr_output_state_set_scale(&state, mr->scale); + wlr_output_state_set_transform(&state, mr->rr); + wlr_output_layout_add(output_layout, m->wlr_output, mr->x, + mr->y); } } + if (adaptive_sync) { + enable_adaptive_sync(m, &state); + } + + wlr_output_commit_state(m->wlr_output, &state); wlr_output_state_finish(&state); - } - 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); + updatemons(NULL, NULL); } } void reapply_cursor_style(void) { - if (hide_cursor_source) { - wl_event_source_timer_update(hide_cursor_source, 0); - wl_event_source_remove(hide_cursor_source); - hide_cursor_source = NULL; + if (hide_source) { + wl_event_source_timer_update(hide_source, 0); + wl_event_source_remove(hide_source); + hide_source = NULL; } wlr_cursor_unset_image(cursor); @@ -3639,10 +3229,7 @@ void reapply_cursor_style(void) { cursor_mgr = NULL; } - set_xcursor_env(); - - cursor_mgr = - wlr_xcursor_manager_create(config.cursor_theme, config.cursor_size); + cursor_mgr = wlr_xcursor_manager_create(config.cursor_theme, cursor_size); Monitor *m = NULL; wl_list_for_each(m, &mons, link) { @@ -3651,20 +3238,15 @@ void reapply_cursor_style(void) { wlr_cursor_set_xcursor(cursor, cursor_mgr, "left_ptr"); - hide_cursor_source = wl_event_loop_add_timer(wl_display_get_event_loop(dpy), - hidecursor, cursor); + hide_source = wl_event_loop_add_timer(wl_display_get_event_loop(dpy), + hidecursor, cursor); if (cursor_hidden) { wlr_cursor_unset_image(cursor); } else { - wl_event_source_timer_update(hide_cursor_source, - config.cursor_hide_timeout * 1000); + wl_event_source_timer_update(hide_source, cursor_hide_timeout * 1000); } } -void reapply_rootbg(void) { - wlr_scene_rect_set_color(root_bg, config.rootcolor); -} - void reapply_border(void) { Client *c = NULL; @@ -3672,7 +3254,7 @@ void reapply_border(void) { wl_list_for_each(c, &clients, link) { if (c && !c->iskilling) { if (!c->isnoborder && !c->isfullscreen) { - c->bw = config.borderpx; + c->bw = borderpx; } } } @@ -3685,7 +3267,7 @@ void reapply_keyboard(void) { continue; } wlr_keyboard_set_repeat_info((struct wlr_keyboard *)id->device_data, - config.repeat_rate, config.repeat_delay); + repeat_rate, repeat_delay); } } @@ -3714,12 +3296,12 @@ void reapply_master(void) { if (!m->wlr_output->enabled) { continue; } - 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; + m->pertag->nmasters[i] = default_nmaster; + m->pertag->mfacts[i] = default_mfact; + m->gappih = gappih; + m->gappiv = gappiv; + m->gappoh = gappoh; + m->gappov = gappov; } } } @@ -3727,48 +3309,14 @@ void reapply_master(void) { void parse_tagrule(Monitor *m) { int32_t i, jk; ConfigTagRule tr; - Client *c = NULL; - bool match_rule = false; - - for (i = 0; i <= LENGTH(tags); i++) { - m->pertag->nmasters[i] = config.default_nmaster; - m->pertag->mfacts[i] = config.default_mfact; - } for (i = 0; i < config.tag_rules_count; i++) { tr = config.tag_rules[i]; - match_rule = true; - - if (tr.monitor_name != NULL) { - if (!regex_match(tr.monitor_name, m->wlr_output->name)) { - match_rule = false; - } - } - - if (tr.monitor_make != NULL) { - if (m->wlr_output->make == NULL || - strcmp(tr.monitor_make, m->wlr_output->make) != 0) { - match_rule = false; - } - } - - if (tr.monitor_model != NULL) { - if (m->wlr_output->model == NULL || - strcmp(tr.monitor_model, m->wlr_output->model) != 0) { - match_rule = false; - } - } - - if (tr.monitor_serial != NULL) { - if (m->wlr_output->serial == NULL || - strcmp(tr.monitor_serial, m->wlr_output->serial) != 0) { - match_rule = false; - } - } - - if (config.tag_rules_count > 0 && match_rule) { + if (config.tag_rules_count > 0 && + (!tr.monitor_name || + regex_match(tr.monitor_name, m->wlr_output->name))) { for (jk = 0; jk < LENGTH(layouts); jk++) { if (tr.layout_name && @@ -3777,23 +3325,7 @@ void parse_tagrule(Monitor *m) { } } - if (tr.no_hide >= 0) - m->pertag->no_hide[tr.id] = tr.no_hide; - if (tr.nmaster >= 1) - m->pertag->nmasters[tr.id] = tr.nmaster; - if (tr.mfact > 0.0f) - m->pertag->mfacts[tr.id] = tr.mfact; - if (tr.no_render_border >= 0) - m->pertag->no_render_border[tr.id] = tr.no_render_border; - } - } - - for (i = 1; i <= LENGTH(tags); i++) { - wl_list_for_each(c, &clients, link) { - if ((c->tags & (1 << (i - 1)) & TAGMASK) && ISTILED(c)) { - if (m->pertag->mfacts[i] > 0.0f) - c->master_mfact_per = m->pertag->mfacts[i]; - } + m->pertag->no_hide[tr.id] = tr.no_hide; } } } @@ -3818,7 +3350,6 @@ void reset_option(void) { reapply_cursor_style(); reapply_border(); - reapply_rootbg(); reapply_keyboard(); reapply_pointer(); reapply_master(); diff --git a/src/config/preset.h b/src/config/preset.h index 6952518e..6f3cd891 100644 --- a/src/config/preset.h +++ b/src/config/preset.h @@ -1,9 +1,128 @@ -#define MODKEY WLR_MODIFIER_ALT +// TODO: remove this file in the future, replace all global variables with +// config.xxx -static const char *tags[] = { - "1", "2", "3", "4", "5", "6", "7", "8", "9", -}; +/* speedie's mango config */ +#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 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 = 0; +int32_t scroller_focus_center = 0; +int32_t scroller_prefer_center = 0; +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; /* Warp cursor to focused client */ +int32_t xwayland_persistence = 1; /* xwayland persistence */ +int32_t syncobj_enable = 0; +int32_t adaptive_sync = 0; +int32_t allow_lock_transparent = 0; +double drag_refresh_interval = 16.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, @@ -11,3 +130,107 @@ 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_declare.h b/src/dispatch/bind_declare.h index 7dced532..22ef6123 100644 --- a/src/dispatch/bind_declare.h +++ b/src/dispatch/bind_declare.h @@ -69,4 +69,4 @@ int32_t setoption(const Arg *arg); int32_t disable_monitor(const Arg *arg); int32_t enable_monitor(const Arg *arg); int32_t toggle_monitor(const Arg *arg); -int32_t scroller_stack(const Arg *arg); +int32_t scroller_stack(const Arg *arg); \ No newline at end of file diff --git a/src/dispatch/bind_define.h b/src/dispatch/bind_define.h index 449adf3b..95d365c8 100644 --- a/src/dispatch/bind_define.h +++ b/src/dispatch/bind_define.h @@ -1,9 +1,8 @@ int32_t bind_to_view(const Arg *arg) { - if (!selmon) - return 0; + uint32_t target = arg->ui; - if (config.view_current_to_back && selmon->pertag->curtag && + if (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 +10,13 @@ int32_t bind_to_view(const Arg *arg) { target = 0; } - if (!config.view_current_to_back && + if (!view_current_to_back && (target & TAGMASK) == (selmon->tagset[selmon->seltags])) { return 0; } if ((int32_t)target == INT_MIN && selmon->pertag->curtag == 0) { - if (config.view_current_to_back && selmon->pertag->prevtag) + if (view_current_to_back && selmon->pertag->prevtag) target = 1 << (selmon->pertag->prevtag - 1); else target = 0; @@ -96,13 +95,11 @@ int32_t destroy_all_virtual_output(const Arg *arg) { } int32_t defaultgaps(const Arg *arg) { - setgaps(config.gappoh, config.gappov, config.gappih, config.gappiv); + setgaps(gappoh, gappov, gappih, gappiv); return 0; } int32_t exchange_client(const Arg *arg) { - if (!selmon) - return 0; Client *c = selmon->sel; if (!c || c->isfloating) return 0; @@ -110,16 +107,11 @@ int32_t exchange_client(const Arg *arg) { if ((c->isfullscreen || c->ismaximizescreen) && !is_scroller_layout(c->mon)) return 0; - Client *tc = direction_select(arg); - tc = get_focused_stack_client(tc); - exchange_two_client(c, tc); + exchange_two_client(c, direction_select(arg)); return 0; } int32_t exchange_stack_client(const Arg *arg) { - if (!selmon) - return 0; - Client *c = selmon->sel; Client *tc = NULL; if (!c || c->isfloating || c->isfullscreen || c->ismaximizescreen) @@ -140,7 +132,7 @@ int32_t focusdir(const Arg *arg) { c = get_focused_stack_client(c); if (c) { focusclient(c, 1); - if (config.warpcursor) + if (warpcursor) warp_cursor(c); } else { if (config.focus_cross_tag) { @@ -196,7 +188,7 @@ int32_t focuslast(const Arg *arg) { } int32_t toggle_trackpad_enable(const Arg *arg) { - config.disable_trackpad = !config.disable_trackpad; + disable_trackpad = !disable_trackpad; return 0; } @@ -212,7 +204,7 @@ int32_t focusmon(const Arg *arg) { if (!m->wlr_output->enabled) { continue; } - if (match_monitor_spec(arg->v, m)) { + if (regex_match(arg->v, m->wlr_output->name)) { tm = m; break; } @@ -225,7 +217,7 @@ int32_t focusmon(const Arg *arg) { return 0; selmon = tm; - if (config.warpcursor) { + if (warpcursor) { warp_cursor_to_selmon(selmon); } c = focustop(selmon); @@ -258,7 +250,7 @@ int32_t focusstack(const Arg *arg) { return 0; focusclient(tc, 1); - if (config.warpcursor) + if (warpcursor) warp_cursor(tc); return 0; } @@ -273,56 +265,42 @@ int32_t incnmaster(const Arg *arg) { } int32_t incgaps(const Arg *arg) { - if (!selmon) - return 0; setgaps(selmon->gappoh + arg->i, selmon->gappov + arg->i, selmon->gappih + arg->i, selmon->gappiv + arg->i); return 0; } int32_t incigaps(const Arg *arg) { - if (!selmon) - return 0; setgaps(selmon->gappoh, selmon->gappov, selmon->gappih + arg->i, selmon->gappiv + arg->i); return 0; } int32_t incogaps(const Arg *arg) { - if (!selmon) - return 0; setgaps(selmon->gappoh + arg->i, selmon->gappov + arg->i, selmon->gappih, selmon->gappiv); return 0; } int32_t incihgaps(const Arg *arg) { - if (!selmon) - return 0; setgaps(selmon->gappoh, selmon->gappov, selmon->gappih + arg->i, selmon->gappiv); return 0; } int32_t incivgaps(const Arg *arg) { - if (!selmon) - return 0; setgaps(selmon->gappoh, selmon->gappov, selmon->gappih, selmon->gappiv + arg->i); return 0; } int32_t incohgaps(const Arg *arg) { - if (!selmon) - return 0; setgaps(selmon->gappoh + arg->i, selmon->gappov, selmon->gappih, selmon->gappiv); return 0; } int32_t incovgaps(const Arg *arg) { - if (!selmon) - return 0; setgaps(selmon->gappoh, selmon->gappov + arg->i, selmon->gappih, selmon->gappiv); return 0; @@ -352,8 +330,6 @@ int32_t setmfact(const Arg *arg) { int32_t killclient(const Arg *arg) { Client *c = NULL; - if (!selmon) - return 0; c = selmon->sel; if (c) { pending_kill_client(c); @@ -362,9 +338,6 @@ int32_t killclient(const Arg *arg) { } int32_t moveresize(const Arg *arg) { - const char *cursors[] = {"nw-resize", "ne-resize", "sw-resize", - "se-resize"}; - if (cursor_mode != CurNormal && cursor_mode != CurPressed) return 0; xytonode(cursor->x, cursor->y, NULL, &grabc, NULL, NULL, NULL); @@ -390,29 +363,10 @@ 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 = config.drag_corner; - grabcx = (int)round(cursor->x); - grabcy = (int)round(cursor->y); - if (rzcorner == 4) - /* identify the closest corner index */ - rzcorner = (grabcx - grabc->geom.x < - grabc->geom.x + grabc->geom.width - grabcx - ? 0 - : 1) + - (grabcy - grabc->geom.y < - grabc->geom.y + grabc->geom.height - grabcy - ? 0 - : 2); - - 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 - : grabc->geom.y; - wlr_cursor_warp_closest(cursor, NULL, grabcx, grabcy); - } - - wlr_cursor_set_xcursor(cursor, cursor_mgr, cursors[rzcorner]); + wlr_cursor_warp_closest(cursor, NULL, + grabc->geom.x + grabc->geom.width, + grabc->geom.y + grabc->geom.height); + wlr_cursor_set_xcursor(cursor, cursor_mgr, "bottom_right_corner"); } else { wlr_cursor_set_xcursor(cursor, cursor_mgr, "grab"); } @@ -423,8 +377,6 @@ int32_t moveresize(const Arg *arg) { int32_t movewin(const Arg *arg) { Client *c = NULL; - if (!selmon) - return 0; c = selmon->sel; if (!c || c->isfullscreen) return 0; @@ -468,17 +420,15 @@ int32_t quit(const Arg *arg) { int32_t resizewin(const Arg *arg) { Client *c = NULL; - if (!selmon) - return 0; c = selmon->sel; int32_t offsetx = 0, offsety = 0; if (!c || c->isfullscreen || c->ismaximizescreen) return 0; - int32_t animations_state_backup = config.animations; + int32_t animations_state_backup = animations; if (!c->isfloating) - config.animations = 0; + animations = 0; if (ISTILED(c)) { switch (arg->ui) { @@ -505,7 +455,7 @@ int32_t resizewin(const Arg *arg) { break; } resize_tile_client(c, false, offsetx, offsety, 0); - config.animations = animations_state_backup; + animations = animations_state_backup; return 0; } @@ -536,7 +486,7 @@ int32_t resizewin(const Arg *arg) { c->iscustomsize = 1; c->float_geom = c->geom; resize(c, c->geom, 0); - config.animations = animations_state_backup; + animations = animations_state_backup; return 0; } @@ -574,8 +524,6 @@ int32_t restore_minimized(const Arg *arg) { int32_t setlayout(const Arg *arg) { int32_t jk; - if (!selmon) - return 0; for (jk = 0; jk < LENGTH(layouts); jk++) { if (strcmp(layouts[jk].name, arg->v) == 0) { @@ -601,14 +549,12 @@ int32_t setkeymode(const Arg *arg) { } int32_t set_proportion(const Arg *arg) { - if (!selmon) - return 0; if (selmon->isoverview || !is_scroller_layout(selmon)) return 0; if (selmon->visible_tiling_clients == 1 && - !config.scroller_ignore_proportion_single) + !scroller_ignore_proportion_single) return 0; Client *tc = selmon->sel; @@ -616,7 +562,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 * config.scroller_structs - config.gappih; + selmon->w.width - 2 * scroller_structs - gappih; tc->scroller_proportion = arg->f; tc->geom.width = max_client_width * arg->f; arrange(selmon, false, false); @@ -628,8 +574,6 @@ int32_t smartmovewin(const Arg *arg) { Client *c = NULL, *tc = NULL; int32_t nx, ny; int32_t buttom, top, left, right, tar; - if (!selmon) - return 0; c = selmon->sel; if (!c || c->isfullscreen) return 0; @@ -650,7 +594,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 + config.gappiv; + buttom = tc->geom.y + tc->geom.height + gappiv; if (top > buttom && ny < buttom) { tar = MAX(tar, buttom); }; @@ -670,7 +614,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 - config.gappiv; + top = tc->geom.y - gappiv; if (buttom < top && (ny + c->geom.height) > top) { tar = MIN(tar, top - c->geom.height); }; @@ -690,7 +634,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 + config.gappih; + right = tc->geom.x + tc->geom.width + gappih; if (left > right && nx < right) { tar = MAX(tar, right); }; @@ -709,7 +653,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 - config.gappih; + left = tc->geom.x - gappih; if (right < left && (nx + c->geom.width) > left) { tar = MIN(tar, left - c->geom.width); }; @@ -731,8 +675,6 @@ int32_t smartresizewin(const Arg *arg) { Client *c = NULL, *tc = NULL; int32_t nw, nh; int32_t buttom, top, left, right, tar; - if (!selmon) - return 0; c = selmon->sel; if (!c || c->isfullscreen) return 0; @@ -757,14 +699,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 - config.gappiv; + top = tc->geom.y - 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 + config.gappov > selmon->w.y + selmon->w.height) - nh = selmon->w.y + selmon->w.height - c->geom.y - config.gappov; + if (c->geom.y + nh + gappov > selmon->w.y + selmon->w.height) + nh = selmon->w.y + selmon->w.height - c->geom.y - gappov; break; case LEFT: nw -= selmon->w.width / 16; @@ -780,15 +722,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 - config.gappih; + left = tc->geom.x - 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 + config.gappoh > selmon->w.x + selmon->w.width) - nw = selmon->w.x + selmon->w.width - c->geom.x - config.gappoh; + if (c->geom.x + nw + gappoh > selmon->w.x + selmon->w.width) + nw = selmon->w.x + selmon->w.width - c->geom.x - gappoh; break; } @@ -801,8 +743,6 @@ int32_t smartresizewin(const Arg *arg) { int32_t centerwin(const Arg *arg) { Client *c = NULL; - if (!selmon) - return 0; c = selmon->sel; if (!c || c->isfullscreen || c->ismaximizescreen) @@ -850,7 +790,7 @@ int32_t spawn_shell(const Arg *arg) { execlp("bash", "bash", "-c", arg->v, (char *)NULL); // if execlp fails, we should not reach here - wlr_log(WLR_DEBUG, + wlr_log(WLR_ERROR, "mango: failed to execute command '%s' with shell: %s\n", arg->v, strerror(errno)); _exit(EXIT_FAILURE); @@ -891,7 +831,7 @@ int32_t spawn(const Arg *arg) { execvp(argv[0], argv); // 4. execvp 失败时:打印错误并直接退出(避免 coredump) - wlr_log(WLR_DEBUG, "mango: execvp '%s' failed: %s\n", argv[0], + wlr_log(WLR_ERROR, "mango: execvp '%s' failed: %s\n", argv[0], strerror(errno)); _exit(EXIT_FAILURE); // 使用 _exit 避免缓冲区刷新等操作 } @@ -938,20 +878,16 @@ int32_t switch_keyboard_layout(const Arg *arg) { wlr_log(WLR_INFO, "Only one layout available"); return 0; } - - xkb_layout_index_t next = 0; - if (arg->i > 0 && arg->i <= num_layouts) { - next = arg->i - 1; - } else { - next = (current + 1) % num_layouts; - } + xkb_layout_index_t next = (current + 1) % num_layouts; // 6. 应用新 keymap uint32_t depressed = keyboard->modifiers.depressed; uint32_t latched = keyboard->modifiers.latched; uint32_t locked = keyboard->modifiers.locked; + wlr_keyboard_set_keymap(keyboard, keyboard->keymap); wlr_keyboard_notify_modifiers(keyboard, depressed, latched, locked, next); + keyboard->modifiers.group = 0; // 7. 更新 seat wlr_seat_set_keyboard(seat, keyboard); @@ -965,7 +901,10 @@ int32_t switch_keyboard_layout(const Arg *arg) { struct wlr_keyboard *tkb = (struct wlr_keyboard *)id->device_data; + wlr_keyboard_set_keymap(tkb, keyboard->keymap); wlr_keyboard_notify_modifiers(tkb, depressed, latched, locked, next); + tkb->modifiers.group = 0; + // 7. 更新 seat wlr_seat_set_keyboard(seat, tkb); wlr_seat_keyboard_notify_modifiers(seat, &tkb->modifiers); @@ -981,9 +920,6 @@ int32_t switch_layout(const Arg *arg) { char *target_layout_name = NULL; uint32_t len; - if (!selmon) - return 0; - if (config.circle_layout_count != 0) { for (jk = 0; jk < config.circle_layout_count; jk++) { @@ -1035,8 +971,6 @@ int32_t switch_layout(const Arg *arg) { int32_t switch_proportion_preset(const Arg *arg) { float target_proportion = 0; - if (!selmon) - return 0; if (config.scroller_proportion_preset_count == 0) { return 0; @@ -1046,7 +980,7 @@ int32_t switch_proportion_preset(const Arg *arg) { return 0; if (selmon->visible_tiling_clients == 1 && - !config.scroller_ignore_proportion_single) + !scroller_ignore_proportion_single) return 0; Client *tc = selmon->sel; @@ -1056,28 +990,13 @@ int32_t switch_proportion_preset(const Arg *arg) { for (int32_t i = 0; i < config.scroller_proportion_preset_count; i++) { if (config.scroller_proportion_preset[i] == tc->scroller_proportion) { - - if (arg->i == NEXT) { - if (i == config.scroller_proportion_preset_count - 1) { - target_proportion = - config.scroller_proportion_preset[0]; - break; - } else { - target_proportion = - config.scroller_proportion_preset[i + 1]; - break; - } + if (i == config.scroller_proportion_preset_count - 1) { + target_proportion = config.scroller_proportion_preset[0]; + break; } else { - if (i == 0) { - target_proportion = - config.scroller_proportion_preset - [config.scroller_proportion_preset_count - 1]; - break; - } else { - target_proportion = - config.scroller_proportion_preset[i - 1]; - break; - } + target_proportion = + config.scroller_proportion_preset[i + 1]; + break; } } } @@ -1087,7 +1006,7 @@ int32_t switch_proportion_preset(const Arg *arg) { } uint32_t max_client_width = - selmon->w.width - 2 * config.scroller_structs - config.gappih; + selmon->w.width - 2 * scroller_structs - gappih; tc->scroller_proportion = target_proportion; tc->geom.width = max_client_width * target_proportion; arrange(selmon, false, false); @@ -1096,8 +1015,6 @@ int32_t switch_proportion_preset(const Arg *arg) { } int32_t tag(const Arg *arg) { - if (!selmon) - return 0; Client *target_client = selmon->sel; tag_client(arg, target_client); return 0; @@ -1105,8 +1022,6 @@ int32_t tag(const Arg *arg) { int32_t tagmon(const Arg *arg) { Monitor *m = NULL, *cm = NULL; - if (!selmon) - return 0; Client *c = focustop(selmon); if (!c) @@ -1119,7 +1034,7 @@ int32_t tagmon(const Arg *arg) { if (!cm->wlr_output->enabled) { continue; } - if (match_monitor_spec(arg->v, cm)) { + if (regex_match(arg->v, cm->wlr_output->name)) { m = cm; break; } @@ -1170,7 +1085,7 @@ int32_t tagmon(const Arg *arg) { focusclient(c, 1); arrange(selmon, false, false); } - if (config.warpcursor) { + if (warpcursor) { warp_cursor_to_selmon(c->mon); } return 0; @@ -1198,9 +1113,6 @@ int32_t tagsilent(const Arg *arg) { } int32_t tagtoleft(const Arg *arg) { - if (!selmon) - return 0; - if (selmon->sel != NULL && __builtin_popcount(selmon->tagset[selmon->seltags] & TAGMASK) == 1 && selmon->tagset[selmon->seltags] > 1) { @@ -1210,9 +1122,6 @@ int32_t tagtoleft(const Arg *arg) { } int32_t tagtoright(const Arg *arg) { - if (!selmon) - return 0; - if (selmon->sel != NULL && __builtin_popcount(selmon->tagset[selmon->seltags] & TAGMASK) == 1 && selmon->tagset[selmon->seltags] & (TAGMASK >> 1)) { @@ -1241,8 +1150,6 @@ int32_t toggle_named_scratchpad(const Arg *arg) { } int32_t toggle_render_border(const Arg *arg) { - if (!selmon) - return 0; render_border = !render_border; arrange(selmon, false, false); return 0; @@ -1257,12 +1164,11 @@ int32_t toggle_scratchpad(const Arg *arg) { return 0; wl_list_for_each_safe(c, tmp, &clients, link) { - if (!config.scratchpad_cross_monitor && c->mon != selmon) { + if (!scratchpad_cross_monitor && c->mon != selmon) { continue; } - if (config.single_scratchpad && c->isnamedscratchpad && - !c->isminimized) { + if (single_scratchpad && c->isnamedscratchpad && !c->isminimized) { set_minimized(c); continue; } @@ -1279,8 +1185,6 @@ int32_t toggle_scratchpad(const Arg *arg) { } int32_t togglefakefullscreen(const Arg *arg) { - if (!selmon) - return 0; Client *sel = focustop(selmon); if (sel) setfakefullscreen(sel, !sel->isfakefullscreen); @@ -1288,9 +1192,6 @@ int32_t togglefakefullscreen(const Arg *arg) { } int32_t togglefloating(const Arg *arg) { - if (!selmon) - return 0; - Client *sel = focustop(selmon); if (selmon && selmon->isoverview) @@ -1299,22 +1200,17 @@ int32_t togglefloating(const Arg *arg) { if (!sel) return 0; - bool isfloating = sel->isfloating; - if ((sel->isfullscreen || sel->ismaximizescreen)) { - isfloating = 1; + sel->isfloating = 1; } else { - isfloating = !sel->isfloating; + sel->isfloating = !sel->isfloating; } - setfloating(sel, isfloating); + setfloating(sel, sel->isfloating); return 0; } int32_t togglefullscreen(const Arg *arg) { - if (!selmon) - return 0; - Client *sel = focustop(selmon); if (!sel) return 0; @@ -1331,9 +1227,6 @@ int32_t togglefullscreen(const Arg *arg) { } int32_t toggleglobal(const Arg *arg) { - if (!selmon) - return 0; - if (!selmon->sel) return 0; if (selmon->sel->is_in_scratchpad) { @@ -1352,18 +1245,12 @@ int32_t toggleglobal(const Arg *arg) { } int32_t togglegaps(const Arg *arg) { - if (!selmon) - return 0; - enablegaps ^= 1; arrange(selmon, false, false); return 0; } int32_t togglemaximizescreen(const Arg *arg) { - if (!selmon) - return 0; - Client *sel = focustop(selmon); if (!sel) return 0; @@ -1382,9 +1269,6 @@ int32_t togglemaximizescreen(const Arg *arg) { } int32_t toggleoverlay(const Arg *arg) { - if (!selmon) - return 0; - if (!selmon->sel || !selmon->sel->mon || selmon->sel->isfullscreen) { return 0; } @@ -1406,9 +1290,6 @@ int32_t toggleoverlay(const Arg *arg) { } int32_t toggletag(const Arg *arg) { - if (!selmon) - return 0; - uint32_t newtags; Client *sel = focustop(selmon); if (!sel) @@ -1432,25 +1313,17 @@ int32_t toggletag(const Arg *arg) { } int32_t toggleview(const Arg *arg) { - if (!selmon) - return 0; - uint32_t newtagset; uint32_t target; - Client *c = NULL; target = arg->ui == 0 ? ~0 & TAGMASK : arg->ui; - newtagset = selmon->tagset[selmon->seltags] ^ (target & TAGMASK); + newtagset = + selmon ? selmon->tagset[selmon->seltags] ^ (target & TAGMASK) : 0; if (newtagset) { selmon->tagset[selmon->seltags] = newtagset; focusclient(focustop(selmon), 1); - wl_list_for_each(c, &clients, link) { - if (VISIBLEON(c, selmon) && ISTILED(c)) { - set_size_per(selmon, c); - } - } arrange(selmon, false, false); } printstatus(); @@ -1458,9 +1331,6 @@ int32_t toggleview(const Arg *arg) { } int32_t viewtoleft(const Arg *arg) { - if (!selmon) - return 0; - uint32_t target = selmon->tagset[selmon->seltags]; if (selmon->isoverview || selmon->pertag->curtag == 0) { @@ -1481,9 +1351,6 @@ int32_t viewtoleft(const Arg *arg) { } int32_t viewtoright(const Arg *arg) { - if (!selmon) - return 0; - if (selmon->isoverview || selmon->pertag->curtag == 0) { return 0; } @@ -1501,9 +1368,6 @@ int32_t viewtoright(const Arg *arg) { } int32_t viewtoleft_have_client(const Arg *arg) { - if (!selmon) - return 0; - uint32_t n; uint32_t current = get_tags_first_tag_num(selmon->tagset[selmon->seltags]); bool found = false; @@ -1528,9 +1392,6 @@ int32_t viewtoleft_have_client(const Arg *arg) { } int32_t viewtoright_have_client(const Arg *arg) { - if (!selmon) - return 0; - uint32_t n; uint32_t current = get_tags_first_tag_num(selmon->tagset[selmon->seltags]); bool found = false; @@ -1555,23 +1416,15 @@ int32_t viewtoright_have_client(const Arg *arg) { } int32_t viewcrossmon(const Arg *arg) { - if (!selmon) - return 0; - focusmon(&(Arg){.v = arg->v, .i = UNDIR}); view_in_mon(arg, true, selmon, true); return 0; } int32_t tagcrossmon(const Arg *arg) { - if (!selmon || !selmon->sel) + if (!selmon->sel) return 0; - if (match_monitor_spec(arg->v, selmon)) { - tag_client(arg, selmon->sel); - return 0; - } - tagmon(&(Arg){.ui = arg->ui, .i = UNDIR, .v = arg->v}); return 0; } @@ -1636,8 +1489,6 @@ int32_t setoption(const Arg *arg) { } int32_t minimized(const Arg *arg) { - if (!selmon) - return 0; if (selmon && selmon->isoverview) return 0; @@ -1648,23 +1499,10 @@ int32_t minimized(const Arg *arg) { return 0; } -void fix_mon_tagset_from_overview(Monitor *m) { - if (m->tagset[m->seltags] == (m->ovbk_prev_tagset & TAGMASK)) { - m->tagset[m->seltags ^ 1] = m->ovbk_current_tagset; - m->pertag->prevtag = get_tags_first_tag_num(m->ovbk_current_tagset); - } else { - m->tagset[m->seltags ^ 1] = m->ovbk_prev_tagset; - m->pertag->prevtag = get_tags_first_tag_num(m->ovbk_prev_tagset); - } -} - int32_t toggleoverview(const Arg *arg) { Client *c = NULL; - if (!selmon) - return 0; - if (selmon->isoverview && config.ov_tab_mode && arg->i != 1 && - selmon->sel) { + if (selmon->isoverview && ov_tab_mode && arg->i != 1 && selmon->sel) { focusstack(&(Arg){.i = 1}); return 0; } @@ -1682,8 +1520,6 @@ int32_t toggleoverview(const Arg *arg) { visible_client_number++; } if (visible_client_number > 0) { - selmon->ovbk_current_tagset = selmon->tagset[selmon->seltags]; - selmon->ovbk_prev_tagset = selmon->tagset[selmon->seltags ^ 1]; target = ~0 & TAGMASK; } else { selmon->isoverview ^= 1; @@ -1694,7 +1530,6 @@ int32_t toggleoverview(const Arg *arg) { } else if (!selmon->isoverview && !selmon->sel) { target = (1 << (selmon->pertag->prevtag - 1)); view(&(Arg){.ui = target}, false); - fix_mon_tagset_from_overview(selmon); refresh_monitors_workspaces_status(selmon); return 0; } @@ -1717,7 +1552,7 @@ int32_t toggleoverview(const Arg *arg) { } view(&(Arg){.ui = target}, false); - fix_mon_tagset_from_overview(selmon); + refresh_monitors_workspaces_status(selmon); return 0; } @@ -1726,7 +1561,7 @@ int32_t disable_monitor(const Arg *arg) { Monitor *m = NULL; struct wlr_output_state state = {0}; wl_list_for_each(m, &mons, link) { - if (match_monitor_spec(arg->v, m)) { + if (regex_match(arg->v, m->wlr_output->name)) { wlr_output_state_set_enabled(&state, false); wlr_output_commit_state(m->wlr_output, &state); m->asleep = 1; @@ -1741,7 +1576,7 @@ int32_t enable_monitor(const Arg *arg) { Monitor *m = NULL; struct wlr_output_state state = {0}; wl_list_for_each(m, &mons, link) { - if (match_monitor_spec(arg->v, m)) { + if (regex_match(arg->v, m->wlr_output->name)) { wlr_output_state_set_enabled(&state, true); wlr_output_commit_state(m->wlr_output, &state); m->asleep = 0; @@ -1756,7 +1591,7 @@ int32_t toggle_monitor(const Arg *arg) { Monitor *m = NULL; struct wlr_output_state state = {0}; wl_list_for_each(m, &mons, link) { - if (match_monitor_spec(arg->v, m)) { + if (regex_match(arg->v, m->wlr_output->name)) { wlr_output_state_set_enabled(&state, !m->wlr_output->enabled); wlr_output_commit_state(m->wlr_output, &state); m->asleep = !m->wlr_output->enabled; @@ -1768,27 +1603,34 @@ int32_t toggle_monitor(const Arg *arg) { } int32_t scroller_stack(const Arg *arg) { - if (!selmon) - return 0; Client *c = selmon->sel; Client *stack_head = NULL; Client *source_stack_head = NULL; if (!c || !c->mon || c->isfloating || !is_scroller_layout(selmon)) return 0; + if (c && (!client_only_in_one_tag(c) || c->isglobal || c->isunglobal)) + return 0; + bool is_horizontal_layout = c->mon->pertag->ltidxs[c->mon->pertag->curtag]->id == SCROLLER ? true : false; Client *target_client = find_client_by_direction(c, arg, false, true); + if (target_client && (!client_only_in_one_tag(target_client) || + target_client->isglobal || target_client->isunglobal)) + return 0; + if (target_client) { stack_head = get_scroll_stack_head(target_client); } - source_stack_head = get_scroll_stack_head(c); + if (c) { + source_stack_head = get_scroll_stack_head(c); + } - if (source_stack_head == stack_head) { + if (stack_head == source_stack_head) { return 0; } @@ -1836,10 +1678,6 @@ int32_t scroller_stack(const Arg *arg) { if (!target_client || target_client->mon != c->mon) { return 0; - } else { - c->isglobal = target_client->isglobal = 0; - c->isunglobal = target_client->isglobal = 0; - c->tags = target_client->tags = get_tags_first_tag(target_client->tags); } exit_scroller_stack(c); @@ -1865,4 +1703,4 @@ int32_t scroller_stack(const Arg *arg) { arrange(selmon, false, false); return 0; -} +} \ No newline at end of file diff --git a/src/ext-protocol/tearing.h b/src/ext-protocol/tearing.h index 5a9851e4..8e02656a 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 (!config.allow_tearing) { + if (!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 (config.allow_tearing == TEARING_ENABLED) { + if (allow_tearing == TEARING_ENABLED) { if (c->force_tearing == STATE_UNSPECIFIED) { return c->tearing_hint; } else { @@ -87,8 +87,7 @@ 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 || - config.allow_tearing == TEARING_FULLSCREEN_ONLY; + return c->tearing_hint || allow_tearing == TEARING_FULLSCREEN_ONLY; } /* honor tearing as requested by action */ diff --git a/src/ext-protocol/text-input.h b/src/ext-protocol/text-input.h index e9f221a4..dbd97e11 100644 --- a/src/ext-protocol/text-input.h +++ b/src/ext-protocol/text-input.h @@ -77,6 +77,15 @@ Monitor *output_from_wlr_output(struct wlr_output *wlr_output) { return NULL; } +Monitor *output_nearest_to(int32_t lx, int32_t ly) { + double closest_x, closest_y; + wlr_output_layout_closest_point(output_layout, NULL, lx, ly, &closest_x, + &closest_y); + + return output_from_wlr_output( + wlr_output_layout_output_at(output_layout, closest_x, closest_y)); +} + bool output_is_usable(Monitor *m) { return m && m->wlr_output->enabled; } static bool @@ -246,7 +255,7 @@ static void update_popup_position(struct dwl_input_method_popup *popup) { cursor_rect = (struct wlr_box){0}; } - output = get_monitor_nearest_to(cursor_rect.x, cursor_rect.y); + output = output_nearest_to(cursor_rect.x, cursor_rect.y); if (!output_is_usable(output)) { return; } diff --git a/src/fetch/client.h b/src/fetch/client.h index 0b142847..e843d691 100644 --- a/src/fetch/client.h +++ b/src/fetch/client.h @@ -12,9 +12,7 @@ bool check_hit_no_border(Client *c) { } } - if (config.no_border_when_single && c && c->mon && - ((ISSCROLLTILED(c) && c->mon->visible_scroll_tiling_clients == 1) || - c->mon->visible_clients == 1)) { + if (no_border_when_single && c && c->mon && c->mon->visible_clients == 1) { hit_no_border = true; } return hit_no_border; @@ -39,7 +37,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 (!config.scratchpad_cross_monitor && c->mon != selmon) { + if (!scratchpad_cross_monitor && c->mon != selmon) { continue; } @@ -83,9 +81,6 @@ setclient_coordinate_center(Client *c, Monitor *tm, struct wlr_box geom, int32_t len = 0; Monitor *m = tm ? tm : selmon; - if (!m) - return geom; - uint32_t cbw = check_hit_no_border(c) ? c->bw : 0; if (!c->no_force_center && m) { @@ -167,7 +162,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 && - (config.focus_cross_monitor || c->mon == tc->mon) && + (focus_cross_monitor || c->mon == tc->mon) && (c->tags & c->mon->tagset[c->mon->seltags])) { last++; } @@ -188,7 +183,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 && - (config.focus_cross_monitor || c->mon == tc->mon) && + (focus_cross_monitor || c->mon == tc->mon) && (c->tags & c->mon->tagset[c->mon->seltags])) { last++; tempClients[last] = c; @@ -511,21 +506,21 @@ Client *get_next_stack_client(Client *c, bool reverse) { float *get_border_color(Client *c) { if (c->mon != selmon) { - return config.bordercolor; + return bordercolor; } else if (c->isurgent) { - return config.urgentcolor; + return urgentcolor; } else if (c->is_in_scratchpad && selmon && c == selmon->sel) { - return config.scratchpadcolor; + return scratchpadcolor; } else if (c->isglobal && selmon && c == selmon->sel) { - return config.globalcolor; + return globalcolor; } else if (c->isoverlay && selmon && c == selmon->sel) { - return config.overlaycolor; + return overlaycolor; } else if (c->ismaximizescreen && selmon && c == selmon->sel) { - return config.maximizescreencolor; + return maximizescreencolor; } else if (selmon && c == selmon->sel) { - return config.focuscolor; + return focuscolor; } else { - return config.bordercolor; + return bordercolor; } } @@ -577,29 +572,23 @@ bool client_is_in_same_stack(Client *sc, Client *tc, Client *fc) { if (id == TILE || id == VERTICAL_TILE || id == DECK || id == VERTICAL_DECK || id == RIGHT_TILE) { - if (tc->ismaster ^ sc->ismaster) + if (fc && !fc->ismaster) return false; - if (fc && !(fc->ismaster ^ sc->ismaster)) - return false; - else + else if (!sc->ismaster) return true; } if (id == TGMIX) { - if (tc->ismaster ^ sc->ismaster) - return false; - if (fc && !(fc->ismaster ^ sc->ismaster)) + if (fc && !fc->ismaster) return false; if (!sc->ismaster && sc->mon->visible_tiling_clients <= 3) return true; } if (id == CENTER_TILE) { - if (tc->ismaster ^ sc->ismaster) + if (fc && !fc->ismaster) return false; - if (fc && !(fc->ismaster ^ sc->ismaster)) - return false; - if (sc->geom.x == tc->geom.x) + if (!sc->ismaster && sc->geom.x == tc->geom.x) return true; else return false; diff --git a/src/fetch/common.h b/src/fetch/common.h index 57a1a8e6..58e69dc1 100644 --- a/src/fetch/common.h +++ b/src/fetch/common.h @@ -100,6 +100,10 @@ void xytonode(double x, double y, struct wlr_surface **psurface, Client **pc, surface = wlr_scene_surface_try_from_buffer( wlr_scene_buffer_from_node(node)) ->surface; + else if (node->type == WLR_SCENE_NODE_RECT) { + surface = NULL; + break; + } /* start from the topmost layer, find a sureface that can be focused by pointer, @@ -115,13 +119,6 @@ void xytonode(double x, double y, struct wlr_surface **psurface, Client **pc, l = pnode->data; } } - - if (node->type == WLR_SCENE_NODE_RECT) { - if (c) { - surface = client_surface(c); - } - break; - } } if (psurface) diff --git a/src/fetch/monitor.h b/src/fetch/monitor.h index d2b4fe62..7a1ca4dc 100644 --- a/src/fetch/monitor.h +++ b/src/fetch/monitor.h @@ -96,81 +96,3 @@ Monitor *xytomon(double x, double y) { struct wlr_output *o = wlr_output_layout_output_at(output_layout, x, y); return o ? o->data : NULL; } - -Monitor *get_monitor_nearest_to(int32_t lx, int32_t ly) { - double closest_x, closest_y; - wlr_output_layout_closest_point(output_layout, NULL, lx, ly, &closest_x, - &closest_y); - - return output_from_wlr_output( - wlr_output_layout_output_at(output_layout, closest_x, closest_y)); -} - -bool match_monitor_spec(char *spec, Monitor *m) { - if (!spec || !m) - return false; - - // if the spec does not contain a colon, treat it as a match on the monitor - // name - if (strchr(spec, ':') == NULL) { - return regex_match(spec, m->wlr_output->name); - } - - char *spec_copy = strdup(spec); - if (!spec_copy) - return false; - - char *name_rule = NULL; - char *make_rule = NULL; - char *model_rule = NULL; - char *serial_rule = NULL; - - char *token = strtok(spec_copy, "&&"); - while (token) { - char *colon = strchr(token, ':'); - if (colon) { - *colon = '\0'; - char *key = token; - char *value = colon + 1; - - if (strcmp(key, "name") == 0) - name_rule = strdup(value); - else if (strcmp(key, "make") == 0) - make_rule = strdup(value); - else if (strcmp(key, "model") == 0) - model_rule = strdup(value); - else if (strcmp(key, "serial") == 0) - serial_rule = strdup(value); - } - token = strtok(NULL, "&&"); - } - - bool match = true; - - if (name_rule) { - if (!regex_match(name_rule, m->wlr_output->name)) - match = false; - } - if (make_rule) { - if (!m->wlr_output->make || strcmp(make_rule, m->wlr_output->make) != 0) - match = false; - } - if (model_rule) { - if (!m->wlr_output->model || - strcmp(model_rule, m->wlr_output->model) != 0) - match = false; - } - if (serial_rule) { - if (!m->wlr_output->serial || - strcmp(serial_rule, m->wlr_output->serial) != 0) - match = false; - } - - free(spec_copy); - free(name_rule); - free(make_rule); - free(model_rule); - free(serial_rule); - - return match; -} \ No newline at end of file diff --git a/src/layout/arrange.h b/src/layout/arrange.h index 04f4554b..6ff1dd25 100644 --- a/src/layout/arrange.h +++ b/src/layout/arrange.h @@ -1,85 +1,3 @@ -void save_old_size_per(Monitor *m) { - Client *c = NULL; - - wl_list_for_each(c, &clients, link) { - if (VISIBLEON(c, m) && ISTILED(c)) { - c->old_master_inner_per = c->master_inner_per; - c->old_stack_inner_per = c->stack_inner_per; - } - } -} - -void restore_size_per(Monitor *m, Client *c) { - Client *fc = NULL; - - 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; - } - } - - c->old_master_inner_per = c->master_inner_per; - c->old_stack_inner_per = c->stack_inner_per; - - pre_caculate_before_arrange(m, false, false, true); - - const Layout *current_layout = m->pertag->ltidxs[m->pertag->curtag]; - - if (current_layout->id == SCROLLER || - current_layout->id == VERTICAL_SCROLLER || current_layout->id == GRID || - current_layout->id == VERTICAL_GRID || current_layout->id == DECK || - current_layout->id == VERTICAL_DECK || current_layout->id == MONOCLE) { - return; - } - - if (current_layout->id == CENTER_TILE) { - wl_list_for_each(fc, &clients, link) { - if (VISIBLEON(fc, m) && ISTILED(fc) && !c->ismaster) { - set_size_per(m, fc); - } - } - return; - } - - // it is possible that the current floating window is moved to another tag, - // but the tag has not executed save_old_size_per - // so it must be judged whether their old size values are initial values - - if (!c->ismaster && c->old_stack_inner_per < 1.0 && - c->old_stack_inner_per > 0.0f && c->stack_inner_per < 1.0 && - c->stack_inner_per > 0.0f) { - c->stack_inner_per = (1.0 - c->stack_inner_per) * - c->old_stack_inner_per / - (1.0 - c->old_stack_inner_per); - } - - if (c->ismaster && c->old_master_inner_per < 1.0 && - c->old_master_inner_per > 0.0f && c->master_inner_per < 1.0 && - c->master_inner_per > 0.0f) { - c->master_inner_per = (1.0 - c->master_inner_per) * - c->old_master_inner_per / - (1.0 - c->old_master_inner_per); - } - - wl_list_for_each(fc, &clients, link) { - if (VISIBLEON(fc, m) && ISTILED(fc) && fc != c && !fc->ismaster && - fc->old_ismaster && fc->old_stack_inner_per < 1.0 && - fc->old_stack_inner_per > 0.0f && fc->stack_inner_per < 1.0 && - fc->stack_inner_per > 0.0f) { - fc->stack_inner_per = (1.0 - fc->stack_inner_per) * - fc->old_stack_inner_per / - (1.0 - fc->old_stack_inner_per); - fc->old_ismaster = false; - } - } -} - void set_size_per(Monitor *m, Client *c) { Client *fc = NULL; bool found = false; @@ -87,13 +5,8 @@ void set_size_per(Monitor *m, Client *c) { if (!m || !c) return; - const Layout *current_layout = m->pertag->ltidxs[m->pertag->curtag]; - wl_list_for_each(fc, &clients, link) { if (VISIBLEON(fc, m) && ISTILED(fc) && fc != c) { - if (current_layout->id == CENTER_TILE && - (fc->isleftstack ^ c->isleftstack)) - continue; c->master_mfact_per = fc->master_mfact_per; c->master_inner_per = fc->master_inner_per; c->stack_inner_per = fc->stack_inner_per; @@ -130,7 +43,8 @@ void resize_tile_master_horizontal(Client *grabc, bool isdrag, int32_t offsetx, break; } - if (!begin_find_nextnext && VISIBLEON(tc, grabc->mon) && ISTILED(tc)) { + if (!begin_find_nextnext && VISIBLEON(tc, grabc->mon) && + ISTILED(tc)) { // 根据你的实际字段名调整 next = tc; begin_find_nextnext = true; continue; @@ -146,7 +60,8 @@ void resize_tile_master_horizontal(Client *grabc, bool isdrag, int32_t offsetx, break; } - if (!begin_find_prevprev && VISIBLEON(tc, grabc->mon) && ISTILED(tc)) { + if (!begin_find_prevprev && VISIBLEON(tc, grabc->mon) && + ISTILED(tc)) { // 根据你的实际字段名调整 prev = tc; begin_find_prevprev = true; continue; @@ -282,23 +197,6 @@ void resize_tile_master_horizontal(Client *grabc, bool isdrag, int32_t offsetx, // 应用到所有平铺窗口 wl_list_for_each(tc, &clients, link) { if (VISIBLEON(tc, grabc->mon) && ISTILED(tc)) { - - if (!isdrag && tc != grabc) { - if (!tc->ismaster && new_stack_inner_per != 1.0f && - grabc->old_stack_inner_per != 1.0f && - (type != CENTER_TILE || - !(grabc->isleftstack ^ tc->isleftstack))) - tc->stack_inner_per = (1 - new_stack_inner_per) / - (1 - grabc->old_stack_inner_per) * - tc->stack_inner_per; - if (tc->ismaster && new_master_inner_per != 1.0f && - grabc->old_master_inner_per != 1.0f) - tc->master_inner_per = - (1.0f - new_master_inner_per) / - (1.0f - grabc->old_master_inner_per) * - tc->master_inner_per; - } - tc->master_mfact_per = new_master_mfact_per; } } @@ -312,7 +210,7 @@ void resize_tile_master_horizontal(Client *grabc, bool isdrag, int32_t offsetx, } if (last_apply_drap_time == 0 || - time - last_apply_drap_time > config.drag_tile_refresh_interval) { + time - last_apply_drap_time > drag_refresh_interval) { arrange(grabc->mon, false, false); last_apply_drap_time = time; } @@ -331,7 +229,8 @@ void resize_tile_master_vertical(Client *grabc, bool isdrag, int32_t offsetx, for (node = grabc->link.next; node != &clients; node = node->next) { tc = wl_container_of(node, tc, link); - if (VISIBLEON(tc, grabc->mon) && ISTILED(tc)) { + if (VISIBLEON(tc, grabc->mon) && + ISTILED(tc)) { // 根据你的实际字段名调整 next = tc; break; } @@ -341,7 +240,8 @@ void resize_tile_master_vertical(Client *grabc, bool isdrag, int32_t offsetx, for (node = grabc->link.prev; node != &clients; node = node->prev) { tc = wl_container_of(node, tc, link); - if (VISIBLEON(tc, grabc->mon) && ISTILED(tc)) { + if (VISIBLEON(tc, grabc->mon) && + ISTILED(tc)) { // 根据你的实际字段名调整 prev = tc; break; } @@ -454,20 +354,6 @@ void resize_tile_master_vertical(Client *grabc, bool isdrag, int32_t offsetx, // 应用到所有平铺窗口 wl_list_for_each(tc, &clients, link) { if (VISIBLEON(tc, grabc->mon) && ISTILED(tc)) { - if (!isdrag && tc != grabc && type != CENTER_TILE) { - if (!tc->ismaster && new_stack_inner_per != 1.0f && - grabc->old_stack_inner_per != 1.0f) - tc->stack_inner_per = (1 - new_stack_inner_per) / - (1 - grabc->old_stack_inner_per) * - tc->stack_inner_per; - if (tc->ismaster && new_master_inner_per != 1.0f && - grabc->old_master_inner_per != 1.0f) - tc->master_inner_per = - (1.0f - new_master_inner_per) / - (1.0f - grabc->old_master_inner_per) * - tc->master_inner_per; - } - tc->master_mfact_per = new_master_mfact_per; } } @@ -481,7 +367,7 @@ void resize_tile_master_vertical(Client *grabc, bool isdrag, int32_t offsetx, } if (last_apply_drap_time == 0 || - time - last_apply_drap_time > config.drag_tile_refresh_interval) { + time - last_apply_drap_time > drag_refresh_interval) { arrange(grabc->mon, false, false); last_apply_drap_time = time; } @@ -490,14 +376,13 @@ void resize_tile_master_vertical(Client *grabc, bool isdrag, int32_t offsetx, void resize_tile_scroller(Client *grabc, bool isdrag, int32_t offsetx, int32_t offsety, uint32_t time, bool isvertical) { - Client *tc = NULL; float delta_x, delta_y; float new_scroller_proportion; float new_stack_proportion; Client *stack_head = get_scroll_stack_head(grabc); if (grabc && grabc->mon->visible_tiling_clients == 1 && - !config.scroller_ignore_proportion_single) + !scroller_ignore_proportion_single) return; if (!start_drag_window && isdrag) { @@ -651,29 +536,19 @@ void resize_tile_scroller(Client *grabc, bool isdrag, int32_t offsetx, // 应用限制,确保比例在合理范围内 new_scroller_proportion = fmaxf(0.1f, fminf(1.0f, new_scroller_proportion)); - new_stack_proportion = fmaxf(0.1f, fminf(0.9f, new_stack_proportion)); + new_stack_proportion = fmaxf(0.1f, fminf(1.0f, new_stack_proportion)); grabc->stack_proportion = new_stack_proportion; stack_head->scroller_proportion = new_scroller_proportion; - wl_list_for_each(tc, &clients, link) { - if (!isdrag && new_stack_proportion != 1.0f && - grabc->old_stack_proportion != 1.0f && tc != grabc && - ISTILED(tc) && get_scroll_stack_head(tc) == stack_head) { - tc->stack_proportion = (1.0f - new_stack_proportion) / - (1.0f - grabc->old_stack_proportion) * - tc->stack_proportion; - } - } - if (!isdrag) { arrange(grabc->mon, false, false); return; } if (last_apply_drap_time == 0 || - time - last_apply_drap_time > config.drag_tile_refresh_interval) { + time - last_apply_drap_time > drag_refresh_interval) { arrange(grabc->mon, false, false); last_apply_drap_time = time; } @@ -709,18 +584,6 @@ void resize_tile_client(Client *grabc, bool isdrag, int32_t offsetx, } } -/* If there are no calculation omissions, -these two functions will never be triggered. -Just in case to facilitate the final investigation*/ - -void check_size_per_valid(Client *c) { - if (c->ismaster) { - assert(c->master_inner_per > 0.0f && c->master_inner_per <= 1.0f); - } else { - assert(c->stack_inner_per > 0.0f && c->stack_inner_per <= 1.0f); - } -} - void reset_size_per_mon(Monitor *m, int32_t tile_cilent_num, double total_left_stack_hight_percent, double total_right_stack_hight_percent, @@ -736,7 +599,6 @@ void reset_size_per_mon(Monitor *m, int32_t tile_cilent_num, wl_list_for_each(c, &clients, link) { if (VISIBLEON(c, m) && ISTILED(c)) { - if (total_master_inner_percent > 0.0 && i < nmasters) { c->ismaster = true; c->stack_inner_per = stack_num ? 1.0f / stack_num : 1.0f; @@ -752,20 +614,17 @@ void reset_size_per_mon(Monitor *m, int32_t tile_cilent_num, : 1.0f; } i++; - - check_size_per_valid(c); } } } else { wl_list_for_each(c, &clients, link) { if (VISIBLEON(c, m) && ISTILED(c)) { - if (total_master_inner_percent > 0.0 && i < nmasters) { c->ismaster = true; if ((stack_index % 2) ^ (tile_cilent_num % 2 == 0)) { c->stack_inner_per = - stack_num > 1 ? 1.0f / ((stack_num - 1) / 2.0f) - : 1.0f; + stack_num > 1 ? 1.0f / ((stack_num - 1) / 2) : 1.0f; + } else { c->stack_inner_per = stack_num > 1 ? 2.0f / stack_num : 1.0f; @@ -794,15 +653,13 @@ void reset_size_per_mon(Monitor *m, int32_t tile_cilent_num, } } i++; - - check_size_per_valid(c); } } } } -void pre_caculate_before_arrange(Monitor *m, bool want_animation, - bool from_view, bool only_caculate) { +void // 17 +arrange(Monitor *m, bool want_animation, bool from_view) { Client *c = NULL; double total_stack_inner_percent = 0; double total_master_inner_percent = 0; @@ -814,6 +671,11 @@ 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; @@ -886,17 +748,14 @@ void pre_caculate_before_arrange(Monitor *m, bool want_animation, i++; } - if (!only_caculate) - set_arrange_visible(m, c, want_animation); + set_arrange_visible(m, c, want_animation); } else { - if (!only_caculate) - set_arrange_hidden(m, c, want_animation); + set_arrange_hidden(m, c, want_animation); } } - if (!only_caculate && c->mon == m && c->ismaximizescreen && - !c->animation.tagouted && !c->animation.tagouting && - VISIBLEON(c, m)) { + if (c->mon == m && c->ismaximizescreen && !c->animation.tagouted && + !c->animation.tagouting && VISIBLEON(c, m)) { reset_maximizescreen_size(c); } } @@ -905,18 +764,6 @@ void pre_caculate_before_arrange(Monitor *m, bool want_animation, m, m->visible_tiling_clients, total_left_stack_hight_percent, total_right_stack_hight_percent, total_stack_inner_percent, total_master_inner_percent, master_num, stack_num); -} - -void // 17 -arrange(Monitor *m, bool want_animation, bool from_view) { - - if (!m) - return; - - if (!m->wlr_output->enabled) - return; - - pre_caculate_before_arrange(m, want_animation, from_view, false); if (m->isoverview) { overviewlayout.arrange(m); diff --git a/src/layout/horizontal.h b/src/layout/horizontal.h index eaa7b5c2..87b6033c 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 ? config.overviewgappo : config.gappoh : 0; + enablegaps ? m->isoverview ? overviewgappo : gappoh : 0; int32_t target_gappi = - enablegaps ? m->isoverview ? config.overviewgappi : config.gappih : 0; + enablegaps ? m->isoverview ? overviewgappi : gappih : 0; float single_width_ratio = m->isoverview ? 0.7 : 0.9; float single_height_ratio = m->isoverview ? 0.8 : 0.9; @@ -117,18 +117,14 @@ void deck(Monitor *m) { Client *c = NULL; Client *fc = NULL; float mfact; - uint32_t nmasters = m->pertag->nmasters[m->pertag->curtag]; int32_t cur_gappih = enablegaps ? m->gappih : 0; int32_t cur_gappoh = enablegaps ? m->gappoh : 0; int32_t cur_gappov = enablegaps ? m->gappov : 0; - 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; + 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; n = m->visible_tiling_clients; @@ -146,8 +142,8 @@ void deck(Monitor *m) { : m->pertag->mfacts[m->pertag->curtag]; // Calculate master width including outer gaps - if (n > nmasters) - mw = nmasters ? round((m->w.width - 2 * cur_gappoh) * mfact) : 0; + if (n > m->nmaster) + mw = m->nmaster ? round((m->w.width - 2 * cur_gappoh) * mfact) : 0; else mw = m->w.width - 2 * cur_gappoh; @@ -155,7 +151,7 @@ void deck(Monitor *m) { wl_list_for_each(c, &clients, link) { if (!VISIBLEON(c, m) || !ISTILED(c)) continue; - if (i < nmasters) { + if (i < m->nmaster) { c->master_mfact_per = mfact; // Master area clients resize( @@ -164,7 +160,7 @@ void deck(Monitor *m) { .y = m->w.y + cur_gappov + my, .width = mw, .height = (m->w.height - 2 * cur_gappov - my) / - (MIN(n, nmasters) - i)}, + (MIN(n, m->nmaster) - i)}, 0); my += c->geom.height; } else { @@ -191,15 +187,12 @@ 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 = 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; + 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; if (c->isfullscreen) { target_geom->height = m->m.height; @@ -289,24 +282,19 @@ void scroller(Monitor *m) { struct wlr_box target_geom; int32_t focus_client_index = 0; bool need_scroller = false; - bool over_overspread_to_left = false; int32_t cur_gappih = enablegaps ? m->gappih : 0; int32_t cur_gappoh = enablegaps ? m->gappoh : 0; int32_t cur_gappov = enablegaps ? m->gappov : 0; int32_t cur_gappiv = enablegaps ? m->gappiv : 0; - 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; + 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; - int32_t max_client_width = - m->w.width - 2 * config.scroller_structs - cur_gappih; + int32_t max_client_width = m->w.width - 2 * scroller_structs - cur_gappih; n = m->visible_scroll_tiling_clients; @@ -330,13 +318,13 @@ void scroller(Monitor *m) { } } - if (n == 1 && !config.scroller_ignore_proportion_single && + if (n == 1 && !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 - : config.scroller_default_proportion_single; + : scroller_default_proportion_single; target_geom.height = m->w.height - 2 * cur_gappov; target_geom.width = (m->w.width - 2 * cur_gappoh) * single_proportion; @@ -370,9 +358,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 + config.scroller_structs && + if (c->geom.x >= m->w.x + scroller_structs && c->geom.x + c->geom.width <= - m->w.x + m->w.width - config.scroller_structs) { + m->w.x + m->w.width - scroller_structs) { need_scroller = false; } else { need_scroller = true; @@ -382,48 +370,7 @@ void scroller(Monitor *m) { } } - bool need_apply_overspread = - 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; - - if (need_apply_overspread) { - - if (focus_client_index == 0) { - over_overspread_to_left = true; - } else { - over_overspread_to_left = false; - } - - if (over_overspread_to_left && - (!INSIDEMON(tempClients[1]) || - (tempClients[1]->scroller_proportion + - tempClients[focus_client_index]->scroller_proportion >= - 1.0f))) { - need_scroller = true; - } else if (!over_overspread_to_left && - (!INSIDEMON(tempClients[focus_client_index - 1]) || - (tempClients[focus_client_index - 1]->scroller_proportion + - tempClients[focus_client_index]->scroller_proportion >= - 1.0f))) { - need_scroller = true; - } else { - need_apply_overspread = false; - } - } - - bool need_apply_center = - 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 * config.scroller_structs - cur_gappih))); - - if (n == 1 && config.scroller_ignore_proportion_single) { + if (n == 1 && scroller_ignore_proportion_single) { need_scroller = true; } @@ -446,29 +393,21 @@ void scroller(Monitor *m) { tempClients[focus_client_index], &target_geom); arrange_stack(tempClients[focus_client_index], target_geom, cur_gappiv); } else if (need_scroller) { - if (need_apply_center) { + if (scroller_focus_center || + ((!m->prevsel || + (ISSCROLLTILED(m->prevsel) && + (m->prevsel->scroller_proportion * max_client_width) + + (root_client->scroller_proportion * max_client_width) > + m->w.width - 2 * scroller_structs - cur_gappih)) && + scroller_prefer_center)) { 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 + config.scroller_structs; - } else { - target_geom.x = - m->w.x + - (m->w.width - - tempClients[focus_client_index]->scroller_proportion * - max_client_width - - config.scroller_structs); - } - } else { - target_geom.x = tempClients[focus_client_index]->geom.x > - m->w.x + (m->w.width) / 2 + target_geom.x = root_client->geom.x > m->w.x + (m->w.width) / 2 ? m->w.x + (m->w.width - - tempClients[focus_client_index] - ->scroller_proportion * + root_client->scroller_proportion * max_client_width - - config.scroller_structs) - : m->w.x + config.scroller_structs; + scroller_structs) + : m->w.x + scroller_structs; } horizontal_check_scroller_root_inside_mon( tempClients[focus_client_index], &target_geom); @@ -533,14 +472,10 @@ void center_tile(Monitor *m) { int32_t cur_gappoh = enablegaps ? m->gappoh : 0; // 外部水平间隙 // 智能间隙处理 - 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; + 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; int32_t nmasters = m->pertag->nmasters[m->pertag->curtag]; mfact = fc->master_mfact_per > 0.0f ? fc->master_mfact_per @@ -553,8 +488,7 @@ void center_tile(Monitor *m) { tw = mw; // 判断是否需要主区域铺满 - int32_t should_overspread = - config.center_master_overspread && (n <= nmasters); + int32_t should_overspread = center_master_overspread && (n <= nmasters); int32_t master_surplus_height = (m->w.height - 2 * cur_gappov - cur_gappiv * ie * (master_num - 1)); @@ -580,7 +514,7 @@ void center_tile(Monitor *m) { mx = cur_gappoh + tw + cur_gappih * ie; } else if (n - nmasters == 1) { // 单个堆叠窗口的处理 - if (config.center_when_single_stack) { + if (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居中 @@ -657,7 +591,7 @@ void center_tile(Monitor *m) { } int32_t stack_x; - if (config.center_when_single_stack) { + if (center_when_single_stack) { // 放在右侧(master居中时,stack在右边) stack_x = m->w.x + mx + mw + cur_gappih * ie; } else { @@ -761,14 +695,10 @@ void tile(Monitor *m) { int32_t cur_gappov = enablegaps ? m->gappov : 0; int32_t cur_gappoh = enablegaps ? m->gappoh : 0; - 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; + 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; wl_list_for_each(fc, &clients, link) { @@ -875,14 +805,10 @@ void right_tile(Monitor *m) { int32_t cur_gappov = enablegaps ? m->gappov : 0; int32_t cur_gappoh = enablegaps ? m->gappoh : 0; - 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; + 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; wl_list_for_each(fc, &clients, link) { @@ -977,10 +903,8 @@ monocle(Monitor *m) { int32_t cur_gappov = enablegaps ? m->gappov : 0; int32_t cur_gappoh = enablegaps ? m->gappoh : 0; - cur_gappoh = - config.smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappoh; - cur_gappov = - config.smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappov; + cur_gappoh = smartgaps && m->visible_tiling_clients == 1 ? 0 : cur_gappoh; + cur_gappov = 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/layout.h b/src/layout/layout.h index f896ac27..169ab119 100644 --- a/src/layout/layout.h +++ b/src/layout/layout.h @@ -17,8 +17,8 @@ static void tgmix(Monitor *m); Layout overviewlayout = {"󰃇", overview, "overview"}; enum { - TILE, SCROLLER, + TILE, GRID, MONOCLE, DECK, @@ -34,8 +34,8 @@ enum { Layout layouts[] = { // 最少两个,不能删除少于两个 /* symbol arrange function name */ - {"T", tile, "tile", TILE}, // 平铺布局 {"S", scroller, "scroller", SCROLLER}, // 滚动布局 + {"T", tile, "tile", TILE}, // 平铺布局 {"G", grid, "grid", GRID}, // 格子布局 {"M", monocle, "monocle", MONOCLE}, // 单屏布局 {"K", deck, "deck", DECK}, // 卡片布局 diff --git a/src/layout/vertical.h b/src/layout/vertical.h index 3d8863af..2c2dc661 100644 --- a/src/layout/vertical.h +++ b/src/layout/vertical.h @@ -19,14 +19,10 @@ void vertical_tile(Monitor *m) { int32_t cur_gapoh = enablegaps ? m->gappoh : 0; int32_t cur_gapov = enablegaps ? m->gappov : 0; - 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; + 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; wl_list_for_each(fc, &clients, link) { if (VISIBLEON(fc, m) && ISTILED(fc)) @@ -114,18 +110,14 @@ void vertical_deck(Monitor *m) { Client *c = NULL; Client *fc = NULL; float mfact; - uint32_t nmasters = m->pertag->nmasters[m->pertag->curtag]; int32_t cur_gappiv = enablegaps ? m->gappiv : 0; int32_t cur_gappoh = enablegaps ? m->gappoh : 0; int32_t cur_gappov = enablegaps ? m->gappov : 0; - 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; + 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; n = m->visible_tiling_clients; @@ -142,8 +134,8 @@ void vertical_deck(Monitor *m) { mfact = fc->master_mfact_per > 0.0f ? fc->master_mfact_per : m->pertag->mfacts[m->pertag->curtag]; - if (n > nmasters) - mh = nmasters ? round((m->w.height - 2 * cur_gappov) * mfact) : 0; + if (n > m->nmaster) + mh = m->nmaster ? round((m->w.height - 2 * cur_gappov) * mfact) : 0; else mh = m->w.height - 2 * cur_gappov; @@ -151,13 +143,13 @@ void vertical_deck(Monitor *m) { wl_list_for_each(c, &clients, link) { if (!VISIBLEON(c, m) || !ISTILED(c)) continue; - if (i < nmasters) { + if (i < m->nmaster) { resize( c, (struct wlr_box){.x = m->w.x + cur_gappoh + mx, .y = m->w.y + cur_gappov, .width = (m->w.width - 2 * cur_gappoh - mx) / - (MIN(n, nmasters) - i), + (MIN(n, m->nmaster) - i), .height = mh}, 0); mx += c->geom.width; @@ -182,15 +174,12 @@ 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 = 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; + 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; if (c->isfullscreen) { target_geom->width = m->m.width; @@ -280,24 +269,19 @@ void vertical_scroller(Monitor *m) { struct wlr_box target_geom; int32_t focus_client_index = 0; bool need_scroller = false; - bool over_overspread_to_up = false; int32_t cur_gappiv = enablegaps ? m->gappiv : 0; int32_t cur_gappov = enablegaps ? m->gappov : 0; int32_t cur_gappoh = enablegaps ? m->gappoh : 0; int32_t cur_gappih = enablegaps ? m->gappih : 0; - 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; + 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; - int32_t max_client_height = - m->w.height - 2 * config.scroller_structs - cur_gappiv; + int32_t max_client_height = m->w.height - 2 * scroller_structs - cur_gappiv; n = m->visible_scroll_tiling_clients; @@ -318,13 +302,13 @@ void vertical_scroller(Monitor *m) { } } - if (n == 1 && !config.scroller_ignore_proportion_single && + if (n == 1 && !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 - : config.scroller_default_proportion_single; + : scroller_default_proportion_single; target_geom.width = m->w.width - 2 * cur_gappoh; target_geom.height = (m->w.height - 2 * cur_gappov) * single_proportion; @@ -358,9 +342,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 + config.scroller_structs && + if (c->geom.y >= m->w.y + scroller_structs && c->geom.y + c->geom.height <= - m->w.y + m->w.height - config.scroller_structs) { + m->w.y + m->w.height - scroller_structs) { need_scroller = false; } else { need_scroller = true; @@ -370,48 +354,7 @@ void vertical_scroller(Monitor *m) { } } - bool need_apply_overspread = - 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; - - if (need_apply_overspread) { - - if (focus_client_index == 0) { - over_overspread_to_up = true; - } else { - over_overspread_to_up = false; - } - - if (over_overspread_to_up && - (!INSIDEMON(tempClients[1]) || - (tempClients[1]->scroller_proportion + - tempClients[focus_client_index]->scroller_proportion >= - 1.0f))) { - need_scroller = true; - } else if (!over_overspread_to_up && - (!INSIDEMON(tempClients[focus_client_index - 1]) || - (tempClients[focus_client_index - 1]->scroller_proportion + - tempClients[focus_client_index]->scroller_proportion >= - 1.0f))) { - need_scroller = true; - } else { - need_apply_overspread = false; - } - } - - bool need_apply_center = - 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 * config.scroller_structs - cur_gappiv))); - - if (n == 1 && config.scroller_ignore_proportion_single) { + if (n == 1 && scroller_ignore_proportion_single) { need_scroller = true; } @@ -437,27 +380,21 @@ void vertical_scroller(Monitor *m) { arrange_stack_vertical(tempClients[focus_client_index], target_geom, cur_gappih); } else if (need_scroller) { - if (need_apply_center) { + if (scroller_focus_center || + ((!m->prevsel || + (ISSCROLLTILED(m->prevsel) && + (m->prevsel->scroller_proportion * max_client_height) + + (root_client->scroller_proportion * max_client_height) > + m->w.height - 2 * scroller_structs - cur_gappiv)) && + scroller_prefer_center)) { 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 + config.scroller_structs; - } else { - target_geom.y = - m->w.y + - (m->w.height - - tempClients[focus_client_index]->scroller_proportion * - max_client_height - - config.scroller_structs); - } } else { target_geom.y = root_client->geom.y > m->w.y + (m->w.height) / 2 ? m->w.y + (m->w.height - - tempClients[focus_client_index] - ->scroller_proportion * + root_client->scroller_proportion * max_client_height - - config.scroller_structs) - : m->w.y + config.scroller_structs; + scroller_structs) + : m->w.y + scroller_structs; } vertical_check_scroller_root_inside_mon(tempClients[focus_client_index], &target_geom); @@ -501,9 +438,9 @@ void vertical_grid(Monitor *m) { int32_t rows, cols, overrows; Client *c = NULL; int32_t target_gappo = - enablegaps ? m->isoverview ? config.overviewgappo : config.gappov : 0; + enablegaps ? m->isoverview ? overviewgappo : gappov : 0; int32_t target_gappi = - enablegaps ? m->isoverview ? config.overviewgappi : config.gappiv : 0; + enablegaps ? m->isoverview ? overviewgappi : 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 df1315a1..3a2331df 100644 --- a/src/mango.c +++ b/src/mango.c @@ -3,7 +3,6 @@ */ #include "wlr-layer-shell-unstable-v1-protocol.h" #include "wlr/util/box.h" -#include "wlr/util/edges.h" #include #include #include @@ -144,8 +143,6 @@ #define BAKED_POINTS_COUNT 256 /* enums */ -enum { TOP_LEFT, TOP_RIGHT, BOTTOM_LEFT, BOTTOM_RIGHT }; - enum { VERTICAL, HORIZONTAL }; enum { SWIPE_UP, SWIPE_DOWN, SWIPE_LEFT, SWIPE_RIGHT }; enum { CurNormal, CurPressed, CurMove, CurResize }; /* cursor */ @@ -338,7 +335,6 @@ struct Client { struct wl_listener configure; struct wl_listener set_hints; struct wl_listener set_geometry; - struct wl_listener commmitx11; #endif uint32_t bw; uint32_t tags, oldtags, mini_restore_tag; @@ -347,7 +343,7 @@ struct Client { struct wlr_foreign_toplevel_handle_v1 *foreign_toplevel; int32_t isfloating, isurgent, isfullscreen, isfakefullscreen, need_float_size_reduce, isminimized, isoverlay, isnosizehint, - ignore_maximize, ignore_minimize, indleinhibit_when_focus; + ignore_maximize, ignore_minimize; int32_t ismaximizescreen; int32_t overview_backup_bw; int32_t fullscreen_backup_x, fullscreen_backup_y, fullscreen_backup_w, @@ -392,7 +388,6 @@ struct Client { int32_t isterm, noswallow; int32_t allow_csd; int32_t force_maximize; - int32_t force_tiled_state; pid_t pid; Client *swallowing, *swallowedby; bool is_clip_to_hide; @@ -412,7 +407,6 @@ struct Client { double old_master_mfact_per, old_master_inner_per, old_stack_inner_per; double old_scroller_pproportion; bool ismaster; - bool old_ismaster; bool cursor_in_upper_half, cursor_in_left_half; bool isleftstack; int32_t tearing_hint; @@ -484,16 +478,8 @@ typedef struct { char *animation_type_open; char *animation_type_close; bool need_output_flush; - bool being_unmapped; } LayerSurface; -typedef struct { - struct wlr_xdg_popup *wlr_popup; - struct wl_listener destroy; - struct wl_listener commit; - struct wl_listener reposition; -} Popup; - typedef struct { const char *symbol; void (*arrange)(Monitor *); @@ -511,15 +497,14 @@ struct Monitor { struct wl_listener request_state; struct wl_listener destroy_lock_surface; struct wlr_session_lock_surface_v1 *lock_surface; - struct wl_event_source *skip_frame_timeout; struct wlr_box m; /* monitor area, layout-relative */ struct wlr_box w; /* window area, layout-relative */ struct wl_list layers[4]; /* LayerSurface::link */ + const Layout *lt; uint32_t seltags; uint32_t tagset[2]; - bool skiping_frame; - uint32_t resizing_count_pending; - uint32_t resizing_count_current; + double mfact; + int32_t nmaster; struct wl_list dwl_ipc_outputs; int32_t gappih; /* horizontal gap between windows */ @@ -527,8 +512,6 @@ struct Monitor { int32_t gappoh; /* horizontal outer gaps */ int32_t gappov; /* vertical outer gaps */ Pertag *pertag; - uint32_t ovbk_current_tagset; - uint32_t ovbk_prev_tagset; Client *sel, *prevsel; int32_t isoverview; int32_t is_in_hotarea; @@ -610,7 +593,7 @@ static void cursorwarptohint(void); static void destroydecoration(struct wl_listener *listener, void *data); static void destroydragicon(struct wl_listener *listener, void *data); static void destroyidleinhibitor(struct wl_listener *listener, void *data); -static void destroylayernodenotify(struct wl_listener *listener, void *data); +static void destroylayersurfacenotify(struct wl_listener *listener, void *data); static void destroylock(SessionLock *lock, int32_t unlocked); static void destroylocksurface(struct wl_listener *listener, void *data); static void destroynotify(struct wl_listener *listener, void *data); @@ -796,16 +779,7 @@ static Client *get_scroll_stack_head(Client *c); static bool client_only_in_one_tag(Client *c); static Client *get_focused_stack_client(Client *sc); static bool client_is_in_same_stack(Client *sc, Client *tc, Client *fc); -static void monitor_stop_skip_frame_timer(Monitor *m); -static int monitor_skip_frame_timeout_callback(void *data); -static Monitor *get_monitor_nearest_to(int32_t lx, int32_t ly); -static bool match_monitor_spec(char *spec, Monitor *m); -static void last_cursor_surface_destroy(struct wl_listener *listener, - void *data); -static int32_t keep_idle_inhibit(void *data); -static void check_keep_idle_inhibit(Client *c); -static void pre_caculate_before_arrange(Monitor *m, bool want_animation, - bool from_view, bool only_caculate); + #include "data/static_keymap.h" #include "dispatch/bind_declare.h" #include "layout/layout.h" @@ -867,7 +841,6 @@ static struct wl_list inputdevices; static struct wl_list keyboard_shortcut_inhibitors; static uint32_t cursor_mode; static Client *grabc; -static int32_t rzcorner; static int32_t grabcx, grabcy; /* client-relative */ static int32_t drag_begin_cursorx, drag_begin_cursory; /* client-relative */ static bool start_drag_window = false; @@ -901,24 +874,14 @@ struct dvec2 *baked_points_focus; struct dvec2 *baked_points_opafadein; struct dvec2 *baked_points_opafadeout; -static struct wl_event_source *hide_cursor_source; -static struct wl_event_source *keep_idle_inhibit_source; +static struct wl_event_source *hide_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", - "XCURSOR_THEME", - "XCURSOR_SIZE", - NULL}; static struct { enum wp_cursor_shape_device_v1_shape shape; struct wlr_surface *surface; @@ -934,13 +897,10 @@ struct Pertag { int32_t nmasters[LENGTH(tags) + 1]; /* number of windows in master area */ float mfacts[LENGTH(tags) + 1]; /* mfacts per tag */ bool no_hide[LENGTH(tags) + 1]; /* no_hide per tag */ - bool no_render_border[LENGTH(tags) + 1]; /* no_render_border per tag */ const Layout *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 = @@ -978,17 +938,12 @@ static struct wl_listener new_session_lock = {.notify = locksession}; static struct wl_listener drm_lease_request = {.notify = requestdrmlease}; static struct wl_listener keyboard_shortcuts_inhibit_new_inhibitor = { .notify = handle_keyboard_shortcuts_inhibit_new_inhibitor}; -static struct wl_listener last_cursor_surface_destroy_listener = { - .notify = last_cursor_surface_destroy}; #ifdef XWAYLAND -static void fix_xwayland_unmanaged_coordinate(Client *c); -static int32_t synckeymap(void *data); static void activatex11(struct wl_listener *listener, void *data); static void configurex11(struct wl_listener *listener, void *data); static void createnotifyx11(struct wl_listener *listener, void *data); static void dissociatex11(struct wl_listener *listener, void *data); -static void commitx11(struct wl_listener *listener, void *data); static void associatex11(struct wl_listener *listener, void *data); static void sethints(struct wl_listener *listener, void *data); static void xwaylandready(struct wl_listener *listener, void *data); @@ -996,13 +951,13 @@ static void setgeometrynotify(struct wl_listener *listener, void *data); static struct wl_listener new_xwayland_surface = {.notify = createnotifyx11}; static struct wl_listener xwayland_ready = {.notify = xwaylandready}; static struct wlr_xwayland *xwayland; -static struct wl_event_source *sync_keymap; #endif #include "animation/client.h" #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" @@ -1012,6 +967,7 @@ static struct wl_event_source *sync_keymap; void client_change_mon(Client *c, Monitor *m) { setmon(c, m, c->tags, true); + reset_foreign_tolevel(c); if (c->isfloating) { c->float_geom = c->geom = setclient_coordinate_center(c, c->mon, c->geom, 0, 0); @@ -1067,7 +1023,7 @@ void show_scratchpad(Client *c) { if (c->isfullscreen || c->ismaximizescreen) { c->isfullscreen = 0; // 清除窗口全屏标志 c->ismaximizescreen = 0; - c->bw = c->isnoborder ? 0 : config.borderpx; + c->bw = c->isnoborder ? 0 : borderpx; } /* return if fullscreen */ @@ -1075,10 +1031,10 @@ void show_scratchpad(Client *c) { setfloating(c, 1); c->geom.width = c->iscustomsize ? c->float_geom.width - : 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->mon->w.width * scratchpad_width_ratio; + c->geom.height = c->iscustomsize + ? c->float_geom.height + : c->mon->w.height * scratchpad_height_ratio; // 重新计算居中的坐标 c->float_geom = c->geom = c->animainit_geom = c->animation.current = setclient_coordinate_center(c, c->mon, c->geom, 0, 0); @@ -1113,9 +1069,6 @@ void swallow(Client *c, Client *w) { c->tags = w->tags; c->geom = w->geom; c->float_geom = w->float_geom; - c->stack_inner_per = w->stack_inner_per; - c->master_inner_per = w->master_inner_per; - c->master_mfact_per = w->master_mfact_per; c->scroller_proportion = w->scroller_proportion; c->next_in_stack = w->next_in_stack; c->prev_in_stack = w->prev_in_stack; @@ -1146,7 +1099,7 @@ void swallow(Client *c, Client *w) { bool switch_scratchpad_client_state(Client *c) { - if (config.scratchpad_cross_monitor && selmon && c->mon != selmon && + if (scratchpad_cross_monitor && selmon && c->mon != selmon && c->is_in_scratchpad) { // 保存原始monitor用于尺寸计算 Monitor *oldmon = c->mon; @@ -1200,12 +1153,12 @@ void apply_named_scratchpad(Client *target_client) { Client *c = NULL; wl_list_for_each(c, &clients, link) { - if (!config.scratchpad_cross_monitor && c->mon != selmon) { + if (!scratchpad_cross_monitor && c->mon != selmon) { continue; } - if (config.single_scratchpad && c->is_in_scratchpad && - c->is_scratchpad_show && c != target_client) { + if (single_scratchpad && c->is_in_scratchpad && c->is_scratchpad_show && + c != target_client) { set_minimized(c); } } @@ -1263,60 +1216,17 @@ void toggle_hotarea(int32_t x_root, int32_t y_root) { if (grabc) return; - // 根据热角位置计算不同的热区坐标 - unsigned hx, hy; + unsigned hx = selmon->m.x + hotarea_size; + unsigned hy = selmon->m.y + selmon->m.height - hotarea_size; - switch (config.hotarea_corner) { - case BOTTOM_RIGHT: // 右下角 - 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 + config.hotarea_size; - hy = selmon->m.y + config.hotarea_size; - break; - case TOP_RIGHT: // 右上角 - 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 + config.hotarea_size; - hy = selmon->m.y + selmon->m.height - config.hotarea_size; - break; - } - - // 判断鼠标是否在热区内 - int in_hotarea = 0; - - switch (config.hotarea_corner) { - case BOTTOM_RIGHT: // 右下角 - in_hotarea = (y_root > hy && x_root > hx && - x_root <= (selmon->m.x + selmon->m.width) && - y_root <= (selmon->m.y + selmon->m.height)); - break; - case TOP_LEFT: // 左上角 - in_hotarea = (y_root < hy && x_root < hx && x_root >= selmon->m.x && - y_root >= selmon->m.y); - break; - case TOP_RIGHT: // 右上角 - in_hotarea = (y_root < hy && x_root > hx && - x_root <= (selmon->m.x + selmon->m.width) && - y_root >= selmon->m.y); - break; - case BOTTOM_LEFT: // 左下角(默认) - default: - in_hotarea = (y_root > hy && x_root < hx && x_root >= selmon->m.x && - y_root <= (selmon->m.y + selmon->m.height)); - break; - } - - if (config.enable_hotarea == 1 && selmon->is_in_hotarea == 0 && - in_hotarea) { + if (enable_hotarea == 1 && selmon->is_in_hotarea == 0 && y_root > hy && + x_root < hx && x_root >= selmon->m.x && + y_root <= (selmon->m.y + selmon->m.height)) { toggleoverview(&arg); selmon->is_in_hotarea = 1; - } else if (config.enable_hotarea == 1 && selmon->is_in_hotarea == 1 && - !in_hotarea) { + } else if (enable_hotarea == 1 && selmon->is_in_hotarea == 1 && + (y_root <= hy || x_root >= hx || x_root < selmon->m.x || + y_root > (selmon->m.y + selmon->m.height))) { selmon->is_in_hotarea = 0; } } @@ -1325,7 +1235,6 @@ static void apply_rule_properties(Client *c, const ConfigWinRule *r) { APPLY_INT_PROP(c, r, isterm); APPLY_INT_PROP(c, r, allow_csd); APPLY_INT_PROP(c, r, force_maximize); - APPLY_INT_PROP(c, r, force_tiled_state); APPLY_INT_PROP(c, r, force_tearing); APPLY_INT_PROP(c, r, noswallow); APPLY_INT_PROP(c, r, nofocus); @@ -1334,7 +1243,6 @@ static void apply_rule_properties(Client *c, const ConfigWinRule *r) { APPLY_INT_PROP(c, r, no_force_center); APPLY_INT_PROP(c, r, isfloating); APPLY_INT_PROP(c, r, isfullscreen); - APPLY_INT_PROP(c, r, isfakefullscreen); APPLY_INT_PROP(c, r, isnoborder); APPLY_INT_PROP(c, r, isnoshadow); APPLY_INT_PROP(c, r, isnoradius); @@ -1347,7 +1255,6 @@ static void apply_rule_properties(Client *c, const ConfigWinRule *r) { APPLY_INT_PROP(c, r, ignore_maximize); APPLY_INT_PROP(c, r, ignore_minimize); APPLY_INT_PROP(c, r, isnosizehint); - APPLY_INT_PROP(c, r, indleinhibit_when_focus); APPLY_INT_PROP(c, r, isunglobal); APPLY_INT_PROP(c, r, noblur); APPLY_INT_PROP(c, r, allow_shortcuts_inhibit); @@ -1411,22 +1318,11 @@ void applyrules(Client *c) { Client *fc = NULL; Client *parent = NULL; - if (!c) - return; - parent = client_get_parent(c); Monitor *mon = parent && parent->mon ? parent->mon : selmon; c->isfloating = client_is_float_type(c) || parent; - -#ifdef XWAYLAND - if (c->isfloating && client_is_x11(c)) { - fix_xwayland_unmanaged_coordinate(c); - c->float_geom = c->geom; - } -#endif - if (!(appid = client_get_appid(c))) appid = broken; if (!(title = client_get_title(c))) @@ -1452,7 +1348,7 @@ void applyrules(Client *c) { // set monitor of client wl_list_for_each(m, &mons, link) { - if (match_monitor_spec(r->monitor, m)) { + if (regex_match(r->monitor, m->wlr_output->name)) { mon = m; } } @@ -1502,8 +1398,7 @@ void applyrules(Client *c) { /*-----------------------apply rule action-------------------------*/ // rule action only apply after map not apply in the init commit - struct wlr_surface *surface = client_surface(c); - if (!surface || !surface->mapped) + if (!client_surface(c)->mapped) return; // apply swallow rule @@ -1529,7 +1424,6 @@ void applyrules(Client *c) { setmon(c, mon, newtags, !c->isopensilent && !(client_is_x11_popup(c) && client_should_ignore_focus(c)) && - mon && (!c->istagsilent || !newtags || newtags & mon->tagset[mon->seltags])); @@ -1542,16 +1436,12 @@ void applyrules(Client *c) { setfullscreen(c, fullscreen_state_backup); - if (c->isfakefullscreen) { - setfakefullscreen(c, 1); - } - /* if there is a new non-floating window in the current tag, the fullscreen window in the current tag will exit fullscreen and participate in tiling */ wl_list_for_each(fc, &clients, - link) if (fc && fc != c && c->tags & fc->tags && c->mon && + link) if (fc && fc != c && c->tags & fc->tags && VISIBLEON(fc, c->mon) && ISFULLSCREEN(fc) && !c->isfloating) { clear_fullscreen_flag(fc); @@ -1570,7 +1460,7 @@ void applyrules(Client *c) { } // apply overlay rule - if (c->isoverlay && c->scene) { + if (c->isoverlay) { wlr_scene_node_reparent(&c->scene->node, layers[LyrOverlay]); wlr_scene_node_raise_to_top(&c->scene->node); } @@ -1588,9 +1478,6 @@ void arrangelayer(Monitor *m, struct wl_list *list, struct wlr_box *usable_area, !layer_surface->initialized) continue; - if (l->being_unmapped) - continue; - wlr_scene_layer_surface_v1_configure(l->scene_layer, &full_area, usable_area); wlr_scene_node_set_position(&l->popups->node, l->scene->node.x, @@ -1608,7 +1495,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 ? config.borderpx : 0; + uint32_t cbw = !render_border || c->fake_no_border ? borderpx : 0; uint32_t tcbw; uint32_t cx, cy, cw, ch, tcx, tcy, tcw, tch; cx = c->geom.x + cbw; @@ -1620,14 +1507,14 @@ void apply_window_snap(Client *c) { if (!c || !c->mon || !client_surface(c)->mapped || c->iskilling) return; - if (!c->isfloating || !config.enable_floating_snap) + if (!c->isfloating || !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 ? config.borderpx : 0; + tcbw = !render_border || tc->fake_no_border ? borderpx : 0; tcx = tc->geom.x + tcbw; tcy = tc->geom.y + tcbw; tcw = tc->geom.width - 2 * tcbw; @@ -1681,19 +1568,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 < config.snap_distance) { + if (snap_left < snap_right && snap_left < snap_distance) { c->geom.x = c->geom.x - snap_left; } - if (snap_right <= snap_left && snap_right < config.snap_distance) { + if (snap_right <= snap_left && snap_right < snap_distance) { c->geom.x = c->geom.x + snap_right; } - if (snap_up < snap_down && snap_up < config.snap_distance) { + if (snap_up < snap_down && snap_up < snap_distance) { c->geom.y = c->geom.y - snap_up; } - if (snap_down <= snap_up && snap_down < config.snap_distance) { + if (snap_down <= snap_up && snap_down < snap_distance) { c->geom.y = c->geom.y + snap_down; } @@ -1707,10 +1594,9 @@ void focuslayer(LayerSurface *l) { client_notify_enter(l->layer_surface->surface, wlr_seat_get_keyboard(seat)); } -void reset_exclusive_layers_focus(Monitor *m) { +void reset_exclusive_layer(Monitor *m) { LayerSurface *l = NULL; int32_t i; - bool neet_change_focus_to_client = false; uint32_t layers_above_shell[] = { ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY, ZWLR_LAYER_SHELL_V1_LAYER_TOP, @@ -1721,47 +1607,28 @@ void reset_exclusive_layers_focus(Monitor *m) { return; for (i = 0; i < (int32_t)LENGTH(layers_above_shell); i++) { - wl_list_for_each(l, &m->layers[layers_above_shell[i]], link) { + wl_list_for_each_reverse(l, &m->layers[layers_above_shell[i]], link) { if (l == exclusive_focus && l->layer_surface->current.keyboard_interactive != - ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) { - + ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) exclusive_focus = NULL; - - neet_change_focus_to_client = true; - } - - if (l->layer_surface->surface == - seat->keyboard_state.focused_surface && - l->being_unmapped) { - neet_change_focus_to_client = true; - } - if (l->layer_surface->current.keyboard_interactive == ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_NONE && l->layer_surface->surface == - seat->keyboard_state.focused_surface) { - neet_change_focus_to_client = true; - } + seat->keyboard_state.focused_surface) + focusclient(focustop(selmon), 1); if (locked || l->layer_surface->current.keyboard_interactive != ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE || - l->being_unmapped) + !l->mapped || l == exclusive_focus) continue; /* Deactivate the focused client. */ exclusive_focus = l; - neet_change_focus_to_client = false; - if (l->layer_surface->surface != - seat->keyboard_state.focused_surface) - focuslayer(l); + focuslayer(l); return; } } - - if (neet_change_focus_to_client) { - focusclient(focustop(selmon), 1); - } } void arrangelayers(Monitor *m) { @@ -1783,6 +1650,9 @@ void arrangelayers(Monitor *m) { /* Arrange non-exlusive surfaces from top->bottom */ for (i = 3; i >= 0; i--) arrangelayer(m, &m->layers[i], &usable_area, 0); + + /* Find topmost keyboard interactive layer, if such a layer exists */ + reset_exclusive_layer(m); } void // 鼠标滚轮事件 @@ -1823,8 +1693,7 @@ 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 > - config.axis_bind_apply_timeout || + if (event->time_msec - axis_apply_time > axis_bind_apply_timeout || axis_apply_dir * event->delta < 0) { a->func(&a->arg); axis_apply_time = event->time_msec; @@ -1844,10 +1713,9 @@ 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 * config.axis_scroll_factor, - roundf(event->delta_discrete * config.axis_scroll_factor), - event->source, event->relative_direction); + event->time_msec, event->orientation, event->delta * axis_scroll_factor, + roundf(event->delta_discrete * axis_scroll_factor), event->source, + event->relative_direction); } int32_t ongesture(struct wlr_pointer_swipe_end_event *event) { @@ -1865,8 +1733,7 @@ int32_t ongesture(struct wlr_pointer_swipe_end_event *event) { } // Require absolute distance movement beyond a small thresh-hold - if (adx * adx + ady * ady < - config.swipe_min_threshold * config.swipe_min_threshold) { + if (adx * adx + ady * ady < swipe_min_threshold * swipe_min_threshold) { return handled; } @@ -2003,7 +1870,7 @@ void place_drag_tile_client(Client *c) { bool check_trackpad_disabled(struct wlr_pointer *pointer) { struct libinput_device *device; - if (!config.disable_trackpad) + if (!disable_trackpad) return false; if (wlr_input_device_is_libinput(&pointer->base) && @@ -2080,21 +1947,14 @@ buttonpress(struct wl_listener *listener, void *data) { if (config.mouse_bindings_count < 1) break; m = &config.mouse_bindings[ji]; - - if (selmon->isoverview && event->button == BTN_LEFT && c) { - toggleoverview(&(Arg){.i = 1}); - return; - } - - if (selmon->isoverview && event->button == BTN_RIGHT && c) { - pending_kill_client(c); - return; - } - if (CLEANMASK(mods) == CLEANMASK(m->mod) && event->button == m->button && m->func && - (CLEANMASK(m->mod) != 0 || - (event->button != BTN_LEFT && event->button != BTN_RIGHT))) { + (selmon->isoverview == 1 || m->button == BTN_MIDDLE) && c) { + m->func(&m->arg); + return; + } else if (CLEANMASK(mods) == CLEANMASK(m->mod) && + event->button == m->button && m->func && + CLEANMASK(m->mod) != 0) { m->func(&m->arg); return; } @@ -2116,13 +1976,14 @@ buttonpress(struct wl_listener *listener, void *data) { selmon = xytomon(cursor->x, cursor->y); client_update_oldmonname_record(grabc, selmon); setmon(grabc, selmon, 0, true); + reset_foreign_tolevel(grabc); selmon->prevsel = ISTILED(selmon->sel) ? selmon->sel : NULL; selmon->sel = grabc; tmpc = grabc; grabc = NULL; start_drag_window = false; last_apply_drap_time = 0; - if (tmpc->drag_to_tile && config.drag_tile_to_tile) { + if (tmpc->drag_to_tile && drag_tile_to_tile) { place_drag_tile_client(tmpc); } else { apply_window_snap(tmpc); @@ -2155,7 +2016,7 @@ void checkidleinhibitor(struct wlr_surface *exclude) { toplevel_from_wlr_surface(inhibitor->surface, &c, NULL); - if (config.idleinhibit_ignore_visible) { + if (idleinhibit_ignore_visible) { inhibited = 1; break; } @@ -2170,11 +2031,6 @@ void checkidleinhibitor(struct wlr_surface *exclude) { wlr_idle_notifier_v1_set_inhibited(idle_notifier, inhibited); } -void last_cursor_surface_destroy(struct wl_listener *listener, void *data) { - last_cursor.surface = NULL; - wl_list_remove(&listener->link); -} - void setcursorshape(struct wl_listener *listener, void *data) { struct wlr_cursor_shape_manager_v1_request_set_shape_event *event = data; if (cursor_mode != CurNormal && cursor_mode != CurPressed) @@ -2183,11 +2039,6 @@ void setcursorshape(struct wl_listener *listener, void *data) { * actually has pointer focus first. If so, we can tell the cursor to * use the provided cursor shape. */ if (event->seat_client == seat->pointer_state.focused_client) { - /* Remove surface destroy listener if active */ - if (last_cursor.surface && - last_cursor_surface_destroy_listener.link.prev != NULL) - wl_list_remove(&last_cursor_surface_destroy_listener.link); - last_cursor.shape = event->shape; last_cursor.surface = NULL; if (!cursor_hidden) @@ -2296,11 +2147,6 @@ void cleanupmon(struct wl_listener *listener, void *data) { wlr_scene_node_destroy(&m->blur->node); m->blur = NULL; } - if (m->skip_frame_timeout) { - monitor_stop_skip_frame_timer(m); - wl_event_source_remove(m->skip_frame_timeout); - m->skip_frame_timeout = NULL; - } m->wlr_output->data = NULL; free(m->pertag); free(m); @@ -2353,26 +2199,13 @@ 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 (config.blur_optimized) { + if (blur_optimized) { wlr_scene_buffer_set_backdrop_blur_optimized(buffer, true); } else { wlr_scene_buffer_set_backdrop_blur_optimized(buffer, false); } } -void layer_flush_blur_background(LayerSurface *l) { - if (!config.blur) - return; - - // 如果背景层发生变化,标记优化的模糊背景缓存需要更新 - if (l->layer_surface->current.layer == - ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND) { - if (l->mon) { - wlr_scene_optimized_blur_mark_dirty(l->mon->blur); - } - } -} - void maplayersurfacenotify(struct wl_listener *listener, void *data) { LayerSurface *l = wl_container_of(listener, l, map); struct wlr_layer_surface_v1 *layer_surface = l->layer_surface; @@ -2417,22 +2250,27 @@ 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, config.border_radius, - config.shadows_blur, config.shadowscolor); + l->shadow = wlr_scene_shadow_create(l->scene, 0, 0, border_radius, + shadows_blur, shadowscolor); wlr_scene_node_lower_to_bottom(&l->shadow->node); wlr_scene_node_set_enabled(&l->shadow->node, true); } // 初始化动画 - if (config.animations && config.layer_animations && !l->noanim) { - l->animation.duration = config.animation_duration_open; + if (animations && layer_animations && !l->noanim) { + l->animation.duration = animation_duration_open; l->animation.action = OPEN; layer_set_pending_state(l); } // 刷新布局,让窗口能感应到exclude_zone变化以及设置独占表面 arrangelayers(l->mon); - reset_exclusive_layers_focus(l->mon); + + // 按需交互layer需要像正常窗口一样抢占非独占layer的焦点 + if (!exclusive_focus && + l->layer_surface->current.keyboard_interactive == + ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND) { + focuslayer(l); + } } void commitlayersurfacenotify(struct wl_listener *listener, void *data) { @@ -2452,28 +2290,13 @@ void commitlayersurfacenotify(struct wl_listener *listener, void *data) { l->layer_surface->current = l->layer_surface->pending; arrangelayers(l->mon); l->layer_surface->current = old_state; - // 按需交互layer只在map之前设置焦点 - if (!exclusive_focus && - l->layer_surface->current.keyboard_interactive == - ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_ON_DEMAND) { - focuslayer(l); - } - return; - } - // 检查surface是否有buffer - // 空buffer,只是隐藏,不改变mapped状态 - if (l->mapped && !layer_surface->surface->buffer) { - wlr_scene_node_set_enabled(&l->scene->node, false); return; - } else { - wlr_scene_node_set_enabled(&l->scene->node, true); } get_layer_target_geometry(l, &box); - if (config.animations && config.layer_animations && !l->noanim && - l->mapped && + if (animations && 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)) { @@ -2483,12 +2306,13 @@ 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 = config.animation_duration_move; + l->animation.duration = animation_duration_move; l->need_output_flush = true; layer_set_pending_state(l); } - if (config.blur && config.blur_layer) { + if (blur && blur_layer) { + // 设置非背景layer模糊 if (!l->noblur && layer_surface->current.layer != ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM && @@ -2500,33 +2324,38 @@ void commitlayersurfacenotify(struct wl_listener *listener, void *data) { } } - layer_flush_blur_background(l); + if (blur) { + // 如果背景层发生变化,标记优化的模糊背景缓存需要更新 + if (layer_surface->current.layer == + ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND) { + if (l->mon) { + wlr_scene_optimized_blur_mark_dirty(l->mon->blur); + } + } + } + + if (layer_surface == exclusive_focus && + layer_surface->current.keyboard_interactive != + ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) + exclusive_focus = NULL; if (layer_surface->current.committed == 0 && l->mapped == layer_surface->surface->mapped) return; l->mapped = layer_surface->surface->mapped; - if (layer_surface->current.committed & WLR_LAYER_SURFACE_V1_STATE_LAYER) { - if (scene_layer != l->scene->node.parent) { - wlr_scene_node_reparent(&l->scene->node, scene_layer); - wl_list_remove(&l->link); - wl_list_insert(&l->mon->layers[layer_surface->current.layer], - &l->link); - wlr_scene_node_reparent( - &l->popups->node, - (layer_surface->current.layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP - ? layers[LyrTop] - : scene_layer)); - } + if (scene_layer != l->scene->node.parent) { + wlr_scene_node_reparent(&l->scene->node, scene_layer); + wl_list_remove(&l->link); + wl_list_insert(&l->mon->layers[layer_surface->current.layer], &l->link); + wlr_scene_node_reparent( + &l->popups->node, + (layer_surface->current.layer < ZWLR_LAYER_SHELL_V1_LAYER_TOP + ? layers[LyrTop] + : scene_layer)); } arrangelayers(l->mon); - - if (layer_surface->current.committed & - WLR_LAYER_SURFACE_V1_STATE_KEYBOARD_INTERACTIVITY) { - reset_exclusive_layers_focus(l->mon); - } } void commitnotify(struct wl_listener *listener, void *data) { @@ -2543,6 +2372,9 @@ void commitnotify(struct wl_listener *listener, void *data) { setmon(c, NULL, 0, true); /* Make sure to reapply rules in mapnotify() */ + client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | + WLR_EDGE_RIGHT); + uint32_t serial = wlr_xdg_surface_schedule_configure(c->surface.xdg); if (serial > 0) { c->configure_serial = serial; @@ -2602,113 +2434,36 @@ void destroydecoration(struct wl_listener *listener, void *data) { wl_list_remove(&c->set_decoration_mode.link); } -static bool popup_unconstrain(Popup *popup) { - struct wlr_xdg_popup *wlr_popup = popup->wlr_popup; - Client *c = NULL; +void commitpopup(struct wl_listener *listener, void *data) { + struct wlr_surface *surface = data; + struct wlr_xdg_popup *popup = wlr_xdg_popup_try_from_wlr_surface(surface); LayerSurface *l = NULL; + Client *c = NULL; + struct wlr_box box; int32_t type = -1; - if (!wlr_popup || !wlr_popup->parent) { - return false; - } + if (!popup->base->initial_commit) + return; - struct wlr_scene_node *parent_node = wlr_popup->parent->data; - if (!parent_node) { - wlr_log(WLR_ERROR, "Popup parent has no scene node"); - return false; - } + type = toplevel_from_wlr_surface(popup->base->surface, &c, &l); + if (!popup->parent || type < 0) + return; - type = toplevel_from_wlr_surface(wlr_popup->base->surface, &c, &l); + wlr_scene_node_raise_to_top(popup->parent->data); + + popup->base->surface->data = + wlr_scene_xdg_surface_create(popup->parent->data, popup->base); if ((l && !l->mon) || (c && !c->mon)) { - return true; - } - - struct wlr_box usable = type == LayerShell ? l->mon->m : c->mon->w; - - int lx, ly; - struct wlr_box constraint_box; - - if (type == LayerShell) { - wlr_scene_node_coords(&l->scene_layer->tree->node, &lx, &ly); - constraint_box.x = usable.x - lx; - constraint_box.y = usable.y - ly; - constraint_box.width = usable.width; - constraint_box.height = usable.height; - } else { - constraint_box.x = - usable.x - (c->geom.x + c->bw - c->surface.xdg->current.geometry.x); - constraint_box.y = - usable.y - (c->geom.y + c->bw - c->surface.xdg->current.geometry.y); - constraint_box.width = usable.width; - constraint_box.height = usable.height; - } - - wlr_xdg_popup_unconstrain_from_box(wlr_popup, &constraint_box); - return false; -} - -static void destroypopup(struct wl_listener *listener, void *data) { - Popup *popup = wl_container_of(listener, popup, destroy); - wl_list_remove(&popup->destroy.link); - wl_list_remove(&popup->reposition.link); - free(popup); -} - -static void commitpopup(struct wl_listener *listener, void *data) { - Popup *popup = wl_container_of(listener, popup, commit); - - struct wlr_surface *surface = data; - bool should_destroy = false; - struct wlr_xdg_popup *wlr_popup = - wlr_xdg_popup_try_from_wlr_surface(surface); - - if (!wlr_popup->base->initial_commit) + wlr_xdg_popup_destroy(popup); return; - - if (!wlr_popup->parent || !wlr_popup->parent->data) { - should_destroy = true; - goto cleanup_popup_commit; } + box = type == LayerShell ? l->mon->m : c->mon->w; + box.x -= (type == LayerShell ? l->scene->node.x : c->geom.x); + box.y -= (type == LayerShell ? l->scene->node.y : c->geom.y); + wlr_xdg_popup_unconstrain_from_box(popup, &box); - wlr_scene_node_raise_to_top(wlr_popup->parent->data); - - wlr_popup->base->surface->data = - wlr_scene_xdg_surface_create(wlr_popup->parent->data, wlr_popup->base); - - popup->wlr_popup = wlr_popup; - - should_destroy = popup_unconstrain(popup); - -cleanup_popup_commit: - - wl_list_remove(&popup->commit.link); - popup->commit.notify = NULL; - - if (should_destroy) { - wlr_xdg_popup_destroy(wlr_popup); - } -} - -static void repositionpopup(struct wl_listener *listener, void *data) { - Popup *popup = wl_container_of(listener, popup, reposition); - (void)popup_unconstrain(popup); -} - -static void createpopup(struct wl_listener *listener, void *data) { - struct wlr_xdg_popup *wlr_popup = data; - - Popup *popup = calloc(1, sizeof(Popup)); - if (!popup) - return; - - popup->destroy.notify = destroypopup; - wl_signal_add(&wlr_popup->events.destroy, &popup->destroy); - - popup->commit.notify = commitpopup; - wl_signal_add(&wlr_popup->base->surface->events.commit, &popup->commit); - - popup->reposition.notify = repositionpopup; - wl_signal_add(&wlr_popup->events.reposition, &popup->reposition); + wl_list_remove(&listener->link); + free(listener); } void createdecoration(struct wl_listener *listener, void *data) { @@ -2766,21 +2521,22 @@ 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, &config.xkb_rules, + if (!(keymap = xkb_keymap_new_from_names(context, &xkb_rules, XKB_KEYMAP_COMPILE_NO_FLAGS))) die("failed to compile keymap"); wlr_keyboard_set_keymap(&group->wlr_group->keyboard, keymap); - if (config.numlockon) { + if (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 (config.capslock) { + if (capslock) { xkb_mod_index_t mod_index = xkb_keymap_mod_get_index(keymap, XKB_MOD_NAME_CAPS); if (mod_index != XKB_MOD_INVALID) @@ -2794,8 +2550,8 @@ KeyboardGroup *createkeyboardgroup(void) { xkb_keymap_unref(keymap); xkb_context_unref(context); - wlr_keyboard_set_repeat_info(&group->wlr_group->keyboard, - config.repeat_rate, config.repeat_delay); + wlr_keyboard_set_repeat_info(&group->wlr_group->keyboard, repeat_rate, + repeat_delay); /* Set up listeners for keyboard events */ LISTEN(&group->wlr_group->keyboard.events.key, &group->key, keypress); @@ -2833,6 +2589,8 @@ void createlayersurface(struct wl_listener *listener, void *data) { LISTEN(&surface->events.commit, &l->surface_commit, commitlayersurfacenotify); LISTEN(&surface->events.unmap, &l->unmap, unmaplayersurfacenotify); + LISTEN(&layer_surface->events.destroy, &l->destroy, + destroylayersurfacenotify); l->layer_surface = layer_surface; l->mon = layer_surface->output->data; @@ -2845,8 +2603,6 @@ void createlayersurface(struct wl_listener *listener, void *data) { : scene_layer); l->scene->node.data = l->popups->node.data = l; - LISTEN(&l->scene->node.events.destroy, &l->destroy, destroylayernodenotify); - wl_list_insert(&l->mon->layers[layer_surface->pending.layer], &l->link); wlr_surface_send_enter(surface, layer_surface->output); } @@ -2903,58 +2659,16 @@ void enable_adaptive_sync(Monitor *m, struct wlr_output_state *state) { } } -bool monitor_matches_rule(Monitor *m, const ConfigMonitorRule *rule) { - if (rule->name != NULL && !regex_match(rule->name, m->wlr_output->name)) - return false; - if (rule->make != NULL && (m->wlr_output->make == NULL || - strcmp(rule->make, m->wlr_output->make) != 0)) - return false; - if (rule->model != NULL && (m->wlr_output->model == NULL || - strcmp(rule->model, m->wlr_output->model) != 0)) - return false; - if (rule->serial != NULL && - (m->wlr_output->serial == NULL || - strcmp(rule->serial, m->wlr_output->serial) != 0)) - return false; - return true; -} - -/* 将规则中的显示参数应用到 wlr_output_state 中,返回是否设置了自定义模式 */ -bool apply_rule_to_state(Monitor *m, const ConfigMonitorRule *rule, - struct wlr_output_state *state, int vrr, int custom) { - bool mode_set = false; - if (rule->width > 0 && rule->height > 0 && rule->refresh > 0) { - struct wlr_output_mode *internal_mode = get_nearest_output_mode( - m->wlr_output, rule->width, rule->height, rule->refresh); - if (internal_mode) { - wlr_output_state_set_mode(state, internal_mode); - mode_set = true; - } else if (custom || wlr_output_is_headless(m->wlr_output)) { - wlr_output_state_set_custom_mode( - state, rule->width, rule->height, - (int32_t)roundf(rule->refresh * 1000)); - mode_set = true; - } - } - if (vrr) { - enable_adaptive_sync(m, state); - } else { - wlr_output_state_set_adaptive_sync_enabled(state, false); - } - wlr_output_state_set_scale(state, rule->scale); - wlr_output_state_set_transform(state, rule->rr); - return mode_set; -} - void createmon(struct wl_listener *listener, void *data) { /* This event is raised by the backend when a new output (aka a display or * monitor) becomes available. */ struct wlr_output *wlr_output = data; const ConfigMonitorRule *r; uint32_t i; - int32_t ji, vrr, custom; + int32_t ji, jk; struct wlr_output_state state; Monitor *m = NULL; + struct wlr_output_mode *internal_mode = NULL; bool custom_monitor_mode = false; if (!wlr_output_init_render(wlr_output, alloc, drw)) @@ -2968,15 +2682,7 @@ void createmon(struct wl_listener *listener, void *data) { return; } - struct wl_event_loop *loop = wl_display_get_event_loop(dpy); m = wlr_output->data = ecalloc(1, sizeof(*m)); - - m->skip_frame_timeout = - wl_event_loop_add_timer(loop, monitor_skip_frame_timeout_callback, m); - m->skiping_frame = false; - m->resizing_count_pending = 0; - m->resizing_count_current = 0; - m->wlr_output = wlr_output; m->wlr_output->data = m; @@ -2985,47 +2691,74 @@ void createmon(struct wl_listener *listener, void *data) { for (i = 0; i < LENGTH(m->layers); i++) wl_list_init(&m->layers[i]); - m->gappih = config.gappih; - m->gappiv = config.gappiv; - m->gappoh = config.gappoh; - m->gappov = config.gappov; + wlr_output_state_init(&state); + /* Initialize monitor state using configured rules */ + m->gappih = gappih; + m->gappiv = gappiv; + m->gappoh = gappoh; + m->gappov = gappov; m->isoverview = 0; m->sel = NULL; m->is_in_hotarea = 0; - m->m.x = INT32_MAX; - m->m.y = INT32_MAX; float scale = 1; + m->mfact = default_mfact; + m->nmaster = default_nmaster; enum wl_output_transform rr = WL_OUTPUT_TRANSFORM_NORMAL; - - wlr_output_state_init(&state); wlr_output_state_set_scale(&state, scale); wlr_output_state_set_transform(&state, rr); + m->lt = &layouts[0]; for (ji = 0; ji < config.monitor_rules_count; ji++) { if (config.monitor_rules_count < 1) break; r = &config.monitor_rules[ji]; - - if (monitor_matches_rule(m, r)) { - m->m.x = r->x == INT32_MAX ? INT32_MAX : r->x; - m->m.y = r->y == INT32_MAX ? INT32_MAX : r->y; - vrr = r->vrr >= 0 ? r->vrr : 0; - custom = r->custom >= 0 ? r->custom : 0; + if (!r->name || regex_match(r->name, wlr_output->name)) { + m->mfact = r->mfact; + m->nmaster = r->nmaster; + m->m.x = r->x; + m->m.y = r->y; + if (r->layout) { + for (jk = 0; jk < LENGTH(layouts); jk++) { + if (strcmp(layouts[jk].name, r->layout) == 0) { + m->lt = &layouts[jk]; + } + } + } scale = r->scale; rr = r->rr; - if (apply_rule_to_state(m, r, &state, vrr, custom)) { - custom_monitor_mode = true; + if (r->width > 0 && r->height > 0 && r->refresh > 0) { + internal_mode = get_nearest_output_mode(m->wlr_output, r->width, + r->height, r->refresh); + if (internal_mode) { + custom_monitor_mode = true; + wlr_output_state_set_mode(&state, internal_mode); + } else if (wlr_output_is_headless(m->wlr_output)) { + custom_monitor_mode = true; + wlr_output_state_set_custom_mode( + &state, r->width, r->height, + (int32_t)roundf(r->refresh * 1000)); + } } - break; // 只应用第一个匹配规则 + wlr_output_state_set_scale(&state, r->scale); + wlr_output_state_set_transform(&state, r->rr); + break; } } + /* The mode is a tuple of (width, height, refresh rate), and each + * monitor supports only a specific set of modes. We just pick the + * monitor's preferred mode; a more sophisticated compositor would let + * the user configure it. */ if (!custom_monitor_mode) wlr_output_state_set_mode(&state, wlr_output_preferred_mode(wlr_output)); + if (adaptive_sync) { + enable_adaptive_sync(m, &state); + } + /* Set up event listeners */ LISTEN(&wlr_output->events.frame, &m->frame, rendermon); LISTEN(&wlr_output->events.destroy, &m->destroy, cleanupmon); @@ -3050,9 +2783,9 @@ void createmon(struct wl_listener *listener, void *data) { } for (i = 0; i <= LENGTH(tags); i++) { - m->pertag->nmasters[i] = config.default_nmaster; - m->pertag->mfacts[i] = config.default_mfact; - m->pertag->ltidxs[i] = &layouts[0]; + m->pertag->nmasters[i] = m->nmaster; + m->pertag->mfacts[i] = m->mfact; + m->pertag->ltidxs[i] = m->lt; } // apply tag rule @@ -3074,16 +2807,17 @@ void createmon(struct wl_listener *listener, void *data) { * output (such as DPI, scale factor, manufacturer, etc). */ m->scene_output = wlr_scene_output_create(scene, wlr_output); - if (m->m.x == INT32_MAX || m->m.y == INT32_MAX) + if (m->m.x == -1 && m->m.y == -1) wlr_output_layout_add_auto(output_layout, wlr_output); else wlr_output_layout_add(output_layout, wlr_output, m->m.x, m->m.y); - if (config.blur) { + if (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 +2843,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 = config.borderpx; + c->bw = borderpx; LISTEN(&toplevel->base->surface->events.commit, &c->commit, commitnotify); LISTEN(&toplevel->base->surface->events.map, &c->map, mapnotify); @@ -3155,54 +2889,44 @@ 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, 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_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_scroll_set_natural_scroll_enabled( - device, config.trackpad_natural_scrolling); + device, trackpad_natural_scrolling); } else { libinput_device_config_scroll_set_natural_scroll_enabled( - device, config.mouse_natural_scrolling); + device, mouse_natural_scrolling); } if (libinput_device_config_dwt_is_available(device)) - libinput_device_config_dwt_set_enabled(device, - config.disable_while_typing); + libinput_device_config_dwt_set_enabled(device, disable_while_typing); if (libinput_device_config_left_handed_is_available(device)) - libinput_device_config_left_handed_set(device, config.left_handed); + libinput_device_config_left_handed_set(device, left_handed); if (libinput_device_config_middle_emulation_is_available(device)) libinput_device_config_middle_emulation_set_enabled( - device, config.middle_button_emulation); + device, middle_button_emulation); if (libinput_device_config_scroll_get_methods(device) != LIBINPUT_CONFIG_SCROLL_NO_SCROLL) - libinput_device_config_scroll_set_method(device, config.scroll_method); + libinput_device_config_scroll_set_method(device, scroll_method); if (libinput_device_config_scroll_get_methods(device) == LIBINPUT_CONFIG_SCROLL_ON_BUTTON_DOWN) - libinput_device_config_scroll_set_button(device, config.scroll_button); + libinput_device_config_scroll_set_button(device, scroll_button); if (libinput_device_config_click_get_methods(device) != LIBINPUT_CONFIG_CLICK_METHOD_NONE) - libinput_device_config_click_set_method(device, config.click_method); + libinput_device_config_click_set_method(device, click_method); if (libinput_device_config_send_events_get_modes(device)) - libinput_device_config_send_events_set_mode(device, - config.send_events_mode); + libinput_device_config_send_events_set_mode(device, send_events_mode); - 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); - libinput_device_config_accel_set_profile(device, 0); - libinput_device_config_accel_set_speed(device, 0); + if (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); } } @@ -3289,6 +3013,13 @@ void createpointerconstraint(struct wl_listener *listener, void *data) { &pointer_constraint->destroy, destroypointerconstraint); } +void createpopup(struct wl_listener *listener, void *data) { + /* This event is raised when a client (either xdg-shell or layer-shell) + * creates a new popup. */ + struct wlr_xdg_popup *popup = data; + LISTEN_STATIC(&popup->base->surface->events.commit, commitpopup); +} + void cursorconstrain(struct wlr_pointer_constraint_v1 *constraint) { if (active_constraint == constraint) return; @@ -3340,7 +3071,7 @@ void destroyidleinhibitor(struct wl_listener *listener, void *data) { free(listener); } -void destroylayernodenotify(struct wl_listener *listener, void *data) { +void destroylayersurfacenotify(struct wl_listener *listener, void *data) { LayerSurface *l = wl_container_of(listener, l, destroy); wl_list_remove(&l->link); @@ -3348,6 +3079,7 @@ void destroylayernodenotify(struct wl_listener *listener, void *data) { wl_list_remove(&l->map.link); wl_list_remove(&l->unmap.link); wl_list_remove(&l->surface_commit.link); + wlr_scene_node_destroy(&l->scene->node); wlr_scene_node_destroy(&l->popups->node); free(l); } @@ -3384,7 +3116,8 @@ void destroylocksurface(struct wl_listener *listener, void *data) { if (lock_surface->surface != seat->keyboard_state.focused_surface) { if (exclusive_focus && !locked) { - reset_exclusive_layers_focus(m); + exclusive_focus = NULL; + reset_exclusive_layer(m); } return; } @@ -3393,7 +3126,9 @@ void destroylocksurface(struct wl_listener *listener, void *data) { surface = wl_container_of(cur_lock->surfaces.next, surface, link); client_notify_enter(surface->surface, wlr_seat_get_keyboard(seat)); } else if (!locked) { - reset_exclusive_layers_focus(selmon); + exclusive_focus = NULL; + reset_exclusive_layer(selmon); + focusclient(focustop(selmon), 1); } else { wlr_seat_keyboard_clear_focus(seat); } @@ -3498,8 +3233,6 @@ void focusclient(Client *c, int32_t lift) { selmon->sel = c; c->isfocusing = true; - check_keep_idle_inhibit(c); - if (last_focus_client && !last_focus_client->iskilling && last_focus_client != c) { last_focus_client->isfocusing = false; @@ -3632,10 +3365,7 @@ void requestmonstate(struct wl_listener *listener, void *data) { void inputdevice(struct wl_listener *listener, void *data) { /* This event is raised by the backend when a new input device becomes - * available. - * when the backend is a headless backend, this event will never be - * triggered. - */ + * available. */ struct wlr_input_device *device = data; uint32_t caps; @@ -3706,6 +3436,11 @@ keybinding(uint32_t state, bool locked, uint32_t mods, xkb_keysym_t sym, int32_t ji; int32_t isbreak = 0; + // not allow modifier keys to be used as a keybinding + if (keycode == 50 || keycode == 37 || keycode == 133 || keycode == 64 || + keycode == 62 || keycode == 108 || keycode == 105 || keycode == 134) + return false; + if (is_keyboard_shortcut_inhibitor(seat->keyboard_state.focused_surface)) { return false; } @@ -3849,7 +3584,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 (config.ov_tab_mode && !locked && group == kb_group && + if (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) && @@ -3933,7 +3668,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 (!config.allow_lock_transparent) { + if (!allow_lock_transparent) { wlr_scene_node_set_enabled(&locked_bg->node, true); } if (cur_lock) { @@ -3970,10 +3705,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 (config.blur && c && !c->noblur) { + if (blur && c && !c->noblur) { wlr_scene_buffer_set_backdrop_blur(buffer, true); wlr_scene_buffer_set_backdrop_blur_ignore_transparent(buffer, false); - if (config.blur_optimized) { + if (blur_optimized) { wlr_scene_buffer_set_backdrop_blur_optimized(buffer, true); } else { wlr_scene_buffer_set_backdrop_blur_optimized(buffer, false); @@ -3985,24 +3720,6 @@ static void iter_xdg_scene_buffers(struct wlr_scene_buffer *buffer, int32_t sx, void init_client_properties(Client *c) { c->isfocusing = false; - c->isfloating = 0; - c->isfakefullscreen = 0; - c->isnoanimation = 0; - c->isopensilent = 0; - c->istagsilent = 0; - c->noswallow = 0; - c->isterm = 0; - c->noblur = 0; - c->tearing_hint = 0; - c->overview_isfullscreenbak = 0; - c->overview_ismaximizescreenbak = 0; - c->overview_isfloatingbak = 0; - c->pid = 0; - c->swallowing = NULL; - c->swallowedby = NULL; - c->ismaster = 0; - c->old_ismaster = 0; - c->isleftstack = 0; c->ismaximizescreen = 0; c->isfullscreen = 0; c->need_float_size_reduce = 0; @@ -4020,13 +3737,13 @@ void init_client_properties(Client *c) { c->is_restoring_from_ov = 0; c->isurgent = 0; c->need_output_flush = 0; - c->scroller_proportion = config.scroller_default_proportion; + c->scroller_proportion = 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 = config.focused_opacity; - c->unfocused_opacity = config.unfocused_opacity; + c->focused_opacity = focused_opacity; + c->unfocused_opacity = unfocused_opacity; c->nofocus = 0; c->nofadein = 0; c->nofadeout = 0; @@ -4042,16 +3759,11 @@ void init_client_properties(Client *c) { c->master_mfact_per = 0.0f; c->master_inner_per = 0.0f; c->stack_inner_per = 0.0f; - c->old_stack_inner_per = 1.0f; - c->old_master_inner_per = 1.0f; - c->old_master_mfact_per = 1.0f; c->isterm = 0; c->allow_csd = 0; c->force_maximize = 0; - c->force_tiled_state = 1; c->force_tearing = 0; c->allow_shortcuts_inhibit = SHORTCUTS_INHIBIT_ENABLE; - c->indleinhibit_when_focus = 0; c->scroller_proportion_single = 0.0f; c->float_geom.width = 0; c->float_geom.height = 0; @@ -4060,13 +3772,6 @@ void init_client_properties(Client *c) { c->stack_proportion = 0.0f; c->next_in_stack = NULL; c->prev_in_stack = NULL; - memset(c->oldmonname, 0, sizeof(c->oldmonname)); - memcpy(c->opacity_animation.initial_border_color, config.bordercolor, - sizeof(c->opacity_animation.initial_border_color)); - 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; } void // old fix to 0.5 @@ -4093,7 +3798,7 @@ mapnotify(struct wl_listener *listener, void *data) { c->bw = 0; c->isnoborder = 1; } else { - c->bw = config.borderpx; + c->bw = borderpx; } if (client_should_global(c)) { @@ -4108,39 +3813,37 @@ mapnotify(struct wl_listener *listener, void *data) { */ if (client_is_unmanaged(c)) { /* Unmanaged clients always are floating */ -#ifdef XWAYLAND - if (client_is_x11(c)) { - fix_xwayland_unmanaged_coordinate(c); - LISTEN(&c->surface.xwayland->events.set_geometry, &c->set_geometry, - setgeometrynotify); - } -#endif wlr_scene_node_reparent(&c->scene->node, layers[LyrOverlay]); wlr_scene_node_set_position(&c->scene->node, c->geom.x, c->geom.y); if (client_wants_focus(c)) { focusclient(c, 1); exclusive_focus = c; } +#ifdef XWAYLAND + if (client_is_x11(c)) { + LISTEN(&c->surface.xwayland->events.set_geometry, &c->set_geometry, + setgeometrynotify); + } +#endif return; } // extra node - c->border = wlr_scene_rect_create( - c->scene, 0, 0, c->isurgent ? config.urgentcolor : config.bordercolor); + c->border = wlr_scene_rect_create(c->scene, 0, 0, + c->isurgent ? urgentcolor : 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, config.border_radius, - config.border_radius_location_default); + wlr_scene_rect_set_corner_radius(c->border, border_radius, + border_radius_location_default); wlr_scene_node_set_enabled(&c->border->node, true); - c->shadow = - wlr_scene_shadow_create(c->scene, 0, 0, config.border_radius, - config.shadows_blur, config.shadowscolor); + c->shadow = wlr_scene_shadow_create(c->scene, 0, 0, border_radius, + shadows_blur, shadowscolor); wlr_scene_node_lower_to_bottom(&c->shadow->node); wlr_scene_node_set_enabled(&c->shadow->node, true); - if (config.new_is_master && selmon && !is_scroller_layout(selmon)) + if (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) && @@ -4167,10 +3870,8 @@ mapnotify(struct wl_listener *listener, void *data) { applyrules(c); - if (!c->isfloating || c->force_tiled_state) { - client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | - WLR_EDGE_RIGHT); - } + client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | + WLR_EDGE_RIGHT); // apply buffer effects of client wlr_scene_node_for_each_buffer(&c->scene_surface->node, @@ -4287,30 +3988,6 @@ void motionabsolute(struct wl_listener *listener, void *data) { motionnotify(event->time_msec, &event->pointer->base, dx, dy, dx, dy); } -void resize_floating_window(Client *grabc) { - int cdx = (int)round(cursor->x) - grabcx; - int cdy = (int)round(cursor->y) - grabcy; - - cdx = !(rzcorner & 1) && grabc->geom.width - 2 * (int)grabc->bw - cdx < 1 - ? 0 - : cdx; - cdy = !(rzcorner & 2) && grabc->geom.height - 2 * (int)grabc->bw - cdy < 1 - ? 0 - : cdy; - - const struct wlr_box box = { - .x = grabc->geom.x + (rzcorner & 1 ? 0 : cdx), - .y = grabc->geom.y + (rzcorner & 2 ? 0 : cdy), - .width = grabc->geom.width + (rzcorner & 1 ? cdx : -cdx), - .height = grabc->geom.height + (rzcorner & 2 ? cdy : -cdy)}; - - grabc->float_geom = box; - - resize(grabc, box, 1); - grabcx += cdx; - grabcy += cdy; -} - void motionnotify(uint32_t time, struct wlr_input_device *device, double dx, double dy, double dx_unaccel, double dy_unaccel) { double sx = 0, sy = 0, sx_confined, sy_confined; @@ -4320,6 +3997,19 @@ void motionnotify(uint32_t time, struct wlr_input_device *device, double dx, struct wlr_pointer_constraint_v1 *constraint; bool should_lock = false; + /* Find the client under the pointer and send the event along. */ + xytonode(cursor->x, cursor->y, &surface, &c, NULL, &sx, &sy); + + if (cursor_mode == CurPressed && !seat->drag && + surface != seat->pointer_state.focused_surface && + toplevel_from_wlr_surface(seat->pointer_state.focused_surface, &w, + &l) >= 0) { + c = w; + surface = seat->pointer_state.focused_surface; + sx = cursor->x - (l ? l->scene->node.x : w->geom.x); + sy = cursor->y - (l ? l->scene->node.y : w->geom.y); + } + /* time is 0 in internal calls meant to restore pointer focus. */ if (time) { wlr_relative_pointer_manager_v1_send_relative_motion( @@ -4353,23 +4043,10 @@ 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 (config.sloppyfocus) + if (sloppyfocus) selmon = xytomon(cursor->x, cursor->y); } - /* Find the client under the pointer and send the event along. */ - xytonode(cursor->x, cursor->y, &surface, &c, NULL, &sx, &sy); - - if (cursor_mode == CurPressed && !seat->drag && - surface != seat->pointer_state.focused_surface && - toplevel_from_wlr_surface(seat->pointer_state.focused_surface, &w, - &l) >= 0) { - c = w; - surface = seat->pointer_state.focused_surface; - sx = cursor->x - (l ? l->scene->node.x : w->geom.x); - sy = cursor->y - (l ? l->scene->node.y : w->geom.y); - } - /* Update drag icon's position */ wlr_scene_node_set_position(&drag_icon->node, (int32_t)round(cursor->x), (int32_t)round(cursor->y)); @@ -4388,10 +4065,14 @@ void motionnotify(uint32_t time, struct wlr_input_device *device, double dx, } else if (cursor_mode == CurResize) { if (grabc->isfloating) { grabc->iscustomsize = 1; + grabc->float_geom = (struct wlr_box){ + .x = grabc->geom.x, + .y = grabc->geom.y, + .width = (int32_t)round(cursor->x) - grabc->geom.x, + .height = (int32_t)round(cursor->y) - grabc->geom.y}; if (last_apply_drap_time == 0 || - time - last_apply_drap_time > - config.drag_floating_refresh_interval) { - resize_floating_window(grabc); + time - last_apply_drap_time > drag_refresh_interval) { + resize(grabc, grabc->float_geom, 1); last_apply_drap_time = time; } return; @@ -4416,7 +4097,7 @@ void motionnotify(uint32_t time, struct wlr_input_device *device, double dx, should_lock = true; } - if (!(!config.edge_scroller_pointer_focus && c && c->mon && + if (!(!edge_scroller_pointer_focus && c && c->mon && is_scroller_layout(c->mon) && !INSIDEMON(c))) pointerfocus(c, surface, sx, sy, time); @@ -4522,7 +4203,7 @@ void pointerfocus(Client *c, struct wlr_surface *surface, double sx, double sy, uint32_t time) { struct timespec now; - if (config.sloppyfocus && !start_drag_window && c && time && c->scene && + if (sloppyfocus && !start_drag_window && c && time && c->scene->node.enabled && !c->animation.tagining && (surface != seat->pointer_state.focused_surface) && !client_is_unmanaged(c) && VISIBLEON(c, c->mon)) @@ -4572,47 +4253,14 @@ void scene_buffer_apply_opacity(struct wlr_scene_buffer *buffer, int32_t sx, } void client_set_opacity(Client *c, double opacity) { - opacity = CLAMP_FLOAT(opacity, 0.0f, 1.0f); wlr_scene_node_for_each_buffer(&c->scene_surface->node, scene_buffer_apply_opacity, &opacity); } -void monitor_stop_skip_frame_timer(Monitor *m) { - if (m->skip_frame_timeout) - wl_event_source_timer_update(m->skip_frame_timeout, 0); - m->skiping_frame = false; - m->resizing_count_pending = 0; - m->resizing_count_current = 0; -} - -static int monitor_skip_frame_timeout_callback(void *data) { - Monitor *m = data; - Client *c, *tmp; - - wl_list_for_each_safe(c, tmp, &clients, link) { c->configure_serial = 0; } - - monitor_stop_skip_frame_timer(m); - wlr_output_schedule_frame(m->wlr_output); - - return 1; -} - -void monitor_check_skip_frame_timeout(Monitor *m) { - if (m->skiping_frame && - m->resizing_count_pending == m->resizing_count_current) { - return; - } - - if (m->skip_frame_timeout) { - m->resizing_count_current = m->resizing_count_pending; - m->skiping_frame = true; - wl_event_source_timer_update(m->skip_frame_timeout, 100); // 100ms - } -} - void rendermon(struct wl_listener *listener, void *data) { Monitor *m = wl_container_of(listener, m, frame); Client *c = NULL, *tmp = NULL; + struct wlr_output_state pending = {0}; LayerSurface *l = NULL, *tmpl = NULL; int32_t i; struct wl_list *layer_list; @@ -4648,19 +4296,15 @@ 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 (!config.animations && !grabc && c->configure_serial && - client_is_rendered_on_mon(c, m)) { - monitor_check_skip_frame_timeout(m); + if (!animations && !(allow_tearing && frame_allow_tearing) && + c->configure_serial && !c->isfloating && + client_is_rendered_on_mon(c, m) && !client_is_stopped(c)) { goto skip; } } - if (m->skiping_frame) { - monitor_stop_skip_frame_timer(m); - } - // 只有在需要帧时才构建和提交状态 - if (config.allow_tearing && frame_allow_tearing) { + if (allow_tearing && frame_allow_tearing) { apply_tear_state(m); } else { wlr_scene_output_commit(m->scene_output, NULL); @@ -4669,7 +4313,12 @@ void rendermon(struct wl_listener *listener, void *data) { skip: // 发送帧完成通知 clock_gettime(CLOCK_MONOTONIC, &now); - wlr_scene_output_send_frame_done(m->scene_output, &now); + if (allow_tearing && frame_allow_tearing) { + wlr_scene_output_send_frame_done(m->scene_output, &now); + } else { + wlr_scene_output_send_frame_done(m->scene_output, &now); + wlr_output_state_finish(&pending); + } // 如果需要更多帧,确保安排下一帧 if (need_more_frames && allow_frame_scheduling) { @@ -4736,7 +4385,7 @@ void exchange_two_client(Client *c1, Client *c2) { float stack_proportion = 0.0f; if (c1 == NULL || c2 == NULL || - (!config.exchange_cross_monitor && c1->mon != c2->mon)) { + (!exchange_cross_monitor && c1->mon != c2->mon)) { return; } @@ -4838,7 +4487,7 @@ void exchange_two_client(Client *c1, Client *c2) { } // 处理跨监视器交换 - if (config.exchange_cross_monitor) { + if (exchange_cross_monitor) { tmp_mon = c2->mon; tmp_tags = c2->tags; setmon(c2, c1->mon, c1->tags, false); @@ -4849,46 +4498,6 @@ void exchange_two_client(Client *c1, Client *c2) { } else { arrange(c1->mon, false, false); } - - // In order to facilitate repeated exchanges for get_focused_stack_client - // set c2 focus order behind c1 - wl_list_remove(&c2->flink); - wl_list_insert(&c1->flink, &c2->flink); -} - -void set_activation_env() { - if (!getenv("DBUS_SESSION_BUS_ADDRESS")) { - wlr_log(WLR_INFO, "Not updating dbus execution environment: " - "DBUS_SESSION_BUS_ADDRESS not set"); - return; - } - - wlr_log(WLR_INFO, "Updating dbus execution environment"); - - char *env_keys = join_strings(env_vars, " "); - - // first command: dbus-update-activation-environment - const char *arg1 = env_keys; - char *cmd1 = string_printf("dbus-update-activation-environment %s", arg1); - if (!cmd1) { - wlr_log(WLR_ERROR, "Failed to allocate command string"); - goto cleanup; - } - spawn(&(Arg){.v = cmd1}); - free(cmd1); - - // second command: systemctl --user - const char *action = "import-environment"; - char *cmd2 = string_printf("systemctl --user %s %s", action, env_keys); - if (!cmd2) { - wlr_log(WLR_ERROR, "Failed to allocate command string"); - goto cleanup; - } - spawn(&(Arg){.v = cmd2}); - free(cmd2); - -cleanup: - free(env_keys); } void // 17 @@ -4948,8 +4557,6 @@ run(char *startup_cmd) { wlr_cursor_set_xcursor(cursor, cursor_mgr, "left_ptr"); handlecursoractivity(); - set_activation_env(); - run_exec(); run_exec_once(); @@ -4978,21 +4585,10 @@ void setcursor(struct wl_listener *listener, void *data) { * hardware cursor on the output that it's currently on and continue to * do so as the cursor moves between outputs. */ if (event->seat_client == seat->pointer_state.focused_client) { - /* Clear previous surface destroy listener if any */ - if (last_cursor.surface && - last_cursor_surface_destroy_listener.link.prev != NULL) - wl_list_remove(&last_cursor_surface_destroy_listener.link); - last_cursor.shape = 0; last_cursor.surface = event->surface; last_cursor.hotspot_x = event->hotspot_x; last_cursor.hotspot_y = event->hotspot_y; - - /* Track surface destruction to avoid dangling pointer */ - if (event->surface) - wl_signal_add(&event->surface->events.destroy, - &last_cursor_surface_destroy_listener); - if (!cursor_hidden) wlr_cursor_set_surface(cursor, event->surface, event->hotspot_x, event->hotspot_y); @@ -5004,7 +4600,6 @@ setfloating(Client *c, int32_t floating) { Client *fc = NULL; struct wlr_box target_box; - int32_t old_floating_state = c->isfloating; c->isfloating = floating; bool window_size_outofrange = false; @@ -5018,7 +4613,7 @@ setfloating(Client *c, int32_t floating) { if (c->isfullscreen || c->ismaximizescreen) { c->isfullscreen = 0; // 清除窗口全屏标志 c->ismaximizescreen = 0; - c->bw = c->isnoborder ? 0 : config.borderpx; + c->bw = c->isnoborder ? 0 : borderpx; } exit_scroller_stack(c); @@ -5032,13 +4627,11 @@ 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 - config.gappoh) { + if (c->mon && c->float_geom.width >= c->mon->w.width - 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 - config.gappov) { + if (c->mon && c->float_geom.height >= c->mon->w.height - gappov) { c->float_geom.height = c->mon->w.height * 0.9; window_size_outofrange = true; } @@ -5076,34 +4669,23 @@ setfloating(Client *c, int32_t floating) { layers[c->isfloating ? LyrTop : LyrTile]); } - if (!c->isfloating && old_floating_state) { - restore_size_per(c->mon, c); - } - - if (c->isfloating && !old_floating_state) { - save_old_size_per(c->mon); + if (!c->isfloating) { + set_size_per(c->mon, c); } if (!c->force_maximize) client_set_maximized(c, false); - if (!c->isfloating || c->force_tiled_state) { - client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | - WLR_EDGE_RIGHT); - } else { - client_set_tiled(c, WLR_EDGE_NONE); - } - arrange(c->mon, false, false); setborder_color(c); printstatus(); } void reset_maximizescreen_size(Client *c) { - 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; + 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; resize(c, c->geom, 0); } @@ -5136,7 +4718,6 @@ void setmaximizescreen(Client *c, int32_t maximizescreen) { if (c->mon->isoverview) return; - int32_t old_maximizescreen_state = c->ismaximizescreen; c->ismaximizescreen = maximizescreen; if (maximizescreen) { @@ -5149,16 +4730,16 @@ void setmaximizescreen(Client *c, int32_t maximizescreen) { if (c->isfloating) c->float_geom = c->geom; - 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); + 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); // 将视图提升到顶层 if (!is_scroller_layout(c->mon) || c->isfloating) resize(c, maximizescreen_box, 0); c->ismaximizescreen = 1; } else { - c->bw = c->isnoborder ? 0 : config.borderpx; + c->bw = c->isnoborder ? 0 : borderpx; c->ismaximizescreen = 0; if (c->isfloating) setfloating(c, 1); @@ -5166,12 +4747,8 @@ void setmaximizescreen(Client *c, int32_t maximizescreen) { wlr_scene_node_reparent(&c->scene->node, layers[c->isfloating ? LyrTop : LyrTile]); - if (!c->ismaximizescreen && old_maximizescreen_state) { - restore_size_per(c->mon, c); - } - - if (c->ismaximizescreen && !old_maximizescreen_state) { - save_old_size_per(c->mon); + if (!c->ismaximizescreen) { + set_size_per(c->mon, c); } if (!c->force_maximize && !c->ismaximizescreen) { @@ -5203,7 +4780,6 @@ void setfullscreen(Client *c, int32_t fullscreen) // 用自定义全屏代理自 if (c->mon->isoverview) return; - int32_t old_fullscreen_state = c->isfullscreen; c->isfullscreen = fullscreen; client_set_fullscreen(c, fullscreen); @@ -5225,7 +4801,7 @@ void setfullscreen(Client *c, int32_t fullscreen) // 用自定义全屏代理自 resize(c, c->mon->m, 1); c->isfullscreen = 1; } else { - c->bw = c->isnoborder ? 0 : config.borderpx; + c->bw = c->isnoborder ? 0 : borderpx; c->isfullscreen = 0; if (c->isfloating) setfloating(c, 1); @@ -5241,12 +4817,8 @@ void setfullscreen(Client *c, int32_t fullscreen) // 用自定义全屏代理自 layers[fullscreen || c->isfloating ? LyrTop : LyrTile]); } - if (!c->isfullscreen && old_fullscreen_state) { - restore_size_per(c->mon, c); - } - - if (c->isfullscreen && !old_fullscreen_state) { - save_old_size_per(c->mon); + if (!c->isfullscreen) { + set_size_per(c->mon, c); } arrange(c->mon, false, false); @@ -5288,8 +4860,9 @@ void reset_keyboard_layout(void) { return; } + // 现在安全地创建真正的keymap struct xkb_keymap *new_keymap = xkb_keymap_new_from_names( - context, &config.xkb_rules, XKB_KEYMAP_COMPILE_NO_FLAGS); + context, &xkb_rules, XKB_KEYMAP_COMPILE_NO_FLAGS); if (!new_keymap) { // 理论上这里不应该失败,因为前面已经验证过了 wlr_log(WLR_ERROR, @@ -5373,17 +4946,10 @@ void setmon(Client *c, Monitor *m, uint32_t newtags, bool focus) { arrange(oldmon, false, false); if (m) { /* Make sure window actually overlaps with the monitor */ - reset_foreign_tolevel(c); resize(c, c->geom, 0); - if (!newtags && !m->isoverview) { - c->tags = m->tagset[m->seltags]; - } else if (!newtags && m->isoverview) { - c->tags = m->ovbk_current_tagset; - } else if (newtags) { - c->tags = newtags; - } else { - c->tags = m->tagset[m->seltags]; - } + c->tags = + newtags ? newtags + : m->tagset[m->seltags]; /* assign tags of target monitor */ setfloating(c, c->isfloating); setfullscreen(c, c->isfullscreen); /* This will call arrange(c->mon) */ } @@ -5391,6 +4957,21 @@ void setmon(Client *c, Monitor *m, uint32_t newtags, bool focus) { if (focus && !client_is_x11_popup(c)) { focusclient(focustop(selmon), 1); } + + if (m) { + + if (c->foreign_toplevel) { + remove_foreign_topleve(c); + } + + add_foreign_toplevel(c); + if (m->sel && m->sel->foreign_toplevel) + wlr_foreign_toplevel_handle_v1_set_activated( + m->sel->foreign_toplevel, false); + if (c->foreign_toplevel) + wlr_foreign_toplevel_handle_v1_set_activated(c->foreign_toplevel, + true); + } } void setpsel(struct wl_listener *listener, void *data) { @@ -5468,13 +5049,9 @@ 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}; @@ -5484,7 +5061,7 @@ void setup(void) { for (i = 0; i < LENGTH(sig); i++) sigaction(sig[i], &sa, NULL); - wlr_log_init(config.log_level, NULL); + wlr_log_init(log_level, NULL); /* The Wayland display is managed by libwayland. It handles accepting * clients from the Unix socket, manging Wayland globals, and so on. */ @@ -5510,7 +5087,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, config.rootcolor); + root_bg = wlr_scene_rect_create(&scene->tree, 0, 0, rootcolor); for (i = 0; i < NUM_LAYERS; i++) layers[i] = wlr_scene_tree_create(&scene->tree); drag_icon = wlr_scene_tree_create(&scene->tree); @@ -5532,10 +5109,10 @@ void setup(void) { if (wlr_renderer_get_texture_formats(drw, WLR_BUFFER_CAP_DMABUF)) { wlr_drm_create(dpy, drw); wlr_scene_set_linux_dmabuf_v1( - scene, wlr_linux_dmabuf_v1_create_with_renderer(dpy, 4, drw)); + scene, wlr_linux_dmabuf_v1_create_with_renderer(dpy, 5, drw)); } - if (config.syncobj_enable && (drm_fd = wlr_renderer_get_drm_fd(drw)) >= 0 && + if (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); @@ -5610,9 +5187,6 @@ void setup(void) { idle_inhibit_mgr = wlr_idle_inhibit_v1_create(dpy); wl_signal_add(&idle_inhibit_mgr->events.new_inhibitor, &new_idle_inhibitor); - keep_idle_inhibit_source = wl_event_loop_add_timer( - wl_display_get_event_loop(dpy), keep_idle_inhibit, NULL); - layer_shell = wlr_layer_shell_v1_create(dpy, 4); wl_signal_add(&layer_shell->events.new_surface, &new_layer_surface); @@ -5654,11 +5228,9 @@ 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 @@ -5682,8 +5254,9 @@ void setup(void) { cursor_shape_mgr = wlr_cursor_shape_manager_v1_create(dpy, 1); wl_signal_add(&cursor_shape_mgr->events.request_set_shape, &request_set_cursor_shape); - hide_cursor_source = wl_event_loop_add_timer(wl_display_get_event_loop(dpy), - hidecursor, cursor); + hide_source = wl_event_loop_add_timer(wl_display_get_event_loop(dpy), + hidecursor, cursor); + /* * Configures a seat, which is a single "seat" at which a user sits and * operates the computer. This conceptually includes up to one keyboard, @@ -5711,8 +5284,6 @@ void setup(void) { LISTEN_STATIC(&cursor->events.hold_end, hold_end); seat = wlr_seat_create(dpy, "seat0"); - - wl_list_init(&last_cursor_surface_destroy_listener.link); wl_signal_add(&seat->events.request_set_cursor, &request_cursor); wl_signal_add(&seat->events.request_set_selection, &request_set_sel); wl_signal_add(&seat->events.request_set_primary_selection, @@ -5731,10 +5302,10 @@ void setup(void) { wl_signal_add(&output_mgr->events.apply, &output_mgr_apply); wl_signal_add(&output_mgr->events.test, &output_mgr_test); - 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); + // 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); /* create text_input-, and input_method-protocol relevant globals */ input_method_manager = wlr_input_method_manager_v2_create(dpy); @@ -5767,8 +5338,7 @@ 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, !config.xwayland_persistence); + xwayland = wlr_xwayland_create(dpy, compositor, !xwayland_persistence); if (xwayland) { wl_signal_add(&xwayland->events.ready, &xwayland_ready); wl_signal_add(&xwayland->events.new_surface, &new_xwayland_surface); @@ -5778,8 +5348,6 @@ void setup(void) { fprintf(stderr, "failed to setup XWayland X server, continuing without it\n"); } - sync_keymap = wl_event_loop_add_timer(wl_display_get_event_loop(dpy), - synckeymap, NULL); #endif } @@ -5853,10 +5421,7 @@ void overview_backup(Client *c) { c->isfullscreen = 0; // 清除窗口全屏标志 c->ismaximizescreen = 0; } - c->bw = c->isnoborder ? 0 : config.borderpx; - - client_set_tiled(c, WLR_EDGE_TOP | WLR_EDGE_BOTTOM | WLR_EDGE_LEFT | - WLR_EDGE_RIGHT); + c->bw = c->isnoborder ? 0 : borderpx; } // overview切回到普通视图还原窗口的状态 @@ -5894,17 +5459,12 @@ void overview_restore(Client *c, const Arg *arg) { if (c->bw == 0 && !c->isfullscreen) { // 如果是在ov模式中创建的窗口,没有bw记录 - c->bw = c->isnoborder ? 0 : config.borderpx; - } - - if (c->isfloating && !c->force_tiled_state) { - client_set_tiled(c, WLR_EDGE_NONE); + c->bw = c->isnoborder ? 0 : borderpx; } } void handlecursoractivity(void) { - wl_event_source_timer_update(hide_cursor_source, - config.cursor_hide_timeout * 1000); + wl_event_source_timer_update(hide_source, cursor_hide_timeout * 1000); if (!cursor_hidden) return; @@ -5914,7 +5474,7 @@ void handlecursoractivity(void) { if (last_cursor.shape) wlr_cursor_set_xcursor(cursor, cursor_mgr, wlr_cursor_shape_v1_name(last_cursor.shape)); - else if (last_cursor.surface) + else wlr_cursor_set_surface(cursor, last_cursor.surface, last_cursor.hotspot_x, last_cursor.hotspot_y); } @@ -5925,36 +5485,6 @@ int32_t hidecursor(void *data) { return 1; } -void check_keep_idle_inhibit(Client *c) { - if (c && c->indleinhibit_when_focus && keep_idle_inhibit_source) { - wl_event_source_timer_update(keep_idle_inhibit_source, 1000); - } -} - -int32_t keep_idle_inhibit(void *data) { - - if (!idle_inhibit_mgr) { - wl_event_source_timer_update(keep_idle_inhibit_source, 0); - return 1; - } - - if (session && !session->active) { - wl_event_source_timer_update(keep_idle_inhibit_source, 0); - return 1; - } - - if (!selmon || !selmon->sel || !selmon->sel->indleinhibit_when_focus) { - wl_event_source_timer_update(keep_idle_inhibit_source, 0); - return 1; - } - - if (seat && idle_notifier) { - wlr_idle_notifier_v1_notify_activity(idle_notifier, seat); - wl_event_source_timer_update(keep_idle_inhibit_source, 1000); - } - return 1; -} - void unlocksession(struct wl_listener *listener, void *data) { SessionLock *lock = wl_container_of(listener, lock, unlock); destroylock(lock, 1); @@ -5964,25 +5494,17 @@ void unmaplayersurfacenotify(struct wl_listener *listener, void *data) { LayerSurface *l = wl_container_of(listener, l, unmap); l->mapped = 0; - l->being_unmapped = true; init_fadeout_layers(l); wlr_scene_node_set_enabled(&l->scene->node, false); - if (l == exclusive_focus) exclusive_focus = NULL; - if (l->layer_surface->output && (l->mon = l->layer_surface->output->data)) arrangelayers(l->mon); - - reset_exclusive_layers_focus(l->mon); - + if (l->layer_surface->surface == seat->keyboard_state.focused_surface) + focusclient(focustop(selmon), 1); motionnotify(0, NULL, 0, 0, 0, 0); - layer_flush_blur_background(l); - wlr_scene_node_destroy(&l->shadow->node); - l->shadow = NULL; - l->being_unmapped = false; } void unmapnotify(struct wl_listener *listener, void *data) { @@ -5995,7 +5517,7 @@ void unmapnotify(struct wl_listener *listener, void *data) { Client *prev_in_stack = c->prev_in_stack; c->iskilling = 1; - if (config.animations && !c->is_clip_to_hide && !c->isminimized && + if (animations && !c->is_clip_to_hide && !c->isminimized && (!c->mon || VISIBLEON(c, c->mon))) init_fadeout_client(c); @@ -6096,7 +5618,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 *output_config = + struct wlr_output_configuration_v1 *config = wlr_output_configuration_v1_create(); Client *c = NULL; struct wlr_output_configuration_head_v1 *config_head; @@ -6107,8 +5629,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(output_config, - m->wlr_output); + config_head = + wlr_output_configuration_head_v1_create(config, m->wlr_output); config_head->state.enabled = 0; /* Remove this output from the layout to avoid cursor enter inside * it */ @@ -6136,8 +5658,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(output_config, - m->wlr_output); + config_head = + wlr_output_configuration_head_v1_create(config, m->wlr_output); oldx = m->m.x; oldy = m->m.y; @@ -6170,7 +5692,7 @@ void updatemons(struct wl_listener *listener, void *data) { */ wlr_scene_output_set_position(m->scene_output, m->m.x, m->m.y); - if (config.blur && m->blur) { + if (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); } @@ -6200,12 +5722,7 @@ void updatemons(struct wl_listener *listener, void *data) { if (selmon && selmon->wlr_output->enabled) { wl_list_for_each(c, &clients, link) { if (!c->mon && client_surface(c)->mapped) { - c->mon = selmon; - reset_foreign_tolevel(c); - } - if (c->tags == 0 && !c->is_in_scratchpad) { - c->tags = selmon->tagset[selmon->seltags]; - set_size_per(selmon, c); + client_change_mon(c, selmon); } } focusclient(focustop(selmon), 1); @@ -6223,7 +5740,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, output_config); + wlr_output_manager_v1_set_configuration(output_mgr, config); } void updatetitle(struct wl_listener *listener, void *data) { @@ -6249,7 +5766,7 @@ urgent(struct wl_listener *listener, void *data) { if (!c || !c->foreign_toplevel) return; - if (config.focus_on_activate && !c->istagsilent && c != selmon->sel) { + if (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); @@ -6348,7 +5865,7 @@ void handle_keyboard_shortcuts_inhibit_new_inhibitor( struct wlr_keyboard_shortcuts_inhibitor_v1 *inhibitor = data; - if (config.allow_shortcuts_inhibit == SHORTCUTS_INHIBIT_DISABLE) { + if (allow_shortcuts_inhibit == SHORTCUTS_INHIBIT_DISABLE) { return; } @@ -6383,8 +5900,6 @@ void handle_keyboard_shortcuts_inhibit_new_inhibitor( void virtualkeyboard(struct wl_listener *listener, void *data) { struct wlr_virtual_keyboard_v1 *kb = data; /* virtual keyboards shouldn't share keyboard group */ - wlr_seat_set_capabilities(seat, - seat->capabilities | WL_SEAT_CAPABILITY_KEYBOARD); KeyboardGroup *group = createkeyboardgroup(); /* Set the keymap to match the group keymap */ wlr_keyboard_set_keymap(&kb->keyboard, group->wlr_group->keyboard.keymap); @@ -6396,7 +5911,8 @@ void virtualkeyboard(struct wl_listener *listener, void *data) { } void warp_cursor(const Client *c) { - if (INSIDEMON(c)) { + if (cursor->x < c->geom.x || cursor->x > c->geom.x + c->geom.width || + cursor->y < c->geom.y || cursor->y > c->geom.y + c->geom.height) { wlr_cursor_warp_closest(cursor, NULL, c->geom.x + c->geom.width / 2.0, c->geom.y + c->geom.height / 2.0); motionnotify(0, NULL, 0, 0, 0, 0); @@ -6414,8 +5930,7 @@ void warp_cursor_to_selmon(Monitor *m) { void virtualpointer(struct wl_listener *listener, void *data) { struct wlr_virtual_pointer_v1_new_pointer_event *event = data; struct wlr_input_device *device = &event->new_pointer->pointer.base; - wlr_seat_set_capabilities(seat, - seat->capabilities | WL_SEAT_CAPABILITY_POINTER); + wlr_cursor_attach_input_device(cursor, device); if (event->suggested_output) wlr_cursor_map_input_to_output(cursor, device, event->suggested_output); @@ -6424,26 +5939,6 @@ void virtualpointer(struct wl_listener *listener, void *data) { } #ifdef XWAYLAND -void fix_xwayland_unmanaged_coordinate(Client *c) { - if (!selmon) - return; - - // 1. 如果窗口已经在当前活动显示器内,直接返回 - if (c->geom.x >= selmon->m.x && c->geom.x < selmon->m.x + selmon->m.width && - c->geom.y >= selmon->m.y && c->geom.y < selmon->m.y + selmon->m.height) - return; - - c->geom = setclient_coordinate_center(c, selmon, c->geom, 0, 0); -} - -int32_t synckeymap(void *data) { - reset_keyboard_layout(); - // we only need to sync keymap once - wlr_log(WLR_INFO, "timer to synckeymap done"); - wl_event_source_timer_update(sync_keymap, 0); - return 0; -} - void activatex11(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, activate); bool need_arrange = false; @@ -6468,7 +5963,7 @@ void activatex11(struct wl_listener *listener, void *data) { } } - if (config.focus_on_activate && !c->istagsilent && c != selmon->sel) { + if (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); @@ -6536,34 +6031,17 @@ void createnotifyx11(struct wl_listener *listener, void *data) { LISTEN(&xsurface->events.request_minimize, &c->minimize, minimizenotify); } -void commitx11(struct wl_listener *listener, void *data) { - Client *c = wl_container_of(listener, c, commmitx11); - struct wlr_surface_state *state = &c->surface.xwayland->surface->current; - - if ((int32_t)c->geom.width - 2 * (int32_t)c->bw == (int32_t)state->width && - (int32_t)c->geom.height - 2 * (int32_t)c->bw == - (int32_t)state->height && - (int32_t)c->surface.xwayland->x == - (int32_t)c->geom.x + (int32_t)c->bw && - (int32_t)c->surface.xwayland->y == - (int32_t)c->geom.y + (int32_t)c->bw) { - c->configure_serial = 0; - } -} - void associatex11(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, associate); LISTEN(&client_surface(c)->events.map, &c->map, mapnotify); LISTEN(&client_surface(c)->events.unmap, &c->unmap, unmapnotify); - LISTEN(&client_surface(c)->events.commit, &c->commmitx11, commitx11); } void dissociatex11(struct wl_listener *listener, void *data) { Client *c = wl_container_of(listener, c, dissociate); wl_list_remove(&c->map.link); wl_list_remove(&c->unmap.link); - wl_list_remove(&c->commmitx11.link); } void sethints(struct wl_listener *listener, void *data) { @@ -6591,10 +6069,6 @@ void xwaylandready(struct wl_listener *listener, void *data) { xwayland, xcursor->images[0]->buffer, xcursor->images[0]->width * 4, xcursor->images[0]->width, xcursor->images[0]->height, xcursor->images[0]->hotspot_x, xcursor->images[0]->hotspot_y); - /* xwayland can't auto sync the keymap, so we do it manually - and we need to wait the xwayland completely inited - */ - wl_event_source_timer_update(sync_keymap, 500); } static void setgeometrynotify(struct wl_listener *listener, void *data) { @@ -6610,21 +6084,17 @@ int32_t main(int32_t argc, char *argv[]) { char *startup_cmd = NULL; int32_t c; - while ((c = getopt(argc, argv, "s:c:hdvp")) != -1) { - if (c == 's') { + while ((c = getopt(argc, argv, "s:c:hdv")) != -1) { + if (c == 's') startup_cmd = optarg; - } else if (c == 'd') { - cli_debug_log = true; - } else if (c == 'v') { - printf("mango " VERSION "\n"); - return EXIT_SUCCESS; - } else if (c == 'c') { + else if (c == 'd') + log_level = WLR_DEBUG; + else if (c == 'v') + die("mango " VERSION); + else if (c == 'c') cli_config_path = optarg; - } else if (c == 'p') { - return parse_config() ? EXIT_SUCCESS : EXIT_FAILURE; - } else { + else goto usage; - } } if (optind < argc) goto usage; @@ -6638,14 +6108,7 @@ int32_t main(int32_t argc, char *argv[]) { run(startup_cmd); cleanup(); return EXIT_SUCCESS; + usage: - printf("Usage: mango [OPTIONS]\n" - "\n" - "Options:\n" - " -v Show mango version\n" - " -d Enable debug log\n" - " -c Use custom configuration file\n" - " -s Execute startup command\n" - " -p Check configuration file error\n"); - return EXIT_SUCCESS; + die("Usage: %s [-v] [-d] [-c config file] [-s startup command]", argv[0]); }