├── .clang-format
├── .gitattributes
├── .github
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ ├── bug.yml
│ └── feature.yml
├── pull_request_template.md
└── workflows
│ ├── ci.yaml
│ ├── man-update.yaml
│ ├── nix-build.yml
│ ├── nix-ci.yml
│ ├── nix-update-inputs.yml
│ ├── nix-update-wlroots.yml
│ ├── release.yaml
│ └── security-checks.yml
├── .gitignore
├── .gitmodules
├── CMakeLists.txt
├── CODE_OF_CONDUCT.md
├── LICENSE
├── Makefile
├── README.md
├── assets
├── header.svg
├── hyprland-portals.conf
├── hyprland.png
├── meson.build
├── wall_2K.png
├── wall_4K.png
├── wall_8K.png
├── wall_anime2_2K.png
├── wall_anime2_4K.png
├── wall_anime2_8K.png
├── wall_anime_2K.png
├── wall_anime_4K.png
└── wall_anime_8K.png
├── docs
├── Hyprland.1
├── Hyprland.1.rst
├── ISSUE_GUIDELINES.md
├── hyprctl.1
├── hyprctl.1.rst
└── meson.build
├── example
├── examplePlugin
│ ├── Makefile
│ ├── customDecoration.cpp
│ ├── customDecoration.hpp
│ ├── customLayout.cpp
│ ├── customLayout.hpp
│ ├── globals.hpp
│ └── main.cpp
├── hyprland.conf
├── hyprland.desktop
├── hyprland.service
├── launch.json
├── meson.build
├── screenShader.frag
└── swaybg@.service
├── flake.lock
├── flake.nix
├── hyprctl
├── CMakeLists.txt
├── Makefile
├── main.cpp
└── meson.build
├── hyprland.pc.in
├── meson.build
├── meson_options.txt
├── nix
├── default.nix
├── hm-module.nix
├── module.nix
├── overlays.nix
├── patches
│ ├── meson-build.patch
│ └── wlroots-nvidia.patch
├── udis86.nix
├── update-inputs.sh
├── update-wlroots.sh
└── wlroots.nix
├── props.json
├── protocols
├── idle.xml
├── meson.build
├── pointer-constraints-unstable-v1.xml
├── tablet-unstable-v2.xml
├── wlr-foreign-toplevel-management-unstable-v1.xml
├── wlr-layer-shell-unstable-v1.xml
├── wlr-output-power-management-unstable-v1.xml
└── wlr-screencopy-unstable-v1.xml
├── scripts
└── generateVersion.sh
├── src
├── Compositor.cpp
├── Compositor.hpp
├── SharedDefs.hpp
├── Window.cpp
├── Window.hpp
├── config
│ ├── ConfigDataValues.hpp
│ ├── ConfigManager.cpp
│ ├── ConfigManager.hpp
│ └── defaultConfig.hpp
├── debug
│ ├── CrashReporter.cpp
│ ├── CrashReporter.hpp
│ ├── HyprCtl.cpp
│ ├── HyprCtl.hpp
│ ├── HyprDebugOverlay.cpp
│ ├── HyprDebugOverlay.hpp
│ ├── HyprNotificationOverlay.cpp
│ ├── HyprNotificationOverlay.hpp
│ ├── Log.cpp
│ ├── Log.hpp
│ └── TracyDefines.hpp
├── defines.hpp
├── events
│ ├── Devices.cpp
│ ├── Events.hpp
│ ├── Layers.cpp
│ ├── Misc.cpp
│ ├── Monitors.cpp
│ ├── Popups.cpp
│ └── Windows.cpp
├── helpers
│ ├── AnimatedVariable.cpp
│ ├── AnimatedVariable.hpp
│ ├── BezierCurve.cpp
│ ├── BezierCurve.hpp
│ ├── Box.cpp
│ ├── Box.hpp
│ ├── Color.cpp
│ ├── Color.hpp
│ ├── MiscFunctions.cpp
│ ├── MiscFunctions.hpp
│ ├── Monitor.cpp
│ ├── Monitor.hpp
│ ├── Region.cpp
│ ├── Region.hpp
│ ├── Splashes.hpp
│ ├── SubsurfaceTree.cpp
│ ├── SubsurfaceTree.hpp
│ ├── Timer.cpp
│ ├── Timer.hpp
│ ├── VarList.cpp
│ ├── VarList.hpp
│ ├── Vector2D.cpp
│ ├── Vector2D.hpp
│ ├── WLClasses.cpp
│ ├── WLClasses.hpp
│ ├── WLListener.cpp
│ ├── WLListener.hpp
│ ├── WLSurface.cpp
│ ├── WLSurface.hpp
│ ├── Watchdog.cpp
│ ├── Watchdog.hpp
│ ├── Workspace.cpp
│ ├── Workspace.hpp
│ ├── X11Stubs.hpp
│ └── XWaylandStubs.hpp
├── hyprerror
│ ├── HyprError.cpp
│ └── HyprError.hpp
├── includes.hpp
├── init
│ ├── initHelpers.cpp
│ └── initHelpers.hpp
├── layout
│ ├── DwindleLayout.cpp
│ ├── DwindleLayout.hpp
│ ├── IHyprLayout.cpp
│ ├── IHyprLayout.hpp
│ ├── MasterLayout.cpp
│ └── MasterLayout.hpp
├── macros.hpp
├── main.cpp
├── managers
│ ├── AnimationManager.cpp
│ ├── AnimationManager.hpp
│ ├── EventManager.cpp
│ ├── EventManager.hpp
│ ├── HookSystemManager.cpp
│ ├── HookSystemManager.hpp
│ ├── KeybindManager.cpp
│ ├── KeybindManager.hpp
│ ├── LayoutManager.cpp
│ ├── LayoutManager.hpp
│ ├── ProtocolManager.cpp
│ ├── ProtocolManager.hpp
│ ├── SessionLockManager.cpp
│ ├── SessionLockManager.hpp
│ ├── ThreadManager.cpp
│ ├── ThreadManager.hpp
│ ├── XWaylandManager.cpp
│ ├── XWaylandManager.hpp
│ └── input
│ │ ├── IdleInhibitor.cpp
│ │ ├── InputManager.cpp
│ │ ├── InputManager.hpp
│ │ ├── InputMethodRelay.cpp
│ │ ├── InputMethodRelay.hpp
│ │ ├── Swipe.cpp
│ │ ├── Tablets.cpp
│ │ └── Touch.cpp
├── meson.build
├── pch
│ └── pch.hpp
├── plugins
│ ├── HookSystem.cpp
│ ├── HookSystem.hpp
│ ├── PluginAPI.cpp
│ ├── PluginAPI.hpp
│ ├── PluginSystem.cpp
│ └── PluginSystem.hpp
├── protocols
│ ├── FractionalScale.cpp
│ ├── FractionalScale.hpp
│ ├── GlobalShortcuts.cpp
│ ├── GlobalShortcuts.hpp
│ ├── Screencopy.cpp
│ ├── Screencopy.hpp
│ ├── TextInputV1.cpp
│ ├── TextInputV1.hpp
│ ├── ToplevelExport.cpp
│ ├── ToplevelExport.hpp
│ ├── ToplevelExportWlrFuncs.hpp
│ ├── WaylandProtocol.cpp
│ ├── WaylandProtocol.hpp
│ ├── XDGOutput.cpp
│ └── XDGOutput.hpp
├── render
│ ├── Framebuffer.cpp
│ ├── Framebuffer.hpp
│ ├── OpenGL.cpp
│ ├── OpenGL.hpp
│ ├── Renderer.cpp
│ ├── Renderer.hpp
│ ├── Shader.cpp
│ ├── Shader.hpp
│ ├── Shaders.hpp
│ ├── Texture.cpp
│ ├── Texture.hpp
│ ├── Transformer.cpp
│ ├── Transformer.hpp
│ ├── decorations
│ │ ├── CHyprDropShadowDecoration.cpp
│ │ ├── CHyprDropShadowDecoration.hpp
│ │ ├── CHyprGroupBarDecoration.cpp
│ │ ├── CHyprGroupBarDecoration.hpp
│ │ ├── IHyprWindowDecoration.cpp
│ │ └── IHyprWindowDecoration.hpp
│ └── shaders
│ │ ├── Border.hpp
│ │ ├── Shadow.hpp
│ │ └── Textures.hpp
└── version.h.in
└── subprojects
├── packagefiles
└── wlroots-meson-build.patch
└── wlroots.wrap
/.clang-format:
--------------------------------------------------------------------------------
1 | ---
2 | Language: Cpp
3 | BasedOnStyle: LLVM
4 |
5 | AccessModifierOffset: -2
6 | AlignAfterOpenBracket: Align
7 | AlignConsecutiveMacros: true
8 | AlignConsecutiveAssignments: true
9 | AlignEscapedNewlines: Right
10 | AlignOperands: false
11 | AlignTrailingComments: true
12 | AllowAllArgumentsOnNextLine: true
13 | AllowAllConstructorInitializersOnNextLine: true
14 | AllowAllParametersOfDeclarationOnNextLine: true
15 | AllowShortBlocksOnASingleLine: true
16 | AllowShortCaseLabelsOnASingleLine: true
17 | AllowShortFunctionsOnASingleLine: Empty
18 | AllowShortIfStatementsOnASingleLine: Never
19 | AllowShortLambdasOnASingleLine: All
20 | AllowShortLoopsOnASingleLine: false
21 | AlwaysBreakAfterDefinitionReturnType: None
22 | AlwaysBreakAfterReturnType: None
23 | AlwaysBreakBeforeMultilineStrings: false
24 | AlwaysBreakTemplateDeclarations: Yes
25 | BreakBeforeBraces: Attach
26 | BreakBeforeTernaryOperators: false
27 | BreakConstructorInitializers: AfterColon
28 | ColumnLimit: 180
29 | CompactNamespaces: false
30 | ConstructorInitializerAllOnOneLineOrOnePerLine: false
31 | ExperimentalAutoDetectBinPacking: false
32 | FixNamespaceComments: false
33 | IncludeBlocks: Preserve
34 | IndentCaseLabels: true
35 | IndentWidth: 4
36 | PointerAlignment: Left
37 | ReflowComments: false
38 | SortIncludes: false
39 | SortUsingDeclarations: false
40 | SpaceAfterCStyleCast: false
41 | SpaceAfterLogicalNot: false
42 | SpaceAfterTemplateKeyword: true
43 | SpaceBeforeCtorInitializerColon: true
44 | SpaceBeforeInheritanceColon: true
45 | SpaceBeforeParens: ControlStatements
46 | SpaceBeforeRangeBasedForLoopColon: true
47 | SpaceInEmptyParentheses: false
48 | SpacesBeforeTrailingComments: 1
49 | SpacesInAngles: false
50 | SpacesInCStyleCastParentheses: false
51 | SpacesInContainerLiterals: false
52 | SpacesInParentheses: false
53 | SpacesInSquareBrackets: false
54 | Standard: Auto
55 | TabWidth: 4
56 | UseTab: Never
57 |
58 | AllowShortEnumsOnASingleLine: false
59 |
60 | BraceWrapping:
61 | AfterEnum: false
62 |
63 | AlignConsecutiveDeclarations: AcrossEmptyLines
64 |
65 | NamespaceIndentation: All
66 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | ko_fi: vaxry
2 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug.yml:
--------------------------------------------------------------------------------
1 | name: Bug Report
2 | description: Something is not working right
3 | labels: ["bug"]
4 | body:
5 | - type: markdown
6 | attributes:
7 | value: |
8 | Before opening a new issue, take a moment to search through the current open ones.
9 |
10 | ---
11 |
12 | - type: input
13 | id: ver
14 | attributes:
15 | label: Hyprland Version
16 | description: "Paste here the output of `hyprctl version`."
17 | placeholder: Hyprland, built from branch main at commit...
18 | validations:
19 | required: true
20 |
21 | - type: dropdown
22 | id: type
23 | attributes:
24 | label: Bug or Regression?
25 | description: Is this a bug or a regression?
26 | options:
27 | - Bug
28 | - Regression
29 | validations:
30 | required: true
31 |
32 | - type: textarea
33 | id: desc
34 | attributes:
35 | label: Description
36 | description: "What went wrong?"
37 | validations:
38 | required: true
39 |
40 | - type: textarea
41 | id: repro
42 | attributes:
43 | label: How to reproduce
44 | description: "How can someone else reproduce the issue?"
45 | validations:
46 | required: true
47 |
48 | - type: textarea
49 | id: logs
50 | attributes:
51 | label: Crash reports, logs, images, videos
52 | description: |
53 | Anything that can help. Please always ATTACH and not paste them.
54 | Logs can be found in /tmp/hypr
55 | Crash reports are stored in ~/.hyprland or $XDG_CACHE_HOME/hyprland
56 |
57 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature.yml:
--------------------------------------------------------------------------------
1 | name: Feature Request
2 | description: I'd like to request additional functionality
3 | labels: ["enhancement"]
4 | body:
5 | - type: markdown
6 | attributes:
7 | value: |
8 | Before opening a new issue, take a moment to search through the current open ones.
9 |
10 | ---
11 |
12 | - type: textarea
13 | id: desc
14 | attributes:
15 | label: Description
16 | description: "Describe your idea"
17 | validations:
18 | required: true
19 |
20 |
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | #### Describe your PR, what does it fix/add?
2 |
3 |
4 | #### Is there anything you want to mention? (unchecked code, possible bugs, found problems, breaking compatibility, etc.)
5 |
6 |
7 | #### Is it ready for merging, or does it need work?
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.github/workflows/man-update.yaml:
--------------------------------------------------------------------------------
1 | name: Build man pages
2 |
3 | on:
4 | workflow_dispatch:
5 | push:
6 | paths:
7 | - docs/**
8 | branches:
9 | - 'main'
10 |
11 | jobs:
12 | main:
13 | name: Build man pages
14 | runs-on: ubuntu-latest
15 | steps:
16 | - name: Install deps
17 | run: sudo apt install pandoc
18 |
19 | - name: Clone repository
20 | uses: actions/checkout@v3
21 | with:
22 | token: ${{ secrets.PAT }}
23 |
24 | - name: Build man pages
25 | run: make man
26 |
27 | - uses: stefanzweifel/git-auto-commit-action@v4
28 | name: Commit
29 | with:
30 | commit_message: "[gha] build man pages"
31 |
--------------------------------------------------------------------------------
/.github/workflows/nix-build.yml:
--------------------------------------------------------------------------------
1 | on:
2 | workflow_call:
3 | secrets:
4 | CACHIX_AUTH_TOKEN:
5 | required: false
6 |
7 | jobs:
8 | build:
9 | strategy:
10 | matrix:
11 | package:
12 | - hyprland
13 | - hyprland-nvidia
14 | - xdg-desktop-portal-hyprland
15 |
16 | runs-on: ubuntu-latest
17 | steps:
18 | - name: Clone repository
19 | uses: actions/checkout@v3
20 | with:
21 | ref: ${{ github.ref }}
22 |
23 | - uses: DeterminateSystems/nix-installer-action@main
24 | - uses: DeterminateSystems/magic-nix-cache-action@main
25 | - uses: cachix/cachix-action@v12
26 | with:
27 | name: polyland
28 | authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
29 |
30 | - run: nix build -L ${{ matrix.command }}
31 |
--------------------------------------------------------------------------------
/.github/workflows/nix-ci.yml:
--------------------------------------------------------------------------------
1 | name: Nix
2 |
3 | on: [push, pull_request, workflow_dispatch]
4 |
5 | jobs:
6 | wlroots:
7 | if: github.event_name != 'pull_request'
8 | uses: ./.github/workflows/nix-update-wlroots.yml
9 | secrets: inherit
10 |
11 | build:
12 | if: always() && !cancelled() && !contains(needs.*.result, 'failure')
13 | needs: wlroots
14 | uses: ./.github/workflows/nix-build.yml
15 | secrets: inherit
16 |
--------------------------------------------------------------------------------
/.github/workflows/nix-update-inputs.yml:
--------------------------------------------------------------------------------
1 | name: Nix
2 |
3 | on:
4 | schedule:
5 | - cron: '0 0 * * *' # check daily
6 |
7 | jobs:
8 | update:
9 | name: inputs
10 | runs-on: ubuntu-latest
11 | steps:
12 | - name: Clone repository
13 | uses: actions/checkout@v3
14 | with:
15 | token: ${{ secrets.PAT }}
16 |
17 | - uses: DeterminateSystems/nix-installer-action@main
18 | - name: Update inputs
19 | run: nix/update-inputs.sh
20 |
21 | - name: Commit
22 | uses: stefanzweifel/git-auto-commit-action@v4
23 | with:
24 | commit_message: "[gha] Nix: update inputs"
25 |
26 | update-build:
27 | needs: update
28 | uses: ./.github/workflows/nix-build.yml
29 | secrets: inherit
30 |
--------------------------------------------------------------------------------
/.github/workflows/nix-update-wlroots.yml:
--------------------------------------------------------------------------------
1 | name: Nix
2 |
3 | on:
4 | workflow_call:
5 | secrets:
6 | PAT:
7 | required: true
8 |
9 | jobs:
10 | update:
11 | name: wlroots
12 | runs-on: ubuntu-latest
13 | steps:
14 | - name: Clone repository
15 | uses: actions/checkout@v3
16 | with:
17 | token: ${{ secrets.PAT }}
18 |
19 | - uses: DeterminateSystems/nix-installer-action@main
20 | - name: Update lockfile
21 | run: nix/update-wlroots.sh
22 |
23 | - name: Commit
24 | uses: stefanzweifel/git-auto-commit-action@v4
25 | with:
26 | commit_message: "[gha] Nix: update wlroots"
27 |
--------------------------------------------------------------------------------
/.github/workflows/release.yaml:
--------------------------------------------------------------------------------
1 | name: Release artifacts
2 |
3 | on:
4 | release:
5 | types: [published]
6 | workflow_dispatch:
7 |
8 | jobs:
9 | source-tarball:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - name: Checkout Polyland
13 | id: checkout
14 | uses: actions/checkout@v3
15 | with:
16 | submodules: recursive
17 |
18 | - name: Generate version
19 | id: genversion
20 | run: |
21 | bash -c scripts/generateVersion.sh
22 | mv scripts/generateVersion.sh scripts/generateVersion.sh.bak
23 |
24 | - name: Create tarball with submodules
25 | id: tar
26 | run: |
27 | mkdir hyprland-source; mv ./* ./hyprland-source || tar -czv --owner=0 --group=0 --no-same-owner --no-same-permissions -f source.tar.gz *
28 |
29 | - id: whatrelease
30 | name: Get latest release
31 | uses: pozetroninc/github-action-get-latest-release@master
32 | with:
33 | owner: poly-land
34 | repo: Polyland
35 | excludes: prerelease, draft
36 |
37 | - name: Upload to release
38 | id: upload
39 | uses: svenstaro/upload-release-action@v2
40 | with:
41 | repo_token: ${{ secrets.GITHUB_TOKEN }}
42 | file: source.tar.gz
43 | asset_name: source-${{ steps.whatrelease.outputs.release }}.tar.gz
44 | tag: ${{ steps.whatrelease.outputs.release }}
45 | overwrite: true
46 |
--------------------------------------------------------------------------------
/.github/workflows/security-checks.yml:
--------------------------------------------------------------------------------
1 | name: Security Checks
2 |
3 | on: [push, pull_request]
4 |
5 | jobs:
6 | flawfinder:
7 | name: Flawfinder Checks
8 | runs-on: ubuntu-latest
9 | permissions:
10 | actions: read
11 | contents: read
12 | security-events: write
13 | steps:
14 | - name: Checkout code
15 | uses: actions/checkout@v3
16 |
17 | - name: Scan with Flawfinder
18 | uses: david-a-wheeler/flawfinder@8e4a779ad59dbfaee5da586aa9210853b701959c
19 | with:
20 | arguments: '--sarif ./'
21 | output: 'flawfinder_results.sarif'
22 |
23 | - name: Upload analysis results to GitHub Security tab
24 | uses: github/codeql-action/upload-sarif@v2
25 | with:
26 | sarif_file: ${{github.workspace}}/flawfinder_results.sarif
27 |
28 | codeql:
29 | name: CodeQL
30 | runs-on: ubuntu-latest
31 | container:
32 | image: archlinux
33 |
34 | permissions:
35 | actions: read
36 | contents: read
37 | security-events: write
38 |
39 | strategy:
40 | fail-fast: false
41 | matrix:
42 | language: [ 'cpp' ]
43 |
44 | steps:
45 | - name: Checkout repository
46 | uses: actions/checkout@v3
47 |
48 | - name: Initialize CodeQL
49 | uses: github/codeql-action/init@v2
50 | with:
51 | languages: ${{ matrix.language }}
52 |
53 | - name: Init Hyprland build
54 | run: |
55 | sed -i 's/SigLevel = Required DatabaseOptional/SigLevel = Optional TrustAll/' /etc/pacman.conf
56 | pacman --noconfirm --noprogressbar -Syyu
57 | pacman --noconfirm --noprogressbar -Sy glslang libepoxy libfontenc libxcvt libxfont2 libxkbfile vulkan-headers vulkan-validation-layers xcb-util-errors xcb-util-renderutil xcb-util-wm xorg-fonts-encodings xorg-server-common xorg-setxkbmap xorg-xkbcomp xorg-xwayland git cmake go clang lld libc++ pkgconf meson ninja wayland wayland-protocols libinput libxkbcommon pixman glm libdrm libglvnd cairo pango systemd scdoc base-devel seatd python libliftoff
58 | useradd -m githubuser
59 | echo -e "root ALL=(ALL:ALL) ALL\ngithubuser ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers
60 | su githubuser -c "cd ~ && git clone https://aur.archlinux.org/libdisplay-info.git && cd ./libdisplay-info && makepkg -si --skippgpcheck --noconfirm --noprogressbar"
61 | git config --global --add safe.directory /__w/Hyprland/Hyprland
62 |
63 | - name: Checkout Hyprland
64 | uses: actions/checkout@v3
65 | with:
66 | submodules: recursive
67 |
68 | - name: Build Hyprland
69 | run: |
70 | git submodule sync --recursive && git submodule update --init --force --recursive
71 | make all
72 |
73 | - name: Perform CodeQL Analysis
74 | uses: github/codeql-action/analyze@v2
75 | with:
76 | category: "/language:${{matrix.language}}"
77 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | CMakeLists.txt.user
2 | CMakeCache.txt
3 | CMakeFiles
4 | CMakeScripts
5 | Testing
6 | cmake_install.cmake
7 | install_manifest.txt
8 | compile_commands.json
9 | CTestTestfile.cmake
10 | _deps
11 |
12 | build/
13 | result*
14 | /.vscode/
15 | /.idea/
16 | .envrc
17 | .cache
18 |
19 | *.o
20 | *-protocol.c
21 | *-protocol.h
22 | .ccls-cache
23 | *.so
24 |
25 | hyprctl/hyprctl
26 |
27 | gmon.out
28 | *.out
29 | *.tar.gz
30 |
31 | PKGBUILD
32 |
33 | src/version.h
34 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "wlroots"]
2 | path = subprojects/wlroots
3 | url = https://gitlab.freedesktop.org/wlroots/wlroots.git
4 | [submodule "subprojects/hyprland-protocols"]
5 | path = subprojects/hyprland-protocols
6 | url = https://github.com/hyprwm/hyprland-protocols
7 | [submodule "subprojects/udis86"]
8 | path = subprojects/udis86
9 | url = https://github.com/canihavesomecoffee/udis86
10 | [submodule "subprojects/tracy"]
11 | path = subprojects/tracy
12 | url = https://github.com/wolfpld/tracy
13 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | ## Goal
2 |
3 | Our goal is to provide a space where it is safe for everyone to contribute to,
4 | and get support for, open-source software in a respectful and cooperative
5 | manner.
6 |
7 | We value all contributions and want to make this organization and its
8 | surrounding community a place for everyone.
9 |
10 | As members, contributors, and everyone else who may participate in the
11 | development, we strive to keep the entire experience civil.
12 |
13 | ## Standards
14 |
15 | Our community standards exist in order to make sure everyone feels comfortable
16 | contributing to the project(s) together.
17 |
18 | Our standards are:
19 | - Do not harass, attack, or in any other way discriminate against anyone, including
20 | for their protected traits, including, but not limited to, sex, religion, race,
21 | appearance, gender, identity, nationality, sexuality, etc.
22 | - Do not go off-topic, do not post spam.
23 | - Treat everyone with respect.
24 |
25 | Examples of breaking each rule respectively include:
26 | - Harassment, bullying or inappropriate jokes about another person.
27 | - Posting distasteful imagery, trolling, or posting things unrelated to the topic at hand.
28 | - Treating someone as worse because of their lack of understanding of an issue.
29 |
30 | ## Enforcement
31 |
32 | Enforcement of this CoC is done by the members of the hyprwm organization.
33 |
34 | We, as the organization, will strive our best to keep this community civil and
35 | following the standards outlined above.
36 |
37 | ### Reporting incidents
38 |
39 | If you believe an incident of breaking our standards has occurred, but nobody has
40 | taken appropriate action, you can privately contact the people responsible for dealing
41 | with such incidents in multiple ways:
42 |
43 | ***E-Mail***
44 | - `vaxry[at]vaxry.net`
45 | - `mihai[at]fufexan.net`
46 |
47 | ***Discord***
48 | - `@vaxry`
49 | - `@fufexan`
50 |
51 | ***Matrix***
52 | - `@vaxry:matrix.vaxry.net`
53 | - `@fufexan:matrix.org`
54 |
55 | We, as members, guarantee your privacy and will not share those reports with anyone.
56 |
57 | ## Enforcement Strategy
58 |
59 | Depending on the severity of the infraction, any action from the list below may be applied.
60 | Please keep in mind cases are reviewed on a per-case basis and members are the ultimate
61 | deciding factor in the type of punishment.
62 |
63 | If the matter would benefit from an outside opinion, a member might reach for more opinions
64 | from people unrelated to the organization, however, the final decision regarding the action
65 | to be taken is still up to the member.
66 |
67 | For example, if the matter at hand regards a representative of a marginalized group or minority,
68 | the member might ask for a first-hand opinion from another representative of such group.
69 |
70 | ### Correction/Edit
71 |
72 | If your message is found to be misleading or poorly worded, a member might
73 | edit your message.
74 |
75 | ### Warning/Deletion
76 |
77 | If your message is found inappropriate, a member might give you a public or private warning,
78 | and/or delete your message.
79 |
80 | ### Mute
81 |
82 | If your message is disruptive, or you have been repeatedly violating the standards,
83 | a member might mute (or temporarily ban) you.
84 |
85 | ### Ban
86 |
87 | If your message is hateful, very disruptive, or other, less serious infractions are repeated
88 | ignoring previous punishments, a member might ban you permanently.
89 |
90 | ## Scope
91 |
92 | This CoC shall apply to all projects ran under the `hyprwm` organization and all _official_ communities
93 | outside of GitHub.
94 |
95 | However, it is worth noting that official communities outside of GitHub might have their own,
96 | additional sets of rules.
97 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | BSD 3-Clause License
2 |
3 | Copyright (c) 2022-2023, vaxerski
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or without
7 | modification, are permitted provided that the following conditions are met:
8 |
9 | 1. Redistributions of source code must retain the above copyright notice, this
10 | list of conditions and the following disclaimer.
11 |
12 | 2. Redistributions in binary form must reproduce the above copyright notice,
13 | this list of conditions and the following disclaimer in the documentation
14 | and/or other materials provided with the distribution.
15 |
16 | 3. Neither the name of the copyright holder nor the names of its
17 | contributors may be used to endorse or promote products derived from
18 | this software without specific prior written permission.
19 |
20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
--------------------------------------------------------------------------------
/assets/hyprland-portals.conf:
--------------------------------------------------------------------------------
1 | [preferred]
2 | default=hyprland;gtk
--------------------------------------------------------------------------------
/assets/hyprland.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/poly-land/Polyland/f757a1023a5248559a13de053f12e911a98a2ebc/assets/hyprland.png
--------------------------------------------------------------------------------
/assets/meson.build:
--------------------------------------------------------------------------------
1 | wallpaper_types = ['', 'anime_', 'anime2_']
2 |
3 | foreach type : wallpaper_types
4 | foreach size : [2, 4, 8]
5 | install_data(f'wall_@type@@size@K.png', install_dir: join_paths(get_option('datadir'), 'hyprland'), install_tag: 'runtime')
6 | endforeach
7 | endforeach
8 |
9 | install_data('hyprland-portals.conf', install_dir: join_paths(get_option('datadir'), 'xdg-desktop-portal'), install_tag: 'runtime')
10 |
--------------------------------------------------------------------------------
/assets/wall_2K.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/poly-land/Polyland/f757a1023a5248559a13de053f12e911a98a2ebc/assets/wall_2K.png
--------------------------------------------------------------------------------
/assets/wall_4K.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/poly-land/Polyland/f757a1023a5248559a13de053f12e911a98a2ebc/assets/wall_4K.png
--------------------------------------------------------------------------------
/assets/wall_8K.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/poly-land/Polyland/f757a1023a5248559a13de053f12e911a98a2ebc/assets/wall_8K.png
--------------------------------------------------------------------------------
/assets/wall_anime2_2K.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/poly-land/Polyland/f757a1023a5248559a13de053f12e911a98a2ebc/assets/wall_anime2_2K.png
--------------------------------------------------------------------------------
/assets/wall_anime2_4K.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/poly-land/Polyland/f757a1023a5248559a13de053f12e911a98a2ebc/assets/wall_anime2_4K.png
--------------------------------------------------------------------------------
/assets/wall_anime2_8K.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/poly-land/Polyland/f757a1023a5248559a13de053f12e911a98a2ebc/assets/wall_anime2_8K.png
--------------------------------------------------------------------------------
/assets/wall_anime_2K.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/poly-land/Polyland/f757a1023a5248559a13de053f12e911a98a2ebc/assets/wall_anime_2K.png
--------------------------------------------------------------------------------
/assets/wall_anime_4K.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/poly-land/Polyland/f757a1023a5248559a13de053f12e911a98a2ebc/assets/wall_anime_4K.png
--------------------------------------------------------------------------------
/assets/wall_anime_8K.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/poly-land/Polyland/f757a1023a5248559a13de053f12e911a98a2ebc/assets/wall_anime_8K.png
--------------------------------------------------------------------------------
/docs/Hyprland.1:
--------------------------------------------------------------------------------
1 | .\" Automatically generated by Pandoc 2.9.2.1
2 | .\"
3 | .TH "Hyprland" "1" "" "" "Hyprland User Manual"
4 | .hy
5 | .SH NAME
6 | .PP
7 | Hyprland - Dynamic tiling Wayland compositor
8 | .SH SYNOPSIS
9 | .PP
10 | \f[B]Hyprland\f[R] [\f[I]arg [...]\f[R]].
11 | .SH DESCRIPTION
12 | .PP
13 | \f[B]Hyprland\f[R] is a dynamic tiling Wayland compositor based on
14 | wlroots that doesn\[aq]t sacrifice on its looks.
15 | .PP
16 | You can launch Hyprland by either going into a TTY and executing
17 | \f[B]Hyprland\f[R], or with a login manager.
18 | .SH NOTICE
19 | .PP
20 | Hyprland is still in pretty early development compared to some other
21 | Wayland compositors.
22 | .PP
23 | Although Hyprland is pretty stable, it may have some bugs.
24 | .SH CONFIGURATION
25 | .PP
26 | For configuration information please see
27 | <\f[I]https://github.com/hyprwm/Hyprland/wiki\f[R]>.
28 | .SH OPTIONS
29 | .TP
30 | \f[B]-h\f[R], \f[B]--help\f[R]
31 | Show command usage.
32 | .TP
33 | \f[B]-c\f[R], \f[B]--config\f[R]
34 | Specify config file to use.
35 | .SH BUGS
36 | .TP
37 | Submit bug reports and request features online at:
38 | <\f[I]https://github.com/hyprwm/Hyprland/issues\f[R]>
39 | .SH SEE ALSO
40 | .PP
41 | Sources at: <\f[I]https://github.com/hyprwm/Hyprland\f[R]>
42 | .SH COPYRIGHT
43 | .PP
44 | Copyright (c) 2022, vaxerski
45 | .SH AUTHORS
46 | Vaxerski <\f[I]https://github.com/vaxerski\f[R]>.
47 |
--------------------------------------------------------------------------------
/docs/Hyprland.1.rst:
--------------------------------------------------------------------------------
1 | :title: Hyprland
2 | :author: Vaxerski <*https://github.com/vaxerski*>
3 |
4 | NAME
5 | ====
6 |
7 | Hyprland - Dynamic tiling Wayland compositor
8 |
9 | SYNOPSIS
10 | ========
11 |
12 | **Hyprland** [*arg [...]*].
13 |
14 | DESCRIPTION
15 | ===========
16 |
17 | **Hyprland** is a dynamic tiling Wayland compositor based on
18 | wlroots that doesn't sacrifice on its looks.
19 |
20 | You can launch Hyprland by either going into a TTY and
21 | executing **Hyprland**, or with a login manager.
22 |
23 | NOTICE
24 | ======
25 |
26 | Hyprland is still in pretty early development compared to some other Wayland compositors.
27 |
28 | Although Hyprland is pretty stable, it may have some bugs.
29 |
30 | CONFIGURATION
31 | =============
32 |
33 | For configuration information please see <*https://github.com/hyprwm/Hyprland/wiki*>.
34 |
35 | OPTIONS
36 | =======
37 |
38 | **-h**, **--help**
39 | Show command usage.
40 |
41 | **-c**, **--config**
42 | Specify config file to use.
43 |
44 | BUGS
45 | ====
46 |
47 | Submit bug reports and request features online at:
48 | <*https://github.com/hyprwm/Hyprland/issues*>
49 |
50 | SEE ALSO
51 | ========
52 |
53 | Sources at: <*https://github.com/hyprwm/Hyprland*>
54 |
55 | COPYRIGHT
56 | =========
57 |
58 | Copyright (c) 2022, vaxerski
59 |
--------------------------------------------------------------------------------
/docs/ISSUE_GUIDELINES.md:
--------------------------------------------------------------------------------
1 | # Issue Guidelines
2 |
3 | First of all, please remember to:
4 | - Check that your issue is not a duplicate
5 | - Read the [FAQ](https://wiki.hyprland.org/FAQ/)
6 | - Read the [Configuring Page](https://wiki.hyprland.org/Configuring/Configuring-Hyprland)
7 |
8 |
9 |
10 | # Reporting suggestions
11 | Suggestions are welcome.
12 |
13 | Many features can be implemented using bash scripts and Hyprland sockets, read up on those [Here](https://wiki.hyprland.org/IPC). Please do not suggest features that can be implemented as such.
14 |
15 |
16 |
17 | # Reporting bugs
18 |
19 | All bug reports should have the following:
20 | - Steps to reproduce
21 | - Expected outcome
22 | - Noted outcome
23 |
24 | If your bug is one that doesn't crash Hyprland, but feels like invalid behavior, that's all you need to say.
25 |
26 | If your bug crashes Hyprland, append additionally:
27 | - The Hyprland log
28 | - Your config
29 | - (v0.22.0beta and up) The Hyprland Crash Report
30 | - (v0.21.0beta and below) Coredump / Coredump analysis (with a stacktrace)
31 |
32 | **Important**: Please do NOT use any package for reporting bugs! Clone and compile from source.
33 |
34 | ## Obtaining the Hyprland log
35 | If you are in a TTY, and the hyprland session that crashed was the last one you launched, the log will be printed with
36 | ```
37 | cat /tmp/hypr/$(ls -t /tmp/hypr/ | head -n 1)/hyprland.log
38 | ```
39 | feel free to send it to a file, save, copy, etc.
40 |
41 | if you are in a Hyprland session, and you want the log of the last session, use
42 | ```
43 | cat /tmp/hypr/$(ls -t /tmp/hypr/ | head -n 2 | tail -n 1)/hyprland.log
44 | ```
45 |
46 | basically, directories in /tmp/hypr are your sessions.
47 |
48 | ## Obtaining the Hyprland Crash Report (v0.22.0beta and up)
49 |
50 | If you have `$XDG_CACHE_HOME` set, the crash report directory is `$XDG_CACHE_HOME/hyprland`. If not, it's `~/.hyprland`
51 |
52 | Go to the crash report directory and you should find a file named `hyprlandCrashReport[XXXX].txt` where `[XXXX]` is the PID of the process that crashed.
53 |
54 | Attach that file to your issue.
55 | ## Obtaining the Hyprland coredump (v0.21.0beta and below)
56 | If you are on systemd, you can simply use
57 | ```
58 | coredumpctl
59 | ```
60 | then go to the end (press END on your keyboard) and remember the PID of the last `Hyprland` occurrence. It's the first number after the time, for example `2891`.
61 |
62 | exit coredumpctl (ctrl+c) and use
63 | ```
64 | coredumpctl info [PID]
65 | ```
66 | where `[PID]` is the PID you remembered.
67 |
68 | ## Obtaining the debug Hyprland coredump
69 | A debug coredump provides more information for debugging and may speed up the process of fixing the bug.
70 |
71 | Make sure you're on latest git. Run `git pull --recurse-submodules` to sync everything.
72 |
73 | 1. [Compile Hyprland with debug mode](http://wiki.hyprland.org/Contributing-and-Debugging/#build-in-debug-mode)
74 | > Note: The config file used will be `hyprlandd.conf` instead of `hyprland.conf`
75 |
76 | 2. `cd ~`
77 | 3. For your own convenience, launch Hyprland from a tty with the envvar `ASAN_OPTIONS="log_path=asan.log" ~/path/to/Hyprland`
78 | 4. Reproduce the crash. Hyprland should instantly close.
79 | 5. Check out your `~` and find a file called `asan.log.XXXXX` where `XXXXX` will be a number corresponding to the PID of the Hyprland instance that crashed.
80 | 6. That is your coredump. Attach it to your issue.
81 |
--------------------------------------------------------------------------------
/docs/hyprctl.1:
--------------------------------------------------------------------------------
1 | .\" Automatically generated by Pandoc 2.9.2.1
2 | .\"
3 | .TH "hyprctl" "1" "" "" "hyprctl User Manual"
4 | .hy
5 | .SH NAME
6 | .PP
7 | hyprctl - Utility for controlling parts of Hyprland from a CLI or a
8 | script
9 | .SH SYNOPSIS
10 | .PP
11 | \f[B]hyprctl\f[R] [\f[I](opt)flags\f[R]] [\f[B]command\f[R]]
12 | [\f[I](opt)args\f[R]]
13 | .SH DESCRIPTION
14 | .PP
15 | \f[B]hyprctl\f[R] is a utility for controlling some parts of the
16 | compositor from a CLI or a script.
17 | .SH CONTROL COMMANDS
18 | .PP
19 | \f[B]dispatch\f[R]
20 | .RS
21 | .PP
22 | Call a dispatcher with an argument.
23 | .PP
24 | An argument must be present.
25 | For dispatchers without parameters it can be anything.
26 | .PP
27 | Returns: \f[I]ok\f[R] on success, and an error message on failure.
28 | .TP
29 | Examples:
30 | \f[B]hyprctl\f[R] \f[I]dispatch exec kitty\f[R]
31 | .RS
32 | .PP
33 | \f[B]hyprctl\f[R] \f[I]dispatch pseudo x\f[R]
34 | .RE
35 | .RE
36 | .PP
37 | \f[B]keyword\f[R]
38 | .RS
39 | .PP
40 | Set a config keyword dynamically.
41 | .PP
42 | Returns: \f[I]ok\f[R] on success, and an error message on failure.
43 | .TP
44 | Examples:
45 | \f[B]hyprctl\f[R] \f[I]keyword bind SUPER,0,pseudo\f[R]
46 | .RS
47 | .PP
48 | \f[B]hyprctl\f[R] \f[I]keyword general:border_size 10\f[R]
49 | .RE
50 | .RE
51 | .PP
52 | \f[B]reload\f[R]
53 | .RS
54 | .PP
55 | Force a reload of the config file.
56 | .RE
57 | .PP
58 | \f[B]kill\f[R]
59 | .RS
60 | .PP
61 | Enter kill mode, where you can kill an app by clicking on it.
62 | You can exit by pressing ESCAPE.
63 | .RE
64 | .SH INFO COMMANDS
65 | .PP
66 | \f[B]version\f[R]
67 | .RS
68 | .PP
69 | Prints the Hyprland version, flags, commit and branch of build.
70 | .RE
71 | .PP
72 | \f[B]monitors\f[R]
73 | .RS
74 | .PP
75 | Lists all the outputs with their properties.
76 | .RE
77 | .PP
78 | \f[B]workspaces\f[R]
79 | .RS
80 | .PP
81 | Lists all workspaces with their properties.
82 | .RE
83 | .PP
84 | \f[B]clients\f[R]
85 | .RS
86 | .PP
87 | Lists all windows with their properties.
88 | .RE
89 | .PP
90 | \f[B]devices\f[R]
91 | .RS
92 | .PP
93 | Lists all connected input devices.
94 | .RE
95 | .PP
96 | \f[B]activewindow\f[R]
97 | .RS
98 | .PP
99 | Returns the active window name.
100 | .RE
101 | .PP
102 | \f[B]layers\f[R]
103 | .RS
104 | .PP
105 | Lists all the layers.
106 | .RE
107 | .PP
108 | \f[B]splash\f[R]
109 | .RS
110 | .PP
111 | Returns the current random splash.
112 | .RE
113 | .SH OPTIONS
114 | .PP
115 | \f[B]--batch\f[R]
116 | .RS
117 | .PP
118 | Specify a batch of commands to execute.
119 | .TP
120 | Example:
121 | \f[B]hyprctl\f[R] \f[I]--batch \[dq]keyword general:border_size 2 ;
122 | keyword general:gaps_out 20\[dq]\f[R]
123 | .RS
124 | .PP
125 | \f[I];\f[R] separates the commands.
126 | .RE
127 | .RE
128 | .PP
129 | \f[B]-j\f[R]
130 | .RS
131 | .PP
132 | Outputs information in JSON.
133 | .RE
134 | .SH BUGS
135 | .TP
136 | Submit bug reports and request features online at:
137 | <\f[I]https://github.com/hyprwm/Hyprland/issues\f[R]>
138 | .SH SEE ALSO
139 | .PP
140 | Sources at: <\f[I]https://github.com/hyprwm/Hyprland\f[R]>
141 | .SH COPYRIGHT
142 | .PP
143 | Copyright (c) 2022, vaxerski
144 | .SH AUTHORS
145 | Vaxerski <\f[I]https://github.com/vaxerski\f[R]>.
146 |
--------------------------------------------------------------------------------
/docs/hyprctl.1.rst:
--------------------------------------------------------------------------------
1 | :title: hyprctl(1)
2 | :author: Vaxerski <*https://github.com/vaxerski*>
3 |
4 | NAME
5 | ====
6 |
7 | hyprctl - Utility for controlling parts of Hyprland from a CLI or a script
8 |
9 | SYNOPSIS
10 | ========
11 |
12 | **hyprctl** [*(opt)flags*] [**command**] [*(opt)args*]
13 |
14 | DESCRIPTION
15 | ===========
16 |
17 | **hyprctl** is a utility for controlling some parts of the compositor from a CLI or a script.
18 |
19 | CONTROL COMMANDS
20 | ================
21 |
22 | **dispatch**
23 |
24 | Call a dispatcher with an argument.
25 |
26 | An argument must be present.
27 | For dispatchers without parameters it can be anything.
28 |
29 | Returns: *ok* on success, and an error message on failure.
30 |
31 | Examples:
32 | **hyprctl** *dispatch exec kitty*
33 |
34 | **hyprctl** *dispatch pseudo x*
35 |
36 | **keyword**
37 |
38 | Set a config keyword dynamically.
39 |
40 | Returns: *ok* on success, and an error message on failure.
41 |
42 | Examples:
43 | **hyprctl** *keyword bind SUPER,0,pseudo*
44 |
45 | **hyprctl** *keyword general:border_size 10*
46 |
47 | **reload**
48 |
49 | Force a reload of the config file.
50 |
51 | **kill**
52 |
53 | Enter kill mode, where you can kill an app by clicking on it.
54 | You can exit by pressing ESCAPE.
55 |
56 | INFO COMMANDS
57 | =============
58 |
59 | **version**
60 |
61 | Prints the Hyprland version, flags, commit and branch of build.
62 |
63 | **monitors**
64 |
65 | Lists all the outputs with their properties.
66 |
67 | **workspaces**
68 |
69 | Lists all workspaces with their properties.
70 |
71 | **clients**
72 |
73 | Lists all windows with their properties.
74 |
75 | **devices**
76 |
77 | Lists all connected input devices.
78 |
79 | **activewindow**
80 |
81 | Returns the active window name.
82 |
83 | **layers**
84 |
85 | Lists all the layers.
86 |
87 | **splash**
88 |
89 | Returns the current random splash.
90 |
91 | OPTIONS
92 | =======
93 |
94 | **--batch**
95 |
96 | Specify a batch of commands to execute.
97 |
98 | Example:
99 | **hyprctl** *--batch "keyword general:border_size 2 ; keyword general:gaps_out 20"*
100 |
101 | *;* separates the commands.
102 |
103 | **-j**
104 |
105 | Outputs information in JSON.
106 |
107 | BUGS
108 | ====
109 |
110 | Submit bug reports and request features online at:
111 | <*https://github.com/hyprwm/Hyprland/issues*>
112 |
113 | SEE ALSO
114 | ========
115 |
116 | Sources at: <*https://github.com/hyprwm/Hyprland*>
117 |
118 | COPYRIGHT
119 | =========
120 |
121 | Copyright (c) 2022, vaxerski
122 |
--------------------------------------------------------------------------------
/docs/meson.build:
--------------------------------------------------------------------------------
1 | install_man ('Hyprland.1')
2 | install_man ('hyprctl.1')
3 |
--------------------------------------------------------------------------------
/example/examplePlugin/Makefile:
--------------------------------------------------------------------------------
1 | # compile with HYPRLAND_HEADERS= make all
2 | # make sure that the path above is to the root hl repo directory, NOT src/
3 | # and that you have ran `make protocols` in the hl dir.
4 |
5 | all:
6 | $(CXX) -shared -fPIC --no-gnu-unique main.cpp customLayout.cpp customDecoration.cpp -o examplePlugin.so -g `pkg-config --cflags pixman-1 libdrm hyprland` -std=c++2b
7 | clean:
8 | rm ./examplePlugin.so
9 |
--------------------------------------------------------------------------------
/example/examplePlugin/customDecoration.cpp:
--------------------------------------------------------------------------------
1 | #include "customDecoration.hpp"
2 | #include
3 | #include
4 | #include "globals.hpp"
5 |
6 | CCustomDecoration::CCustomDecoration(CWindow* pWindow) {
7 | m_pWindow = pWindow;
8 | m_vLastWindowPos = pWindow->m_vRealPosition.vec();
9 | m_vLastWindowSize = pWindow->m_vRealSize.vec();
10 | }
11 |
12 | CCustomDecoration::~CCustomDecoration() {
13 | damageEntire();
14 | }
15 |
16 | SWindowDecorationExtents CCustomDecoration::getWindowDecorationExtents() {
17 | return m_seExtents;
18 | }
19 |
20 | void CCustomDecoration::draw(CMonitor* pMonitor, float a, const Vector2D& offset) {
21 | if (!g_pCompositor->windowValidMapped(m_pWindow))
22 | return;
23 |
24 | if (!m_pWindow->m_sSpecialRenderData.decorate)
25 | return;
26 |
27 | static auto* const PCOLOR = &HyprlandAPI::getConfigValue(PHANDLE, "plugin:example:border_color")->intValue;
28 | static auto* const PROUNDING = &HyprlandAPI::getConfigValue(PHANDLE, "decoration:rounding")->intValue;
29 | static auto* const PBORDERSIZE = &HyprlandAPI::getConfigValue(PHANDLE, "general:border_size")->intValue;
30 |
31 | const auto ROUNDING = !m_pWindow->m_sSpecialRenderData.rounding ?
32 | 0 :
33 | (m_pWindow->m_sAdditionalConfigData.rounding.toUnderlying() == -1 ? *PROUNDING : m_pWindow->m_sAdditionalConfigData.rounding.toUnderlying());
34 |
35 | // draw the border
36 | CBox fullBox = {(int)(m_vLastWindowPos.x - *PBORDERSIZE), (int)(m_vLastWindowPos.y - *PBORDERSIZE), (int)(m_vLastWindowSize.x + 2.0 * *PBORDERSIZE),
37 | (int)(m_vLastWindowSize.y + 2.0 * *PBORDERSIZE)};
38 |
39 | fullBox.x -= pMonitor->vecPosition.x;
40 | fullBox.y -= pMonitor->vecPosition.y;
41 |
42 | m_seExtents = {{m_vLastWindowPos.x - fullBox.x - pMonitor->vecPosition.x + 2, m_vLastWindowPos.y - fullBox.y - pMonitor->vecPosition.y + 2},
43 | {fullBox.x + fullBox.width + pMonitor->vecPosition.x - m_vLastWindowPos.x - m_vLastWindowSize.x + 2,
44 | fullBox.y + fullBox.height + pMonitor->vecPosition.y - m_vLastWindowPos.y - m_vLastWindowSize.y + 2}};
45 |
46 | fullBox.x += offset.x;
47 | fullBox.y += offset.y;
48 |
49 | if (fullBox.width < 1 || fullBox.height < 1)
50 | return; // don't draw invisible shadows
51 |
52 | g_pHyprOpenGL->scissor((CBox*)nullptr);
53 |
54 | fullBox.scale(pMonitor->scale);
55 | g_pHyprOpenGL->renderBorder(&fullBox, CColor(*PCOLOR), *PROUNDING * pMonitor->scale + *PBORDERSIZE * 2, a);
56 | }
57 |
58 | eDecorationType CCustomDecoration::getDecorationType() {
59 | return DECORATION_CUSTOM;
60 | }
61 |
62 | void CCustomDecoration::updateWindow(CWindow* pWindow) {
63 |
64 | m_vLastWindowPos = pWindow->m_vRealPosition.vec();
65 | m_vLastWindowSize = pWindow->m_vRealSize.vec();
66 |
67 | damageEntire();
68 | }
69 |
70 | void CCustomDecoration::damageEntire() {
71 | CBox dm = {(int)(m_vLastWindowPos.x - m_seExtents.topLeft.x), (int)(m_vLastWindowPos.y - m_seExtents.topLeft.y),
72 | (int)(m_vLastWindowSize.x + m_seExtents.topLeft.x + m_seExtents.bottomRight.x), (int)m_seExtents.topLeft.y};
73 | g_pHyprRenderer->damageBox(&dm);
74 | }
--------------------------------------------------------------------------------
/example/examplePlugin/customDecoration.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #define WLR_USE_UNSTABLE
4 |
5 | #include
6 |
7 | class CCustomDecoration : public IHyprWindowDecoration {
8 | public:
9 | CCustomDecoration(CWindow*);
10 | virtual ~CCustomDecoration();
11 |
12 | virtual SWindowDecorationExtents getWindowDecorationExtents();
13 |
14 | virtual void draw(CMonitor*, float a, const Vector2D& offset);
15 |
16 | virtual eDecorationType getDecorationType();
17 |
18 | virtual void updateWindow(CWindow*);
19 |
20 | virtual void damageEntire();
21 |
22 | private:
23 | SWindowDecorationExtents m_seExtents;
24 |
25 | CWindow* m_pWindow = nullptr;
26 |
27 | Vector2D m_vLastWindowPos;
28 | Vector2D m_vLastWindowSize;
29 | };
--------------------------------------------------------------------------------
/example/examplePlugin/customLayout.cpp:
--------------------------------------------------------------------------------
1 | #include "customLayout.hpp"
2 | #include
3 | #include "globals.hpp"
4 |
5 | void CHyprCustomLayout::onWindowCreatedTiling(CWindow* pWindow) {
6 | const auto PMONITOR = g_pCompositor->getMonitorFromID(pWindow->m_iMonitorID);
7 | const auto SIZE = PMONITOR->vecSize;
8 |
9 | // these are used for focus and move calculations, and are *required* to touch for moving focus to work properly.
10 | pWindow->m_vPosition = Vector2D{(SIZE.x / 2.0) * (m_vWindowData.size() % 2), (SIZE.y / 2.0) * (int)(m_vWindowData.size() > 1)};
11 | pWindow->m_vSize = SIZE / 2.0;
12 |
13 | // this is the actual pos and size of the window (where it's rendered)
14 | pWindow->m_vRealPosition = pWindow->m_vPosition + Vector2D{10, 10};
15 | pWindow->m_vRealSize = pWindow->m_vSize - Vector2D{20, 20};
16 |
17 | const auto PDATA = &m_vWindowData.emplace_back();
18 | PDATA->pWindow = pWindow;
19 | }
20 |
21 | void CHyprCustomLayout::onWindowRemovedTiling(CWindow* pWindow) {
22 | std::erase_if(m_vWindowData, [&](const auto& other) { return other.pWindow == pWindow; });
23 | }
24 |
25 | bool CHyprCustomLayout::isWindowTiled(CWindow* pWindow) {
26 | return std::find_if(m_vWindowData.begin(), m_vWindowData.end(), [&](const auto& other) { return other.pWindow == pWindow; }) != m_vWindowData.end();
27 | }
28 |
29 | void CHyprCustomLayout::recalculateMonitor(const int& eIdleInhibitMode) {
30 | ; // empty
31 | }
32 |
33 | void CHyprCustomLayout::recalculateWindow(CWindow* pWindow) {
34 | ; // empty
35 | }
36 |
37 | void CHyprCustomLayout::resizeActiveWindow(const Vector2D& delta, CWindow* pWindow) {
38 | ; // empty
39 | }
40 |
41 | void CHyprCustomLayout::fullscreenRequestForWindow(CWindow* pWindow, eFullscreenMode mode, bool on) {
42 | ; // empty
43 | }
44 |
45 | std::any CHyprCustomLayout::layoutMessage(SLayoutMessageHeader header, std::string content) {
46 | return "";
47 | }
48 |
49 | SWindowRenderLayoutHints CHyprCustomLayout::requestRenderHints(CWindow* pWindow) {
50 | return {};
51 | }
52 |
53 | void CHyprCustomLayout::switchWindows(CWindow* pWindowA, CWindow* pWindowB) {
54 | ; // empty
55 | }
56 |
57 | void CHyprCustomLayout::alterSplitRatio(CWindow* pWindow, float delta, bool exact) {
58 | ; // empty
59 | }
60 |
61 | std::string CHyprCustomLayout::getLayoutName() {
62 | return "custom";
63 | }
64 |
65 | void CHyprCustomLayout::replaceWindowDataWith(CWindow* from, CWindow* to) {
66 | ; // empty
67 | }
68 |
69 | void CHyprCustomLayout::onEnable() {
70 | for (auto& w : g_pCompositor->m_vWindows) {
71 | if (w->isHidden() || !w->m_bIsMapped || w->m_bFadingOut || w->m_bIsFloating)
72 | continue;
73 |
74 | onWindowCreatedTiling(w.get());
75 | }
76 | }
77 |
78 | void CHyprCustomLayout::onDisable() {
79 | m_vWindowData.clear();
80 | }
--------------------------------------------------------------------------------
/example/examplePlugin/customLayout.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #define WLR_USE_UNSTABLE
4 |
5 | #include
6 |
7 | struct SWindowData {
8 | CWindow* pWindow = nullptr;
9 | };
10 |
11 | class CHyprCustomLayout : public IHyprLayout {
12 | public:
13 | virtual void onWindowCreatedTiling(CWindow*);
14 | virtual void onWindowRemovedTiling(CWindow*);
15 | virtual bool isWindowTiled(CWindow*);
16 | virtual void recalculateMonitor(const int&);
17 | virtual void recalculateWindow(CWindow*);
18 | virtual void resizeActiveWindow(const Vector2D&, CWindow* pWindow = nullptr);
19 | virtual void fullscreenRequestForWindow(CWindow*, eFullscreenMode, bool);
20 | virtual std::any layoutMessage(SLayoutMessageHeader, std::string);
21 | virtual SWindowRenderLayoutHints requestRenderHints(CWindow*);
22 | virtual void switchWindows(CWindow*, CWindow*);
23 | virtual void alterSplitRatio(CWindow*, float, bool);
24 | virtual std::string getLayoutName();
25 | virtual void replaceWindowDataWith(CWindow* from, CWindow* to);
26 |
27 | virtual void onEnable();
28 | virtual void onDisable();
29 |
30 | private:
31 | std::vector m_vWindowData;
32 | };
--------------------------------------------------------------------------------
/example/examplePlugin/globals.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | inline HANDLE PHANDLE = nullptr;
--------------------------------------------------------------------------------
/example/hyprland.desktop:
--------------------------------------------------------------------------------
1 | [Desktop Entry]
2 | Name=Hyprland
3 | Comment=An intelligent dynamic tiling Wayland compositor
4 | Exec=Hyprland
5 | Type=Application
--------------------------------------------------------------------------------
/example/hyprland.service:
--------------------------------------------------------------------------------
1 | ; a primitive systemd --user example
2 | [Unit]
3 | Description = %p
4 | BindsTo = graphical-session.target
5 | Upholds = swaybg@333333.service
6 |
7 | [Service]
8 | Type = notify
9 | ExecStart = /usr/bin/Hyprland
10 |
11 | [Install]
12 | WantedBy = default.target
13 |
--------------------------------------------------------------------------------
/example/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | // Use IntelliSense to learn about possible attributes.
3 | // Hover to view descriptions of existing attributes.
4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5 | "version": "0.2.0",
6 | "configurations": [
7 | {
8 | "name": "(gdb) Launch",
9 | "type": "cppdbg",
10 | "request": "launch",
11 | "program": "${workspaceFolder}/build/Hyprland",
12 | "args": [],
13 | "stopAtEntry": false,
14 | "cwd": "${fileDirname}",
15 | "externalConsole": false,
16 | "MIMode": "gdb",
17 | "setupCommands": [
18 | {
19 | "description": "Enable pretty-printing for gdb",
20 | "text": "-enable-pretty-printing",
21 | "ignoreFailures": true
22 | }
23 | ]
24 | },
25 | ]
26 | }
--------------------------------------------------------------------------------
/example/meson.build:
--------------------------------------------------------------------------------
1 | install_data('hyprland.conf', install_dir: join_paths(get_option('datadir'), 'hyprland'), install_tag: 'runtime')
2 | install_data('hyprland.desktop', install_dir: join_paths(get_option('datadir'), 'wayland-sessions'), install_tag: 'runtime')
3 |
--------------------------------------------------------------------------------
/example/screenShader.frag:
--------------------------------------------------------------------------------
1 | //
2 | // Example blue light filter shader.
3 | //
4 |
5 | precision mediump float;
6 | varying vec2 v_texcoord;
7 | uniform sampler2D tex;
8 |
9 | void main() {
10 |
11 | vec4 pixColor = texture2D(tex, v_texcoord);
12 |
13 | pixColor[2] *= 0.8;
14 |
15 | gl_FragColor = pixColor;
16 | }
17 |
--------------------------------------------------------------------------------
/example/swaybg@.service:
--------------------------------------------------------------------------------
1 | ; a primitive systemd --user example
2 | ; see example/hyprland.service for more details
3 | [Unit]
4 | Description = %p
5 | BindsTo = hyprland.service
6 | Wants = hyprland.service
7 | After = hyprland.service
8 |
9 | [Service]
10 | ExecStart = /usr/bin/swaybg --color #%i
11 |
12 | [Install]
13 | WantedBy = default.target
14 |
--------------------------------------------------------------------------------
/flake.lock:
--------------------------------------------------------------------------------
1 | {
2 | "nodes": {
3 | "hyprland-protocols": {
4 | "inputs": {
5 | "nixpkgs": [
6 | "nixpkgs"
7 | ],
8 | "systems": [
9 | "systems"
10 | ]
11 | },
12 | "locked": {
13 | "lastModified": 1691753796,
14 | "narHash": "sha256-zOEwiWoXk3j3+EoF3ySUJmberFewWlagvewDRuWYAso=",
15 | "owner": "hyprwm",
16 | "repo": "hyprland-protocols",
17 | "rev": "0c2ce70625cb30aef199cb388f99e19a61a6ce03",
18 | "type": "github"
19 | },
20 | "original": {
21 | "owner": "hyprwm",
22 | "repo": "hyprland-protocols",
23 | "type": "github"
24 | }
25 | },
26 | "hyprlang": {
27 | "inputs": {
28 | "nixpkgs": [
29 | "xdph",
30 | "nixpkgs"
31 | ]
32 | },
33 | "locked": {
34 | "lastModified": 1704287638,
35 | "narHash": "sha256-TuRXJGwtK440AXQNl5eiqmQqY4LZ/9+z/R7xC0ie3iA=",
36 | "owner": "hyprwm",
37 | "repo": "hyprlang",
38 | "rev": "6624f2bb66d4d27975766e81f77174adbe58ec97",
39 | "type": "github"
40 | },
41 | "original": {
42 | "owner": "hyprwm",
43 | "repo": "hyprlang",
44 | "type": "github"
45 | }
46 | },
47 | "nixpkgs": {
48 | "locked": {
49 | "lastModified": 1707546158,
50 | "narHash": "sha256-nYYJTpzfPMDxI8mzhQsYjIUX+grorqjKEU9Np6Xwy/0=",
51 | "owner": "NixOS",
52 | "repo": "nixpkgs",
53 | "rev": "d934204a0f8d9198e1e4515dd6fec76a139c87f0",
54 | "type": "github"
55 | },
56 | "original": {
57 | "owner": "NixOS",
58 | "ref": "nixos-unstable",
59 | "repo": "nixpkgs",
60 | "type": "github"
61 | }
62 | },
63 | "root": {
64 | "inputs": {
65 | "hyprland-protocols": "hyprland-protocols",
66 | "nixpkgs": "nixpkgs",
67 | "systems": "systems",
68 | "wlroots": "wlroots",
69 | "xdph": "xdph"
70 | }
71 | },
72 | "systems": {
73 | "locked": {
74 | "lastModified": 1689347949,
75 | "narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=",
76 | "owner": "nix-systems",
77 | "repo": "default-linux",
78 | "rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68",
79 | "type": "github"
80 | },
81 | "original": {
82 | "owner": "nix-systems",
83 | "repo": "default-linux",
84 | "type": "github"
85 | }
86 | },
87 | "wlroots": {
88 | "flake": false,
89 | "locked": {
90 | "host": "gitlab.freedesktop.org",
91 | "lastModified": 1697909146,
92 | "narHash": "sha256-jU0I6FoCKnj4zIBL4daosFWh81U1fM719Z6cae8PxSY=",
93 | "owner": "wlroots",
94 | "repo": "wlroots",
95 | "rev": "47bf87ade2bd32395615a385ebde1fefbcdf79a2",
96 | "type": "gitlab"
97 | },
98 | "original": {
99 | "host": "gitlab.freedesktop.org",
100 | "owner": "wlroots",
101 | "repo": "wlroots",
102 | "rev": "47bf87ade2bd32395615a385ebde1fefbcdf79a2",
103 | "type": "gitlab"
104 | }
105 | },
106 | "xdph": {
107 | "inputs": {
108 | "hyprland-protocols": [
109 | "hyprland-protocols"
110 | ],
111 | "hyprlang": "hyprlang",
112 | "nixpkgs": [
113 | "nixpkgs"
114 | ],
115 | "systems": [
116 | "systems"
117 | ]
118 | },
119 | "locked": {
120 | "lastModified": 1706521509,
121 | "narHash": "sha256-AInZ50acOJ3wzUwGzNr1TmxGTMx+8j6oSTzz4E7Vbp8=",
122 | "owner": "hyprwm",
123 | "repo": "xdg-desktop-portal-hyprland",
124 | "rev": "c06fd88b3da492b8f9067be021b9184f7012b5a8",
125 | "type": "github"
126 | },
127 | "original": {
128 | "owner": "hyprwm",
129 | "repo": "xdg-desktop-portal-hyprland",
130 | "type": "github"
131 | }
132 | }
133 | },
134 | "root": "root",
135 | "version": 7
136 | }
137 |
--------------------------------------------------------------------------------
/flake.nix:
--------------------------------------------------------------------------------
1 | {
2 | description = "Polyland is a queer-friendly dynamic tiling Wayland compositor that doesn't sacrifice on its looks";
3 |
4 | inputs = {
5 | nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
6 |
7 | #
8 | systems.url = "github:nix-systems/default-linux";
9 |
10 | wlroots = {
11 | type = "gitlab";
12 | host = "gitlab.freedesktop.org";
13 | owner = "wlroots";
14 | repo = "wlroots";
15 | rev = "47bf87ade2bd32395615a385ebde1fefbcdf79a2";
16 | flake = false;
17 | };
18 |
19 | hyprland-protocols = {
20 | url = "github:hyprwm/hyprland-protocols";
21 | inputs.nixpkgs.follows = "nixpkgs";
22 | inputs.systems.follows = "systems";
23 | };
24 |
25 | xdph = {
26 | url = "github:hyprwm/xdg-desktop-portal-hyprland";
27 | inputs.nixpkgs.follows = "nixpkgs";
28 | inputs.systems.follows = "systems";
29 | inputs.hyprland-protocols.follows = "hyprland-protocols";
30 | };
31 | };
32 |
33 | outputs = inputs @ {
34 | self,
35 | nixpkgs,
36 | systems,
37 | ...
38 | }: let
39 | inherit (nixpkgs) lib;
40 | eachSystem = lib.genAttrs (import systems);
41 | pkgsFor = eachSystem (system:
42 | import nixpkgs {
43 | localSystem = system;
44 | overlays = with self.overlays; [
45 | hyprland-packages
46 | hyprland-extras
47 | ];
48 | });
49 | in {
50 | overlays = import ./nix/overlays.nix {inherit self lib inputs;};
51 |
52 | checks = eachSystem (system:
53 | (lib.filterAttrs
54 | (n: _: (lib.hasPrefix "hyprland" n) && !(lib.hasSuffix "debug" n))
55 | self.packages.${system})
56 | // {
57 | inherit (self.packages.${system}) xdg-desktop-portal-hyprland;
58 | });
59 |
60 | packages = eachSystem (system: {
61 | default = self.packages.${system}.hyprland;
62 | inherit
63 | (pkgsFor.${system})
64 | # hyprland-packages
65 | hyprland
66 | hyprland-unwrapped
67 | hyprland-debug
68 | hyprland-nvidia
69 | # hyprland-extras
70 | xdg-desktop-portal-hyprland
71 | # dependencies
72 | hyprland-protocols
73 | wlroots-hyprland
74 | udis86
75 | ;
76 | });
77 |
78 | devShells = eachSystem (system: {
79 | default = pkgsFor.${system}.mkShell.override {
80 | stdenv = pkgsFor.${system}.gcc13Stdenv;
81 | } {
82 | name = "hyprland-shell";
83 | nativeBuildInputs = with pkgsFor.${system}; [cmake python3];
84 | buildInputs = [self.packages.${system}.wlroots-hyprland];
85 | inputsFrom = [
86 | self.packages.${system}.wlroots-hyprland
87 | self.packages.${system}.hyprland
88 | ];
89 | };
90 | });
91 |
92 | formatter = eachSystem (system: nixpkgs.legacyPackages.${system}.alejandra);
93 |
94 | nixosModules.default = import ./nix/module.nix inputs;
95 | homeManagerModules.default = import ./nix/hm-module.nix self;
96 | };
97 | }
98 |
--------------------------------------------------------------------------------
/hyprctl/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.19)
2 |
3 | project(
4 | hyprctl
5 | DESCRIPTION "Control utility for Hyprland"
6 | )
7 |
8 | add_executable(hyprctl "main.cpp")
--------------------------------------------------------------------------------
/hyprctl/Makefile:
--------------------------------------------------------------------------------
1 | all:
2 | $(CXX) -std=c++2b ./main.cpp -o ./hyprctl
3 | clean:
4 | rm ./hyprctl
5 |
--------------------------------------------------------------------------------
/hyprctl/meson.build:
--------------------------------------------------------------------------------
1 | executable('hyprctl', 'main.cpp',
2 | install: true
3 | )
4 |
--------------------------------------------------------------------------------
/hyprland.pc.in:
--------------------------------------------------------------------------------
1 | prefix="@PREFIX@"
2 | includedir="${prefix}/include"
3 |
4 | Name: Hyprland
5 | URL: https://github.com/hyprwm/Hyprland
6 | Description: Hyprland header files
7 | Version: @HYPRLAND_VERSION@
8 | Cflags: -I"${includedir}/hyprland/protocols" -I"${includedir}/hyprland/wlroots" -I"${includedir}"
9 |
--------------------------------------------------------------------------------
/meson.build:
--------------------------------------------------------------------------------
1 | project('Hyprland', 'cpp', 'c',
2 | version : run_command('jq', '-r', '.version', join_paths(meson.source_root(), 'props.json'), check: true).stdout().strip(),
3 | default_options : [
4 | 'warning_level=2',
5 | 'default_library=static',
6 | 'optimization=3',
7 | 'buildtype=release',
8 | 'debug=false'
9 | # 'cpp_std=c++23' # not yet supported by meson, as of version 0.63.0
10 | ])
11 |
12 | # clang v14.0.6 uses C++2b instead of C++23, so we've gotta account for that
13 | # replace the following with a project default option once meson gets support for C++23
14 | cpp_compiler = meson.get_compiler('cpp')
15 | if cpp_compiler.has_argument('-std=c++23')
16 | add_global_arguments('-std=c++23', language: 'cpp')
17 | elif cpp_compiler.has_argument('-std=c++2b')
18 | add_global_arguments('-std=c++2b', language: 'cpp')
19 | else
20 | error('Could not configure current C++ compiler (' + cpp_compiler.get_id() + ' ' + cpp_compiler.version() + ') with required C++ standard (C++23)')
21 | endif
22 |
23 | add_project_arguments(
24 | [
25 | '-Wno-unused-parameter',
26 | '-Wno-unused-value',
27 | '-Wno-missing-field-initializers',
28 | '-Wno-narrowing',
29 | ],
30 | language: 'cpp')
31 |
32 | if cpp_compiler.check_header('execinfo.h')
33 | add_project_arguments('-DHAS_EXECINFO', language: 'cpp')
34 | endif
35 |
36 | wlroots = subproject('wlroots', default_options: ['examples=false', 'renderers=gles2'])
37 | have_xwlr = wlroots.get_variable('features').get('xwayland')
38 | xcb_dep = dependency('xcb', required: get_option('xwayland'))
39 |
40 | cmake = import('cmake')
41 | udis = cmake.subproject('udis86')
42 | udis86 = udis.dependency('libudis86')
43 |
44 | if get_option('xwayland').enabled() and not have_xwlr
45 | error('Cannot enable Xwayland in Hyprland: wlroots has been built without Xwayland support')
46 | endif
47 | have_xwayland = xcb_dep.found() and have_xwlr
48 |
49 | if not have_xwayland
50 | add_project_arguments('-DNO_XWAYLAND', language: 'cpp')
51 | endif
52 |
53 | backtrace_dep = cpp_compiler.find_library('execinfo', required: false)
54 | systemd_dep = dependency('libsystemd', required: get_option('systemd'))
55 |
56 | if get_option('systemd').enabled()
57 | if systemd_dep.found()
58 | add_project_arguments('-DUSES_SYSTEMD', language: 'cpp')
59 | else
60 | error('Cannot enable systemd in Hyprland: libsystemd was not found')
61 | endif
62 | endif
63 |
64 | if get_option('legacy_renderer').enabled()
65 | add_project_arguments('-DLEGACY_RENDERER', language: 'cpp')
66 | endif
67 |
68 | if get_option('buildtype') == 'debug'
69 | add_project_arguments('-DHYPRLAND_DEBUG', language: 'cpp')
70 | endif
71 |
72 | version_h = run_command('sh', '-c', 'scripts/generateVersion.sh')
73 |
74 | globber = run_command('find', 'src', '-name', '*.h*', check: true)
75 | headers = globber.stdout().strip().split('\n')
76 | foreach file : headers
77 | install_headers(file, subdir: 'hyprland', preserve_path: true)
78 | endforeach
79 |
80 | subdir('protocols')
81 | subdir('src')
82 | subdir('hyprctl')
83 | subdir('assets')
84 | subdir('example')
85 | subdir('docs')
86 |
87 | pkg_install_dir = join_paths(get_option('datadir'), 'pkgconfig')
88 |
89 | import('pkgconfig').generate(
90 | name: 'Hyprland',
91 | filebase: 'hyprland',
92 | url: 'https://github.com/hyprwm/Hyprland',
93 | description: 'Hyprland header files',
94 | install_dir: pkg_install_dir,
95 | subdirs: ['', 'hyprland/protocols', 'hyprland/wlroots'],
96 | )
97 |
--------------------------------------------------------------------------------
/meson_options.txt:
--------------------------------------------------------------------------------
1 | option('xwayland', type: 'feature', value: 'auto', description: 'Enable support for X11 applications')
2 | option('systemd', type: 'feature', value: 'auto', description: 'Enable systemd integration')
3 | option('legacy_renderer', type: 'feature', value: 'disabled', description: 'Enable legacy renderer')
4 |
--------------------------------------------------------------------------------
/nix/module.nix:
--------------------------------------------------------------------------------
1 | inputs: {
2 | config,
3 | lib,
4 | pkgs,
5 | options,
6 | ...
7 | }:
8 | with lib; let
9 | cfg = config.programs.hyprland;
10 | inherit (pkgs.stdenv.hostPlatform) system;
11 |
12 | finalPortalPackage = cfg.portalPackage.override {
13 | hyprland = cfg.finalPackage;
14 | };
15 | in {
16 | # disables Nixpkgs Hyprland module to avoid conflicts
17 | disabledModules = ["programs/hyprland.nix"];
18 |
19 | options.programs.hyprland = {
20 | enable =
21 | mkEnableOption null
22 | // {
23 | description = mdDoc ''
24 | Hyprland, the dynamic tiling Wayland compositor that doesn't sacrifice on its looks.
25 |
26 | You can manually launch Hyprland by executing {command}`Hyprland` on a TTY.
27 |
28 | A configuration file will be generated in {file}`~/.config/hypr/hyprland.conf`.
29 | See for more information.
30 | '';
31 | };
32 |
33 | package = mkPackageOptionMD inputs.self.packages.${system} "hyprland" { };
34 |
35 | finalPackage = mkOption {
36 | type = types.package;
37 | readOnly = true;
38 | default = cfg.package.override {
39 | enableXWayland = cfg.xwayland.enable;
40 | enableNvidiaPatches = cfg.enableNvidiaPatches;
41 | };
42 | defaultText =
43 | literalExpression
44 | "`programs.hyprland.package` with applied configuration";
45 | description = mdDoc ''
46 | The Hyprland package after applying configuration.
47 | '';
48 | };
49 |
50 | portalPackage = mkPackageOptionMD inputs.xdph.packages.${system} "xdg-desktop-portal-hyprland" {};
51 |
52 | xwayland.enable = mkEnableOption (mdDoc "support for XWayland") // {default = true;};
53 |
54 | enableNvidiaPatches =
55 | mkEnableOption null
56 | // {
57 | description = mdDoc "Whether to apply patches to wlroots for better Nvidia support.";
58 | };
59 | };
60 |
61 | config = mkIf cfg.enable {
62 | environment.systemPackages = [cfg.finalPackage];
63 |
64 | # NixOS changed the name of this attribute between NixOS 23.05 and
65 | # 23.11
66 | fonts = if builtins.hasAttr "enableDefaultPackages" options.fonts
67 | then {enableDefaultPackages = mkDefault true;}
68 | else {enableDefaultFonts = mkDefault true;};
69 |
70 | hardware.opengl.enable = mkDefault true;
71 |
72 | programs = {
73 | dconf.enable = mkDefault true;
74 | xwayland.enable = mkDefault cfg.xwayland.enable;
75 | };
76 |
77 | security.polkit.enable = true;
78 |
79 | services.xserver.displayManager.sessionPackages = [cfg.finalPackage];
80 |
81 | xdg.portal = {
82 | enable = mkDefault true;
83 | extraPortals = [finalPortalPackage];
84 | };
85 | };
86 |
87 | imports = with lib; [
88 | (
89 | mkRemovedOptionModule
90 | ["programs" "hyprland" "xwayland" "hidpi"]
91 | "XWayland patches are deprecated. Refer to https://wiki.hyprland.org/Configuring/XWayland"
92 | )
93 | (
94 | mkRenamedOptionModule
95 | ["programs" "hyprland" "nvidiaPatches"]
96 | ["programs" "hyprland" "enableNvidiaPatches"]
97 | )
98 | ];
99 | }
100 |
--------------------------------------------------------------------------------
/nix/overlays.nix:
--------------------------------------------------------------------------------
1 | {
2 | self,
3 | lib,
4 | inputs,
5 | }: let
6 | props = builtins.fromJSON (builtins.readFile ../props.json);
7 |
8 | mkDate = longDate: (lib.concatStringsSep "-" [
9 | (builtins.substring 0 4 longDate)
10 | (builtins.substring 4 2 longDate)
11 | (builtins.substring 6 2 longDate)
12 | ]);
13 |
14 | mkJoinedOverlays = overlays: final: prev:
15 | lib.foldl' (attrs: overlay: attrs // (overlay final prev)) {} overlays;
16 | in {
17 | # Contains what a user is most likely to care about:
18 | # Hyprland itself, XDPH and the Share Picker.
19 | default = mkJoinedOverlays (with self.overlays; [
20 | hyprland-packages
21 | hyprland-extras
22 | ]);
23 |
24 | # Packages for variations of Hyprland, dependencies included.
25 | hyprland-packages = mkJoinedOverlays [
26 | # Dependencies
27 | inputs.hyprland-protocols.overlays.default
28 | self.overlays.wlroots-hyprland
29 | self.overlays.udis86
30 | # Hyprland packages themselves
31 | (final: prev: {
32 | hyprland = final.callPackage ./default.nix {
33 | stdenv = final.gcc13Stdenv;
34 | version = "${props.version}+date=${mkDate (self.lastModifiedDate or "19700101")}_${self.shortRev or "dirty"}";
35 | wlroots = final.wlroots-hyprland;
36 | commit = self.rev or "";
37 | inherit (final) udis86 hyprland-protocols;
38 | };
39 | hyprland-unwrapped = final.hyprland.override {wrapRuntimeDeps = false;};
40 | hyprland-debug = final.hyprland.override {debug = true;};
41 | hyprland-nvidia = final.hyprland.override {enableNvidiaPatches = true;};
42 | hyprland-hidpi =
43 | builtins.trace ''
44 | hyprland-hidpi was removed. Please use the hyprland package.
45 | For more information, refer to https://wiki.hyprland.org/Configuring/XWayland.
46 | ''
47 | final.hyprland;
48 | })
49 | ];
50 |
51 | # Packages for extra software recommended for usage with Hyprland,
52 | # including forked or patched packages for compatibility.
53 | hyprland-extras = mkJoinedOverlays [
54 | inputs.xdph.overlays.xdg-desktop-portal-hyprland
55 | ];
56 |
57 | udis86 = final: prev: {
58 | udis86 = final.callPackage ./udis86.nix {};
59 | };
60 |
61 | # Patched version of wlroots for Hyprland.
62 | # It is under a new package name so as to not conflict with
63 | # the standard version in nixpkgs.
64 | wlroots-hyprland = final: prev: {
65 | wlroots-hyprland = final.callPackage ./wlroots.nix {
66 | version = "${mkDate (inputs.wlroots.lastModifiedDate or "19700101")}_${inputs.wlroots.shortRev or "dirty"}";
67 | src = inputs.wlroots;
68 |
69 | libdisplay-info = prev.libdisplay-info.overrideAttrs (old: {
70 | version = "0.1.1+date=2023-03-02";
71 | src = final.fetchFromGitLab {
72 | domain = "gitlab.freedesktop.org";
73 | owner = "emersion";
74 | repo = old.pname;
75 | rev = "147d6611a64a6ab04611b923e30efacaca6fc678";
76 | sha256 = "sha256-/q79o13Zvu7x02SBGu0W5yQznQ+p7ltZ9L6cMW5t/o4=";
77 | };
78 | });
79 |
80 | libliftoff = prev.libliftoff.overrideAttrs (old: {
81 | version = "0.5.0-dev";
82 | src = final.fetchFromGitLab {
83 | domain = "gitlab.freedesktop.org";
84 | owner = "emersion";
85 | repo = old.pname;
86 | rev = "d98ae243280074b0ba44bff92215ae8d785658c0";
87 | sha256 = "sha256-DjwlS8rXE7srs7A8+tHqXyUsFGtucYSeq6X0T/pVOc8=";
88 | };
89 |
90 | NIX_CFLAGS_COMPILE = toString ["-Wno-error=sign-conversion"];
91 | });
92 | };
93 | };
94 | }
95 |
--------------------------------------------------------------------------------
/nix/patches/meson-build.patch:
--------------------------------------------------------------------------------
1 | diff --git a/meson.build b/meson.build
2 | index 1d2c7f9f..c5ef4e67 100644
3 | --- a/meson.build
4 | +++ b/meson.build
5 | @@ -33,20 +33,7 @@ if cpp_compiler.check_header('execinfo.h')
6 | add_project_arguments('-DHAS_EXECINFO', language: 'cpp')
7 | endif
8 |
9 | -wlroots = subproject('wlroots', default_options: ['examples=false', 'renderers=gles2'])
10 | -have_xwlr = wlroots.get_variable('features').get('xwayland')
11 | -xcb_dep = dependency('xcb', required: get_option('xwayland'))
12 | -
13 | -cmake = import('cmake')
14 | -udis = cmake.subproject('udis86')
15 | -udis86 = udis.dependency('libudis86')
16 | -
17 | -if get_option('xwayland').enabled() and not have_xwlr
18 | - error('Cannot enable Xwayland in Hyprland: wlroots has been built without Xwayland support')
19 | -endif
20 | -have_xwayland = xcb_dep.found() and have_xwlr
21 | -
22 | -if not have_xwayland
23 | +if get_option('xwayland').disabled()
24 | add_project_arguments('-DNO_XWAYLAND', language: 'cpp')
25 | endif
26 |
27 | @@ -69,8 +56,6 @@ if get_option('buildtype') == 'debug'
28 | add_project_arguments('-DHYPRLAND_DEBUG', language: 'cpp')
29 | endif
30 |
31 | -version_h = run_command('sh', '-c', 'scripts/generateVersion.sh')
32 | -
33 | globber = run_command('find', 'src', '-name', '*.h*', check: true)
34 | headers = globber.stdout().strip().split('\n')
35 | foreach file : headers
36 | diff --git a/src/meson.build b/src/meson.build
37 | index 0af864b9..38723b8c 100644
38 | --- a/src/meson.build
39 | +++ b/src/meson.build
40 | @@ -9,16 +9,16 @@ executable('Hyprland', src,
41 | server_protos,
42 | dependency('wayland-server'),
43 | dependency('wayland-client'),
44 | - wlroots.get_variable('wlroots'),
45 | + dependency('wlroots'),
46 | dependency('cairo'),
47 | dependency('libdrm'),
48 | dependency('egl'),
49 | dependency('xkbcommon'),
50 | dependency('libinput'),
51 | - xcb_dep,
52 | + dependency('xcb', required: get_option('xwayland')),
53 | backtrace_dep,
54 | systemd_dep,
55 | - udis86,
56 | + dependency('udis86'),
57 |
58 | dependency('pixman-1'),
59 | dependency('gl', 'opengl'),
60 |
--------------------------------------------------------------------------------
/nix/patches/wlroots-nvidia.patch:
--------------------------------------------------------------------------------
1 | diff --git a/render/gles2/renderer.c b/render/gles2/renderer.c
2 | index 9fe934f7..9662d4ee 100644
3 | --- a/render/gles2/renderer.c
4 | +++ b/render/gles2/renderer.c
5 | @@ -176,7 +176,7 @@ static bool gles2_bind_buffer(struct wlr_renderer *wlr_renderer,
6 | assert(wlr_egl_is_current(renderer->egl));
7 |
8 | push_gles2_debug(renderer);
9 | - glFlush();
10 | + glFinish();
11 | glBindFramebuffer(GL_FRAMEBUFFER, 0);
12 | pop_gles2_debug(renderer);
13 |
14 | diff --git a/types/output/render.c b/types/output/render.c
15 | index 2e38919a..97f78608 100644
16 | --- a/types/output/render.c
17 | +++ b/types/output/render.c
18 | @@ -240,22 +240,7 @@ bool output_pick_format(struct wlr_output *output,
19 | }
20 |
21 | uint32_t wlr_output_preferred_read_format(struct wlr_output *output) {
22 | - struct wlr_renderer *renderer = output->renderer;
23 | - assert(renderer != NULL);
24 | -
25 | - if (!renderer->impl->preferred_read_format || !renderer->impl->read_pixels) {
26 | - return DRM_FORMAT_INVALID;
27 | - }
28 | -
29 | - if (!wlr_output_attach_render(output, NULL)) {
30 | - return false;
31 | - }
32 | -
33 | - uint32_t fmt = renderer->impl->preferred_read_format(renderer);
34 | -
35 | - output_clear_back_buffer(output);
36 | -
37 | - return fmt;
38 | + return DRM_FORMAT_XRGB8888;
39 | }
40 |
41 | struct wlr_render_pass *wlr_output_begin_render_pass(struct wlr_output *output,
42 |
--------------------------------------------------------------------------------
/nix/udis86.nix:
--------------------------------------------------------------------------------
1 | {
2 | lib,
3 | stdenv,
4 | fetchFromGitHub,
5 | autoreconfHook,
6 | python3,
7 | }:
8 | stdenv.mkDerivation {
9 | pname = "udis86";
10 | version = "unstable-2022-10-13";
11 |
12 | src = fetchFromGitHub {
13 | owner = "canihavesomecoffee";
14 | repo = "udis86";
15 | rev = "5336633af70f3917760a6d441ff02d93477b0c86";
16 | hash = "sha256-HifdUQPGsKQKQprByeIznvRLONdOXeolOsU5nkwIv3g=";
17 | };
18 |
19 | nativeBuildInputs = [autoreconfHook python3];
20 |
21 | configureFlags = ["--enable-shared"];
22 |
23 | outputs = ["bin" "out" "dev" "lib"];
24 |
25 | meta = with lib; {
26 | homepage = "https://udis86.sourceforge.net";
27 | license = licenses.bsd2;
28 | mainProgram = "udcli";
29 | description = "Easy-to-use, minimalistic x86 disassembler library (libudis86)";
30 | platforms = platforms.all;
31 | };
32 | }
33 |
--------------------------------------------------------------------------------
/nix/update-inputs.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env -S nix shell nixpkgs#jq -c bash
2 |
3 | # Update inputs when the Mesa version is outdated. We don't want
4 | # incompatibilities between the user's system and Hyprland.
5 |
6 | # get the current Nixpkgs revision
7 | REV=$(jq $NEW_VER and flake inputs"
14 |
15 | # update inputs to latest versions
16 | nix flake update
17 | else
18 | echo "nixpkgs is up to date!"
19 | fi
20 |
--------------------------------------------------------------------------------
/nix/update-wlroots.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env -S nix shell nixpkgs#gawk nixpkgs#git nixpkgs#gnused nixpkgs#ripgrep -c bash
2 |
3 | # get wlroots revision from submodule
4 | SUB_REV=$(git submodule status | rg wlroots | awk '{ print substr($1,2) }')
5 | # and from lockfile
6 | CRT_REV=$(rg rev flake.nix | awk '{ print substr($3, 2, 40) }')
7 |
8 | if [ "$SUB_REV" != "$CRT_REV" ]; then
9 | echo "Updating wlroots..."
10 | # update wlroots to submodule revision
11 | sed -Ei "s/\w{40}/$SUB_REV/g" flake.nix subprojects/wlroots.wrap
12 | nix flake lock
13 |
14 | echo "wlroots: $CRT_REV -> $SUB_REV"
15 | else
16 | echo "wlroots is up to date!"
17 | fi
18 |
--------------------------------------------------------------------------------
/nix/wlroots.nix:
--------------------------------------------------------------------------------
1 | {
2 | lib,
3 | version,
4 | src,
5 | wlroots,
6 | hwdata,
7 | libdisplay-info,
8 | libliftoff,
9 | enableXWayland ? true,
10 | enableNvidiaPatches ? false,
11 | }:
12 | wlroots.overrideAttrs (old: {
13 | inherit version src enableXWayland;
14 |
15 | pname = "${old.pname}-hyprland${lib.optionalString enableNvidiaPatches "-nvidia"}";
16 |
17 | patches =
18 | (old.patches or [])
19 | ++ (lib.optionals enableNvidiaPatches [
20 | ./patches/wlroots-nvidia.patch
21 | ]);
22 |
23 | buildInputs = old.buildInputs ++ [hwdata libliftoff libdisplay-info];
24 |
25 | NIX_CFLAGS_COMPILE = toString [
26 | "-Wno-error=maybe-uninitialized"
27 | ];
28 | })
29 |
--------------------------------------------------------------------------------
/props.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.31.0"
3 | }
--------------------------------------------------------------------------------
/protocols/idle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | .
18 | ]]>
19 |
20 |
21 | This interface allows to monitor user idle time on a given seat. The interface
22 | allows to register timers which trigger after no user activity was registered
23 | on the seat for a given interval. It notifies when user activity resumes.
24 |
25 | This is useful for applications wanting to perform actions when the user is not
26 | interacting with the system, e.g. chat applications setting the user as away, power
27 | management features to dim screen, etc..
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/protocols/meson.build:
--------------------------------------------------------------------------------
1 | wayland_protos = dependency('wayland-protocols',
2 | version: '>=1.25',
3 | fallback: 'wayland-protocols',
4 | default_options: ['tests=false'],
5 | )
6 |
7 | hyprland_protos = dependency('hyprland-protocols',
8 | version: '>=0.2',
9 | fallback: 'hyprland-protocols',
10 | )
11 |
12 | wl_protocol_dir = wayland_protos.get_variable('pkgdatadir')
13 | hl_protocol_dir = hyprland_protos.get_variable('pkgdatadir')
14 |
15 | wayland_scanner_dep = dependency('wayland-scanner', native: true)
16 | wayland_scanner = find_program(
17 | wayland_scanner_dep.get_variable('wayland_scanner'),
18 | native: true,
19 | )
20 |
21 | protocols = [
22 | [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'],
23 | [wl_protocol_dir, 'unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml'],
24 | [wl_protocol_dir, 'unstable/text-input/text-input-unstable-v1.xml'],
25 | [wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'],
26 | [wl_protocol_dir, 'staging/fractional-scale/fractional-scale-v1.xml'],
27 | [wl_protocol_dir, 'staging/cursor-shape/cursor-shape-v1.xml'],
28 | [wl_protocol_dir, 'staging/tearing-control/tearing-control-v1.xml'],
29 | ['wlr-foreign-toplevel-management-unstable-v1.xml'],
30 | ['wlr-layer-shell-unstable-v1.xml'],
31 | ['wlr-output-power-management-unstable-v1.xml'],
32 | ['wlr-screencopy-unstable-v1.xml'],
33 | ['pointer-constraints-unstable-v1.xml'],
34 | ['tablet-unstable-v2.xml'],
35 | ['idle.xml'],
36 | [hl_protocol_dir, 'protocols/hyprland-toplevel-export-v1.xml'],
37 | [hl_protocol_dir, 'protocols/hyprland-global-shortcuts-v1.xml']
38 | ]
39 | wl_protos_src = []
40 | wl_protos_headers = []
41 | foreach p : protocols
42 | xml = join_paths(p)
43 | wl_protos_src += custom_target(
44 | xml.underscorify() + '_server_c',
45 | input: xml,
46 | output: '@BASENAME@-protocol.c',
47 | command: [wayland_scanner, 'private-code', '@INPUT@', '@OUTPUT@'],
48 | )
49 | wl_protos_headers += custom_target(
50 | xml.underscorify() + '_server_h',
51 | input: xml,
52 | install: true,
53 | install_dir: join_paths(get_option('includedir'), 'hyprland/protocols'),
54 | output: '@BASENAME@-protocol.h',
55 | command: [wayland_scanner, 'server-header', '@INPUT@', '@OUTPUT@'],
56 | )
57 | endforeach
58 |
59 | wayland_server = dependency('wayland-server', version: '>=1.20.0')
60 |
61 | lib_server_protos = static_library(
62 | 'server_protos',
63 | wl_protos_src + wl_protos_headers,
64 | dependencies: wayland_server.partial_dependency(compile_args: true),
65 | )
66 |
67 | server_protos = declare_dependency(
68 | link_with: lib_server_protos,
69 | sources: wl_protos_headers,
70 | )
71 |
--------------------------------------------------------------------------------
/scripts/generateVersion.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | cp -fr ./src/version.h.in ./src/version.h
3 |
4 | HASH=$(git rev-parse HEAD)
5 | BRANCH=$(git rev-parse --abbrev-ref HEAD)
6 | MESSAGE=$(git show ${GIT_COMMIT_HASH} | head -n 5 | tail -n 1 | sed -e 's/#//g' -e 's/\"//g')
7 | DIRTY=$(git diff-index --quiet HEAD -- || echo dirty)
8 | TAG=$(git describe --tags)
9 |
10 | sed -i -e "s#@HASH@#${HASH}#" ./src/version.h
11 | sed -i -e "s#@BRANCH@#${BRANCH}#" ./src/version.h
12 | sed -i -e "s#@MESSAGE@#${MESSAGE}#" ./src/version.h
13 | sed -i -e "s#@DIRTY@#${DIRTY}#" ./src/version.h
14 | sed -i -e "s#@TAG@#${TAG}#" ./src/version.h
--------------------------------------------------------------------------------
/src/SharedDefs.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "helpers/Vector2D.hpp"
4 |
5 | enum eIcons
6 | {
7 | ICON_WARNING = 0,
8 | ICON_INFO,
9 | ICON_HINT,
10 | ICON_ERROR,
11 | ICON_CONFUSED,
12 | ICON_OK,
13 | ICON_NONE
14 | };
15 |
16 | enum eRenderStage
17 | {
18 | RENDER_PRE = 0, /* Before binding the gl context */
19 | RENDER_BEGIN, /* Just when the rendering begins, nothing has been rendered yet. Damage, current render data in opengl valid. */
20 | RENDER_PRE_WINDOWS, /* Pre windows, post bottom and overlay layers */
21 | RENDER_POST_WINDOWS, /* Post windows, pre top/overlay layers, etc */
22 | RENDER_LAST_MOMENT, /* Last moment to render with the gl context */
23 | RENDER_POST, /* After rendering is finished, gl context not available anymore */
24 | RENDER_POST_MIRROR, /* After rendering a mirror */
25 | RENDER_PRE_WINDOW, /* Before rendering a window (any pass) Note some windows (e.g. tiled) may have 2 passes (main & popup) */
26 | RENDER_POST_WINDOW, /* After rendering a window (any pass) */
27 | };
28 |
29 | struct SCallbackInfo {
30 | bool cancelled = false; /* on cancellable events, will cancel the event. */
31 | };
32 |
33 | struct SWindowDecorationExtents {
34 | Vector2D topLeft;
35 | Vector2D bottomRight;
36 |
37 | //
38 | SWindowDecorationExtents operator*(const double& scale) const {
39 | return SWindowDecorationExtents{topLeft * scale, bottomRight * scale};
40 | }
41 |
42 | SWindowDecorationExtents floor() {
43 | return {topLeft.floor(), bottomRight.floor()};
44 | }
45 | };
--------------------------------------------------------------------------------
/src/config/ConfigDataValues.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "../defines.hpp"
3 | #include
4 |
5 | enum eConfigValueDataTypes {
6 | CVD_TYPE_INVALID = -1,
7 | CVD_TYPE_GRADIENT = 0
8 | };
9 |
10 | class ICustomConfigValueData {
11 | public:
12 | virtual ~ICustomConfigValueData() = 0;
13 |
14 | virtual eConfigValueDataTypes getDataType() = 0;
15 | };
16 |
17 | class CGradientValueData : public ICustomConfigValueData {
18 | public:
19 | CGradientValueData(CColor col) {
20 | m_vColors.push_back(col);
21 | };
22 | virtual ~CGradientValueData(){};
23 |
24 | virtual eConfigValueDataTypes getDataType() {
25 | return CVD_TYPE_GRADIENT;
26 | }
27 |
28 | void reset(CColor col) {
29 | m_vColors.clear();
30 | m_vColors.emplace_back(col);
31 | m_fAngle = 0;
32 | }
33 |
34 | /* Vector containing the colors */
35 | std::vector m_vColors;
36 |
37 | /* Float corresponding to the angle (rad) */
38 | float m_fAngle = 0;
39 |
40 | //
41 | bool operator==(const CGradientValueData& other) const {
42 | if (other.m_vColors.size() != m_vColors.size() || m_fAngle != other.m_fAngle)
43 | return false;
44 |
45 | for (size_t i = 0; i < m_vColors.size(); ++i)
46 | if (m_vColors[i] != other.m_vColors[i])
47 | return false;
48 |
49 | return true;
50 | }
51 | };
52 |
--------------------------------------------------------------------------------
/src/debug/CrashReporter.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../defines.hpp"
4 |
5 | namespace CrashReporter {
6 | void createAndSaveCrash(int sig);
7 | };
--------------------------------------------------------------------------------
/src/debug/HyprCtl.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../Compositor.hpp"
4 | #include
5 | #include "../helpers/MiscFunctions.hpp"
6 |
7 | namespace HyprCtl {
8 | void startHyprCtlSocket();
9 | std::string makeDynamicCall(const std::string& input);
10 |
11 | // very simple thread-safe request method
12 | inline bool requestMade = false;
13 | inline bool requestReady = false;
14 | inline std::string request = "";
15 |
16 | inline std::ifstream requestStream;
17 |
18 | inline wl_event_source* hyprCtlTickSource = nullptr;
19 |
20 | inline int iSocketFD = -1;
21 |
22 | enum eHyprCtlOutputFormat {
23 | FORMAT_NORMAL = 0,
24 | FORMAT_JSON
25 | };
26 | };
--------------------------------------------------------------------------------
/src/debug/HyprDebugOverlay.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../defines.hpp"
4 | #include "../helpers/Monitor.hpp"
5 | #include "../render/Texture.hpp"
6 | #include
7 | #include
8 | #include
9 |
10 | class CHyprRenderer;
11 |
12 | class CHyprMonitorDebugOverlay {
13 | public:
14 | int draw(int offset);
15 |
16 | void renderData(CMonitor* pMonitor, float µs);
17 | void renderDataNoOverlay(CMonitor* pMonitor, float µs);
18 | void frameData(CMonitor* pMonitor);
19 |
20 | private:
21 | std::deque m_dLastFrametimes;
22 | std::deque m_dLastRenderTimes;
23 | std::deque m_dLastRenderTimesNoOverlay;
24 | std::deque m_dLastAnimationTicks;
25 | std::chrono::high_resolution_clock::time_point m_tpLastFrame;
26 | CMonitor* m_pMonitor = nullptr;
27 | CBox m_wbLastDrawnBox;
28 |
29 | friend class CHyprRenderer;
30 | };
31 |
32 | class CHyprDebugOverlay {
33 | public:
34 | void draw();
35 | void renderData(CMonitor*, float µs);
36 | void renderDataNoOverlay(CMonitor*, float µs);
37 | void frameData(CMonitor*);
38 |
39 | private:
40 | std::unordered_map m_mMonitorOverlays;
41 |
42 | cairo_surface_t* m_pCairoSurface = nullptr;
43 | cairo_t* m_pCairo = nullptr;
44 |
45 | CTexture m_tTexture;
46 |
47 | friend class CHyprMonitorDebugOverlay;
48 | friend class CHyprRenderer;
49 | };
50 |
51 | inline std::unique_ptr g_pDebugOverlay;
--------------------------------------------------------------------------------
/src/debug/HyprNotificationOverlay.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../defines.hpp"
4 | #include "../helpers/Timer.hpp"
5 | #include "../helpers/Monitor.hpp"
6 | #include "../render/Texture.hpp"
7 | #include "../SharedDefs.hpp"
8 |
9 | #include
10 |
11 | #include
12 |
13 | enum eIconBackend
14 | {
15 | ICONS_BACKEND_NONE = 0,
16 | ICONS_BACKEND_NF,
17 | ICONS_BACKEND_FA
18 | };
19 |
20 | static const std::array, 3 /* backends */> ICONS_ARRAY = {
21 | std::array{"[!]", "[i]", "[Hint]", "[Err]", "[?]", "[ok]", ""}, std::array{"", "", "", "", "", "", ""},
22 | std::array{"", "", "", "", "", ""}};
23 | static const std::array ICONS_COLORS = {CColor{255.0 / 255.0, 204 / 255.0, 102 / 255.0, 1.0},
24 | CColor{128 / 255.0, 255 / 255.0, 255 / 255.0, 1.0},
25 | CColor{179 / 255.0, 255 / 255.0, 204 / 255.0, 1.0},
26 | CColor{255 / 255.0, 77 / 255.0, 77 / 255.0, 1.0},
27 | CColor{255 / 255.0, 204 / 255.0, 153 / 255.0, 1.0},
28 | CColor{128 / 255.0, 255 / 255.0, 128 / 255.0, 1.0},
29 | CColor{0, 0, 0, 1.0}};
30 |
31 | struct SNotification {
32 | std::string text = "";
33 | CColor color;
34 | CTimer started;
35 | float timeMs = 0;
36 | eIcons icon = ICON_NONE;
37 | };
38 |
39 | class CHyprNotificationOverlay {
40 | public:
41 | CHyprNotificationOverlay();
42 |
43 | void draw(CMonitor* pMonitor);
44 | void addNotification(const std::string& text, const CColor& color, const float timeMs, const eIcons icon = ICON_NONE);
45 |
46 | private:
47 | CBox drawNotifications(CMonitor* pMonitor);
48 | CBox m_bLastDamage;
49 |
50 | std::deque> m_dNotifications;
51 |
52 | cairo_surface_t* m_pCairoSurface = nullptr;
53 | cairo_t* m_pCairo = nullptr;
54 |
55 | CMonitor* m_pLastMonitor = nullptr;
56 |
57 | CTexture m_tTexture;
58 |
59 | eIconBackend m_eIconBackend = ICONS_BACKEND_NONE;
60 | std::string m_szIconFontName = "Sans";
61 | };
62 |
63 | inline std::unique_ptr g_pHyprNotificationOverlay;
--------------------------------------------------------------------------------
/src/debug/Log.cpp:
--------------------------------------------------------------------------------
1 | #include "Log.hpp"
2 | #include "../defines.hpp"
3 | #include "../Compositor.hpp"
4 |
5 | #include
6 | #include
7 |
8 | void Debug::init(const std::string& IS) {
9 | logFile = "/tmp/hypr/" + IS + (ISDEBUG ? "/hyprlandd.log" : "/hyprland.log");
10 | }
11 |
12 | void Debug::wlrLog(wlr_log_importance level, const char* fmt, va_list args) {
13 | if (disableLogs && *disableLogs)
14 | return;
15 |
16 | if (level > wlr_log_get_verbosity())
17 | return;
18 |
19 | char* outputStr = nullptr;
20 |
21 | std::ofstream ofs;
22 | ofs.open(logFile, std::ios::out | std::ios::app);
23 |
24 | vasprintf(&outputStr, fmt, args);
25 |
26 | std::string output = std::string(outputStr);
27 | free(outputStr);
28 |
29 | ofs << "[wlr] " << output << "\n";
30 |
31 | ofs.close();
32 |
33 | if (!disableStdout)
34 | std::cout << output << "\n";
35 | }
36 |
--------------------------------------------------------------------------------
/src/debug/Log.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include "../includes.hpp"
8 | #include "../helpers/MiscFunctions.hpp"
9 |
10 | #define LOGMESSAGESIZE 1024
11 |
12 | enum LogLevel {
13 | NONE = -1,
14 | LOG = 0,
15 | WARN,
16 | ERR,
17 | CRIT,
18 | INFO,
19 | TRACE
20 | };
21 |
22 | namespace Debug {
23 | inline std::string logFile;
24 | inline int64_t* disableLogs = nullptr;
25 | inline int64_t* disableTime = nullptr;
26 | inline bool disableStdout = false;
27 | inline bool trace = false;
28 |
29 | void init(const std::string& IS);
30 | template
31 | void log(LogLevel level, std::format_string fmt, Args&&... args) {
32 | if (disableLogs && *disableLogs)
33 | return;
34 |
35 | if (level == TRACE && !trace)
36 | return;
37 |
38 | std::string logMsg = "";
39 |
40 | switch (level) {
41 | case LOG: logMsg += "[LOG] "; break;
42 | case WARN: logMsg += "[WARN] "; break;
43 | case ERR: logMsg += "[ERR] "; break;
44 | case CRIT: logMsg += "[CRITICAL] "; break;
45 | case INFO: logMsg += "[INFO] "; break;
46 | case TRACE: logMsg += "[TRACE] "; break;
47 | default: break;
48 | }
49 |
50 | // log to a file
51 | std::ofstream ofs;
52 | ofs.open(logFile, std::ios::out | std::ios::app);
53 |
54 | // print date and time to the ofs
55 | if (disableTime && !*disableTime) {
56 | #ifndef _LIBCPP_VERSION
57 | logMsg += std::format("[{:%T}] ", std::chrono::hh_mm_ss{std::chrono::system_clock::now() - std::chrono::floor(std::chrono::system_clock::now())});
58 | #else
59 | auto c = std::chrono::hh_mm_ss{std::chrono::system_clock::now() - std::chrono::floor(std::chrono::system_clock::now())};
60 | logMsg += std::format("{:%H}:{:%M}:{:%S}", c.hours(), c.minutes(), c.subseconds());
61 |
62 | #endif
63 | }
64 |
65 | // no need for try {} catch {} because std::format_string ensures that vformat never throw std::format_error
66 | // because
67 | // 1. any faulty format specifier that sucks will cause a compilation error.
68 | // 2. and `std::bad_alloc` is catastrophic, (Almost any operation in stdlib could throw this.)
69 | // 3. this is actually what std::format in stdlib does
70 | logMsg += std::vformat(fmt.get(), std::make_format_args(args...));
71 |
72 | ofs << logMsg << "\n";
73 |
74 | ofs.close();
75 |
76 | // log it to the stdout too.
77 | if (!disableStdout)
78 | std::cout << logMsg << "\n";
79 | }
80 |
81 | void wlrLog(wlr_log_importance level, const char* fmt, va_list args);
82 | };
83 |
--------------------------------------------------------------------------------
/src/debug/TracyDefines.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #ifdef USE_TRACY_GPU
4 |
5 | #include "Log.hpp"
6 |
7 | #include
8 | #include
9 |
10 | inline PFNGLQUERYCOUNTEREXTPROC glQueryCounter;
11 | inline PFNGLGETQUERYOBJECTIVEXTPROC glGetQueryObjectiv;
12 | inline PFNGLGETQUERYOBJECTUI64VEXTPROC glGetQueryObjectui64v;
13 |
14 | #include "../../subprojects/tracy/public/tracy/TracyOpenGL.hpp"
15 |
16 | inline void loadGLProc(void* pProc, const char* name) {
17 | void* proc = (void*)eglGetProcAddress(name);
18 | if (proc == NULL) {
19 | Debug::log(CRIT, "[Tracy GPU Profiling] eglGetProcAddress({}) failed", name);
20 | abort();
21 | }
22 | *(void**)pProc = proc;
23 | }
24 |
25 | #define TRACY_GPU_CONTEXT TracyGpuContext
26 | #define TRACY_GPU_ZONE(e) TracyGpuZone(e)
27 | #define TRACY_GPU_COLLECT TracyGpuCollect
28 |
29 | #else
30 |
31 | #define TRACY_GPU_CONTEXT
32 | #define TRACY_GPU_ZONE(e)
33 | #define TRACY_GPU_COLLECT
34 |
35 | #endif
--------------------------------------------------------------------------------
/src/defines.hpp:
--------------------------------------------------------------------------------
1 | #include "includes.hpp"
2 | #include "debug/Log.hpp"
3 | #include "helpers/WLListener.hpp"
4 | #include "helpers/Color.hpp"
5 | #include "macros.hpp"
6 |
--------------------------------------------------------------------------------
/src/helpers/AnimatedVariable.cpp:
--------------------------------------------------------------------------------
1 | #include "AnimatedVariable.hpp"
2 | #include "../managers/AnimationManager.hpp"
3 | #include "../config/ConfigManager.hpp"
4 |
5 | CAnimatedVariable::CAnimatedVariable() {
6 | ; // dummy var
7 | }
8 |
9 | void CAnimatedVariable::create(ANIMATEDVARTYPE type, SAnimationPropertyConfig* pAnimConfig, void* pWindow, AVARDAMAGEPOLICY policy) {
10 | m_eVarType = type;
11 | m_eDamagePolicy = policy;
12 | m_pConfig = pAnimConfig;
13 | m_pWindow = pWindow;
14 |
15 | m_bDummy = false;
16 | }
17 |
18 | void CAnimatedVariable::create(ANIMATEDVARTYPE type, std::any val, SAnimationPropertyConfig* pAnimConfig, void* pWindow, AVARDAMAGEPOLICY policy) {
19 | create(type, pAnimConfig, pWindow, policy);
20 |
21 | try {
22 | switch (type) {
23 | case AVARTYPE_FLOAT: {
24 | const auto V = std::any_cast(val);
25 | m_fValue = V;
26 | m_fGoal = V;
27 | break;
28 | }
29 | case AVARTYPE_VECTOR: {
30 | const auto V = std::any_cast(val);
31 | m_vValue = V;
32 | m_vGoal = V;
33 | break;
34 | }
35 | case AVARTYPE_COLOR: {
36 | const auto V = std::any_cast(val);
37 | m_cValue = V;
38 | m_cGoal = V;
39 | break;
40 | }
41 | default: ASSERT(false); break;
42 | }
43 | } catch (std::exception& e) {
44 | Debug::log(ERR, "CAnimatedVariable create error: {}", e.what());
45 | RASSERT(false, "CAnimatedVariable create error: {}", e.what());
46 | }
47 | }
48 |
49 | CAnimatedVariable::~CAnimatedVariable() {
50 | unregister();
51 | }
52 |
53 | void CAnimatedVariable::unregister() {
54 | if (!g_pAnimationManager)
55 | return;
56 | std::erase_if(g_pAnimationManager->m_vAnimatedVariables, [&](const auto& other) { return other == this; });
57 | m_bIsRegistered = false;
58 | disconnectFromActive();
59 | }
60 |
61 | void CAnimatedVariable::registerVar() {
62 | if (!m_bIsRegistered)
63 | g_pAnimationManager->m_vAnimatedVariables.push_back(this);
64 | m_bIsRegistered = true;
65 | }
66 |
67 | int CAnimatedVariable::getDurationLeftMs() {
68 | return std::max(
69 | (int)(m_pConfig->pValues->internalSpeed * 100) - (int)std::chrono::duration_cast(std::chrono::system_clock::now() - animationBegin).count(), 0);
70 | }
71 |
72 | float CAnimatedVariable::getPercent() {
73 | const auto DURATIONPASSED = std::chrono::duration_cast(std::chrono::system_clock::now() - animationBegin).count();
74 | return std::clamp((DURATIONPASSED / 100.f) / m_pConfig->pValues->internalSpeed, 0.f, 1.f);
75 | }
76 |
77 | float CAnimatedVariable::getCurveValue() {
78 | const auto SPENT = getPercent();
79 |
80 | if (SPENT >= 1.f)
81 | return 1.f;
82 |
83 | return g_pAnimationManager->getBezier(m_pConfig->pValues->internalBezier)->getYForPoint(SPENT);
84 | }
85 |
86 | void CAnimatedVariable::connectToActive() {
87 | g_pAnimationManager->scheduleTick(); // otherwise the animation manager will never pick this up
88 |
89 | if (!m_bIsConnectedToActive)
90 | g_pAnimationManager->m_vActiveAnimatedVariables.push_back(this);
91 |
92 | m_bIsConnectedToActive = true;
93 | }
94 |
95 | void CAnimatedVariable::disconnectFromActive() {
96 | std::erase_if(g_pAnimationManager->m_vActiveAnimatedVariables, [&](const auto& other) { return other == this; });
97 | m_bIsConnectedToActive = false;
98 | }
--------------------------------------------------------------------------------
/src/helpers/BezierCurve.cpp:
--------------------------------------------------------------------------------
1 | #include "BezierCurve.hpp"
2 | #include "../debug/Log.hpp"
3 | #include "../macros.hpp"
4 |
5 | #include
6 | #include
7 |
8 | void CBezierCurve::setup(std::vector* pVec) {
9 | m_dPoints.clear();
10 |
11 | const auto BEGIN = std::chrono::high_resolution_clock::now();
12 |
13 | m_dPoints.emplace_back(Vector2D(0, 0));
14 |
15 | for (auto& p : *pVec) {
16 | m_dPoints.push_back(p);
17 | }
18 |
19 | m_dPoints.emplace_back(Vector2D(1, 1));
20 |
21 | RASSERT(m_dPoints.size() == 4, "CBezierCurve only supports cubic beziers! (points num: {})", m_dPoints.size());
22 |
23 | // bake BAKEDPOINTS points for faster lookups
24 | // T -> X ( / BAKEDPOINTS )
25 | for (int i = 0; i < BAKEDPOINTS; ++i) {
26 | m_aPointsBaked[i] = Vector2D(getXForT((i + 1) / (float)BAKEDPOINTS), getYForT((i + 1) / (float)BAKEDPOINTS));
27 | }
28 |
29 | const auto ELAPSEDUS = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - BEGIN).count() / 1000.f;
30 | const auto POINTSSIZE = m_aPointsBaked.size() * sizeof(m_aPointsBaked[0]) / 1000.f;
31 |
32 | const auto BEGINCALC = std::chrono::high_resolution_clock::now();
33 | for (float i = 0.1f; i < 1.f; i += 0.1f)
34 | getYForPoint(i);
35 | const auto ELAPSEDCALCAVG = std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - BEGINCALC).count() / 1000.f / 10.f;
36 |
37 | Debug::log(LOG, "Created a bezier curve, baked {} points, mem usage: {:.2f}kB, time to bake: {:.2f}µs. Estimated average calc time: {:.2f}µs.", BAKEDPOINTS, POINTSSIZE,
38 | ELAPSEDUS, ELAPSEDCALCAVG);
39 | }
40 |
41 | float CBezierCurve::getYForT(float t) {
42 | return 3 * t * pow(1 - t, 2) * m_dPoints[1].y + 3 * pow(t, 2) * (1 - t) * m_dPoints[2].y + pow(t, 3);
43 | }
44 |
45 | float CBezierCurve::getXForT(float t) {
46 | return 3 * t * pow(1 - t, 2) * m_dPoints[1].x + 3 * pow(t, 2) * (1 - t) * m_dPoints[2].x + pow(t, 3);
47 | }
48 |
49 | // Todo: this probably can be done better and faster
50 | float CBezierCurve::getYForPoint(float x) {
51 | if (x >= 1.f)
52 | return 1.f;
53 |
54 | int index = 0;
55 | bool below = true;
56 | for (int step = (BAKEDPOINTS + 1) / 2; step > 0; step /= 2) {
57 | if (below)
58 | index += step;
59 | else
60 | index -= step;
61 |
62 | below = m_aPointsBaked[index].x < x;
63 | }
64 |
65 | int lowerIndex = index - (!below || index == BAKEDPOINTS - 1);
66 |
67 | // in the name of performance i shall make a hack
68 | const auto LOWERPOINT = &m_aPointsBaked[lowerIndex];
69 | const auto UPPERPOINT = &m_aPointsBaked[lowerIndex + 1];
70 |
71 | const auto PERCINDELTA = (x - LOWERPOINT->x) / (UPPERPOINT->x - LOWERPOINT->x);
72 |
73 | if (std::isnan(PERCINDELTA) || std::isinf(PERCINDELTA)) // can sometimes happen for VERY small x
74 | return 0.f;
75 |
76 | return LOWERPOINT->y + (UPPERPOINT->y - LOWERPOINT->y) * PERCINDELTA;
77 | }
78 |
--------------------------------------------------------------------------------
/src/helpers/BezierCurve.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 | #include "Vector2D.hpp"
7 |
8 | constexpr int BAKEDPOINTS = 255;
9 | constexpr float INVBAKEDPOINTS = 1.f / BAKEDPOINTS;
10 |
11 | // an implementation of a cubic bezier curve
12 | // might do better later
13 | class CBezierCurve {
14 | public:
15 | // sets up the bezier curve.
16 | // this EXCLUDES the 0,0 and 1,1 points,
17 | void setup(std::vector* points);
18 |
19 | float getYForT(float t);
20 | float getXForT(float t);
21 | float getYForPoint(float x);
22 |
23 | private:
24 | // this INCLUDES the 0,0 and 1,1 points.
25 | std::deque m_dPoints;
26 |
27 | std::array m_aPointsBaked;
28 | };
29 |
--------------------------------------------------------------------------------
/src/helpers/Box.cpp:
--------------------------------------------------------------------------------
1 | #include "Box.hpp"
2 | wlr_box CBox::wlr() {
3 | CBox rounded = roundInternal();
4 | m_bWlrBox = wlr_box{(int)rounded.x, (int)rounded.y, (int)rounded.w, (int)rounded.h};
5 | return m_bWlrBox;
6 | }
7 |
8 | wlr_box* CBox::pWlr() {
9 | CBox rounded = roundInternal();
10 | m_bWlrBox = wlr_box{(int)rounded.x, (int)rounded.y, (int)rounded.w, (int)rounded.h};
11 | return &m_bWlrBox;
12 | }
13 |
14 | CBox& CBox::scale(double scale) {
15 | x *= scale;
16 | y *= scale;
17 | w *= scale;
18 | h *= scale;
19 |
20 | return *this;
21 | }
22 |
23 | CBox& CBox::scale(const Vector2D& scale) {
24 | x *= scale.x;
25 | y *= scale.y;
26 | w *= scale.x;
27 | h *= scale.y;
28 |
29 | return *this;
30 | }
31 |
32 | CBox& CBox::translate(const Vector2D& vec) {
33 | x += vec.x;
34 | y += vec.y;
35 |
36 | return *this;
37 | }
38 |
39 | Vector2D CBox::middle() const {
40 | return Vector2D{x + w / 2.0, y + h / 2.0};
41 | }
42 |
43 | bool CBox::containsPoint(const Vector2D& vec) const {
44 | return VECINRECT(vec, x, y, x + w, y + h);
45 | }
46 |
47 | bool CBox::empty() const {
48 | return w == 0 || h == 0;
49 | }
50 |
51 | CBox& CBox::applyFromWlr() {
52 | x = m_bWlrBox.x;
53 | y = m_bWlrBox.y;
54 | w = m_bWlrBox.width;
55 | h = m_bWlrBox.height;
56 |
57 | return *this;
58 | }
59 |
60 | CBox& CBox::round() {
61 | float newW = x + w - std::round(x);
62 | float newH = y + h - std::round(y);
63 | x = std::round(x);
64 | y = std::round(y);
65 | w = std::round(newW);
66 | h = std::round(newH);
67 |
68 | return *this;
69 | }
70 |
71 | CBox& CBox::transform(const wl_output_transform t, double w, double h) {
72 | wlr_box_transform(&m_bWlrBox, pWlr(), t, w, h);
73 | applyFromWlr();
74 |
75 | return *this;
76 | }
77 |
78 | CBox& CBox::addExtents(const SWindowDecorationExtents& e) {
79 | x -= e.topLeft.x;
80 | y -= e.topLeft.y;
81 | w += e.topLeft.x + e.bottomRight.x;
82 | h += e.topLeft.y + e.bottomRight.y;
83 |
84 | return *this;
85 | }
86 |
87 | CBox& CBox::scaleFromCenter(double scale) {
88 | double oldW = w, oldH = h;
89 |
90 | w *= scale;
91 | h *= scale;
92 |
93 | x -= (w - oldW) / 2.0;
94 | y -= (h - oldH) / 2.0;
95 |
96 | return *this;
97 | }
98 |
99 | CBox CBox::roundInternal() {
100 | float newW = x + w - std::floor(x);
101 | float newH = y + h - std::floor(y);
102 |
103 | return CBox{std::floor(x), std::floor(y), std::floor(newW), std::floor(newH)};
104 | }
105 |
106 | Vector2D CBox::pos() const {
107 | return {x, y};
108 | }
109 |
110 | Vector2D CBox::size() const {
111 | return {w, h};
112 | }
113 |
--------------------------------------------------------------------------------
/src/helpers/Box.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "Vector2D.hpp"
4 | #include "../SharedDefs.hpp"
5 | #include "../includes.hpp"
6 |
7 | class CBox {
8 | public:
9 | CBox(double x_, double y_, double w_, double h_) {
10 | x = x_;
11 | y = y_;
12 | w = w_;
13 | h = h_;
14 | }
15 |
16 | CBox() {
17 | w = 0;
18 | h = 0;
19 | }
20 |
21 | CBox(const wlr_box& box) {
22 | x = box.x;
23 | y = box.y;
24 | w = box.width;
25 | h = box.height;
26 | }
27 |
28 | CBox(const double d) {
29 | x = d;
30 | y = d;
31 | w = d;
32 | h = d;
33 | }
34 |
35 | CBox(const Vector2D& pos, const Vector2D& size) {
36 | x = pos.x;
37 | y = pos.y;
38 | w = size.x;
39 | h = size.y;
40 | }
41 |
42 | wlr_box wlr();
43 | wlr_box* pWlr();
44 |
45 | CBox& applyFromWlr();
46 | CBox& scale(double scale);
47 | CBox& scaleFromCenter(double scale);
48 | CBox& scale(const Vector2D& scale);
49 | CBox& translate(const Vector2D& vec);
50 | CBox& round();
51 | CBox& transform(const wl_output_transform t, double w, double h);
52 | CBox& addExtents(const SWindowDecorationExtents& e);
53 |
54 | Vector2D middle() const;
55 | Vector2D pos() const;
56 | Vector2D size() const;
57 |
58 | bool containsPoint(const Vector2D& vec) const;
59 | bool empty() const;
60 |
61 | double x = 0, y = 0;
62 | union {
63 | double w;
64 | double width;
65 | };
66 | union {
67 | double h;
68 | double height;
69 | };
70 |
71 | //
72 | bool operator==(const CBox& rhs) const {
73 | return x == rhs.x && y == rhs.y && w == rhs.w && h == rhs.h;
74 | }
75 |
76 | private:
77 | CBox roundInternal();
78 |
79 | wlr_box m_bWlrBox;
80 | };
81 |
--------------------------------------------------------------------------------
/src/helpers/Color.cpp:
--------------------------------------------------------------------------------
1 | #include "Color.hpp"
2 |
3 | #define ALPHA(c) ((double)(((c) >> 24) & 0xff) / 255.0)
4 | #define RED(c) ((double)(((c) >> 16) & 0xff) / 255.0)
5 | #define GREEN(c) ((double)(((c) >> 8) & 0xff) / 255.0)
6 | #define BLUE(c) ((double)(((c)) & 0xff) / 255.0)
7 |
8 | CColor::CColor() {}
9 |
10 | CColor::CColor(float r, float g, float b, float a) {
11 | this->r = r;
12 | this->g = g;
13 | this->b = b;
14 | this->a = a;
15 | }
16 |
17 | CColor::CColor(uint64_t hex) {
18 | this->r = RED(hex);
19 | this->g = GREEN(hex);
20 | this->b = BLUE(hex);
21 | this->a = ALPHA(hex);
22 | }
23 |
24 | uint64_t CColor::getAsHex() {
25 | return ((int)a) * 0x1000000 + ((int)r) * 0x10000 + ((int)g) * 0x100 + ((int)b) * 0x1;
26 | }
--------------------------------------------------------------------------------
/src/helpers/Color.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | class CColor {
6 | public:
7 | CColor();
8 | CColor(float, float, float, float);
9 | CColor(uint64_t);
10 |
11 | float r = 0, g = 0, b = 0, a = 1.f;
12 |
13 | uint64_t getAsHex();
14 |
15 | CColor operator-(const CColor& c2) const {
16 | return CColor(r - c2.r, g - c2.g, b - c2.b, a - c2.a);
17 | }
18 |
19 | CColor operator+(const CColor& c2) const {
20 | return CColor(r + c2.r, g + c2.g, b + c2.b, a + c2.a);
21 | }
22 |
23 | CColor operator*(const float& v) const {
24 | return CColor(r * v, g * v, b * v, a * v);
25 | }
26 |
27 | bool operator==(const CColor& c2) const {
28 | return r == c2.r && g == c2.g && b == c2.b && a == c2.a;
29 | }
30 | };
31 |
--------------------------------------------------------------------------------
/src/helpers/MiscFunctions.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include "Vector2D.hpp"
8 | #include
9 | #include
10 |
11 | struct SCallstackFrameInfo {
12 | void* adr = nullptr;
13 | std::string desc;
14 | };
15 |
16 | std::string absolutePath(const std::string&, const std::string&);
17 | void addWLSignal(wl_signal*, wl_listener*, void* pOwner, const std::string& ownerString);
18 | std::string escapeJSONStrings(const std::string& str);
19 | std::string removeBeginEndSpacesTabs(std::string);
20 | bool isNumber(const std::string&, bool allowfloat = false);
21 | bool isDirection(const std::string&);
22 | bool isDirection(const char&);
23 | int getWorkspaceIDFromString(const std::string&, std::string&);
24 | std::optional cleanCmdForWorkspace(const std::string&, std::string);
25 | float vecToRectDistanceSquared(const Vector2D& vec, const Vector2D& p1, const Vector2D& p2);
26 | void logSystemInfo();
27 | std::string execAndGet(const char*);
28 | int64_t getPPIDof(int64_t pid);
29 | int64_t configStringToInt(const std::string&);
30 | float getPlusMinusKeywordResult(std::string in, float relative);
31 | void matrixProjection(float mat[9], int w, int h, wl_output_transform tr);
32 | double normalizeAngleRad(double ang);
33 | std::string replaceInString(std::string subject, const std::string& search, const std::string& replace);
34 | std::vector getBacktrace();
35 | void throwError(const std::string& err);
36 | uint32_t drmFormatToGL(uint32_t drm);
37 |
38 | template
39 | [[deprecated("use std::format instead")]] std::string getFormat(std::format_string fmt, Args&&... args) {
40 | // no need for try {} catch {} because std::format_string ensures that vformat never throw std::format_error
41 | // because any suck format specifier will cause a compilation error
42 | // this is actually what std::format in stdlib does
43 | return std::vformat(fmt.get(), std::make_format_args(args...));
44 | }
--------------------------------------------------------------------------------
/src/helpers/Region.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include
4 | #include "Vector2D.hpp"
5 | #include "Box.hpp"
6 |
7 | struct wlr_box;
8 |
9 | class CRegion {
10 | public:
11 | /* Create an empty region */
12 | CRegion();
13 | /* Create from a reference. Copies, does not own. */
14 | CRegion(pixman_region32_t* ref);
15 | /* Create from a box */
16 | CRegion(double x, double y, double w, double h);
17 | /* Create from a wlr_box */
18 | CRegion(wlr_box* box);
19 | /* Create from a CBox */
20 | CRegion(CBox* box);
21 | /* Create from a pixman_box32_t */
22 | CRegion(pixman_box32_t* box);
23 |
24 | CRegion(const CRegion&);
25 | CRegion(CRegion&&);
26 |
27 | ~CRegion();
28 |
29 | CRegion& operator=(CRegion&& other) {
30 | pixman_region32_copy(&m_rRegion, other.pixman());
31 | return *this;
32 | }
33 |
34 | CRegion& operator=(CRegion& other) {
35 | pixman_region32_copy(&m_rRegion, other.pixman());
36 | return *this;
37 | }
38 |
39 | CRegion& clear();
40 | CRegion& set(const CRegion& other);
41 | CRegion& add(const CRegion& other);
42 | CRegion& add(double x, double y, double w, double h);
43 | CRegion& subtract(const CRegion& other);
44 | CRegion& intersect(const CRegion& other);
45 | CRegion& intersect(double x, double y, double w, double h);
46 | CRegion& translate(const Vector2D& vec);
47 | CRegion& invert(pixman_box32_t* box);
48 | CRegion& scale(float scale);
49 | CBox getExtents();
50 | bool containsPoint(const Vector2D& vec) const;
51 | bool empty() const;
52 | Vector2D closestPoint(const Vector2D& vec) const;
53 |
54 | std::vector getRects() const;
55 |
56 | pixman_region32_t* pixman() {
57 | return &m_rRegion;
58 | }
59 |
60 | private:
61 | pixman_region32_t m_rRegion;
62 | };
63 |
--------------------------------------------------------------------------------
/src/helpers/Splashes.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 |
6 | inline const std::vector SPLASHES = {
7 | // clang-format off
8 | "Woo, animations!",
9 | "It's like Hypr, but better.",
10 | "Release 1.0 when?",
11 | "It's not awesome, it's Hyprland!",
12 | "\"I commit too often, people can't catch up lmao\" - Vaxry",
13 | "This text is random.",
14 | "\"There are reasons to not use rust.\" - Boga",
15 | "Read the wiki.",
16 | "\"Hello everyone this is YOUR daily dose of ‘read the wiki’\" - Vaxry",
17 | "h",
18 | "\"‘why no work’, bro I haven't hacked your pc to get live feeds yet\" - Vaxry",
19 | "Compile, wait for 20 minutes, notice a new commit, compile again.",
20 | "To rice, or not to rice, that is the question.",
21 | "Now available on Fedora!",
22 | // music reference / quote section
23 | "J'remue le ciel, le jour, la nuit.",
24 | "aezakmi, aezakmi, aezakmi, aezakmi, aezakmi, aezakmi, aezakmi!",
25 | "Wir sind schon sehr lang zusammen...",
26 | "I see a red door and I want it painted black.",
27 | "Take on me, take me on...",
28 | "You spin me right round baby right round",
29 | "Stayin' alive, stayin' alive",
30 | "Say no way, say no way ya, no way!",
31 | "Ground control to Major Tom...",
32 | "Alors on danse",
33 | "And all that I can see, is just a yellow lemon tree.",
34 | "Got a one-way ticket to the blues",
35 | "Is this the real life, is this just fantasy",
36 | "What's in your head, in your head?",
37 | "We're all living in America, America, America.",
38 | "I'm still standing, better than I ever did",
39 | "Here comes the sun, bringing you love and shining on everyone",
40 | "Two trailer park girls go round the outside",
41 | "With the lights out, it's less dangerous",
42 | "Here we go back, this is the moment, tonight is the night",
43 | "Now you're just somebody that I used to know...",
44 | "Black bird, black moon, black sky",
45 | "Some legends are told, some turn to dust or to gold",
46 | "Your brain gets smart, but your head gets dumb.",
47 | "Save your mercy for someone who needs it more",
48 | "You're gonna hear my voice when I shout it out loud",
49 | "Ding ding pch n daa, bam-ba-ba-re-bam baram bom bom baba-bam-bam-bommm",
50 | "Súbeme la radio que esta es mi canción",
51 | "I'm beggin', beggin' you",
52 | "Never gonna let you down (I am trying!)",
53 | "\"I use Arch, btw\" - John Cena",
54 | "\"Hyper\".replace(\"e\", \"\")",
55 | "\"my win11 install runs hyprland that is true\" - raf",
56 | "\"stop playing league loser\" - hyprBot",
57 | "\"If it ain't broke, don't fix it\" - Lucascito_03",
58 | "\"@vaxry how do i learn c++\" - flicko",
59 | //
60 | "Join the discord server!",
61 | "Thanks ThatOneCalculator!",
62 | "The AUR packages always work, except for the times they don't.",
63 | "Funny animation compositor woo"
64 | // clang-format on
65 | };
--------------------------------------------------------------------------------
/src/helpers/SubsurfaceTree.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../defines.hpp"
4 | #include
5 | #include "WLSurface.hpp"
6 |
7 | struct SSubsurface;
8 | class CWindow;
9 |
10 | typedef void (*applyGlobalOffsetFn)(void*, int*, int*);
11 |
12 | struct SSurfaceTreeNode {
13 | CWLSurface* pSurface = nullptr; // actual surface
14 | CWLSurface pInternalSurface; // not present for head nodes to not dupe wlr_surface ownership
15 |
16 | DYNLISTENER(newSubsurface);
17 | DYNLISTENER(commit);
18 | DYNLISTENER(destroy);
19 |
20 | SSurfaceTreeNode* pParent = nullptr;
21 | SSubsurface* pSubsurface = nullptr;
22 |
23 | std::list childSubsurfaces;
24 |
25 | applyGlobalOffsetFn offsetfn;
26 | void* globalOffsetData;
27 | CWindow* pWindowOwner = nullptr;
28 |
29 | //
30 | bool operator==(const SSurfaceTreeNode& rhs) const {
31 | return pSurface == rhs.pSurface;
32 | }
33 | };
34 |
35 | struct SSubsurface {
36 | wlr_subsurface* pSubsurface = nullptr;
37 |
38 | SSurfaceTreeNode* pParent = nullptr;
39 | SSurfaceTreeNode* pChild = nullptr;
40 |
41 | DYNLISTENER(map);
42 | DYNLISTENER(unmap);
43 | DYNLISTENER(destroy);
44 |
45 | CWindow* pWindowOwner = nullptr;
46 |
47 | //
48 | bool operator==(const SSubsurface& rhs) const {
49 | return pSubsurface == rhs.pSubsurface;
50 | }
51 | };
52 |
53 | namespace SubsurfaceTree {
54 | SSurfaceTreeNode* createTreeRoot(wlr_surface*, applyGlobalOffsetFn, void*, CWindow* pWindow = nullptr);
55 | void destroySurfaceTree(SSurfaceTreeNode*);
56 |
57 | inline std::list surfaceTreeNodes;
58 | };
59 |
--------------------------------------------------------------------------------
/src/helpers/Timer.cpp:
--------------------------------------------------------------------------------
1 | #include "Timer.hpp"
2 |
3 | void CTimer::reset() {
4 | m_tpLastReset = std::chrono::system_clock::now();
5 | }
6 |
7 | std::chrono::system_clock::duration CTimer::getDuration() {
8 | return std::chrono::system_clock::now() - m_tpLastReset;
9 | }
10 |
11 | int CTimer::getMillis() {
12 | return std::chrono::duration_cast(getDuration()).count();
13 | }
14 |
15 | float CTimer::getSeconds() {
16 | return std::chrono::duration_cast(getDuration()).count() / 1000.f;
17 | }
18 |
19 | const std::chrono::system_clock::time_point& CTimer::chrono() const {
20 | return m_tpLastReset;
21 | }
--------------------------------------------------------------------------------
/src/helpers/Timer.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 |
5 | class CTimer {
6 | public:
7 | void reset();
8 | float getSeconds();
9 | int getMillis();
10 | const std::chrono::system_clock::time_point& chrono() const;
11 |
12 | private:
13 | std::chrono::system_clock::time_point m_tpLastReset;
14 |
15 | std::chrono::system_clock::duration getDuration();
16 | };
--------------------------------------------------------------------------------
/src/helpers/VarList.cpp:
--------------------------------------------------------------------------------
1 | #include "MiscFunctions.hpp"
2 | #include "VarList.hpp"
3 | #include
4 | #include
5 |
6 | CVarList::CVarList(const std::string& in, const size_t lastArgNo, const char delim, const bool removeEmpty) {
7 | if (in.empty())
8 | m_vArgs.emplace_back("");
9 |
10 | std::string args{in};
11 | size_t idx = 0;
12 | size_t pos = 0;
13 | std::ranges::replace_if(
14 | args, [&](const char& c) { return delim == 's' ? std::isspace(c) : c == delim; }, 0);
15 |
16 | for (const auto& s : args | std::views::split(0)) {
17 | if (removeEmpty && s.empty())
18 | continue;
19 | if (++idx == lastArgNo) {
20 | m_vArgs.emplace_back(removeBeginEndSpacesTabs(in.substr(pos)));
21 | break;
22 | }
23 | pos += s.size() + 1;
24 | m_vArgs.emplace_back(removeBeginEndSpacesTabs(std::string_view{s}.data()));
25 | }
26 | }
27 |
28 | std::string CVarList::join(const std::string& joiner, size_t from, size_t to) const {
29 | size_t last = to == 0 ? size() : to;
30 |
31 | std::string rolling;
32 | for (size_t i = from; i < last; ++i) {
33 | rolling += m_vArgs[i] + (i + 1 < last ? joiner : "");
34 | }
35 |
36 | return rolling;
37 | }
--------------------------------------------------------------------------------
/src/helpers/VarList.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include
4 | #include
5 | #include "../macros.hpp"
6 |
7 | class CVarList {
8 | public:
9 | /** Split string into arg list
10 | @param lastArgNo stop splitting after argv reaches maximum size, last arg will contain rest of unsplit args
11 | @param delim if delimiter is 's', use std::isspace
12 | @param removeEmpty remove empty args from argv
13 | */
14 | CVarList(const std::string& in, const size_t maxSize = 0, const char delim = ',', const bool removeEmpty = false);
15 |
16 | ~CVarList() = default;
17 |
18 | size_t size() const {
19 | return m_vArgs.size();
20 | }
21 |
22 | std::string join(const std::string& joiner, size_t from = 0, size_t to = 0) const;
23 |
24 | void map(std::function func) {
25 | for (auto& s : m_vArgs)
26 | func(s);
27 | }
28 |
29 | void append(const std::string arg) {
30 | m_vArgs.emplace_back(arg);
31 | }
32 |
33 | std::string operator[](const size_t& idx) const {
34 | if (idx >= m_vArgs.size())
35 | return "";
36 | return m_vArgs[idx];
37 | }
38 |
39 | // for range-based loops
40 | std::vector::iterator begin() {
41 | return m_vArgs.begin();
42 | }
43 | std::vector::const_iterator begin() const {
44 | return m_vArgs.begin();
45 | }
46 | std::vector::iterator end() {
47 | return m_vArgs.end();
48 | }
49 | std::vector::const_iterator end() const {
50 | return m_vArgs.end();
51 | }
52 |
53 | private:
54 | std::vector m_vArgs;
55 | };
--------------------------------------------------------------------------------
/src/helpers/Vector2D.cpp:
--------------------------------------------------------------------------------
1 | #include "Vector2D.hpp"
2 | #include
3 | #include
4 |
5 | Vector2D::Vector2D(double xx, double yy) {
6 | x = xx;
7 | y = yy;
8 | }
9 |
10 | Vector2D::Vector2D() {
11 | x = 0;
12 | y = 0;
13 | }
14 |
15 | Vector2D::~Vector2D() {}
16 |
17 | double Vector2D::normalize() {
18 | // get max abs
19 | const auto max = std::abs(x) > std::abs(y) ? std::abs(x) : std::abs(y);
20 |
21 | x /= max;
22 | y /= max;
23 |
24 | return max;
25 | }
26 |
27 | Vector2D Vector2D::floor() const {
28 | return Vector2D(std::floor(x), std::floor(y));
29 | }
30 |
31 | Vector2D Vector2D::clamp(const Vector2D& min, const Vector2D& max) const {
32 | return Vector2D(std::clamp(this->x, min.x, max.x < min.x ? INFINITY : max.x), std::clamp(this->y, min.y, max.y < min.y ? INFINITY : max.y));
33 | }
34 |
35 | double Vector2D::distance(const Vector2D& other) const {
36 | double dx = x - other.x;
37 | double dy = y - other.y;
38 | return std::sqrt(dx * dx + dy * dy);
39 | }
40 |
41 | bool Vector2D::inTriangle(const Vector2D& p1, const Vector2D& p2, const Vector2D& p3) const {
42 | const auto a = ((p2.y - p3.y) * (x - p3.x) + (p3.x - p2.x) * (y - p3.y)) / ((p2.y - p3.y) * (p1.x - p3.x) + (p3.x - p2.x) * (p1.y - p3.y));
43 | const auto b = ((p3.y - p1.y) * (x - p3.x) + (p1.x - p3.x) * (y - p3.y)) / ((p2.y - p3.y) * (p1.x - p3.x) + (p3.x - p2.x) * (p1.y - p3.y));
44 | const auto c = 1 - a - b;
45 |
46 | return 0 <= a && a <= 1 && 0 <= b && b <= 1 && 0 <= c && c <= 1;
47 | }
48 |
49 | double Vector2D::size() const {
50 | return std::sqrt(x * x + y * y);
51 | }
52 |
--------------------------------------------------------------------------------
/src/helpers/Vector2D.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include "../macros.hpp"
6 |
7 | class Vector2D {
8 | public:
9 | Vector2D(double, double);
10 | Vector2D();
11 | ~Vector2D();
12 |
13 | double x = 0;
14 | double y = 0;
15 |
16 | // returns the scale
17 | double normalize();
18 |
19 | Vector2D operator+(const Vector2D& a) const {
20 | return Vector2D(this->x + a.x, this->y + a.y);
21 | }
22 | Vector2D operator-(const Vector2D& a) const {
23 | return Vector2D(this->x - a.x, this->y - a.y);
24 | }
25 | Vector2D operator-() const {
26 | return Vector2D(-this->x, -this->y);
27 | }
28 | Vector2D operator*(const float& a) const {
29 | return Vector2D(this->x * a, this->y * a);
30 | }
31 | Vector2D operator/(const float& a) const {
32 | return Vector2D(this->x / a, this->y / a);
33 | }
34 |
35 | bool operator==(const Vector2D& a) const {
36 | return a.x == x && a.y == y;
37 | }
38 |
39 | bool operator!=(const Vector2D& a) const {
40 | return a.x != x || a.y != y;
41 | }
42 |
43 | Vector2D operator*(const Vector2D& a) const {
44 | return Vector2D(this->x * a.x, this->y * a.y);
45 | }
46 |
47 | Vector2D operator/(const Vector2D& a) const {
48 | return Vector2D(this->x / a.x, this->y / a.y);
49 | }
50 |
51 | bool operator>(const Vector2D& a) const {
52 | return this->x > a.x && this->y > a.y;
53 | }
54 |
55 | bool operator<(const Vector2D& a) const {
56 | return this->x < a.x && this->y < a.y;
57 | }
58 |
59 | double distance(const Vector2D& other) const;
60 | double size() const;
61 | Vector2D clamp(const Vector2D& min, const Vector2D& max = Vector2D()) const;
62 |
63 | Vector2D floor() const;
64 |
65 | bool inTriangle(const Vector2D& p1, const Vector2D& p2, const Vector2D& p3) const;
66 | };
67 |
68 | /**
69 | format specification
70 | - 'j', as json array
71 | - 'X', same as std::format("{}x{}", vec.x, vec.y)
72 | - number, floating point precision, use `0` to format as integer
73 | */
74 | template
75 | struct std::formatter : std::formatter {
76 | bool formatJson = false;
77 | bool formatX = false;
78 | std::string precision = "";
79 | FORMAT_PARSE(FORMAT_FLAG('j', formatJson) //
80 | FORMAT_FLAG('X', formatX) //
81 | FORMAT_NUMBER(precision),
82 | Vector2D)
83 |
84 | template
85 | auto format(const Vector2D& vec, FormatContext& ctx) const {
86 | std::string formatString = precision.empty() ? "{}" : std::format("{{:.{}f}}", precision);
87 |
88 | if (formatJson)
89 | formatString = std::format("[{0}, {0}]", formatString);
90 | else if (formatX)
91 | formatString = std::format("{0}x{0}", formatString);
92 | else
93 | formatString = std::format("[Vector2D: x: {0}, y: {0}]", formatString);
94 | try {
95 | string buf = std::vformat(formatString, std::make_format_args(vec.x, vec.y));
96 | return std::format_to(ctx.out(), "{}", buf);
97 | } catch (std::format_error& e) { return std::format_to(ctx.out(), "[{}, {}]", vec.x, vec.y); }
98 | }
99 | };
100 |
--------------------------------------------------------------------------------
/src/helpers/WLListener.cpp:
--------------------------------------------------------------------------------
1 | #include "WLListener.hpp"
2 | #include "MiscFunctions.hpp"
3 | #include
4 | #include "../debug/Log.hpp"
5 | #include "Watchdog.hpp"
6 |
7 | void handleWrapped(wl_listener* listener, void* data) {
8 | CHyprWLListener::SWrapper* pWrap = wl_container_of(listener, pWrap, m_sListener);
9 |
10 | g_pWatchdog->startWatching();
11 |
12 | try {
13 | pWrap->m_pSelf->emit(data);
14 | } catch (std::exception& e) { Debug::log(ERR, "Listener {} timed out and was killed by Watchdog!!!", (uintptr_t)listener); }
15 |
16 | g_pWatchdog->endWatching();
17 | }
18 |
19 | CHyprWLListener::CHyprWLListener(wl_signal* pSignal, std::function callback, void* pOwner) {
20 | initCallback(pSignal, callback, pOwner);
21 | }
22 |
23 | CHyprWLListener::CHyprWLListener() {
24 | m_swWrapper.m_pSelf = this;
25 | m_swWrapper.m_sListener.notify = &handleWrapped;
26 | wl_list_init(&m_swWrapper.m_sListener.link);
27 | }
28 |
29 | CHyprWLListener::~CHyprWLListener() {
30 | removeCallback();
31 | }
32 |
33 | void CHyprWLListener::removeCallback() {
34 | if (isConnected()) {
35 | Debug::log(LOG, "Callback {:x} -> {:x}, {} removed.", (uintptr_t)&m_pCallback, (uintptr_t)&m_pOwner, m_szAuthor);
36 | wl_list_remove(&m_swWrapper.m_sListener.link);
37 | wl_list_init(&m_swWrapper.m_sListener.link);
38 | }
39 | }
40 |
41 | bool CHyprWLListener::isConnected() {
42 | return !wl_list_empty(&m_swWrapper.m_sListener.link);
43 | }
44 |
45 | void CHyprWLListener::initCallback(wl_signal* pSignal, std::function callback, void* pOwner, std::string author) {
46 | if (isConnected()) {
47 | Debug::log(ERR, "Tried to connect a listener twice?!");
48 | return;
49 | }
50 |
51 | m_pOwner = pOwner;
52 | m_pCallback = callback;
53 | m_szAuthor = author;
54 |
55 | addWLSignal(pSignal, &m_swWrapper.m_sListener, pOwner, m_szAuthor);
56 | }
57 |
58 | void CHyprWLListener::emit(void* data) {
59 | m_pCallback(m_pOwner, data);
60 | }
61 |
--------------------------------------------------------------------------------
/src/helpers/WLListener.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 |
7 | class CHyprWLListener {
8 | public:
9 | CHyprWLListener(wl_signal*, std::function, void* owner);
10 | CHyprWLListener();
11 | ~CHyprWLListener();
12 |
13 | CHyprWLListener(const CHyprWLListener&) = delete;
14 | CHyprWLListener(CHyprWLListener&&) = delete;
15 | CHyprWLListener& operator=(const CHyprWLListener&) = delete;
16 | CHyprWLListener& operator=(CHyprWLListener&&) = delete;
17 |
18 | void initCallback(wl_signal*, std::function, void* owner, std::string author = "");
19 |
20 | void removeCallback();
21 |
22 | bool isConnected();
23 |
24 | struct SWrapper {
25 | wl_listener m_sListener;
26 | CHyprWLListener* m_pSelf;
27 | };
28 |
29 | void emit(void*);
30 |
31 | private:
32 | SWrapper m_swWrapper;
33 |
34 | void* m_pOwner = nullptr;
35 |
36 | std::function m_pCallback = nullptr;
37 |
38 | std::string m_szAuthor = "";
39 | };
--------------------------------------------------------------------------------
/src/helpers/WLSurface.cpp:
--------------------------------------------------------------------------------
1 | #include "WLSurface.hpp"
2 | #include "../Compositor.hpp"
3 |
4 | CWLSurface::CWLSurface(wlr_surface* pSurface) {
5 | m_pWLRSurface = pSurface;
6 | init();
7 | }
8 |
9 | void CWLSurface::assign(wlr_surface* pSurface) {
10 | m_pWLRSurface = pSurface;
11 | init();
12 | }
13 |
14 | void CWLSurface::unassign() {
15 | destroy();
16 | }
17 |
18 | CWLSurface::~CWLSurface() {
19 | destroy();
20 | }
21 |
22 | bool CWLSurface::exists() const {
23 | return m_pWLRSurface;
24 | }
25 |
26 | wlr_surface* CWLSurface::wlr() const {
27 | return m_pWLRSurface;
28 | }
29 |
30 | bool CWLSurface::small() const {
31 | if (!m_pOwner || !exists())
32 | return false;
33 |
34 | return m_pOwner->m_vReportedSize.x > m_pWLRSurface->current.buffer_width + 1 || m_pOwner->m_vReportedSize.y > m_pWLRSurface->current.buffer_height + 1;
35 | }
36 |
37 | Vector2D CWLSurface::correctSmallVec() const {
38 | if (!m_pOwner || !exists() || !small() || m_bFillIgnoreSmall)
39 | return {};
40 |
41 | const auto SIZE = getViewporterCorrectedSize();
42 |
43 | return Vector2D{(m_pOwner->m_vReportedSize.x - SIZE.x) / 2, (m_pOwner->m_vReportedSize.y - SIZE.y) / 2}.clamp({}, {INFINITY, INFINITY}) *
44 | (m_pOwner->m_vRealSize.vec() / m_pOwner->m_vReportedSize);
45 | }
46 |
47 | Vector2D CWLSurface::getViewporterCorrectedSize() const {
48 | if (!exists())
49 | return {};
50 |
51 | return m_pWLRSurface->current.viewport.has_dst ? Vector2D{m_pWLRSurface->current.viewport.dst_width, m_pWLRSurface->current.viewport.dst_height} :
52 | Vector2D{m_pWLRSurface->current.buffer_width, m_pWLRSurface->current.buffer_height};
53 | }
54 |
55 | void CWLSurface::destroy() {
56 | if (!m_pWLRSurface)
57 | return;
58 |
59 | hyprListener_destroy.removeCallback();
60 | m_pWLRSurface->data = nullptr;
61 | m_pOwner = nullptr;
62 |
63 | if (g_pCompositor->m_pLastFocus == m_pWLRSurface)
64 | g_pCompositor->m_pLastFocus = nullptr;
65 | if (g_pInputManager->m_pLastMouseSurface == m_pWLRSurface)
66 | g_pInputManager->m_pLastMouseSurface = nullptr;
67 | if (g_pHyprRenderer->m_sLastCursorData.surf == m_pWLRSurface)
68 | g_pInputManager->setCursorImageOverride("left_ptr");
69 |
70 | m_pWLRSurface = nullptr;
71 |
72 | Debug::log(LOG, "CWLSurface {:x} called destroy()", (uintptr_t)this);
73 | }
74 |
75 | void CWLSurface::init() {
76 | if (!m_pWLRSurface)
77 | return;
78 |
79 | RASSERT(!m_pWLRSurface->data, "Attempted to duplicate CWLSurface ownership!");
80 |
81 | m_pWLRSurface->data = this;
82 |
83 | hyprListener_destroy.initCallback(
84 | &m_pWLRSurface->events.destroy, [&](void* owner, void* data) { destroy(); }, this, "CWLSurface");
85 |
86 | Debug::log(LOG, "CWLSurface {:x} called init()", (uintptr_t)this);
87 | }
--------------------------------------------------------------------------------
/src/helpers/WLSurface.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../defines.hpp"
4 |
5 | class CWindow;
6 |
7 | class CWLSurface {
8 | public:
9 | CWLSurface() = default;
10 | CWLSurface(wlr_surface* pSurface);
11 | ~CWLSurface();
12 |
13 | void assign(wlr_surface* pSurface);
14 | void unassign();
15 |
16 | CWLSurface(const CWLSurface&) = delete;
17 | CWLSurface(CWLSurface&&) = delete;
18 | CWLSurface& operator=(const CWLSurface&) = delete;
19 | CWLSurface& operator=(CWLSurface&&) = delete;
20 |
21 | wlr_surface* wlr() const;
22 | bool exists() const;
23 | bool small() const; // means surface is smaller than the requested size
24 | Vector2D correctSmallVec() const; // returns a corrective vector for small() surfaces
25 | Vector2D getViewporterCorrectedSize() const;
26 |
27 | // allow stretching. Useful for plugins.
28 | bool m_bFillIgnoreSmall = false;
29 |
30 | // if present, means this is a base surface of a window. Cleaned on unassign()
31 | CWindow* m_pOwner = nullptr;
32 |
33 | CWLSurface& operator=(wlr_surface* pSurface) {
34 | destroy();
35 | m_pWLRSurface = pSurface;
36 | init();
37 |
38 | return *this;
39 | }
40 |
41 | bool operator==(const CWLSurface& other) const {
42 | return other.wlr() == wlr();
43 | }
44 |
45 | bool operator==(const wlr_surface* other) const {
46 | return other == wlr();
47 | }
48 |
49 | explicit operator bool() const {
50 | return exists();
51 | }
52 |
53 | static CWLSurface* surfaceFromWlr(wlr_surface* pSurface) {
54 | return (CWLSurface*)pSurface->data;
55 | }
56 |
57 | private:
58 | wlr_surface* m_pWLRSurface = nullptr;
59 |
60 | void destroy();
61 | void init();
62 |
63 | DYNLISTENER(destroy);
64 | };
--------------------------------------------------------------------------------
/src/helpers/Watchdog.cpp:
--------------------------------------------------------------------------------
1 | #include "Watchdog.hpp"
2 | #include
3 | #include "config/ConfigManager.hpp"
4 |
5 | CWatchdog::~CWatchdog() {
6 | m_bExitThread = true;
7 | m_bNotified = true;
8 | m_cvWatchdogCondition.notify_all();
9 | m_pWatchdog.reset();
10 | }
11 |
12 | CWatchdog::CWatchdog() {
13 | m_iMainThreadPID = pthread_self();
14 |
15 | m_pWatchdog = std::make_unique([this] {
16 | static auto* const PTIMEOUT = &g_pConfigManager->getConfigValuePtr("debug:watchdog_timeout")->intValue;
17 |
18 | while (1337) {
19 | std::unique_lock lk(m_mWatchdogMutex);
20 |
21 | if (!m_bWillWatch)
22 | m_cvWatchdogCondition.wait(lk, [this] { return m_bNotified; });
23 | else {
24 | if (m_cvWatchdogCondition.wait_for(lk, std::chrono::milliseconds((int)(*PTIMEOUT * 1000.0)), [this] { return m_bNotified; }) == false)
25 | pthread_kill(m_iMainThreadPID, SIGUSR1);
26 | }
27 |
28 | if (m_bExitThread)
29 | break;
30 |
31 | m_bWatching = false;
32 | m_bNotified = false;
33 | }
34 | });
35 |
36 | m_pWatchdog->detach();
37 | }
38 |
39 | void CWatchdog::startWatching() {
40 | static auto* const PTIMEOUT = &g_pConfigManager->getConfigValuePtr("debug:watchdog_timeout")->intValue;
41 |
42 | if (*PTIMEOUT == 0)
43 | return;
44 |
45 | m_tTriggered = std::chrono::high_resolution_clock::now();
46 | m_bWillWatch = true;
47 | m_bWatching = true;
48 |
49 | m_bNotified = true;
50 | m_cvWatchdogCondition.notify_all();
51 | }
52 |
53 | void CWatchdog::endWatching() {
54 | m_bWatching = false;
55 | m_bWillWatch = false;
56 |
57 | m_bNotified = true;
58 | m_cvWatchdogCondition.notify_all();
59 | }
--------------------------------------------------------------------------------
/src/helpers/Watchdog.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | class CWatchdog {
9 | public:
10 | // must be called from the main thread
11 | CWatchdog();
12 | ~CWatchdog();
13 |
14 | void startWatching();
15 | void endWatching();
16 |
17 | private:
18 | std::chrono::high_resolution_clock::time_point m_tTriggered;
19 |
20 | pthread_t m_iMainThreadPID = 0;
21 |
22 | bool m_bWatching = false;
23 | bool m_bWillWatch = false;
24 |
25 | std::unique_ptr m_pWatchdog;
26 | std::mutex m_mWatchdogMutex;
27 | bool m_bNotified = false;
28 | bool m_bExitThread = false;
29 | std::condition_variable m_cvWatchdogCondition;
30 | };
31 |
32 | inline std::unique_ptr g_pWatchdog;
--------------------------------------------------------------------------------
/src/helpers/Workspace.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "AnimatedVariable.hpp"
4 | #include
5 | #include "../defines.hpp"
6 |
7 | enum eFullscreenMode : int8_t {
8 | FULLSCREEN_INVALID = -1,
9 | FULLSCREEN_FULL = 0,
10 | FULLSCREEN_MAXIMIZED
11 | };
12 |
13 | class CWindow;
14 |
15 | class CWorkspace {
16 | public:
17 | CWorkspace(int monitorID, std::string name, bool special = false);
18 | ~CWorkspace();
19 |
20 | // Workspaces ID-based have IDs > 0
21 | // and workspaces name-based have IDs starting with -1337
22 | int m_iID = -1;
23 | std::string m_szName = "";
24 | uint64_t m_iMonitorID = -1;
25 | // Previous workspace ID is stored during a workspace change, allowing travel
26 | // to the previous workspace.
27 | struct SPrevWorkspaceData {
28 | int iID = -1;
29 | std::string name = "";
30 | } m_sPrevWorkspace;
31 |
32 | bool m_bHasFullscreenWindow = false;
33 | eFullscreenMode m_efFullscreenMode = FULLSCREEN_FULL;
34 |
35 | wl_array m_wlrCoordinateArr;
36 |
37 | // for animations
38 | CAnimatedVariable m_vRenderOffset;
39 | CAnimatedVariable m_fAlpha;
40 | bool m_bForceRendering = false;
41 |
42 | // "scratchpad"
43 | bool m_bIsSpecialWorkspace = false;
44 |
45 | // last window
46 | CWindow* m_pLastFocusedWindow = nullptr;
47 |
48 | // user-set
49 | bool m_bDefaultFloating = false;
50 | bool m_bDefaultPseudo = false;
51 |
52 | // last monitor (used on reconnect)
53 | std::string m_szLastMonitor = "";
54 |
55 | // Whether the user configured command for on-created-empty has been executed, if any
56 | bool m_bOnCreatedEmptyExecuted = false;
57 |
58 | void startAnim(bool in, bool left, bool instant = false);
59 | void setActive(bool on);
60 |
61 | void moveToMonitor(const int&);
62 |
63 | CWindow* getLastFocusedWindow();
64 | void rememberPrevWorkspace(const CWorkspace* prevWorkspace);
65 |
66 | std::string getConfigName();
67 | };
68 |
--------------------------------------------------------------------------------
/src/helpers/X11Stubs.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | inline bool wlr_backend_is_x11(void*) {
4 | return false;
5 | }
6 |
7 | inline void wlr_x11_output_create(void*) {}
8 |
--------------------------------------------------------------------------------
/src/hyprerror/HyprError.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../defines.hpp"
4 | #include "../render/Texture.hpp"
5 | #include "../helpers/AnimatedVariable.hpp"
6 |
7 | #include
8 |
9 | class CHyprError {
10 | public:
11 | CHyprError();
12 | ~CHyprError();
13 |
14 | void queueCreate(std::string message, const CColor& color);
15 | void draw();
16 | void destroy();
17 |
18 | private:
19 | void createQueued();
20 | std::string m_szQueued = "";
21 | CColor m_cQueued;
22 | bool m_bQueuedDestroy = false;
23 | bool m_bIsCreated = false;
24 | CTexture m_tTexture;
25 | CAnimatedVariable m_fFadeOpacity;
26 | CBox m_bDamageBox = {0, 0, 0, 0};
27 |
28 | bool m_bMonitorChanged = false;
29 | };
30 |
31 | inline std::unique_ptr g_pHyprError; // This is a full-screen error. Treat it with respect, and there can only be one at a time.
--------------------------------------------------------------------------------
/src/init/initHelpers.cpp:
--------------------------------------------------------------------------------
1 | #include "initHelpers.hpp"
2 |
3 | bool Init::isSudo() {
4 | return getuid() != geteuid() || !geteuid();
5 | }
6 |
7 | void Init::gainRealTime() {
8 | const int minPrio = sched_get_priority_min(SCHED_RR);
9 | int old_policy;
10 | struct sched_param param;
11 |
12 | if (pthread_getschedparam(pthread_self(), &old_policy, ¶m)) {
13 | Debug::log(WARN, "Failed to get old pthread scheduling priority");
14 | return;
15 | }
16 |
17 | param.sched_priority = minPrio;
18 |
19 | if (pthread_setschedparam(pthread_self(), SCHED_RR, ¶m)) {
20 | Debug::log(WARN, "Failed to change process scheduling strategy");
21 | return;
22 | }
23 |
24 | pthread_atfork(NULL, NULL, []() {
25 | const struct sched_param param = {.sched_priority = 0};
26 | if (pthread_setschedparam(pthread_self(), SCHED_OTHER, ¶m))
27 | Debug::log(WARN, "Failed to reset process scheduling strategy");
28 | });
29 | }
--------------------------------------------------------------------------------
/src/init/initHelpers.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../defines.hpp"
4 |
5 | namespace Init {
6 | bool isSudo();
7 | void gainRealTime();
8 | };
--------------------------------------------------------------------------------
/src/main.cpp:
--------------------------------------------------------------------------------
1 | #include "defines.hpp"
2 | #include "debug/Log.hpp"
3 | #include "Compositor.hpp"
4 | #include "config/ConfigManager.hpp"
5 | #include "init/initHelpers.hpp"
6 |
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 |
14 | void help() {
15 | std::cout << "usage: Hyprland [arg [...]].\n";
16 | std::cout << "\nArguments:\n";
17 | std::cout << " --help -h - Show this message again\n";
18 | std::cout << " --config FILE -c FILE - Specify config file to use\n";
19 | std::cout << " --i-am-really-stupid - Omits root user privileges check (why would you do that?)\n";
20 | }
21 |
22 | int main(int argc, char** argv) {
23 |
24 | if (!getenv("XDG_RUNTIME_DIR"))
25 | throwError("XDG_RUNTIME_DIR is not set!");
26 |
27 | // export HYPRLAND_CMD
28 | std::string cmd = "";
29 | for (auto i = 0; i < argc; ++i)
30 | cmd += std::string(i == 0 ? "" : " ") + argv[i];
31 |
32 | setenv("HYPRLAND_CMD", cmd.c_str(), 1);
33 | setenv("XDG_BACKEND", "wayland", 1);
34 | setenv("_JAVA_AWT_WM_NONREPARENTING", "1", 1);
35 | setenv("MOZ_ENABLE_WAYLAND", "1", 1);
36 | setenv("XDG_CURRENT_DESKTOP", "Hyprland", 1);
37 |
38 | // parse some args
39 | std::string configPath;
40 | bool ignoreSudo = false;
41 |
42 | std::vector args{argv + 1, argv + argc};
43 |
44 | for (auto it = args.begin(); it != args.end(); it++) {
45 | if (it->compare("--i-am-really-stupid") == 0 && !ignoreSudo) {
46 | std::cout << "[ WARNING ] Running Hyprland with superuser privileges might damage your system\n";
47 |
48 | ignoreSudo = true;
49 | } else if (it->compare("-c") == 0 || it->compare("--config") == 0) {
50 | if (std::next(it) == args.end()) {
51 | help();
52 |
53 | return 1;
54 | }
55 | std::string next_arg = std::next(it)->c_str();
56 |
57 | if (!std::filesystem::exists(next_arg)) {
58 | std::cerr << "[ ERROR ] Config path '" << next_arg << "' doesn't exist!\n";
59 | help();
60 |
61 | return 1;
62 | }
63 |
64 | configPath = next_arg;
65 | Debug::log(LOG, "User-specified config location: '{}'", configPath);
66 |
67 | it++;
68 |
69 | continue;
70 | } else if (it->compare("-h") == 0 || it->compare("--help") == 0) {
71 | help();
72 |
73 | return 0;
74 | } else {
75 | std::cerr << "[ ERROR ] Unknown option '" << it->c_str() << "'!\n";
76 | help();
77 |
78 | return 1;
79 | }
80 | }
81 |
82 | if (!ignoreSudo && Init::isSudo()) {
83 | std::cerr << "[ ERROR ] Hyprland was launched with superuser priveleges, but the privileges check is not omitted.\n";
84 | std::cerr << " Hint: Use the --i-am-really-stupid flag to omit that check.\n";
85 |
86 | return 1;
87 | } else if (ignoreSudo && Init::isSudo()) {
88 | std::cout << "Superuser privileges check is omitted. I hope you know what you're doing.\n";
89 | }
90 |
91 | std::cout << "Welcome to Hyprland!\n";
92 |
93 | // let's init the compositor.
94 | // it initializes basic Wayland stuff in the constructor.
95 | g_pCompositor = std::make_unique();
96 | g_pCompositor->explicitConfigPath = configPath;
97 |
98 | g_pCompositor->initServer();
99 |
100 | Init::gainRealTime();
101 |
102 | Debug::log(LOG, "Hyprland init finished.");
103 |
104 | // If all's good to go, start.
105 | g_pCompositor->startCompositor();
106 |
107 | // If we are here it means we got yote.
108 | Debug::log(LOG, "Hyprland reached the end.");
109 | g_pCompositor.reset();
110 |
111 | return EXIT_SUCCESS;
112 | }
113 |
--------------------------------------------------------------------------------
/src/managers/AnimationManager.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../defines.hpp"
4 | #include
5 | #include
6 | #include "../helpers/AnimatedVariable.hpp"
7 | #include "../helpers/BezierCurve.hpp"
8 | #include "../Window.hpp"
9 | #include "../helpers/Timer.hpp"
10 |
11 | class CAnimationManager {
12 | public:
13 | CAnimationManager();
14 |
15 | void tick();
16 | bool shouldTickForNext();
17 | void onTicked();
18 | void scheduleTick();
19 | void addBezierWithName(std::string, const Vector2D&, const Vector2D&);
20 | void removeAllBeziers();
21 |
22 | void onWindowPostCreateClose(CWindow*, bool close = false);
23 |
24 | bool bezierExists(const std::string&);
25 | CBezierCurve* getBezier(const std::string&);
26 |
27 | std::string styleValidInConfigVar(const std::string&, const std::string&);
28 |
29 | std::unordered_map getAllBeziers();
30 |
31 | std::vector m_vAnimatedVariables;
32 | std::vector m_vActiveAnimatedVariables;
33 |
34 | wl_event_source* m_pAnimationTick;
35 |
36 | float m_fLastTickTime; // in ms
37 |
38 | private:
39 | bool deltaSmallToFlip(const Vector2D& a, const Vector2D& b);
40 | bool deltaSmallToFlip(const CColor& a, const CColor& b);
41 | bool deltaSmallToFlip(const float& a, const float& b);
42 | bool deltazero(const Vector2D& a, const Vector2D& b);
43 | bool deltazero(const CColor& a, const CColor& b);
44 | bool deltazero(const float& a, const float& b);
45 |
46 | std::unordered_map m_mBezierCurves;
47 |
48 | bool m_bTickScheduled = false;
49 |
50 | // Anim stuff
51 | void animationPopin(CWindow*, bool close = false, float minPerc = 0.f);
52 | void animationSlide(CWindow*, std::string force = "", bool close = false);
53 | };
54 |
55 | inline std::unique_ptr g_pAnimationManager;
--------------------------------------------------------------------------------
/src/managers/EventManager.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include
4 | #include
5 |
6 | #include "../defines.hpp"
7 | #include "../helpers/MiscFunctions.hpp"
8 |
9 | struct SHyprIPCEvent {
10 | std::string event;
11 | std::string data;
12 | };
13 |
14 | class CEventManager {
15 | public:
16 | CEventManager();
17 |
18 | void postEvent(const SHyprIPCEvent event);
19 |
20 | void startThread();
21 |
22 | std::thread m_tThread;
23 | private:
24 | void flushEvents();
25 |
26 | std::mutex eventQueueMutex;
27 | std::deque m_dQueuedEvents;
28 |
29 | std::deque> m_dAcceptedSocketFDs;
30 | };
31 |
32 | inline std::unique_ptr g_pEventManager;
33 |
--------------------------------------------------------------------------------
/src/managers/HookSystemManager.cpp:
--------------------------------------------------------------------------------
1 | #include "HookSystemManager.hpp"
2 |
3 | #include "../plugins/PluginSystem.hpp"
4 |
5 | CHookSystemManager::CHookSystemManager() {
6 | ; //
7 | }
8 |
9 | // returns the pointer to the function
10 | HOOK_CALLBACK_FN* CHookSystemManager::hookDynamic(const std::string& event, HOOK_CALLBACK_FN fn, HANDLE handle) {
11 | const auto PVEC = getVecForEvent(event);
12 | const auto PFN = &m_lCallbackFunctions.emplace_back(fn);
13 | PVEC->emplace_back(SCallbackFNPtr{PFN, handle});
14 | return PFN;
15 | }
16 |
17 | void CHookSystemManager::hookStatic(const std::string& event, HOOK_CALLBACK_FN* fn, HANDLE handle) {
18 | const auto PVEC = getVecForEvent(event);
19 | PVEC->emplace_back(SCallbackFNPtr{fn, handle});
20 | }
21 |
22 | void CHookSystemManager::unhook(HOOK_CALLBACK_FN* fn) {
23 | std::erase_if(m_lCallbackFunctions, [&](const auto& other) { return &other == fn; });
24 | for (auto& [k, v] : m_lpRegisteredHooks) {
25 | std::erase_if(v, [&](const auto& other) { return other.fn == fn; });
26 | }
27 | }
28 |
29 | void CHookSystemManager::emit(const std::vector* callbacks, SCallbackInfo& info, std::any data) {
30 | if (callbacks->empty())
31 | return;
32 |
33 | std::vector faultyHandles;
34 |
35 | for (auto& cb : *callbacks) {
36 |
37 | m_bCurrentEventPlugin = false;
38 |
39 | if (!cb.handle) {
40 | // we don't guard hl hooks
41 | (*cb.fn)(cb.fn, info, data);
42 | continue;
43 | }
44 |
45 | m_bCurrentEventPlugin = true;
46 |
47 | if (std::find(faultyHandles.begin(), faultyHandles.end(), cb.handle) != faultyHandles.end())
48 | continue;
49 |
50 | try {
51 | if (!setjmp(m_jbHookFaultJumpBuf))
52 | (*cb.fn)(cb.fn, info, data);
53 | else {
54 | // this module crashed.
55 | throw std::exception();
56 | }
57 | } catch (std::exception& e) {
58 | // TODO: this works only once...?
59 | faultyHandles.push_back(cb.handle);
60 | Debug::log(ERR, "[hookSystem] Hook from plugin {:x} caused a SIGSEGV, queueing for unloading.", (uintptr_t)cb.handle);
61 | }
62 | }
63 |
64 | if (!faultyHandles.empty()) {
65 | for (auto& h : faultyHandles)
66 | g_pPluginSystem->unloadPlugin(g_pPluginSystem->getPluginByHandle(h), true);
67 | }
68 | }
69 |
70 | std::vector* CHookSystemManager::getVecForEvent(const std::string& event) {
71 | auto IT = std::find_if(m_lpRegisteredHooks.begin(), m_lpRegisteredHooks.end(), [&](const auto& other) { return other.first == event; });
72 |
73 | if (IT != m_lpRegisteredHooks.end())
74 | return &IT->second;
75 |
76 | Debug::log(LOG, "[hookSystem] New hook event registered: {}", event);
77 |
78 | return &m_lpRegisteredHooks.emplace_back(std::make_pair<>(event, std::vector{})).second;
79 | }
--------------------------------------------------------------------------------
/src/managers/HookSystemManager.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../defines.hpp"
4 |
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | #include
11 |
12 | #include "../plugins/PluginAPI.hpp"
13 |
14 | // global typedef for hooked functions. Passes itself as a ptr when called, and `data` additionally.
15 |
16 | typedef std::function HOOK_CALLBACK_FN;
17 |
18 | struct SCallbackFNPtr {
19 | HOOK_CALLBACK_FN* fn = nullptr;
20 | HANDLE handle = nullptr;
21 | };
22 |
23 | #define EMIT_HOOK_EVENT(name, param) \
24 | { \
25 | static auto* const PEVENTVEC = g_pHookSystem->getVecForEvent(name); \
26 | SCallbackInfo info; \
27 | g_pHookSystem->emit(PEVENTVEC, info, param); \
28 | }
29 |
30 | #define EMIT_HOOK_EVENT_CANCELLABLE(name, param) \
31 | { \
32 | static auto* const PEVENTVEC = g_pHookSystem->getVecForEvent(name); \
33 | SCallbackInfo info; \
34 | g_pHookSystem->emit(PEVENTVEC, info, param); \
35 | if (info.cancelled) \
36 | return; \
37 | }
38 |
39 | class CHookSystemManager {
40 | public:
41 | CHookSystemManager();
42 |
43 | // returns the pointer to the function
44 | HOOK_CALLBACK_FN* hookDynamic(const std::string& event, HOOK_CALLBACK_FN fn, HANDLE handle = nullptr);
45 | void hookStatic(const std::string& event, HOOK_CALLBACK_FN* fn, HANDLE handle = nullptr);
46 | void unhook(HOOK_CALLBACK_FN* fn);
47 |
48 | void emit(const std::vector* callbacks, SCallbackInfo& info, std::any data = 0);
49 | std::vector* getVecForEvent(const std::string& event);
50 |
51 | bool m_bCurrentEventPlugin = false;
52 | jmp_buf m_jbHookFaultJumpBuf;
53 |
54 | private:
55 | // todo: this is slow. Maybe static ptrs should be somehow allowed. unique ptr for vec?
56 | std::list>> m_lpRegisteredHooks;
57 | std::list m_lCallbackFunctions;
58 | };
59 |
60 | inline std::unique_ptr g_pHookSystem;
--------------------------------------------------------------------------------
/src/managers/LayoutManager.cpp:
--------------------------------------------------------------------------------
1 | #include "LayoutManager.hpp"
2 |
3 | CLayoutManager::CLayoutManager() {
4 | m_vLayouts.emplace_back(std::make_pair<>("dwindle", &m_cDwindleLayout));
5 | m_vLayouts.emplace_back(std::make_pair<>("master", &m_cMasterLayout));
6 | }
7 |
8 | IHyprLayout* CLayoutManager::getCurrentLayout() {
9 | return m_vLayouts[m_iCurrentLayoutID].second;
10 | }
11 |
12 | void CLayoutManager::switchToLayout(std::string layout) {
13 | for (size_t i = 0; i < m_vLayouts.size(); ++i) {
14 | if (m_vLayouts[i].first == layout) {
15 | if (i == (size_t)m_iCurrentLayoutID)
16 | return;
17 |
18 | getCurrentLayout()->onDisable();
19 | m_iCurrentLayoutID = i;
20 | getCurrentLayout()->onEnable();
21 | return;
22 | }
23 | }
24 |
25 | Debug::log(ERR, "Unknown layout!");
26 | }
27 |
28 | bool CLayoutManager::addLayout(const std::string& name, IHyprLayout* layout) {
29 | if (std::find_if(m_vLayouts.begin(), m_vLayouts.end(), [&](const auto& other) { return other.first == name || other.second == layout; }) != m_vLayouts.end())
30 | return false;
31 |
32 | m_vLayouts.emplace_back(std::make_pair<>(name, layout));
33 |
34 | Debug::log(LOG, "Added new layout {} at {:x}", name, (uintptr_t)layout);
35 |
36 | return true;
37 | }
38 |
39 | bool CLayoutManager::removeLayout(IHyprLayout* layout) {
40 | const auto IT = std::find_if(m_vLayouts.begin(), m_vLayouts.end(), [&](const auto& other) { return other.second == layout; });
41 |
42 | if (IT == m_vLayouts.end() || IT->first == "dwindle" || IT->first == "master")
43 | return false;
44 |
45 | if (m_iCurrentLayoutID == IT - m_vLayouts.begin())
46 | switchToLayout("dwindle");
47 |
48 | Debug::log(LOG, "Removed a layout {} at {:x}", IT->first, (uintptr_t)layout);
49 |
50 | std::erase(m_vLayouts, *IT);
51 |
52 | return true;
53 | }
54 |
--------------------------------------------------------------------------------
/src/managers/LayoutManager.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../layout/DwindleLayout.hpp"
4 | #include "../layout/MasterLayout.hpp"
5 |
6 | class CLayoutManager {
7 | public:
8 | CLayoutManager();
9 |
10 | IHyprLayout* getCurrentLayout();
11 |
12 | void switchToLayout(std::string);
13 |
14 | bool addLayout(const std::string& name, IHyprLayout* layout);
15 | bool removeLayout(IHyprLayout* layout);
16 |
17 | private:
18 | enum HYPRLAYOUTS
19 | {
20 | LAYOUT_DWINDLE = 0,
21 | LAYOUT_MASTER
22 | };
23 |
24 | int m_iCurrentLayoutID = LAYOUT_DWINDLE;
25 |
26 | CHyprDwindleLayout m_cDwindleLayout;
27 | CHyprMasterLayout m_cMasterLayout;
28 |
29 | std::vector> m_vLayouts;
30 | };
31 |
32 | inline std::unique_ptr g_pLayoutManager;
--------------------------------------------------------------------------------
/src/managers/ProtocolManager.cpp:
--------------------------------------------------------------------------------
1 | #include "ProtocolManager.hpp"
2 |
3 | #include "xdg-output-unstable-v1-protocol.h"
4 |
5 | CProtocolManager::CProtocolManager() {
6 | m_pToplevelExportProtocolManager = std::make_unique();
7 | m_pFractionalScaleProtocolManager = std::make_unique();
8 | m_pTextInputV1ProtocolManager = std::make_unique();
9 | m_pGlobalShortcutsProtocolManager = std::make_unique();
10 | m_pScreencopyProtocolManager = std::make_unique();
11 |
12 | m_pXDGOutputProtocol = std::make_unique(&zxdg_output_manager_v1_interface, 3, "XDGOutput");
13 | }
14 |
--------------------------------------------------------------------------------
/src/managers/ProtocolManager.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../defines.hpp"
4 | #include "../protocols/ToplevelExport.hpp"
5 | #include "../protocols/FractionalScale.hpp"
6 | #include "../protocols/TextInputV1.hpp"
7 | #include "../protocols/GlobalShortcuts.hpp"
8 | #include "../protocols/Screencopy.hpp"
9 | #include "../protocols/XDGOutput.hpp"
10 |
11 | class CProtocolManager {
12 | public:
13 | CProtocolManager();
14 |
15 | // TODO: rewrite to use the new protocol framework
16 | std::unique_ptr m_pToplevelExportProtocolManager;
17 | std::unique_ptr m_pFractionalScaleProtocolManager;
18 | std::unique_ptr m_pTextInputV1ProtocolManager;
19 | std::unique_ptr m_pGlobalShortcutsProtocolManager;
20 | std::unique_ptr m_pScreencopyProtocolManager;
21 |
22 | // New protocols
23 | std::unique_ptr m_pXDGOutputProtocol;
24 | };
25 |
26 | inline std::unique_ptr g_pProtocolManager;
27 |
--------------------------------------------------------------------------------
/src/managers/SessionLockManager.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../defines.hpp"
4 |
5 | struct SSessionLockSurface {
6 | wlr_session_lock_surface_v1* pWlrLockSurface = nullptr;
7 | int iMonitorID = -1;
8 |
9 | bool mapped = false;
10 |
11 | DYNLISTENER(map);
12 | DYNLISTENER(destroy);
13 | DYNLISTENER(commit);
14 | };
15 |
16 | struct SSessionLock {
17 | bool active = false;
18 | wlr_session_lock_v1* pWlrLock = nullptr;
19 |
20 | std::vector> vSessionLockSurfaces;
21 |
22 | DYNLISTENER(newSurface);
23 | DYNLISTENER(unlock);
24 | DYNLISTENER(destroy);
25 | };
26 |
27 | class CSessionLockManager {
28 | public:
29 | CSessionLockManager() = default;
30 | ~CSessionLockManager() = default;
31 |
32 | void onNewSessionLock(wlr_session_lock_v1*);
33 | SSessionLockSurface* getSessionLockSurfaceForMonitor(const int&);
34 |
35 | bool isSessionLocked();
36 | bool isSurfaceSessionLock(wlr_surface*);
37 |
38 | void removeSessionLockSurface(SSessionLockSurface*);
39 |
40 | void activateLock();
41 |
42 | private:
43 | SSessionLock m_sSessionLock;
44 | };
45 |
46 | inline std::unique_ptr g_pSessionLockManager;
--------------------------------------------------------------------------------
/src/managers/ThreadManager.cpp:
--------------------------------------------------------------------------------
1 | #include "ThreadManager.hpp"
2 | #include "../debug/HyprCtl.hpp"
3 | #include "../Compositor.hpp"
4 |
5 | int slowUpdate = 0;
6 |
7 | int handleTimer(void* data) {
8 | const auto PTM = (CThreadManager*)data;
9 |
10 | static auto* const PDISABLECFGRELOAD = &g_pConfigManager->getConfigValuePtr("misc:disable_autoreload")->intValue;
11 |
12 | if (*PDISABLECFGRELOAD != 1)
13 | g_pConfigManager->tick();
14 |
15 | wl_event_source_timer_update(PTM->m_esConfigTimer, 1000);
16 |
17 | return 0;
18 | }
19 |
20 | CThreadManager::CThreadManager() {
21 | HyprCtl::startHyprCtlSocket();
22 |
23 | m_esConfigTimer = wl_event_loop_add_timer(g_pCompositor->m_sWLEventLoop, handleTimer, this);
24 |
25 | wl_event_source_timer_update(m_esConfigTimer, 1000);
26 | }
27 |
28 | CThreadManager::~CThreadManager() {
29 | //
30 | }
--------------------------------------------------------------------------------
/src/managers/ThreadManager.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../defines.hpp"
4 | #include
5 | #include "../Compositor.hpp"
6 |
7 | class CThreadManager {
8 | public:
9 | CThreadManager();
10 | ~CThreadManager();
11 |
12 | wl_event_source* m_esConfigTimer;
13 |
14 | private:
15 | };
16 |
17 | inline std::unique_ptr g_pThreadManager;
--------------------------------------------------------------------------------
/src/managers/XWaylandManager.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../defines.hpp"
4 | #include
5 |
6 | class CWindow; // because clangd
7 |
8 | class CHyprXWaylandManager {
9 | public:
10 | CHyprXWaylandManager();
11 | ~CHyprXWaylandManager();
12 |
13 | wlr_xwayland* m_sWLRXWayland = nullptr;
14 |
15 | wlr_surface* getWindowSurface(CWindow*);
16 | void activateSurface(wlr_surface*, bool);
17 | void activateWindow(CWindow*, bool);
18 | void getGeometryForWindow(CWindow*, CBox*);
19 | std::string getTitle(CWindow*);
20 | std::string getAppIDClass(CWindow*);
21 | void sendCloseWindow(CWindow*);
22 | void setWindowSize(CWindow*, Vector2D, bool force = false);
23 | void setWindowStyleTiled(CWindow*, uint32_t);
24 | void setWindowFullscreen(CWindow*, bool);
25 | wlr_surface* surfaceAt(CWindow*, const Vector2D&, Vector2D&);
26 | bool shouldBeFloated(CWindow*);
27 | void moveXWaylandWindow(CWindow*, const Vector2D&);
28 | void checkBorders(CWindow*);
29 | Vector2D getMaxSizeForWindow(CWindow*);
30 | Vector2D xwaylandToWaylandCoords(const Vector2D&);
31 | };
32 |
33 | inline std::unique_ptr g_pXWaylandManager;
--------------------------------------------------------------------------------
/src/managers/input/IdleInhibitor.cpp:
--------------------------------------------------------------------------------
1 | #include "InputManager.hpp"
2 | #include "../../Compositor.hpp"
3 |
4 | void Events::listener_newIdleInhibitor(wl_listener* listener, void* data) {
5 | const auto WLRIDLEINHIBITOR = (wlr_idle_inhibitor_v1*)data;
6 |
7 | if (!WLRIDLEINHIBITOR)
8 | return;
9 |
10 | g_pInputManager->newIdleInhibitor(WLRIDLEINHIBITOR);
11 | }
12 |
13 | void CInputManager::newIdleInhibitor(wlr_idle_inhibitor_v1* pInhibitor) {
14 | const auto PINHIBIT = &m_lIdleInhibitors.emplace_back();
15 |
16 | Debug::log(LOG, "New idle inhibitor registered");
17 |
18 | PINHIBIT->pWlrInhibitor = pInhibitor;
19 |
20 | PINHIBIT->hyprListener_Destroy.initCallback(
21 | &pInhibitor->events.destroy,
22 | [](void* owner, void* data) {
23 | const auto PINH = (SIdleInhibitor*)owner;
24 |
25 | g_pInputManager->m_lIdleInhibitors.remove(*PINH);
26 |
27 | Debug::log(LOG, "Destroyed an idleinhibitor");
28 |
29 | g_pInputManager->recheckIdleInhibitorStatus();
30 | },
31 | PINHIBIT, "IdleInhibitor");
32 |
33 | PINHIBIT->pWindow = g_pCompositor->getWindowFromSurface(pInhibitor->surface);
34 |
35 | if (PINHIBIT->pWindow)
36 | Debug::log(LOG, "IdleInhibitor got window {}", PINHIBIT->pWindow);
37 |
38 | recheckIdleInhibitorStatus();
39 | }
40 |
41 | void CInputManager::recheckIdleInhibitorStatus() {
42 |
43 | for (auto& ii : m_lIdleInhibitors) {
44 | if (!ii.pWindow) {
45 | g_pCompositor->setIdleActivityInhibit(false);
46 | return;
47 | } else if (g_pHyprRenderer->shouldRenderWindow(ii.pWindow)) {
48 | g_pCompositor->setIdleActivityInhibit(false);
49 | return;
50 | }
51 | }
52 |
53 | // check manual user-set inhibitors
54 | for (auto& w : g_pCompositor->m_vWindows) {
55 | if (w->m_eIdleInhibitMode == IDLEINHIBIT_NONE)
56 | continue;
57 |
58 | if (w->m_eIdleInhibitMode == IDLEINHIBIT_ALWAYS) {
59 | g_pCompositor->setIdleActivityInhibit(false);
60 | return;
61 | }
62 |
63 | if (w->m_eIdleInhibitMode == IDLEINHIBIT_FOCUS && g_pCompositor->isWindowActive(w.get())) {
64 | g_pCompositor->setIdleActivityInhibit(false);
65 | return;
66 | }
67 |
68 | if (w->m_eIdleInhibitMode == IDLEINHIBIT_FULLSCREEN && w->m_bIsFullscreen && g_pCompositor->isWorkspaceVisible(w->m_iWorkspaceID)) {
69 | g_pCompositor->setIdleActivityInhibit(false);
70 | return;
71 | }
72 | }
73 |
74 | g_pCompositor->setIdleActivityInhibit(true);
75 | return;
76 | }
--------------------------------------------------------------------------------
/src/managers/input/InputMethodRelay.hpp:
--------------------------------------------------------------------------------
1 | #pragma once
2 |
3 | #include "../../defines.hpp"
4 | #include "../../helpers/WLClasses.hpp"
5 |
6 | class CInputManager;
7 | struct STextInputV1;
8 |
9 | class CInputMethodRelay {
10 | public:
11 | CInputMethodRelay();
12 |
13 | void onNewIME(wlr_input_method_v2*);
14 | void onNewTextInput(wlr_text_input_v3*);
15 |
16 | wlr_input_method_v2* m_pWLRIME = nullptr;
17 |
18 | void commitIMEState(STextInput* pInput);
19 | void removeTextInput(STextInput* pInput);
20 |
21 | void onKeyboardFocus(wlr_surface*);
22 |
23 | STextInput* getFocusedTextInput();
24 | STextInput* getFocusableTextInput();
25 |
26 | void setPendingSurface(STextInput*, wlr_surface*);
27 |
28 | SIMEKbGrab* getIMEKeyboardGrab(SKeyboard*);
29 |
30 | void setIMEPopupFocus(SIMEPopup*, wlr_surface*);
31 | void updateInputPopup(SIMEPopup*);
32 | void damagePopup(SIMEPopup*);
33 | void removePopup(SIMEPopup*);
34 |
35 | private:
36 | std::unique_ptr m_pKeyboardGrab;
37 |
38 | std::list m_lTextInputs;
39 | std::list m_lIMEPopups;
40 |
41 | DYNLISTENER(textInputNew);
42 | DYNLISTENER(IMECommit);
43 | DYNLISTENER(IMEDestroy);
44 | DYNLISTENER(IMEGrab);
45 | DYNLISTENER(IMENewPopup);
46 |
47 | void createNewTextInput(wlr_text_input_v3*, STextInputV1* tiv1 = nullptr);
48 | wlr_surface* focusedSurface(STextInput* pInput);
49 |
50 | friend class CHyprRenderer;
51 | friend class CInputManager;
52 | friend class CTextInputV1ProtocolManager;
53 | };
--------------------------------------------------------------------------------
/src/meson.build:
--------------------------------------------------------------------------------
1 | globber = run_command('sh', '-c', 'find . -name "*.cpp" | sort', check: true)
2 | src = globber.stdout().strip().split('\n')
3 |
4 | executable('Hyprland', src,
5 | cpp_args: ['-DWLR_USE_UNSTABLE'],
6 | link_args: '-rdynamic',
7 | cpp_pch: 'pch/pch.hpp',
8 | dependencies: [
9 | server_protos,
10 | dependency('wayland-server'),
11 | dependency('wayland-client'),
12 | wlroots.get_variable('wlroots'),
13 | dependency('cairo'),
14 | dependency('libdrm'),
15 | dependency('egl'),
16 | dependency('xkbcommon'),
17 | dependency('libinput'),
18 | xcb_dep,
19 | backtrace_dep,
20 | systemd_dep,
21 | udis86,
22 |
23 | dependency('pixman-1'),
24 | dependency('gl', 'opengl'),
25 | dependency('threads'),
26 | dependency('pango'),
27 | dependency('pangocairo')
28 | ],
29 | install : true
30 | )
31 |
--------------------------------------------------------------------------------
/src/pch/pch.hpp:
--------------------------------------------------------------------------------
1 | #include "Compositor.hpp"
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include