diff --git a/.clang-tidy b/.clang-tidy
new file mode 100644
index 00000000..db499035
--- /dev/null
+++ b/.clang-tidy
@@ -0,0 +1,208 @@
+WarningsAsErrors: >
+ -*,
+ bugprone-*,
+ -bugprone-multi-level-implicit-pointer-conversion,
+ -bugprone-empty-catch,
+ -bugprone-unused-return-value,
+ -bugprone-reserved-identifier,
+ -bugprone-switch-missing-default-case,
+ -bugprone-unused-local-non-trivial-variable,
+ -bugprone-easily-swappable-parameters,
+ -bugprone-forward-declararion-namespace,
+ -bugprone-forward-declararion-namespace,
+ -bugprone-macro-parentheses,
+ -bugprone-narrowing-conversions,
+ -bugprone-branch-clone,
+ -bugprone-assignment-in-if-condition,
+ concurrency-*,
+ -concurrency-mt-unsafe,
+ cppcoreguidelines-*,
+ -cppcoreguidelines-pro-type-const-cast,
+ -cppcoreguidelines-owning-memory,
+ -cppcoreguidelines-avoid-magic-numbers,
+ -cppcoreguidelines-pro-bounds-constant-array-index,
+ -cppcoreguidelines-avoid-const-or-ref-data-members,
+ -cppcoreguidelines-non-private-member-variables-in-classes,
+ -cppcoreguidelines-avoid-goto,
+ -cppcoreguidelines-pro-bounds-array-to-pointer-decay,
+ -cppcoreguidelines-avoid-do-while,
+ -cppcoreguidelines-avoid-non-const-global-variables,
+ -cppcoreguidelines-special-member-functions,
+ -cppcoreguidelines-explicit-virtual-functions,
+ -cppcoreguidelines-avoid-c-arrays,
+ -cppcoreguidelines-pro-bounds-pointer-arithmetic,
+ -cppcoreguidelines-narrowing-conversions,
+ -cppcoreguidelines-pro-type-union-access,
+ -cppcoreguidelines-pro-type-member-init,
+ -cppcoreguidelines-macro-usage,
+ -cppcoreguidelines-macro-to-enum,
+ -cppcoreguidelines-init-variables,
+ -cppcoreguidelines-pro-type-cstyle-cast,
+ -cppcoreguidelines-pro-type-vararg,
+ -cppcoreguidelines-pro-type-reinterpret-cast,
+ -google-global-names-in-headers,
+ -google-readability-casting,
+ google-runtime-operator,
+ misc-*,
+ -misc-use-internal-linkage,
+ -misc-unused-parameters,
+ -misc-no-recursion,
+ -misc-non-private-member-variables-in-classes,
+ -misc-include-cleaner,
+ -misc-use-anonymous-namespace,
+ -misc-const-correctness,
+ modernize-*,
+ -modernize-use-emplace,
+ -modernize-redundant-void-arg,
+ -modernize-use-starts-ends-with,
+ -modernize-use-designated-initializers,
+ -modernize-use-std-numbers,
+ -modernize-return-braced-init-list,
+ -modernize-use-trailing-return-type,
+ -modernize-use-using,
+ -modernize-use-override,
+ -modernize-avoid-c-arrays,
+ -modernize-macro-to-enum,
+ -modernize-loop-convert,
+ -modernize-use-nodiscard,
+ -modernize-pass-by-value,
+ -modernize-use-auto,
+ performance-*,
+ -performance-inefficient-vector-operation,
+ -performance-inefficient-string-concatenation,
+ -performance-enum-size,
+ -performance-move-const-arg,
+ -performance-avoid-endl,
+ -performance-unnecessary-value-param,
+ portability-std-allocator-const,
+ readability-*,
+ -readability-identifier-naming,
+ -readability-use-std-min-max,
+ -readability-math-missing-parentheses,
+ -readability-simplify-boolean-expr,
+ -readability-static-accessed-through-instance,
+ -readability-use-anyofallof,
+ -readability-enum-initial-value,
+ -readability-redundant-inline-specifier,
+ -readability-function-cognitive-complexity,
+ -readability-function-size,
+ -readability-identifier-length,
+ -readability-magic-numbers,
+ -readability-uppercase-literal-suffix,
+ -readability-braces-around-statements,
+ -readability-redundant-access-specifiers,
+ -readability-else-after-return,
+ -readability-container-data-pointer,
+ -readability-implicit-bool-conversion,
+ -readability-avoid-nested-conditional-operator,
+ -readability-redundant-member-init,
+ -readability-redundant-string-init,
+ -readability-avoid-const-params-in-decls,
+ -readability-named-parameter,
+ -readability-convert-member-functions-to-static,
+ -readability-qualified-auto,
+ -readability-make-member-function-const,
+ -readability-isolate-declaration,
+ -readability-inconsistent-declaration-parameter-name,
+ -clang-diagnostic-error,
+
+HeaderFilterRegex: '.*\.hpp'
+FormatStyle: file
+Checks: >
+ -*,
+ bugprone-*,
+ -bugprone-easily-swappable-parameters,
+ -bugprone-forward-declararion-namespace,
+ -bugprone-forward-declararion-namespace,
+ -bugprone-macro-parentheses,
+ -bugprone-narrowing-conversions,
+ -bugprone-branch-clone,
+ -bugprone-assignment-in-if-condition,
+ concurrency-*,
+ -concurrency-mt-unsafe,
+ cppcoreguidelines-*,
+ -cppcoreguidelines-owning-memory,
+ -cppcoreguidelines-avoid-magic-numbers,
+ -cppcoreguidelines-pro-bounds-constant-array-index,
+ -cppcoreguidelines-avoid-const-or-ref-data-members,
+ -cppcoreguidelines-non-private-member-variables-in-classes,
+ -cppcoreguidelines-avoid-goto,
+ -cppcoreguidelines-pro-bounds-array-to-pointer-decay,
+ -cppcoreguidelines-avoid-do-while,
+ -cppcoreguidelines-avoid-non-const-global-variables,
+ -cppcoreguidelines-special-member-functions,
+ -cppcoreguidelines-explicit-virtual-functions,
+ -cppcoreguidelines-avoid-c-arrays,
+ -cppcoreguidelines-pro-bounds-pointer-arithmetic,
+ -cppcoreguidelines-narrowing-conversions,
+ -cppcoreguidelines-pro-type-union-access,
+ -cppcoreguidelines-pro-type-member-init,
+ -cppcoreguidelines-macro-usage,
+ -cppcoreguidelines-macro-to-enum,
+ -cppcoreguidelines-init-variables,
+ -cppcoreguidelines-pro-type-cstyle-cast,
+ -cppcoreguidelines-pro-type-vararg,
+ -cppcoreguidelines-pro-type-reinterpret-cast,
+ google-global-names-in-headers,
+ -google-readability-casting,
+ google-runtime-operator,
+ misc-*,
+ -misc-unused-parameters,
+ -misc-no-recursion,
+ -misc-non-private-member-variables-in-classes,
+ -misc-include-cleaner,
+ -misc-use-anonymous-namespace,
+ -misc-const-correctness,
+ modernize-*,
+ -modernize-return-braced-init-list,
+ -modernize-use-trailing-return-type,
+ -modernize-use-using,
+ -modernize-use-override,
+ -modernize-avoid-c-arrays,
+ -modernize-macro-to-enum,
+ -modernize-loop-convert,
+ -modernize-use-nodiscard,
+ -modernize-pass-by-value,
+ -modernize-use-auto,
+ performance-*,
+ -performance-avoid-endl,
+ -performance-unnecessary-value-param,
+ portability-std-allocator-const,
+ readability-*,
+ -readability-function-cognitive-complexity,
+ -readability-function-size,
+ -readability-identifier-length,
+ -readability-magic-numbers,
+ -readability-uppercase-literal-suffix,
+ -readability-braces-around-statements,
+ -readability-redundant-access-specifiers,
+ -readability-else-after-return,
+ -readability-container-data-pointer,
+ -readability-implicit-bool-conversion,
+ -readability-avoid-nested-conditional-operator,
+ -readability-redundant-member-init,
+ -readability-redundant-string-init,
+ -readability-avoid-const-params-in-decls,
+ -readability-named-parameter,
+ -readability-convert-member-functions-to-static,
+ -readability-qualified-auto,
+ -readability-make-member-function-const,
+ -readability-isolate-declaration,
+ -readability-inconsistent-declaration-parameter-name,
+ -clang-diagnostic-error,
+
+CheckOptions:
+ performance-for-range-copy.WarnOnAllAutoCopies: true
+ performance-inefficient-string-concatenation.StrictMode: true
+ readability-braces-around-statements.ShortStatementLines: 0
+ readability-identifier-naming.ClassCase: CamelCase
+ readability-identifier-naming.ClassIgnoredRegexp: I.*
+ readability-identifier-naming.ClassPrefix: C # We can't use regex here?!?!?!?
+ readability-identifier-naming.EnumCase: CamelCase
+ readability-identifier-naming.EnumPrefix: e
+ readability-identifier-naming.EnumConstantCase: UPPER_CASE
+ readability-identifier-naming.FunctionCase: camelBack
+ readability-identifier-naming.NamespaceCase: CamelCase
+ readability-identifier-naming.NamespacePrefix: N
+ readability-identifier-naming.StructPrefix: S
+ readability-identifier-naming.StructCase: CamelCase
diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml
index 285a15a1..fd5797d5 100644
--- a/.github/ISSUE_TEMPLATE/bug.yml
+++ b/.github/ISSUE_TEMPLATE/bug.yml
@@ -1,71 +1,15 @@
-name: Bug Report
-description: Something is not working right
-labels: ["bug"]
+name: Do not open issues, go to discussions please!
+description: Do not open an issue
body:
- - type: markdown
+ - type: checkboxes
attributes:
- value: |
- Before opening a new issue, take a moment to search through the current open ones.
-
- ---
-
- - type: dropdown
- id: type
- attributes:
- label: Bug or Regression?
- description: Is this a bug or a regression?
+ label: Please close this issue.
+ description: Users cannot open issues. I want my issue to be closed.
options:
- - Bug
- - Regression
- validations:
- required: true
+ - label: Yes, I want this issue to be closed.
+ required: true
- type: textarea
- id: ver
+ id: body
attributes:
- label: System Info and Version
- description: |
- Paste the output of `hyprctl systeminfo -c` here (If you are on a
- version that shows you help menu, omit the `-c` and attach config files
- to the issue). If you have configs outside of the main config shown
- here, please attach.
- value: "
- System/Version info
-
-
- ```sh
-
-
-
- ```
-
-
- "
- validations:
- required: true
-
- - type: textarea
- id: desc
- attributes:
- label: Description
- description: "What went wrong?"
- validations:
- required: true
-
- - type: textarea
- id: repro
- attributes:
- label: How to reproduce
- description: "How can someone else reproduce the issue?"
- validations:
- required: true
-
- - type: textarea
- id: logs
- attributes:
- label: Crash reports, logs, images, videos
- description: |
- Anything that can help. Please always ATTACH and not paste them.
- Logs can be found in $XDG_RUNTIME_DIR/hypr
- Crash reports are stored in ~/.cache/hyprland or $XDG_CACHE_HOME/hyprland
-
+ label: Issue body
diff --git a/.github/ISSUE_TEMPLATE/feature.yml b/.github/ISSUE_TEMPLATE/feature.yml
deleted file mode 100644
index b34786a0..00000000
--- a/.github/ISSUE_TEMPLATE/feature.yml
+++ /dev/null
@@ -1,19 +0,0 @@
-name: Feature Request
-description: I'd like to request additional functionality
-labels: ["enhancement"]
-body:
- - type: markdown
- attributes:
- value: |
- Before opening a new issue, take a moment to search through the current open ones.
-
- ---
-
- - type: textarea
- id: desc
- attributes:
- label: Description
- description: "Describe your idea"
- validations:
- required: true
-
diff --git a/.github/actions/setup_base/action.yml b/.github/actions/setup_base/action.yml
index a7b9994c..9fcaabfb 100644
--- a/.github/actions/setup_base/action.yml
+++ b/.github/actions/setup_base/action.yml
@@ -20,9 +20,11 @@ runs:
clang \
cmake \
git \
+ glaze \
glm \
glslang \
go \
+ gtest \
hyprlang \
hyprcursor \
jq \
@@ -33,13 +35,18 @@ runs:
libfontenc \
libglvnd \
libinput \
+ libjxl \
libliftoff \
+ libspng \
+ libwebp \
+ libxcursor \
libxcvt \
libxfont2 \
libxkbcommon \
libxkbfile \
lld \
meson \
+ muparser \
ninja \
pango \
pixman \
@@ -57,7 +64,8 @@ runs:
xcb-util \
xcb-util-image \
libzip \
- librsvg
+ librsvg \
+ re2
- name: Get hyprwayland-scanner-git
shell: bash
@@ -68,11 +76,30 @@ runs:
cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
cmake --install build
+ - name: Get hyprwire-git
+ shell: bash
+ run: |
+ git clone https://github.com/hyprwm/hyprwire --recursive
+ cd hyprwire
+ cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:PATH=/usr -S . -B ./build
+ cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
+ cmake --install build
+
- name: Get hyprutils-git
shell: bash
run: |
git clone https://github.com/hyprwm/hyprutils && cd hyprutils && cmake -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:PATH=/usr -B build && cmake --build build --target hyprutils && cmake --install build
+ - name: Get hyprgraphics-git
+ shell: bash
+ run: |
+ git clone https://github.com/hyprwm/hyprgraphics && cd hyprgraphics && cmake -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:PATH=/usr -B build && cmake --build build --target hyprgraphics && cmake --install build
+
+ - name: Get aquamarine-git
+ shell: bash
+ run: |
+ git clone https://github.com/hyprwm/aquamarine && cd aquamarine && cmake -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:PATH=/usr -B build && cmake --build build --target aquamarine && cmake --install build
+
- name: Get Xorg pacman pkgs
shell: bash
if: inputs.INSTALL_XORG_PKGS == 'true'
diff --git a/.github/labeler.yml b/.github/labeler.yml
index a0685fcf..6b89255a 100644
--- a/.github/labeler.yml
+++ b/.github/labeler.yml
@@ -22,6 +22,10 @@ protocols:
- changed-files:
- any-glob-to-any-file: ["protocols/**", "src/protocols/**"]
+start:
+ - changed-files:
+ - any-glob-to-any-file: "start/**"
+
core:
- changed-files:
- any-glob-to-any-file: "src/**"
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index 073333bc..75b4b7c5 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -1,3 +1,11 @@
+
+
+
#### Describe your PR, what does it fix/add?
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 6d25e027..2ec558ed 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -3,6 +3,7 @@ name: Build Hyprland
on: [push, pull_request, workflow_dispatch]
jobs:
gcc:
+ if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork
name: "Build Hyprland (Arch)"
runs-on: ubuntu-latest
container:
@@ -20,104 +21,63 @@ jobs:
- name: Build Hyprland
run: |
- make all
+ CFLAGS=-Werror CXXFLAGS=-Werror make nopch
- name: Compress and package artifacts
run: |
mkdir x86_64-pc-linux-gnu
mkdir hyprland
- mkdir hyprland/example
- mkdir hyprland/assets
cp ./LICENSE hyprland/
cp build/Hyprland hyprland/
cp build/hyprctl/hyprctl hyprland/
cp build/hyprpm/hyprpm hyprland/
- cp build/Hyprland hyprland/
cp -r example/ hyprland/
cp -r assets/ hyprland/
- tar -cvf Hyprland.tar.xz hyprland
+ tar -cvJf Hyprland.tar.xz hyprland
- name: Release
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
name: Build archive
path: Hyprland.tar.xz
- meson:
- name: "Build Hyprland with Meson (Arch)"
- runs-on: ubuntu-latest
- container:
- image: archlinux
- steps:
- - name: Checkout repository actions
- uses: actions/checkout@v4
- with:
- sparse-checkout: .github/actions
-
- - name: Setup base
- uses: ./.github/actions/setup_base
-
- - name: Configure
- run: meson setup build -Ddefault_library=static
-
- - name: Compile
- run: ninja -C build
-
- no-pch:
- name: "Build Hyprland without precompiled headers (Arch)"
- runs-on: ubuntu-latest
- container:
- image: archlinux
- steps:
- - name: Checkout repository actions
- uses: actions/checkout@v4
- with:
- sparse-checkout: .github/actions
-
- - name: Setup base
- uses: ./.github/actions/setup_base
- with:
- INSTALL_XORG_PKGS: true
-
- - name: Compile
- run: make nopch
-
- noxwayland:
- name: "Build Hyprland in pure Wayland (Arch)"
- runs-on: ubuntu-latest
- container:
- image: archlinux
- steps:
- - name: Checkout repository actions
- uses: actions/checkout@v4
- with:
- sparse-checkout: .github/actions
-
- - name: Setup base
- uses: ./.github/actions/setup_base
-
- - name: Configure
- run: mkdir -p build && cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DNO_XWAYLAND:STRING=true -H./ -B./build -G Ninja
-
- - name: Compile
- run: make release
-
clang-format:
- name: "Code Style (Arch)"
+ permissions: read-all
+ if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork
+ name: "Code Style"
runs-on: ubuntu-latest
container:
image: archlinux
steps:
- - name: Checkout repository actions
+ - name: Checkout repository
uses: actions/checkout@v4
- with:
- sparse-checkout: .github/actions
- - name: Setup base
- uses: ./.github/actions/setup_base
+ # - name: clang-format check
+ # uses: jidicula/clang-format-action@v4.16.0
+ # with:
+ # exclude-regex: ^subprojects$
- - name: Configure
- run: meson setup build -Ddefault_library=static
+ - name: Install clang-format
+ run: |
+ pacman --noconfirm --noprogressbar -Syyu
+ pacman --noconfirm --noprogressbar -Sy clang
- name: clang-format check
- run: ninja -C build clang-format-check
+ run: .github/workflows/clang-format-check.sh "." "llvm" "^subprojects$" ""
+
+ - name: Save PR head commit SHA
+ if: failure() && github.event_name == 'pull_request'
+ shell: bash
+ run: |
+ SHA="${{ github.event.pull_request.head.sha }}"
+ echo "SHA=$SHA" >> $GITHUB_ENV
+ - name: Save latest commit SHA if not PR
+ if: failure() && github.event_name != 'pull_request'
+ shell: bash
+ run: echo "SHA=${{ github.sha }}" >> $GITHUB_ENV
+
+ - name: Report failure in job summary
+ if: failure()
+ run: |
+ DEEPLINK="${{ github.server_url }}/${{ github.repository }}/commit/${{ env.SHA }}"
+ echo -e "Format check failed on commit [${GITHUB_SHA:0:8}]($DEEPLINK) with files:\n$(<$GITHUB_WORKSPACE/failing-files.txt)" >> $GITHUB_STEP_SUMMARY
diff --git a/.github/workflows/clang-format-check.sh b/.github/workflows/clang-format-check.sh
new file mode 100755
index 00000000..41237aa7
--- /dev/null
+++ b/.github/workflows/clang-format-check.sh
@@ -0,0 +1,92 @@
+#!/usr/bin/env bash
+#
+# Adapted from https://github.com/jidicula/clang-format-action
+
+###############################################################################
+# check.sh #
+###############################################################################
+# USAGE: ./entrypoint.sh [] []
+#
+# Checks all C/C++/Protobuf/CUDA files (.h, .H, .hpp, .hh, .h++, .hxx and .c,
+# .C, .cpp, .cc, .c++, .cxx, .proto, .cu) in the provided GitHub repository path
+# (arg1) for conforming to clang-format. If no path is provided or provided path
+# is not a directory, all C/C++/Protobuf/CUDA files are checked. If any files
+# are incorrectly formatted, the script lists them and exits with 1.
+#
+# Define your own formatting rules in a .clang-format file at your repository
+# root. Otherwise, the provided style guide (arg2) is used as a fallback.
+
+# format_diff function
+# Accepts a filepath argument. The filepath passed to this function must point
+# to a C/C++/Protobuf/CUDA file.
+format_diff() {
+ local filepath="$1"
+
+ # Invoke clang-format with dry run and formatting error output
+ local_format="$(clang-format \
+ --dry-run \
+ --Werror \
+ --style=file \
+ --fallback-style="$FALLBACK_STYLE" \
+ "${filepath}")"
+
+ local format_status="$?"
+ if [[ ${format_status} -ne 0 ]]; then
+ # Append Markdown-bulleted monospaced filepath of failing file to
+ # summary file.
+ echo "* \`$filepath\`" >>failing-files.txt
+
+ echo "Failed on file: $filepath" >&2
+ echo "$local_format" >&2
+ exit_code=1 # flip the global exit code
+ return "${format_status}"
+ fi
+ return 0
+}
+
+CHECK_PATH="$1"
+FALLBACK_STYLE="$2"
+EXCLUDE_REGEX="$3"
+INCLUDE_REGEX="$4"
+
+# Set the regex to an empty string regex if nothing was provided
+if [[ -z $EXCLUDE_REGEX ]]; then
+ EXCLUDE_REGEX="^$"
+fi
+
+# Set the filetype regex if nothing was provided.
+# Find all C/C++/Protobuf/CUDA files:
+# h, H, hpp, hh, h++, hxx
+# c, C, cpp, cc, c++, cxx
+# ino, pde
+# proto
+# cu
+if [[ -z $INCLUDE_REGEX ]]; then
+ INCLUDE_REGEX='^.*\.((((c|C)(c|pp|xx|\+\+)?$)|((h|H)h?(pp|xx|\+\+)?$))|(ino|pde|proto|cu))$'
+fi
+
+cd "$GITHUB_WORKSPACE" || exit 2
+
+if [[ ! -d $CHECK_PATH ]]; then
+ echo "Not a directory in the workspace, fallback to all files." >&2
+ CHECK_PATH="."
+fi
+
+# initialize exit code
+exit_code=0
+
+# All files improperly formatted will be printed to the output.
+src_files=$(find "$CHECK_PATH" -name .git -prune -o -regextype posix-egrep -regex "$INCLUDE_REGEX" -print)
+
+# check formatting in each source file
+IFS=$'\n' # Loop below should separate on new lines, not spaces.
+for file in $src_files; do
+ # Only check formatting if the path doesn't match the regex
+ if ! [[ ${file} =~ $EXCLUDE_REGEX ]]; then
+ format_diff "${file}"
+ fi
+done
+
+# global exit code is flipped to nonzero if any invocation of `format_diff` has
+# a formatting difference.
+exit "$exit_code"
diff --git a/.github/workflows/clang-format.yml b/.github/workflows/clang-format.yml
new file mode 100644
index 00000000..505829e3
--- /dev/null
+++ b/.github/workflows/clang-format.yml
@@ -0,0 +1,28 @@
+name: clang-format
+on: pull_request_target
+jobs:
+ clang-format:
+ permissions: write-all
+ if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork
+ name: "Code Style"
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+
+ - name: clang-format check
+ uses: jidicula/clang-format-action@v4.16.0
+ with:
+ exclude-regex: ^subprojects$
+
+ - name: Create comment
+ if: ${{ failure() && github.event_name == 'pull_request' }}
+ run: |
+ echo 'Please fix the formatting issues by running [`clang-format`](https://wiki.hyprland.org/Contributing-and-Debugging/PR-Guidelines/#code-style).' > clang-format.patch
+
+ - name: Post comment
+ if: ${{ failure() && github.event_name == 'pull_request' }}
+ uses: mshick/add-pr-comment@v2
+ with:
+ message-path: |
+ clang-format.patch
diff --git a/.github/workflows/close-issues.yml b/.github/workflows/close-issues.yml
new file mode 100644
index 00000000..55f4e126
--- /dev/null
+++ b/.github/workflows/close-issues.yml
@@ -0,0 +1,101 @@
+name: Close Unauthorized Issues
+
+on:
+ workflow_dispatch:
+ issues:
+ types: [opened]
+
+jobs:
+ close-unauthorized-issues:
+ runs-on: ubuntu-latest
+ permissions:
+ issues: write
+ steps:
+ # XXX: This *could* be done in Bash by abusing GitHub's own tool to interact with its API
+ # but that's too much of a hack, and we'll be adding a layer of abstraction. github-script
+ # is a workflow that eases interaction with GitHub API in the workflow run context.
+ - name: "Close 'unauthorized' issues"
+ uses: actions/github-script@v7
+ with:
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+ script: |
+ const ALLOWED_USERS = ['vaxerski', 'fufexan', 'NotAShelf'];
+ const CLOSING_COMMENT = 'Users are no longer allowed to open issues themselves, please open a discussion instead.\n\nPlease see the [wiki](https://wiki.hyprland.org/Contributing-and-Debugging/Issue-Guidelines/) on why this is the case.\n\nWe are volunteers, and we need your cooperation to make the best software we can. Thank you for understanding! ❤️\n\n[Open a discussion here](https://github.com/hyprwm/Hyprland/discussions)';
+
+ async function closeUnauthorizedIssue(issueNumber, userName) {
+ if (ALLOWED_USERS.includes(userName)) {
+ console.log(`Issue #${issueNumber} - Created by authorized user ${userName}`);
+ return;
+ }
+
+ console.log(`Issue #${issueNumber} - Unauthorized, closing`);
+
+ await github.rest.issues.update({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: issueNumber,
+ state: 'closed',
+ state_reason: 'not_planned'
+ });
+
+ await github.rest.issues.createComment({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: issueNumber,
+ body: CLOSING_COMMENT
+ });
+ }
+
+ if (context.eventName === 'issues' && context.payload.action === 'opened') {
+ // Direct access to the issue that triggered the workflow
+ const issue = context.payload.issue;
+
+ // Skip if this is a PR
+ if (issue.pull_request) {
+ console.log(`Issue #${issue.number} - Skipping, this is a pull request`);
+ return;
+ }
+
+ // Process the single issue that triggered the workflow
+ await closeUnauthorizedIssue(issue.number, issue.user.login);
+ } else {
+ // For manual runs, we need to handle pagination
+ async function* fetchAllOpenIssues() {
+ let page = 1;
+ let hasNextPage = true;
+
+ while (hasNextPage) {
+ const response = await github.rest.issues.listForRepo({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ state: 'open',
+ per_page: 100,
+ page: page
+ });
+
+ if (response.data.length === 0) {
+ hasNextPage = false;
+ } else {
+ for (const issue of response.data) {
+ yield issue;
+ }
+ page++;
+ }
+ }
+ }
+
+ // Process issues one by one
+ for await (const issue of fetchAllOpenIssues()) {
+ try {
+ // Skip pull requests
+ if (issue.pull_request) {
+ console.log(`Issue #${issue.number} - Skipping, this is a pull request`);
+ continue;
+ }
+
+ await closeUnauthorizedIssue(issue.number, issue.user.login);
+ } catch (error) {
+ console.error(`Error processing issue #${issue.number}: ${error.message}`);
+ }
+ }
+ }
diff --git a/.github/workflows/man-update.yaml b/.github/workflows/man-update.yaml
index b47787c0..6c0a72f3 100644
--- a/.github/workflows/man-update.yaml
+++ b/.github/workflows/man-update.yaml
@@ -17,14 +17,14 @@ jobs:
run: sudo apt install pandoc
- name: Clone repository
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
token: ${{ secrets.PAT }}
- name: Build man pages
run: make man
- - uses: stefanzweifel/git-auto-commit-action@v4
+ - uses: stefanzweifel/git-auto-commit-action@v5
name: Commit
with:
commit_message: "[gha] build man pages"
diff --git a/.github/workflows/new-pr-comment.yml b/.github/workflows/new-pr-comment.yml
new file mode 100644
index 00000000..36ea1909
--- /dev/null
+++ b/.github/workflows/new-pr-comment.yml
@@ -0,0 +1,45 @@
+name: "New MR welcome comment"
+
+on:
+ pull_request_target:
+ types:
+ - opened
+
+jobs:
+ comment:
+ if: >
+ github.event.pull_request.user.login != 'vaxerski' &&
+ github.event.pull_request.user.login != 'fufexan' &&
+ github.event.pull_request.user.login != 'gulafaran' &&
+ github.event.pull_request.user.login != 'ujint34' &&
+ github.event.pull_request.user.login != 'paideiadilemma' &&
+ github.event.pull_request.user.login != 'notashelf'
+ runs-on: ubuntu-latest
+ permissions:
+ pull-requests: write
+
+ env:
+ PR_COMMENT: |
+ Hello and thank you for making a PR to Hyprland!
+
+ Please check the [PR Guidelines](https://wiki.hypr.land/Contributing-and-Debugging/PR-Guidelines/) and make sure your PR follows them.
+ It will make the entire review process faster. :)
+
+ If your code can be tested, please always add tests. See more [here](https://wiki.hypr.land/Contributing-and-Debugging/Tests/).
+
+ _beep boop, I'm just a bot. A real human will review your PR soon._
+
+ steps:
+ - name: Add comment to PR
+ uses: actions/github-script@v7
+ with:
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+ script: |
+ const pr = context.payload.pull_request;
+
+ await github.rest.issues.createComment({
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ issue_number: pr.number,
+ body: process.env.PR_COMMENT,
+ });
diff --git a/.github/workflows/nix-build.yml b/.github/workflows/nix-build.yml
deleted file mode 100644
index 33ee5cac..00000000
--- a/.github/workflows/nix-build.yml
+++ /dev/null
@@ -1,30 +0,0 @@
-on:
- workflow_call:
- secrets:
- CACHIX_AUTH_TOKEN:
- required: false
-
-jobs:
- build:
- strategy:
- matrix:
- package:
- - hyprland
- - xdg-desktop-portal-hyprland
-
- runs-on: ubuntu-latest
- steps:
- - name: Clone repository
- uses: actions/checkout@v3
- with:
- ref: ${{ github.ref }}
- submodules: recursive
-
- - uses: cachix/install-nix-action@v26
- - uses: DeterminateSystems/magic-nix-cache-action@main
- - uses: cachix/cachix-action@v12
- with:
- name: hyprland
- authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
-
- - run: nix build '.?submodules=1#${{ matrix.package }}' -L --extra-substituters "https://hyprland.cachix.org"
diff --git a/.github/workflows/nix-ci.yml b/.github/workflows/nix-ci.yml
index a66307c4..5b22e992 100644
--- a/.github/workflows/nix-ci.yml
+++ b/.github/workflows/nix-ci.yml
@@ -4,12 +4,26 @@ on: [push, pull_request, workflow_dispatch]
jobs:
update-inputs:
- if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
+ if: (github.event_name == 'push' || github.event_name == 'workflow_dispatch')
uses: ./.github/workflows/nix-update-inputs.yml
secrets: inherit
- build:
- if: always() && !cancelled() && !contains(needs.*.result, 'failure')
- needs: update-inputs
- uses: ./.github/workflows/nix-build.yml
+ hyprland:
+ if: (github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork)
+ uses: ./.github/workflows/nix.yml
+ secrets: inherit
+ with:
+ command: nix build 'github:${{ github.repository }}?ref=${{ github.ref }}' -L --extra-substituters "https://hyprland.cachix.org"
+
+ xdph:
+ if: (github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork)
+ needs: hyprland
+ uses: ./.github/workflows/nix.yml
+ secrets: inherit
+ with:
+ command: nix build 'github:${{ github.repository }}?ref=${{ github.ref }}#xdg-desktop-portal-hyprland' -L --extra-substituters "https://hyprland.cachix.org"
+
+ test:
+ if: (github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork)
+ uses: ./.github/workflows/nix-test.yml
secrets: inherit
diff --git a/.github/workflows/nix-test.yml b/.github/workflows/nix-test.yml
new file mode 100644
index 00000000..68357093
--- /dev/null
+++ b/.github/workflows/nix-test.yml
@@ -0,0 +1,47 @@
+name: Nix (Test)
+
+on:
+ workflow_call:
+ secrets:
+ CACHIX_AUTH_TOKEN:
+ required: false
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Install Nix
+ uses: nixbuild/nix-quick-install-action@v31
+ with:
+ nix_conf: |
+ keep-env-derivations = true
+ keep-outputs = true
+
+ - name: Restore and save Nix store
+ uses: nix-community/cache-nix-action@v6
+ with:
+ # restore and save a cache using this key (per job)
+ primary-key: nix-${{ runner.os }}-${{ github.job }}
+ # if there's no cache hit, restore a cache by this prefix
+ restore-prefixes-first-match: nix-${{ runner.os }}
+ # collect garbage until the Nix store size (in bytes) is at most this number
+ # before trying to save a new cache
+ gc-max-store-size-linux: 5G
+
+ - uses: cachix/cachix-action@v15
+ with:
+ name: hyprland
+ authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
+
+ - name: Run test VM
+ run: nix build 'github:${{ github.repository }}?ref=${{ github.ref }}#checks.x86_64-linux.tests' -L --extra-substituters "https://hyprland.cachix.org"
+
+ - name: Check exit status
+ run: grep 0 result/exit_status
+
+ - name: Upload artifacts
+ if: always()
+ uses: actions/upload-artifact@v4
+ with:
+ name: logs
+ path: result
diff --git a/.github/workflows/nix-update-inputs.yml b/.github/workflows/nix-update-inputs.yml
index 000900d9..a3084b27 100644
--- a/.github/workflows/nix-update-inputs.yml
+++ b/.github/workflows/nix-update-inputs.yml
@@ -1,4 +1,4 @@
-name: Nix
+name: Nix (Update Inputs)
on:
workflow_call:
@@ -8,19 +8,37 @@ on:
jobs:
update:
+ if: github.repository == 'hyprwm/Hyprland'
name: inputs
runs-on: ubuntu-latest
steps:
- name: Clone repository
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
with:
token: ${{ secrets.PAT }}
- - uses: DeterminateSystems/nix-installer-action@main
+ - name: Install Nix
+ uses: nixbuild/nix-quick-install-action@v31
+ with:
+ nix_conf: |
+ keep-env-derivations = true
+ keep-outputs = true
+
+ - name: Restore and save Nix store
+ uses: nix-community/cache-nix-action@v6
+ with:
+ # restore and save a cache using this key (per job)
+ primary-key: nix-${{ runner.os }}-${{ github.job }}
+ # if there's no cache hit, restore a cache by this prefix
+ restore-prefixes-first-match: nix-${{ runner.os }}
+ # collect garbage until the Nix store size (in bytes) is at most this number
+ # before trying to save a new cache
+ gc-max-store-size-linux: 5G
+
- name: Update inputs
run: nix/update-inputs.sh
- name: Commit
- uses: stefanzweifel/git-auto-commit-action@v4
+ uses: stefanzweifel/git-auto-commit-action@v5
with:
commit_message: "[gha] Nix: update inputs"
diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml
new file mode 100644
index 00000000..b46b3795
--- /dev/null
+++ b/.github/workflows/nix.yml
@@ -0,0 +1,41 @@
+name: Build
+
+on:
+ workflow_call:
+ inputs:
+ command:
+ required: true
+ type: string
+ description: Command to run
+ secrets:
+ CACHIX_AUTH_TOKEN:
+ required: false
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Install Nix
+ uses: nixbuild/nix-quick-install-action@v31
+ with:
+ nix_conf: |
+ keep-env-derivations = true
+ keep-outputs = true
+
+ - name: Restore and save Nix store
+ uses: nix-community/cache-nix-action@v6
+ with:
+ # restore and save a cache using this key (per job)
+ primary-key: nix-${{ runner.os }}-${{ github.job }}
+ # if there's no cache hit, restore a cache by this prefix
+ restore-prefixes-first-match: nix-${{ runner.os }}
+ # collect garbage until the Nix store size (in bytes) is at most this number
+ # before trying to save a new cache
+ gc-max-store-size-linux: 5G
+
+ - uses: cachix/cachix-action@v15
+ with:
+ name: hyprland
+ authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}"
+
+ - run: ${{ inputs.command }}
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index 1f52b4ff..09aae111 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -9,18 +9,36 @@ jobs:
source-tarball:
runs-on: ubuntu-latest
steps:
- - name: Checkout Hyprland
- id: checkout
- uses: actions/checkout@v3
+ - name: Checkout repository
+ uses: actions/checkout@v5
with:
+ fetch-depth: 0
submodules: recursive
- - name: Generate version
- id: genversion
+ - name: Populate git info in version.h.in
run: |
- git fetch --unshallow || echo "failed unshallowing"
- bash -c scripts/generateVersion.sh
- mv scripts/generateVersion.sh scripts/generateVersion.sh.bak
+ git fetch --tags --unshallow || true
+
+ COMMIT_HASH=$(git rev-parse HEAD)
+ BRANCH="${GITHUB_REF_NAME:-$(git rev-parse --abbrev-ref HEAD)}"
+ COMMIT_MSG=$(git show -s --format=%s | sed 's/[&/]/\\&/g')
+ COMMIT_DATE=$(git show -s --format=%cd --date=local)
+ GIT_DIRTY=$(git diff-index --quiet HEAD -- && echo "clean" || echo "dirty")
+ GIT_TAG=$(git describe --tags --always || echo "unknown")
+ GIT_COMMITS=$(git rev-list --count HEAD)
+
+ echo "Branch: $BRANCH"
+ echo "Tag: $GIT_TAG"
+
+ sed -i \
+ -e "s|@GIT_COMMIT_HASH@|$COMMIT_HASH|" \
+ -e "s|@GIT_BRANCH@|$BRANCH|" \
+ -e "s|@GIT_COMMIT_MESSAGE@|$COMMIT_MSG|" \
+ -e "s|@GIT_COMMIT_DATE@|$COMMIT_DATE|" \
+ -e "s|@GIT_DIRTY@|$GIT_DIRTY|" \
+ -e "s|@GIT_TAG@|$GIT_TAG|" \
+ -e "s|@GIT_COMMITS@|$GIT_COMMITS|" \
+ src/version.h.in
- name: Create tarball with submodules
id: tar
diff --git a/.github/workflows/security-checks.yml b/.github/workflows/security-checks.yml
index 564013cf..284500e6 100644
--- a/.github/workflows/security-checks.yml
+++ b/.github/workflows/security-checks.yml
@@ -4,6 +4,7 @@ on: [push, pull_request]
jobs:
flawfinder:
+ if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork
name: Flawfinder Checks
runs-on: ubuntu-latest
permissions:
@@ -12,7 +13,7 @@ jobs:
security-events: write
steps:
- name: Checkout code
- uses: actions/checkout@v3
+ uses: actions/checkout@v4
- name: Scan with Flawfinder
uses: david-a-wheeler/flawfinder@8e4a779ad59dbfaee5da586aa9210853b701959c
diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml
deleted file mode 100644
index 51f6b91e..00000000
--- a/.github/workflows/stale.yml
+++ /dev/null
@@ -1,28 +0,0 @@
-# This workflow warns and then closes issues and PRs that have had no activity for a specified amount of time.
-#
-# You can adjust the behavior by modifying this file.
-# For more information, see:
-# https://github.com/actions/stale
-name: Mark stale issues and pull requests
-
-on:
- schedule:
- - cron: '7 */4 * * *'
- workflow_dispatch:
-
-jobs:
- stale:
-
- runs-on: ubuntu-latest
- permissions:
- issues: write
- pull-requests: write
-
- steps:
- - uses: actions/stale@v5
- with:
- repo-token: ${{ secrets.STALEBOT_PAT }}
- stale-issue-label: 'stale'
- stale-pr-label: 'stale'
- operations-per-run: 40
- days-before-close: -1
diff --git a/.github/workflows/translation-ai-check.yml b/.github/workflows/translation-ai-check.yml
new file mode 100644
index 00000000..d6a62a60
--- /dev/null
+++ b/.github/workflows/translation-ai-check.yml
@@ -0,0 +1,139 @@
+name: AI Translation Check
+
+on:
+ # pull_request_target:
+ # types:
+ # - opened
+ issue_comment:
+ types:
+ - created
+
+permissions:
+ contents: read
+ pull-requests: write
+ issues: write
+
+jobs:
+ review:
+ name: Review Translation
+ if: ${{ github.event_name == 'pull_request_target' || (github.event_name == 'issue_comment' && github.event.action == 'created' && github.event.issue.pull_request != null && github.event.comment.user.login == 'vaxerski' && github.event.comment.body == 'ai, please recheck' ) }}
+ runs-on: ubuntu-latest
+ env:
+ OPENAI_MODEL: gpt-5-mini
+ SYSTEM_PROMPT: |
+ You are a programmer and a translator. Your job is to review the attached patch for adding translation to a piece of software and make sure the submitted translation is not malicious, and that it makes sense. If the translation is not malicious, and doesn't contain obvious grammatical mistakes, say "Translation check OK". Otherwise, say "Translation check not ok" and list bad entries.
+ Examples of bad translations include obvious trolling (slurs, etc) or nonsense sentences. Meaningful improvements may be suggested, but if there are only minor improvements, just reply with "Translation check OK". Do not provide anything but the result and (if applicable) the bad entries or improvements.
+
+ AI_PROMPT: Translation patch below.
+
+ steps:
+ - name: Checkout source code
+ uses: actions/checkout@v5
+
+ - uses: dorny/paths-filter@v3
+ id: changes
+ with:
+ filters: |
+ i18n:
+ - 'src/i18n/**'
+
+ - name: Stop if i18n not changed
+ if: steps.changes.outputs.i18n != 'true'
+ run: echo "No i18n changes in this PR; skipping." && exit 0
+
+ - name: Determine PR number
+ id: pr
+ run: |
+ if [ "${{ github.event_name }}" = "pull_request_target" ]; then
+ echo "number=${{ github.event.pull_request.number }}" >> "$GITHUB_OUTPUT"
+ else
+ echo "number=${{ github.event.issue.number }}" >> "$GITHUB_OUTPUT"
+ fi
+
+ - name: Download combined PR diff
+ id: get_diff
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ PR_NUMBER: ${{ steps.pr.outputs.number }}
+ run: |
+ # Get the combined diff for the entire PR
+ curl -sSL \
+ -H "Authorization: token $GITHUB_TOKEN" \
+ -H "Accept: application/vnd.github.v3.diff" \
+ "https://api.github.com/repos/${{ github.repository }}/pulls/$PR_NUMBER" \
+ -o pr.diff
+
+ # Compute character length
+ LEN=$(wc -c < pr.diff | tr -d ' ')
+ echo "len=$LEN" >> "$GITHUB_OUTPUT"
+ if [ "$LEN" -gt 25000 ]; then
+ echo "too_long=true" >> "$GITHUB_OUTPUT"
+ else
+ echo "too_long=false" >> "$GITHUB_OUTPUT"
+ fi
+
+ echo "got diff:"
+ cat pr.diff
+
+ - name: Comment when diff length exceeded
+ if: steps.get_diff.outputs.too_long == 'true'
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ PR_NUMBER: ${{ steps.pr.outputs.number }}
+ run: |
+ jq -n --arg body "Diff length exceeded, can't query API" '{body: ("AI translation check result:\n\n" + $body)}' > body.json
+ curl -sS -X POST \
+ -H "Authorization: token $GITHUB_TOKEN" \
+ -H "Content-Type: application/json" \
+ "https://api.github.com/repos/${{ github.repository }}/issues/$PR_NUMBER/comments" \
+ --data @body.json
+
+ - name: Query OpenAI and post review
+ if: steps.get_diff.outputs.too_long == 'false'
+ env:
+ OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
+ OPENAI_MODEL: ${{ env.OPENAI_MODEL }}
+ SYSTEM_PROMPT: ${{ env.SYSTEM_PROMPT }}
+ AI_PROMPT: ${{ env.AI_PROMPT }}
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ PR_NUMBER: ${{ steps.pr.outputs.number }}
+ run: |
+ # Prepare OpenAI chat request payload (embed diff safely)
+ jq -n \
+ --arg model "$OPENAI_MODEL" \
+ --arg sys "$SYSTEM_PROMPT" \
+ --arg prompt "$AI_PROMPT" \
+ --rawfile diff pr.diff \
+ '{model:$model,
+ messages:[
+ {role:"system", content:$sys},
+ {role:"user", content: ($prompt + "\n\n```diff\n" + $diff + "\n```")}
+ ]
+ }' > payload.json
+
+ # Call OpenAI
+ curl -sS https://api.openai.com/v1/chat/completions \
+ -H "Authorization: Bearer $OPENAI_API_KEY" \
+ -H "Content-Type: application/json" \
+ -d @payload.json > response.json
+
+ # Extract response text
+ COMMENT=$(jq -r '.choices[0].message.content // empty' response.json)
+ if [ -z "$COMMENT" ]; then
+ COMMENT="AI did not return a response."
+ fi
+
+ # If failed, add a note
+ ADDITIONAL_NOTE=""
+ if [[ "$COMMENT" == *"not ok"* ]]; then
+ ADDITIONAL_NOTE=$(echo -ne "\n\nPlease note this check is a guideline, not a hard requirement. It is here to help you translate. If you disagree with some points, just state that. Any typos should be fixed.")
+ fi
+
+ # Post the review as a PR comment
+ jq -n --arg body "$COMMENT" --arg note "$ADDITIONAL_NOTE" '{body: ("AI translation check result:\n\n" + $body + $note)}' > body.json
+ echo "CURLing https://api.github.com/repos/${{ github.repository }}/issues/$PR_NUMBER/comments"
+ curl -sS -X POST \
+ -H "Authorization: token $GITHUB_TOKEN" \
+ -H "Content-Type: application/json" \
+ "https://api.github.com/repos/${{ github.repository }}/issues/$PR_NUMBER/comments" \
+ --data @body.json
diff --git a/.gitignore b/.gitignore
index 3601f422..4e5c2323 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,22 +7,33 @@ cmake_install.cmake
install_manifest.txt
compile_commands.json
CTestTestfile.cmake
+CPackConfig.cmake
+CPackSourceConfig.cmake
+hyprland.pc
_deps
build/
result*
+/.pre-commit-config.yaml
/.vscode/
/.idea/
.envrc
.cache
+.direnv
+/.cmake/
+/.worktree/
*.o
protocols/*.c*
protocols/*.h*
.ccls-cache
*.so
+src/render/shaders/*.inc
+src/render/shaders/Shaders.hpp
hyprctl/hyprctl
+hyprctl/hw-protocols/*.c*
+hyprctl/hw-protocols/*.h*
gmon.out
*.out
@@ -31,5 +42,9 @@ gmon.out
PKGBUILD
src/version.h
+hyprpm/Makefile
+hyprctl/Makefile
+example/hyprland.desktop
-.direnv
+**/.#*.*
+**/#*.*#
diff --git a/.gitmodules b/.gitmodules
index 37b48a5a..638f8ba9 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -7,7 +7,3 @@
[submodule "subprojects/tracy"]
path = subprojects/tracy
url = https://github.com/wolfpld/tracy
-[submodule "subprojects/wlroots-hyprland"]
- path = subprojects/wlroots-hyprland
- url = https://github.com/hyprwm/wlroots-hyprland
- ignore = dirty
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 7aa2bf5c..87574b82 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,98 +1,120 @@
-cmake_minimum_required(VERSION 3.27)
-
-include(CheckIncludeFile)
-include(ExternalProject)
-include(GNUInstallDirs)
+cmake_minimum_required(VERSION 3.30)
# Get version
-file(READ ${CMAKE_CURRENT_SOURCE_DIR}/props.json PROPS)
-string(JSON VER GET ${PROPS} version)
+file(READ "${CMAKE_SOURCE_DIR}/VERSION" VER_RAW)
+string(STRIP ${VER_RAW} VER)
-project(Hyprland
- DESCRIPTION "A Modern C++ Wayland Compositor"
- VERSION ${VER}
-)
+project(
+ Hyprland
+ DESCRIPTION "A Modern C++ Wayland Compositor"
+ VERSION ${VER})
+
+include(CTest)
+include(CheckIncludeFile)
+include(GNUInstallDirs)
set(HYPRLAND_VERSION ${VER})
set(PREFIX ${CMAKE_INSTALL_PREFIX})
set(INCLUDEDIR ${CMAKE_INSTALL_INCLUDEDIR})
-configure_file(hyprland.pc.in hyprland.pc @ONLY)
+set(BINDIR ${CMAKE_INSTALL_BINDIR})
set(CMAKE_MESSAGE_LOG_LEVEL "STATUS")
message(STATUS "Gathering git info")
-# Get git info
-# hash and branch
-execute_process(
- COMMAND ./scripts/generateVersion.sh
- WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
-
-# udis
-add_subdirectory("subprojects/udis86")
-
-# wlroots
-message(STATUS "Setting up wlroots")
-
-if(CMAKE_BUILD_TYPE)
- string(TOLOWER ${CMAKE_BUILD_TYPE} BUILDTYPE_LOWER)
- if(BUILDTYPE_LOWER STREQUAL "release")
- # Pass.
- elseif(BUILDTYPE_LOWER STREQUAL "debug")
- # Pass.
- elseif(BUILDTYPE_LOWER STREQUAL "relwithdebinfo")
- set(BUILDTYPE_LOWER "debugoptimized")
- elseif(BUILDTYPE_LOWER STREQUAL "minsizerel")
- set(BUILDTYPE_LOWER "minsize")
- elseif(BUILDTYPE_LOWER STREQUAL "none")
- set(BUILDTYPE_LOWER "plain")
- else()
- set(BUILDTYPE_LOWER "release")
- endif()
-else()
- set(BUILDTYPE_LOWER "release")
+# Make shader files includable
+execute_process(COMMAND ./scripts/generateShaderIncludes.sh
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+ RESULT_VARIABLE HYPR_SHADER_GEN_RESULT)
+if(NOT HYPR_SHADER_GEN_RESULT EQUAL 0)
+ message(
+ FATAL_ERROR
+ "Failed to generate shader includes (scripts/generateShaderIncludes.sh), exit code: ${HYPR_SHADER_GEN_RESULT}"
+ )
endif()
-ExternalProject_Add(
- wlroots-hyprland
- PREFIX ${CMAKE_SOURCE_DIR}/subprojects/wlroots-hyprland
- SOURCE_DIR ${CMAKE_SOURCE_DIR}/subprojects/wlroots-hyprland
- CONFIGURE_COMMAND meson setup --reconfigure build --buildtype=${BUILDTYPE_LOWER} -Dwerror=false -Dxwayland=$,disabled,enabled> -Dexamples=false -Drenderers=gles2 -Dbackends=drm,libinput $,-Db_sanitize=address,-Db_sanitize=none>
- BUILD_COMMAND ninja -C build
- BUILD_ALWAYS true
- BUILD_IN_SOURCE true
- BUILD_BYPRODUCTS ${CMAKE_SOURCE_DIR}/subprojects/wlroots-hyprland/build/libwlroots.a
- INSTALL_COMMAND echo "wlroots-hyprland: install not needed"
-)
-
find_package(PkgConfig REQUIRED)
-pkg_get_variable(WaylandScanner wayland-scanner wayland_scanner)
-message(STATUS "Found WaylandScanner at ${WaylandScanner}")
-pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir)
-message(STATUS "Found wayland-protocols at ${WAYLAND_PROTOCOLS_DIR}")
-pkg_get_variable(WAYLAND_SERVER_DIR wayland-server pkgdatadir)
+# Try to find canihavesomecoffee's udis86 using pkgconfig vmd/udis86 does not
+# provide a .pc file and won't be detected this way
+pkg_check_modules(udis_dep IMPORTED_TARGET udis86>=1.7.2)
-if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
- message(STATUS "Configuring Hyprland in Debug with CMake")
- add_compile_definitions(HYPRLAND_DEBUG)
-else()
- add_compile_options(-O3)
- message(STATUS "Configuring Hyprland in Release with CMake")
+# Find non-pkgconfig udis86, otherwise fallback to subproject
+if(NOT udis_dep_FOUND)
+ find_library(udis_nopc udis86)
+ if(NOT("${udis_nopc}" MATCHES "udis_nopc-NOTFOUND"))
+ message(STATUS "Found udis86 at ${udis_nopc}")
+ else()
+ add_subdirectory("subprojects/udis86")
+ include_directories("subprojects/udis86")
+ message(STATUS "udis86 dependency not found, falling back to subproject")
+ endif()
endif()
-include_directories(
- .
- "src/"
- "subprojects/wlroots-hyprland/include/"
- "subprojects/wlroots-hyprland/build/include/"
- "subprojects/udis86/"
- "protocols/")
-set(CMAKE_CXX_STANDARD 23)
-add_compile_definitions(WLR_USE_UNSTABLE)
-add_compile_options(-Wall -Wextra -Wno-unused-parameter -Wno-unused-value
- -Wno-missing-field-initializers -Wno-narrowing -Wno-pointer-arith
- -fmacro-prefix-map=${CMAKE_SOURCE_DIR}/=)
+find_library(librt rt)
+if("${librt}" MATCHES "librt-NOTFOUND")
+ unset(LIBRT)
+else()
+ set(LIBRT rt)
+endif()
+
+if(CMAKE_BUILD_TYPE)
+ string(TOLOWER ${CMAKE_BUILD_TYPE} BUILDTYPE_LOWER)
+ if(BUILDTYPE_LOWER STREQUAL "release")
+ # Pass.
+ elseif(BUILDTYPE_LOWER STREQUAL "debug")
+ # Pass.
+ elseif(BUILDTYPE_LOWER STREQUAL "relwithdebinfo")
+ set(BUILDTYPE_LOWER "debugoptimized")
+ elseif(BUILDTYPE_LOWER STREQUAL "minsizerel")
+ set(BUILDTYPE_LOWER "minsize")
+ elseif(BUILDTYPE_LOWER STREQUAL "none")
+ set(BUILDTYPE_LOWER "plain")
+ else()
+ set(BUILDTYPE_LOWER "release")
+ endif()
+else()
+ set(BUILDTYPE_LOWER "release")
+endif()
+
+pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir)
+message(STATUS "Found wayland-protocols at ${WAYLAND_PROTOCOLS_DIR}")
+pkg_get_variable(WAYLAND_SCANNER_PKGDATA_DIR wayland-scanner pkgdatadir)
+message(
+ STATUS "Found wayland-scanner pkgdatadir at ${WAYLAND_SCANNER_PKGDATA_DIR}")
+
+if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
+ message(STATUS "Configuring Hyprland in Debug with CMake")
+ add_compile_definitions(HYPRLAND_DEBUG)
+ set(BUILD_TESTING ON)
+else()
+ add_compile_options(-O3)
+ message(STATUS "Configuring Hyprland in Release with CMake")
+ set(BUILD_TESTING OFF)
+endif()
+
+add_compile_definitions(HYPRLAND_VERSION="${HYPRLAND_VERSION}")
+
+include_directories(. "src/" "protocols/")
+
+set(CMAKE_CXX_STANDARD 26)
+set(CXX_STANDARD_REQUIRED ON)
+add_compile_options(
+ -Wall
+ -Wextra
+ -Wpedantic
+ -Wno-unused-parameter
+ -Wno-unused-value
+ -Wno-missing-field-initializers
+ -Wno-gnu-zero-variadic-macro-arguments
+ -Wno-narrowing
+ -Wno-pointer-arith
+ -Wno-clobbered
+ -frtti
+ -fmacro-prefix-map=${CMAKE_SOURCE_DIR}/=)
+
+# disable lto as it may break plugins
+add_compile_options(-fno-lto)
set(CMAKE_EXECUTABLE_ENABLE_EXPORTS TRUE)
set(CMAKE_EXPORT_COMPILE_COMMANDS TRUE)
@@ -101,283 +123,558 @@ message(STATUS "Checking deps...")
find_package(Threads REQUIRED)
-if(LEGACY_RENDERER)
- set(GLES_VERSION "GLES2")
-else()
- set(GLES_VERSION "GLES3")
-endif()
+set(GLES_VERSION "GLES3")
find_package(OpenGL REQUIRED COMPONENTS ${GLES_VERSION})
+find_package(glslang CONFIG REQUIRED)
-pkg_check_modules(deps REQUIRED IMPORTED_TARGET
- xkbcommon uuid
- wayland-server wayland-client wayland-cursor wayland-protocols
- cairo pango pangocairo pixman-1
- libdrm libinput hwdata libseat libdisplay-info libliftoff libudev gbm
- hyprlang>=0.3.2 hyprcursor>=0.1.7 hyprutils>=0.1.1
+set(AQUAMARINE_MINIMUM_VERSION 0.9.3)
+set(HYPRLANG_MINIMUM_VERSION 0.6.7)
+set(HYPRCURSOR_MINIMUM_VERSION 0.1.7)
+set(HYPRUTILS_MINIMUM_VERSION 0.11.0)
+set(HYPRGRAPHICS_MINIMUM_VERSION 0.1.6)
+
+pkg_check_modules(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine>=${AQUAMARINE_MINIMUM_VERSION})
+pkg_check_modules(hyprlang_dep REQUIRED IMPORTED_TARGET hyprlang>=${HYPRLANG_MINIMUM_VERSION})
+pkg_check_modules(hyprcursor_dep REQUIRED IMPORTED_TARGET hyprcursor>=${HYPRCURSOR_MINIMUM_VERSION})
+pkg_check_modules(hyprutils_dep REQUIRED IMPORTED_TARGET hyprutils>=${HYPRUTILS_MINIMUM_VERSION})
+pkg_check_modules(hyprgraphics_dep REQUIRED IMPORTED_TARGET hyprgraphics>=${HYPRGRAPHICS_MINIMUM_VERSION})
+
+string(REPLACE "." ";" AQ_VERSION_LIST ${aquamarine_dep_VERSION})
+list(GET AQ_VERSION_LIST 0 AQ_VERSION_MAJOR)
+list(GET AQ_VERSION_LIST 1 AQ_VERSION_MINOR)
+list(GET AQ_VERSION_LIST 2 AQ_VERSION_PATCH)
+
+set(AQUAMARINE_VERSION "${aquamarine_dep_VERSION}")
+set(AQUAMARINE_VERSION_MAJOR "${AQ_VERSION_MAJOR}")
+set(AQUAMARINE_VERSION_MINOR "${AQ_VERSION_MINOR}")
+set(AQUAMARINE_VERSION_PATCH "${AQ_VERSION_PATCH}")
+set(HYPRLANG_VERSION "${hyprlang_dep_VERSION}")
+set(HYPRUTILS_VERSION "${hyprutils_dep_VERSION}")
+set(HYPRCURSOR_VERSION "${hyprcursor_dep_VERSION}")
+set(HYPRGRAPHICS_VERSION "${hyprgraphics_dep_VERSION}")
+
+
+find_package(Git QUIET)
+
+# Populate variables with env vars if present
+set(GIT_COMMIT_HASH "$ENV{GIT_COMMIT_HASH}")
+if(NOT GIT_COMMIT_HASH)
+ set(GIT_COMMIT_HASH "unknown")
+endif()
+
+set(GIT_BRANCH "$ENV{GIT_BRANCH}")
+if(NOT GIT_BRANCH)
+ set(GIT_BRANCH "unknown")
+endif()
+
+set(GIT_COMMIT_MESSAGE "$ENV{GIT_COMMIT_MESSAGE}")
+if(NOT GIT_COMMIT_MESSAGE)
+ set(GIT_COMMIT_MESSAGE "unknown")
+endif()
+
+set(GIT_COMMIT_DATE "$ENV{GIT_COMMIT_DATE}")
+if(NOT GIT_COMMIT_DATE)
+ set(GIT_COMMIT_DATE "unknown")
+endif()
+
+set(GIT_DIRTY "$ENV{GIT_DIRTY}")
+if(NOT GIT_DIRTY)
+ set(GIT_DIRTY "unknown")
+endif()
+
+set(GIT_TAG "$ENV{GIT_TAG}")
+if(NOT GIT_TAG)
+ set(GIT_TAG "unknown")
+endif()
+
+set(GIT_COMMITS "$ENV{GIT_COMMITS}")
+if(NOT GIT_COMMITS)
+ set(GIT_COMMITS "0")
+endif()
+
+if(Git_FOUND)
+ execute_process(
+ COMMAND ${GIT_EXECUTABLE} rev-parse --show-toplevel
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+ OUTPUT_VARIABLE GIT_TOPLEVEL
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ ERROR_QUIET
+ RESULT_VARIABLE GIT_TOPLEVEL_RESULT
+ )
+
+ if(GIT_TOPLEVEL_RESULT EQUAL 0)
+ message(STATUS "Detected git repository root: ${GIT_TOPLEVEL}")
+
+ execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse HEAD
+ WORKING_DIRECTORY ${GIT_TOPLEVEL}
+ OUTPUT_VARIABLE GIT_COMMIT_HASH OUTPUT_STRIP_TRAILING_WHITESPACE)
+ execute_process(COMMAND ${GIT_EXECUTABLE} branch --show-current
+ WORKING_DIRECTORY ${GIT_TOPLEVEL}
+ OUTPUT_VARIABLE GIT_BRANCH OUTPUT_STRIP_TRAILING_WHITESPACE)
+ execute_process(COMMAND sh "-c" "${GIT_EXECUTABLE} show -s --format=%s --no-show-signature | sed \"s/\\\"/\'/g\""
+ WORKING_DIRECTORY ${GIT_TOPLEVEL}
+ OUTPUT_VARIABLE GIT_COMMIT_MESSAGE OUTPUT_STRIP_TRAILING_WHITESPACE)
+ execute_process(COMMAND ${GIT_EXECUTABLE} show -s --format=%cd --date=local --no-show-signature
+ WORKING_DIRECTORY ${GIT_TOPLEVEL}
+ OUTPUT_VARIABLE GIT_COMMIT_DATE OUTPUT_STRIP_TRAILING_WHITESPACE)
+ execute_process(COMMAND ${GIT_EXECUTABLE} diff-index --quiet HEAD --
+ WORKING_DIRECTORY ${GIT_TOPLEVEL}
+ RESULT_VARIABLE GIT_DIRTY_RESULT)
+ if(NOT GIT_DIRTY_RESULT EQUAL 0)
+ set(GIT_DIRTY "dirty")
+ else()
+ set(GIT_DIRTY "clean")
+ endif()
+ execute_process(COMMAND ${GIT_EXECUTABLE} describe --tags
+ WORKING_DIRECTORY ${GIT_TOPLEVEL}
+ OUTPUT_VARIABLE GIT_TAG OUTPUT_STRIP_TRAILING_WHITESPACE)
+ execute_process(COMMAND ${GIT_EXECUTABLE} rev-list --count HEAD
+ WORKING_DIRECTORY ${GIT_TOPLEVEL}
+ OUTPUT_VARIABLE GIT_COMMITS OUTPUT_STRIP_TRAILING_WHITESPACE)
+ else()
+ message(WARNING "No Git repository detected in ${CMAKE_SOURCE_DIR}")
+ endif()
+endif()
+
+configure_file(
+ ${CMAKE_SOURCE_DIR}/src/version.h.in
+ ${CMAKE_SOURCE_DIR}/src/version.h
+ @ONLY
)
+set_source_files_properties(${CMAKE_SOURCE_DIR}/src/version.h PROPERTIES GENERATED TRUE)
+
+set(XKBCOMMON_MINIMUM_VERSION 1.11.0)
+set(WAYLAND_SERVER_MINIMUM_VERSION 1.22.91)
+set(WAYLAND_SERVER_PROTOCOLS_MINIMUM_VERSION 1.45)
+set(LIBINPUT_MINIMUM_VERSION 1.28)
+
+pkg_check_modules(
+ deps
+ REQUIRED
+ IMPORTED_TARGET GLOBAL
+ xkbcommon>=${XKBCOMMON_MINIMUM_VERSION}
+ uuid
+ wayland-server>=${WAYLAND_SERVER_MINIMUM_VERSION}
+ wayland-protocols>=${WAYLAND_SERVER_PROTOCOLS_MINIMUM_VERSION}
+ cairo
+ pango
+ pangocairo
+ pixman-1
+ xcursor
+ libdrm
+ libinput>=${LIBINPUT_MINIMUM_VERSION}
+ gbm
+ gio-2.0
+ re2
+ muparser
+ lcms2)
+
find_package(hyprwayland-scanner 0.3.10 REQUIRED)
file(GLOB_RECURSE SRCFILES "src/*.cpp")
+get_filename_component(FULL_MAIN_PATH ${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp ABSOLUTE)
+list(REMOVE_ITEM SRCFILES "${FULL_MAIN_PATH}")
set(TRACY_CPP_FILES "")
if(USE_TRACY)
- set(TRACY_CPP_FILES "subprojects/tracy/public/TracyClient.cpp")
- message(STATUS "Tracy enabled, TRACY_CPP_FILES: " ${TRACY_CPP_FILES})
+ set(TRACY_CPP_FILES "subprojects/tracy/public/TracyClient.cpp")
+ message(STATUS "Tracy enabled, TRACY_CPP_FILES: " ${TRACY_CPP_FILES})
endif()
-add_executable(Hyprland ${SRCFILES} ${TRACY_CPP_FILES})
-add_dependencies(Hyprland wlroots-hyprland)
+add_library(hyprland_lib STATIC ${SRCFILES})
+add_executable(Hyprland src/main.cpp ${TRACY_CPP_FILES})
+target_link_libraries(Hyprland hyprland_lib)
-set(USE_GPROF ON)
+target_include_directories(hyprland_lib PUBLIC ${deps_INCLUDE_DIRS})
+target_include_directories(Hyprland PUBLIC ${deps_INCLUDE_DIRS})
+
+set(USE_GPROF OFF)
if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG)
- message(STATUS "Setting debug flags")
+ message(STATUS "Setting debug flags")
- if (WITH_ASAN)
- message(STATUS "Enabling ASan")
+ if(WITH_ASAN)
+ message(STATUS "Enabling ASan")
- target_link_libraries(Hyprland asan)
- target_compile_options(Hyprland PUBLIC -fsanitize=address)
- endif()
+ target_link_libraries(hyprland_lib PUBLIC asan)
+ target_compile_options(hyprland_lib PUBLIC -fsanitize=address)
+ endif()
- if(USE_TRACY)
- message(STATUS "Tracy is turned on")
+ add_compile_options(-fno-pie -fno-builtin)
+ add_link_options(-no-pie -fno-builtin)
+ if(USE_GPROF)
+ add_compile_options(-pg)
+ add_link_options(-pg)
+ endif()
+endif()
- option( TRACY_ENABLE "" ON)
- option( TRACY_ON_DEMAND "" ON)
- add_subdirectory (subprojects/tracy)
+if(USE_TRACY)
+ message(STATUS "Tracy is turned on")
- target_link_libraries(Hyprland Tracy::TracyClient)
+ option(TRACY_ENABLE "" ON)
+ option(TRACY_ON_DEMAND "" ON)
+ add_subdirectory(subprojects/tracy)
- if(USE_TRACY_GPU)
- message(STATUS "Tracy GPU Profiling is turned on")
- add_compile_definitions(USE_TRACY_GPU)
- endif()
- endif()
+ add_compile_options(-fno-omit-frame-pointer)
- add_compile_options(-fno-pie -fno-builtin)
- add_link_options(-no-pie -fno-builtin)
- if(USE_GPROF)
- add_compile_options(-pg)
- add_link_options(-pg)
- endif()
+ target_link_libraries(hyprland_lib PUBLIC Tracy::TracyClient)
+
+ if(USE_TRACY_GPU)
+ message(STATUS "Tracy GPU Profiling is turned on")
+ add_compile_definitions(USE_TRACY_GPU)
+ endif()
+endif()
+
+if(BUILT_WITH_NIX)
+ add_compile_definitions(BUILT_WITH_NIX)
endif()
check_include_file("execinfo.h" EXECINFOH)
if(EXECINFOH)
- message(STATUS "Configuration supports execinfo")
- add_compile_definitions(HAS_EXECINFO)
+ message(STATUS "Configuration supports execinfo")
+ add_compile_definitions(HAS_EXECINFO)
endif()
include(CheckLibraryExists)
check_library_exists(execinfo backtrace "" HAVE_LIBEXECINFO)
if(HAVE_LIBEXECINFO)
- target_link_libraries(Hyprland execinfo)
+ target_link_libraries(hyprland_lib PUBLIC execinfo)
endif()
check_include_file("sys/timerfd.h" HAS_TIMERFD)
pkg_check_modules(epoll IMPORTED_TARGET epoll-shim)
if(NOT HAS_TIMERFD AND epoll_FOUND)
- target_link_libraries(Hyprland PkgConfig::epoll)
+ target_link_libraries(hyprland_lib PUBLIC PkgConfig::epoll)
endif()
-if(LEGACY_RENDERER)
- message(STATUS "Using the legacy GLES2 renderer!")
- add_compile_definitions(LEGACY_RENDERER)
+check_include_file("sys/inotify.h" HAS_INOTIFY)
+pkg_check_modules(inotify IMPORTED_TARGET libinotify)
+if(NOT HAS_INOTIFY AND inotify_FOUND)
+ target_link_libraries(hyprland_lib PUBLIC PkgConfig::inotify)
endif()
if(NO_XWAYLAND)
- message(STATUS "Using the NO_XWAYLAND flag, disabling XWayland!")
- add_compile_definitions(NO_XWAYLAND)
+ message(STATUS "Using the NO_XWAYLAND flag, disabling XWayland!")
+ add_compile_definitions(NO_XWAYLAND)
else()
- message(STATUS "XWAYLAND Enabled (NO_XWAYLAND not defined) checking deps...")
- pkg_check_modules(xdeps REQUIRED IMPORTED_TARGET xcb xwayland xcb-util xcb-render xcb-xfixes xcb-icccm xcb-composite xcb-res xcb-ewmh xcb-errors)
- target_link_libraries(Hyprland PkgConfig::xdeps)
+ message(STATUS "XWAYLAND Enabled (NO_XWAYLAND not defined) checking deps...")
+ set(XWAYLAND_DEPENDENCIES
+ xcb
+ xcb-render
+ xcb-xfixes
+ xcb-icccm
+ xcb-composite
+ xcb-res
+ xcb-errors)
+
+ pkg_check_modules(
+ xdeps
+ REQUIRED
+ IMPORTED_TARGET
+ ${XWAYLAND_DEPENDENCIES})
+
+ string(JOIN ", " PKGCONFIG_XWAYLAND_DEPENDENCIES ${XWAYLAND_DEPENDENCIES})
+ string(PREPEND PKGCONFIG_XWAYLAND_DEPENDENCIES ", ")
+
+ target_link_libraries(hyprland_lib PUBLIC PkgConfig::xdeps)
endif()
+configure_file(hyprland.pc.in hyprland.pc @ONLY)
+
if(NO_SYSTEMD)
- message(STATUS "SYSTEMD support is disabled...")
+ message(STATUS "SYSTEMD support is disabled...")
else()
- message(STATUS "SYSTEMD support is requested (NO_SYSTEMD not defined)...")
- add_compile_definitions(USES_SYSTEMD)
+ message(STATUS "SYSTEMD support is requested (NO_SYSTEMD not defined)...")
+ add_compile_definitions(USES_SYSTEMD)
+
+ # session file -uwsm
+ if(NO_UWSM)
+ message(STATUS "UWSM support is disabled...")
+ else()
+ message(STATUS "UWSM support is enabled (NO_UWSM not defined)...")
+ install(FILES ${CMAKE_SOURCE_DIR}/systemd/hyprland-uwsm.desktop
+ DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/wayland-sessions)
+ endif()
endif()
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
include(CPack)
-message(STATUS "Setting precompiled headers")
-
-target_precompile_headers(Hyprland PRIVATE $<$:src/pch/pch.hpp>)
+if(CMAKE_DISABLE_PRECOMPILE_HEADERS)
+ message(STATUS "Not using precompiled headers")
+else()
+ message(STATUS "Setting precompiled headers")
+ target_precompile_headers(hyprland_lib PRIVATE
+ $<$:src/pch/pch.hpp>)
+endif()
message(STATUS "Setting link libraries")
-target_link_libraries(Hyprland rt PkgConfig::deps)
+target_link_libraries(
+ hyprland_lib
+ PUBLIC
+ PkgConfig::aquamarine_dep
+ PkgConfig::hyprlang_dep
+ PkgConfig::hyprutils_dep
+ PkgConfig::hyprcursor_dep
+ PkgConfig::hyprgraphics_dep
+ PkgConfig::deps
+)
+
+target_link_libraries(
+ Hyprland
+ ${LIBRT}
+ hyprland_lib)
+if(udis_dep_FOUND)
+ target_link_libraries(hyprland_lib PUBLIC PkgConfig::udis_dep)
+elseif(NOT("${udis_nopc}" MATCHES "udis_nopc-NOTFOUND"))
+ target_link_libraries(hyprland_lib PUBLIC ${udis_nopc})
+else()
+ target_link_libraries(hyprland_lib PUBLIC libudis86)
+endif()
# used by `make installheaders`, to ensure the headers are generated
add_custom_target(generate-protocol-headers)
+set(PROTOCOL_SOURCES "")
-function(protocol protoPath protoName external)
- if (external)
- set(path ${CMAKE_SOURCE_DIR}/${protoPath})
- else()
- set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath})
- endif()
+function(protocolnew protoPath protoName external)
+ if(external)
+ set(path ${protoPath})
+ else()
+ set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath})
+ endif()
+ add_custom_command(
+ OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}.cpp
+ ${CMAKE_SOURCE_DIR}/protocols/${protoName}.hpp
+ COMMAND hyprwayland-scanner ${path}/${protoName}.xml
+ ${CMAKE_SOURCE_DIR}/protocols/
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
+ target_sources(hyprland_lib PRIVATE protocols/${protoName}.cpp
+ protocols/${protoName}.hpp)
+ target_sources(generate-protocol-headers
+ PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}.hpp)
- add_custom_command(
- OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h
- COMMAND ${WaylandScanner} server-header ${path} protocols/${protoName}-protocol.h
- WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
- )
- add_custom_command(
- OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.c
- COMMAND ${WaylandScanner} private-code ${path} protocols/${protoName}-protocol.c
- WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
- )
- target_sources(Hyprland PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.c)
- target_sources(generate-protocol-headers PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}-protocol.h)
-endfunction()
-
-function(protocolNew protoPath protoName external)
- if (external)
- set(path ${CMAKE_SOURCE_DIR}/${protoPath})
- else()
- set(path ${WAYLAND_PROTOCOLS_DIR}/${protoPath})
- endif()
- add_custom_command(
- OUTPUT ${CMAKE_SOURCE_DIR}/protocols/${protoName}.cpp
- ${CMAKE_SOURCE_DIR}/protocols/${protoName}.hpp
- COMMAND hyprwayland-scanner ${path}/${protoName}.xml ${CMAKE_SOURCE_DIR}/protocols/
- WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
- )
- target_sources(Hyprland PRIVATE protocols/${protoName}.cpp protocols/${protoName}.hpp)
- target_sources(generate-protocol-headers PRIVATE ${CMAKE_SOURCE_DIR}/protocols/${protoName}.hpp)
+ list(APPEND PROTOCOL_SOURCES "${CMAKE_SOURCE_DIR}/protocols/${protoName}.cpp")
+ set(PROTOCOL_SOURCES "${PROTOCOL_SOURCES}" PARENT_SCOPE)
+ list(APPEND PROTOCOL_SOURCES "${CMAKE_SOURCE_DIR}/protocols/${protoName}.hpp")
+ set(PROTOCOL_SOURCES "${PROTOCOL_SOURCES}" PARENT_SCOPE)
endfunction()
function(protocolWayland)
- add_custom_command(
- OUTPUT ${CMAKE_SOURCE_DIR}/protocols/wayland.cpp
- ${CMAKE_SOURCE_DIR}/protocols/wayland.hpp
- COMMAND hyprwayland-scanner --wayland-enums ${WAYLAND_SERVER_DIR}/wayland.xml ${CMAKE_SOURCE_DIR}/protocols/
- WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
- )
- target_sources(Hyprland PRIVATE protocols/wayland.cpp protocols/wayland.hpp)
- target_sources(generate-protocol-headers PRIVATE ${CMAKE_SOURCE_DIR}/protocols/wayland.hpp)
+ add_custom_command(
+ OUTPUT ${CMAKE_SOURCE_DIR}/protocols/wayland.cpp
+ ${CMAKE_SOURCE_DIR}/protocols/wayland.hpp
+ COMMAND
+ hyprwayland-scanner --wayland-enums
+ ${WAYLAND_SCANNER_PKGDATA_DIR}/wayland.xml ${CMAKE_SOURCE_DIR}/protocols/
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR})
+ target_sources(hyprland_lib PRIVATE protocols/wayland.cpp protocols/wayland.hpp)
+ target_sources(generate-protocol-headers
+ PRIVATE ${CMAKE_SOURCE_DIR}/protocols/wayland.hpp)
+
+ list(APPEND PROTOCOL_SOURCES "${CMAKE_SOURCE_DIR}/protocols/wayland.hpp")
+ set(PROTOCOL_SOURCES "${PROTOCOL_SOURCES}" PARENT_SCOPE)
+ list(APPEND PROTOCOL_SOURCES "${CMAKE_SOURCE_DIR}/protocols/wayland.cpp")
+ set(PROTOCOL_SOURCES "${PROTOCOL_SOURCES}" PARENT_SCOPE)
endfunction()
-target_link_libraries(Hyprland
- ${CMAKE_SOURCE_DIR}/subprojects/wlroots-hyprland/build/libwlroots.a
- OpenGL::EGL
- OpenGL::GL
- Threads::Threads
- libudis86
- uuid
-)
+if(TARGET OpenGL::GL)
+ target_link_libraries(hyprland_lib PUBLIC OpenGL::EGL OpenGL::GL glslang::glslang glslang::glslang-default-resource-limits glslang::SPIRV Threads::Threads)
+else()
+ target_link_libraries(hyprland_lib PUBLIC OpenGL::EGL OpenGL::GLES3 glslang::glslang glslang::glslang-default-resource-limits glslang::SPIRV Threads::Threads)
+endif()
-protocol("protocols/wlr-screencopy-unstable-v1.xml" "wlr-screencopy-unstable-v1" true)
-protocol("subprojects/hyprland-protocols/protocols/hyprland-global-shortcuts-v1.xml" "hyprland-global-shortcuts-v1" true)
-protocol("subprojects/hyprland-protocols/protocols/hyprland-toplevel-export-v1.xml" "hyprland-toplevel-export-v1" true)
-protocol("unstable/text-input/text-input-unstable-v1.xml" "text-input-unstable-v1" false)
+pkg_check_modules(hyprland_protocols_dep hyprland-protocols>=0.6.4)
+if(hyprland_protocols_dep_FOUND)
+ pkg_get_variable(HYPRLAND_PROTOCOLS hyprland-protocols pkgdatadir)
+ message(STATUS "hyprland-protocols dependency set to ${HYPRLAND_PROTOCOLS}")
+else()
+ set(HYPRLAND_PROTOCOLS "subprojects/hyprland-protocols")
+ message(STATUS "hyprland-protocols subproject set to ${HYPRLAND_PROTOCOLS}")
+endif()
-protocolNew("protocols" "wlr-gamma-control-unstable-v1" true)
-protocolNew("protocols" "wlr-foreign-toplevel-management-unstable-v1" true)
-protocolNew("protocols" "wlr-output-power-management-unstable-v1" true)
-protocolNew("protocols" "virtual-keyboard-unstable-v1" true)
-protocolNew("protocols" "wlr-virtual-pointer-unstable-v1" true)
-protocolNew("protocols" "input-method-unstable-v2" true)
-protocolNew("protocols" "wlr-output-management-unstable-v1" true)
-protocolNew("protocols" "kde-server-decoration" true)
-protocolNew("protocols" "wlr-data-control-unstable-v1" true)
-protocolNew("subprojects/hyprland-protocols/protocols" "hyprland-focus-grab-v1" true)
-protocolNew("protocols" "wlr-layer-shell-unstable-v1" true)
-protocolNew("protocols" "wayland-drm" true)
-protocolNew("staging/tearing-control" "tearing-control-v1" false)
-protocolNew("staging/fractional-scale" "fractional-scale-v1" false)
-protocolNew("unstable/xdg-output" "xdg-output-unstable-v1" false)
-protocolNew("staging/cursor-shape" "cursor-shape-v1" false)
-protocolNew("unstable/idle-inhibit" "idle-inhibit-unstable-v1" false)
-protocolNew("unstable/relative-pointer" "relative-pointer-unstable-v1" false)
-protocolNew("unstable/xdg-decoration" "xdg-decoration-unstable-v1" false)
-protocolNew("staging/alpha-modifier" "alpha-modifier-v1" false)
-protocolNew("staging/ext-foreign-toplevel-list" "ext-foreign-toplevel-list-v1" false)
-protocolNew("unstable/pointer-gestures" "pointer-gestures-unstable-v1" false)
-protocolNew("unstable/keyboard-shortcuts-inhibit" "keyboard-shortcuts-inhibit-unstable-v1" false)
-protocolNew("unstable/text-input" "text-input-unstable-v3" false)
-protocolNew("unstable/pointer-constraints" "pointer-constraints-unstable-v1" false)
-protocolNew("staging/xdg-activation" "xdg-activation-v1" false)
-protocolNew("staging/ext-idle-notify" "ext-idle-notify-v1" false)
-protocolNew("staging/ext-session-lock" "ext-session-lock-v1" false)
-protocolNew("stable/tablet" "tablet-v2" false)
-protocolNew("stable/presentation-time" "presentation-time" false)
-protocolNew("stable/xdg-shell" "xdg-shell" false)
-protocolNew("unstable/primary-selection" "primary-selection-unstable-v1" false)
-protocolNew("staging/xwayland-shell" "xwayland-shell-v1" false)
-protocolNew("stable/viewporter" "viewporter" false)
-protocolNew("stable/linux-dmabuf" "linux-dmabuf-v1" false)
+protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-global-shortcuts-v1"
+ true)
+protocolnew("unstable/text-input" "text-input-unstable-v1" false)
+protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-toplevel-export-v1"
+ true)
+protocolnew("protocols" "wlr-screencopy-unstable-v1" true)
+protocolnew("protocols" "wlr-gamma-control-unstable-v1" true)
+protocolnew("protocols" "wlr-foreign-toplevel-management-unstable-v1" true)
+protocolnew("protocols" "wlr-output-power-management-unstable-v1" true)
+protocolnew("protocols" "virtual-keyboard-unstable-v1" true)
+protocolnew("protocols" "wlr-virtual-pointer-unstable-v1" true)
+protocolnew("protocols" "input-method-unstable-v2" true)
+protocolnew("protocols" "wlr-output-management-unstable-v1" true)
+protocolnew("protocols" "kde-server-decoration" true)
+protocolnew("protocols" "wlr-data-control-unstable-v1" true)
+protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-focus-grab-v1" true)
+protocolnew("protocols" "wlr-layer-shell-unstable-v1" true)
+protocolnew("protocols" "wayland-drm" true)
+protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-ctm-control-v1" true)
+protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-surface-v1" true)
+protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-lock-notify-v1" true)
+protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-toplevel-mapping-v1"
+ true)
-protocolWayland()
+protocolnew("staging/tearing-control" "tearing-control-v1" false)
+protocolnew("staging/fractional-scale" "fractional-scale-v1" false)
+protocolnew("unstable/xdg-output" "xdg-output-unstable-v1" false)
+protocolnew("staging/cursor-shape" "cursor-shape-v1" false)
+protocolnew("unstable/idle-inhibit" "idle-inhibit-unstable-v1" false)
+protocolnew("unstable/relative-pointer" "relative-pointer-unstable-v1" false)
+protocolnew("unstable/xdg-decoration" "xdg-decoration-unstable-v1" false)
+protocolnew("staging/alpha-modifier" "alpha-modifier-v1" false)
+protocolnew("staging/ext-foreign-toplevel-list" "ext-foreign-toplevel-list-v1"
+ false)
+protocolnew("unstable/pointer-gestures" "pointer-gestures-unstable-v1" false)
+protocolnew("unstable/keyboard-shortcuts-inhibit"
+ "keyboard-shortcuts-inhibit-unstable-v1" false)
+protocolnew("unstable/text-input" "text-input-unstable-v3" false)
+protocolnew("unstable/pointer-constraints" "pointer-constraints-unstable-v1"
+ false)
+protocolnew("staging/xdg-activation" "xdg-activation-v1" false)
+protocolnew("staging/ext-idle-notify" "ext-idle-notify-v1" false)
+protocolnew("staging/ext-session-lock" "ext-session-lock-v1" false)
+protocolnew("stable/tablet" "tablet-v2" false)
+protocolnew("stable/presentation-time" "presentation-time" false)
+protocolnew("stable/xdg-shell" "xdg-shell" false)
+protocolnew("unstable/primary-selection" "primary-selection-unstable-v1" false)
+protocolnew("staging/xwayland-shell" "xwayland-shell-v1" false)
+protocolnew("stable/viewporter" "viewporter" false)
+protocolnew("stable/linux-dmabuf" "linux-dmabuf-v1" false)
+protocolnew("staging/drm-lease" "drm-lease-v1" false)
+protocolnew("staging/linux-drm-syncobj" "linux-drm-syncobj-v1" false)
+protocolnew("staging/xdg-dialog" "xdg-dialog-v1" false)
+protocolnew("staging/single-pixel-buffer" "single-pixel-buffer-v1" false)
+protocolnew("staging/security-context" "security-context-v1" false)
+protocolnew("staging/content-type" "content-type-v1" false)
+protocolnew("staging/color-management" "color-management-v1" false)
+protocolnew("staging/xdg-toplevel-tag" "xdg-toplevel-tag-v1" false)
+protocolnew("staging/xdg-system-bell" "xdg-system-bell-v1" false)
+protocolnew("staging/ext-workspace" "ext-workspace-v1" false)
+protocolnew("staging/ext-data-control" "ext-data-control-v1" false)
+protocolnew("staging/pointer-warp" "pointer-warp-v1" false)
+protocolnew("staging/fifo" "fifo-v1" false)
+protocolnew("staging/commit-timing" "commit-timing-v1" false)
+protocolnew("staging/ext-image-capture-source" "ext-image-capture-source-v1" false)
+protocolnew("staging/ext-image-copy-capture" "ext-image-copy-capture-v1" false)
+
+protocolwayland()
# tools
add_subdirectory(hyprctl)
-add_subdirectory(hyprpm)
+add_subdirectory(start)
+
+if(NO_HYPRPM)
+ message(STATUS "hyprpm is disabled")
+else()
+ add_subdirectory(hyprpm)
+ message(STATUS "hyprpm is enabled (NO_HYPRPM not defined)")
+endif()
# binary and symlink
install(TARGETS Hyprland)
-install(CODE "execute_process( \
+install(
+ CODE "execute_process( \
COMMAND ${CMAKE_COMMAND} -E create_symlink \
- ${CMAKE_INSTALL_BINDIR}/Hyprland \
- ${CMAKE_INSTALL_BINDIR}/hyprland
- )"
-)
-
+ ${CMAKE_INSTALL_FULL_BINDIR}/Hyprland \
+ \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_BINDIR}/hyprland\" \
+ )")
# session file
+configure_file(
+ ${CMAKE_SOURCE_DIR}/example/hyprland.desktop.in
+ ${CMAKE_SOURCE_DIR}/example/hyprland.desktop
+ @ONLY
+)
install(FILES ${CMAKE_SOURCE_DIR}/example/hyprland.desktop
- DESTINATION ${CMAKE_INSTALL_DATADIR}/wayland-sessions)
+ DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/wayland-sessions)
-# wallpapers
-file(GLOB_RECURSE WALLPAPERS "assets/wall*")
-install(FILES ${WALLPAPERS}
- DESTINATION ${CMAKE_INSTALL_DATADIR}/hyprland)
+# allow Hyprland to find assets
+add_compile_definitions(DATAROOTDIR="${CMAKE_INSTALL_FULL_DATAROOTDIR}")
+
+# installable assets
+file(GLOB_RECURSE INSTALLABLE_ASSETS "assets/install/*")
+install(FILES ${INSTALLABLE_ASSETS}
+ DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/hypr)
# default config
install(FILES ${CMAKE_SOURCE_DIR}/example/hyprland.conf
- DESTINATION ${CMAKE_INSTALL_DATADIR}/hyprland)
+ DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/hypr)
# portal config
install(FILES ${CMAKE_SOURCE_DIR}/assets/hyprland-portals.conf
- DESTINATION ${CMAKE_INSTALL_DATADIR}/xdg-desktop-portal)
+ DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/xdg-desktop-portal)
# man pages
file(GLOB_RECURSE MANPAGES "docs/*.1")
-install(FILES ${MANPAGES}
- DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
-
+install(FILES ${MANPAGES} DESTINATION ${CMAKE_INSTALL_MANDIR}/man1)
# pkgconfig entry
install(FILES ${CMAKE_BINARY_DIR}/hyprland.pc
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig)
-# wlroots headers
-set(HEADERS_WLR "${CMAKE_CURRENT_SOURCE_DIR}/subprojects/wlroots-hyprland/include/wlr")
-install(DIRECTORY ${HEADERS_WLR}
- DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland
- FILES_MATCHING PATTERN "*.h")
-
-# config.h and version.h
-set(HEADERS_WLR_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/subprojects/wlroots-hyprland/build/include/wlr")
-install(DIRECTORY ${HEADERS_WLR_ROOT}/
- DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland/wlr
- FILES_MATCHING PATTERN "*.h")
-
# protocol headers
set(HEADERS_PROTO "${CMAKE_CURRENT_SOURCE_DIR}/protocols")
-install(DIRECTORY ${HEADERS_PROTO}
- DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland
- FILES_MATCHING PATTERN "*.h*")
+install(
+ DIRECTORY ${HEADERS_PROTO}
+ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland
+ FILES_MATCHING
+ PATTERN "*.h*")
# hyprland headers
set(HEADERS_SRC "${CMAKE_CURRENT_SOURCE_DIR}/src")
-install(DIRECTORY ${HEADERS_SRC}
- DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland
- FILES_MATCHING PATTERN "*.h*")
+install(
+ DIRECTORY ${HEADERS_SRC}
+ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/hyprland
+ FILES_MATCHING
+ PATTERN "*.h"
+ PATTERN "*.hpp"
+ PATTERN "*.inc")
+
+if(BUILD_TESTING OR WITH_TESTS)
+ message(STATUS "Building tests")
+
+ # hyprtester
+ add_subdirectory(hyprtester)
+
+ # GTest
+ find_package(GTest CONFIG REQUIRED)
+ include(GoogleTest)
+ file(GLOB_RECURSE TESTFILES "tests/*.cpp")
+ add_executable(hyprland_gtests ${TESTFILES})
+ target_compile_options(hyprland_gtests PRIVATE --coverage)
+ target_link_options(hyprland_gtests PRIVATE --coverage)
+ target_include_directories(
+ hyprland_gtests
+ PUBLIC "./include"
+ PRIVATE "./src" "./src/include" "./protocols" "${CMAKE_BINARY_DIR}")
+
+ target_link_libraries(hyprland_gtests hyprland_lib GTest::gtest_main)
+
+ gtest_discover_tests(hyprland_gtests)
+
+ # Enable coverage in main hyprland lib
+ target_compile_options(hyprland_lib PRIVATE --coverage)
+ target_link_options(hyprland_lib PRIVATE --coverage)
+ target_link_libraries(hyprland_lib PUBLIC gcov)
+
+ # Enable coverage in hyprland exe
+ target_compile_options(Hyprland PRIVATE --coverage)
+ target_link_options(Hyprland PRIVATE --coverage)
+ target_link_libraries(Hyprland gcov)
+endif()
+
+if(BUILD_TESTING)
+ message(STATUS "Testing is enabled")
+
+ enable_testing()
+ add_custom_target(tests)
+
+ add_dependencies(tests hyprland_gtests)
+
+else()
+ message(STATUS "Testing is disabled")
+endif()
diff --git a/LICENSE b/LICENSE
index a34afebb..efdec21a 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
BSD 3-Clause License
-Copyright (c) 2022-2024, vaxerski
+Copyright (c) 2022-2026, vaxerski
All rights reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/Makefile b/Makefile
index a33f4cb7..852fcddf 100644
--- a/Makefile
+++ b/Makefile
@@ -1,33 +1,24 @@
PREFIX = /usr/local
-legacyrenderer:
- cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./build -G Ninja
- cmake --build ./build --config Release --target all
- chmod -R 777 ./build
-
-legacyrendererdebug:
- cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./build -G Ninja
- cmake --build ./build --config Release --target all
- chmod -R 777 ./build
+stub:
+ @echo "Do not run $(MAKE) directly without any arguments. Please refer to the wiki on how to compile Hyprland."
release:
- cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build -G Ninja
- cmake --build ./build --config Release --target all
- chmod -R 777 ./build
+ cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build
+ cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
debug:
- cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build -G Ninja
- cmake --build ./build --config Debug --target all
- chmod -R 777 ./build
+ cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DTESTS=true -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -S . -B ./build
+ cmake --build ./build --config Debug --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
nopch:
- cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DCMAKE_DISABLE_PRECOMPILE_HEADERS=ON -S . -B ./build -G Ninja
- cmake --build ./build --config Release --target all
+ cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DCMAKE_DISABLE_PRECOMPILE_HEADERS=ON -S . -B ./build
+ cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF`
clear:
rm -rf build
rm -f ./protocols/*.h ./protocols/*.c ./protocols/*.cpp ./protocols/*.hpp
- rm -rf ./subprojects/wlroots-hyprland/build
+ rm -f ./hyprctl/hw-protocols/*.cpp ./hyprctl/hw-protocols/*.hpp
all:
$(MAKE) clear
@@ -42,7 +33,7 @@ uninstall:
pluginenv:
@echo -en "$(MAKE) pluginenv has been deprecated.\nPlease run $(MAKE) all && sudo $(MAKE) installheaders\n"
@exit 1
-
+
installheaders:
@if [ ! -f ./src/version.h ]; then echo -en "You need to run $(MAKE) all first.\n" && exit 1; fi
@@ -50,14 +41,11 @@ installheaders:
rm -fr ${PREFIX}/include/hyprland
mkdir -p ${PREFIX}/include/hyprland
mkdir -p ${PREFIX}/include/hyprland/protocols
- mkdir -p ${PREFIX}/include/hyprland/wlr
mkdir -p ${PREFIX}/share/pkgconfig
cmake --build ./build --config Release --target generate-protocol-headers
- find src -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland
- cd subprojects/wlroots-hyprland/include/wlr && find . -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland/wlr && cd ../../../..
- cd subprojects/wlroots-hyprland/build/include && find . -name '*.h*' -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland/wlr && cd ../../../..
+ find src -type f \( -name '*.hpp' -o -name '*.h' -o -name '*.inc' \) -print0 | cpio --quiet -0dump ${PREFIX}/include/hyprland
cp ./protocols/*.h* ${PREFIX}/include/hyprland/protocols
cp ./build/hyprland.pc ${PREFIX}/share/pkgconfig
if [ -d /usr/share/pkgconfig ]; then cp ./build/hyprland.pc /usr/share/pkgconfig 2>/dev/null || true; fi
@@ -88,11 +76,11 @@ asan:
@pidof Hyprland > /dev/null && exit 1 || echo ""
rm -rf ./wayland
- git reset --hard
+ #git reset --hard
@echo -en "If you want to apply a patch, input its path (leave empty for none):\n"
- @read patchvar
- @if [-n "$patchvar"]; then patch -p1 < $patchvar || echo ""; else echo "No patch specified"; fi
+ @read patchvar; \
+ if [ -n "$$patchvar" ]; then patch -p1 < "$$patchvar" || echo ""; else echo "No patch specified"; fi
git clone --recursive https://gitlab.freedesktop.org/wayland/wayland
cd wayland && patch -p1 < ../scripts/waylandStatic.diff && meson setup build --buildtype=debug -Db_sanitize=address -Ddocumentation=false && ninja -C build && cd ..
@@ -100,8 +88,12 @@ asan:
@echo "Wayland done"
patch -p1 < ./scripts/hyprlandStaticAsan.diff
- cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DWITH_ASAN:STRING=True -DUSE_TRACY:STRING=False -DUSE_TRACY_GPU:STRING=False -S . -B ./build -G Ninja
+ cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DWITH_ASAN:STRING=True -DUSE_TRACY:STRING=False -DUSE_TRACY_GPU:STRING=False -S . -B ./build
cmake --build ./build --config Debug --target all
@echo "Hyprland done"
ASAN_OPTIONS="detect_odr_violation=0,log_path=asan.log" HYPRLAND_NO_CRASHREPORTER=1 ./build/Hyprland -c ~/.config/hypr/hyprland.conf
+
+test:
+ $(MAKE) debug
+ ./build/hyprtester/hyprtester -c hyprtester/test.conf -b ./build/Hyprland -p hyprtester/plugin/hyprtestplugin.so
diff --git a/README.md b/README.md
index ca44621d..bb74c4e4 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,10 @@
-
+
-![Badge Workflow]
+[![Badge Workflow]][Workflow]
[![Badge License]][License]
![Badge Language]
[![Badge Pull Requests]][Pull Requests]
@@ -13,10 +13,10 @@
-Hyprland is a dynamic tiling Wayland compositor based on wlroots that doesn't sacrifice on its looks.
+Hyprland is a 100% independent, dynamic tiling Wayland compositor that doesn't sacrifice on its looks.
It provides the latest Wayland features, is highly customizable, has all the eyecandy, the most powerful plugins,
-easy IPC, much more QoL stuff than other wlr-based compositors and more...
+easy IPC, much more QoL stuff than other compositors and more...
@@ -37,7 +37,7 @@ easy IPC, much more QoL stuff than other wlr-based compositors and more...
- All of the eyecandy: gradient borders, blur, animations, shadows and much more
- A lot of customization
-- Much more QoL stuff than other wlr-based compositors
+- 100% independent, no wlroots, no libweston, no kwin, no mutter.
- Custom bezier curves for the best animations
- Powerful plugin support
- Built-in plugin manager
@@ -48,7 +48,6 @@ easy IPC, much more QoL stuff than other wlr-based compositors and more...
- Config reloaded instantly upon saving
- Fully dynamic workspaces
- Two built-in layouts and more available as plugins
-- Uses forked wlroots with QoL patches
- Global keybinds passed to your apps of choice
- Tiling/pseudotiling/floating/fullscreen windows
- Special workspaces (scratchpads)
@@ -86,7 +85,7 @@ easy IPC, much more QoL stuff than other wlr-based compositors and more...
-**[wlroots]** - *For their amazing library*
+**[wlroots]** - *For powering Hyprland in the past*
**[tinywl]** - *For showing how 2 do stuff*
@@ -101,7 +100,7 @@ easy IPC, much more QoL stuff than other wlr-based compositors and more...
-[Configure]: https://wiki.hyprland.org/Configuring/Configuring-Hyprland/
+[Configure]: https://wiki.hypr.land/Configuring/
[Stars]: https://starchart.cc/hyprwm/Hyprland
[Hypr]: https://github.com/hyprwm/Hypr
@@ -109,9 +108,10 @@ easy IPC, much more QoL stuff than other wlr-based compositors and more...
[Issues]: https://github.com/hyprwm/Hyprland/issues
[Todo]: https://github.com/hyprwm/Hyprland/projects?type=beta
-[Contribute]: https://wiki.hyprland.org/Contributing-and-Debugging/
-[Install]: https://wiki.hyprland.org/Getting-Started/Installation/
-[Quick Start]: https://wiki.hyprland.org/Getting-Started/Master-Tutorial/
+[Contribute]: https://wiki.hypr.land/Contributing-and-Debugging/
+[Install]: https://wiki.hypr.land/Getting-Started/Installation/
+[Quick Start]: https://wiki.hypr.land/Getting-Started/Master-Tutorial/
+[Workflow]: https://github.com/hyprwm/Hyprland/actions/workflows/ci.yaml
[License]: LICENSE
@@ -126,10 +126,9 @@ easy IPC, much more QoL stuff than other wlr-based compositors and more...
-[Stars Preview]: https://starchart.cc/vaxerski/Hyprland.svg
-[Preview A]: https://i.ibb.co/C1yTb0r/falf.png
-[Preview B]: https://linfindel.github.io/cdn/hyprland-preview-b.png
-[Preview C]: https://i.ibb.co/B3GJg28/20221126-20h53m26s-grim.png
+[Preview A]: https://i.ibb.co/XxFY75Mk/greerggergerhtrytghjnyhjn.png
+[Preview B]: https://i.ibb.co/C1yTb0r/falf.png
+[Preview C]: https://i.ibb.co/2Yc4q835/hyprland-preview-b.png
diff --git a/SECURITY.md b/SECURITY.md
new file mode 100644
index 00000000..187165ce
--- /dev/null
+++ b/SECURITY.md
@@ -0,0 +1,32 @@
+# Hyprland Development Security Policy
+
+If you have a bug that affects the security of your system, you may
+want to privately disclose it instead of making it immediately public.
+
+## Supported versions
+
+_Only_ the most recent release on Github is supported. There are no LTS releases.
+
+## What is not a security issue
+
+Some examples of issues that should not be reported as security issues:
+
+- An app can execute a command when ran outside of a sandbox
+- An app can write / read hyprland sockets when ran outside of a sandbox
+- Crashes
+- Things that are protected via permissions when the permission system is disabled
+
+## What is a security issue
+
+Some examples of issues that should be reported as security issues:
+
+- Sandboxed application executing arbitrary code via Hyprland
+- Application being able to modify Hyprland's code on the fly
+- Application being able to keylog / track user's activity beyond what the wayland protocols allow
+
+## How to report security issues
+
+Please report your security issues via either of these channels:
+- Mail: `vaxry [at] vaxry [dot] net`
+- Matrix: `@vaxry:matrix.vaxry.net`
+- Discord: `@vaxry`
diff --git a/VERSION b/VERSION
new file mode 100644
index 00000000..524456c7
--- /dev/null
+++ b/VERSION
@@ -0,0 +1 @@
+0.54.0
diff --git a/assets/header.svg b/assets/header.svg
index c8cf8222..a2b32551 100644
--- a/assets/header.svg
+++ b/assets/header.svg
@@ -1,72 +1,64 @@
-
+ .st4 {
+ fill: url(#e);
+ }
+
+ .st5 {
+ fill: url(#f);
+ }
+
+ .st6 {
+ fill: url(#g);
+ }
+
+ .st7 {
+ fill: url(#h);
+ }
+
+ .st8 {
+ fill: url(#i);
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/assets/install/lockdead.png b/assets/install/lockdead.png
new file mode 100644
index 00000000..f8bae225
Binary files /dev/null and b/assets/install/lockdead.png differ
diff --git a/assets/install/lockdead2.png b/assets/install/lockdead2.png
new file mode 100644
index 00000000..3f46c434
Binary files /dev/null and b/assets/install/lockdead2.png differ
diff --git a/assets/wall0.png b/assets/install/wall0.png
similarity index 100%
rename from assets/wall0.png
rename to assets/install/wall0.png
diff --git a/assets/wall1.png b/assets/install/wall1.png
similarity index 100%
rename from assets/wall1.png
rename to assets/install/wall1.png
diff --git a/assets/wall2.png b/assets/install/wall2.png
similarity index 100%
rename from assets/wall2.png
rename to assets/install/wall2.png
diff --git a/assets/meson.build b/assets/meson.build
deleted file mode 100644
index 8c4a60ec..00000000
--- a/assets/meson.build
+++ /dev/null
@@ -1,7 +0,0 @@
-wallpapers = ['0', '1', '2']
-
-foreach type : wallpapers
- install_data(f'wall@type@.png', install_dir: join_paths(get_option('datadir'), 'hyprland'), install_tag: 'runtime')
-endforeach
-
-install_data('hyprland-portals.conf', install_dir: join_paths(get_option('datadir'), 'xdg-desktop-portal'), install_tag: 'runtime')
diff --git a/docs/Hyprland.1 b/docs/Hyprland.1
index f43d2c5d..6a833508 100644
--- a/docs/Hyprland.1
+++ b/docs/Hyprland.1
@@ -1,5 +1,19 @@
-.\" Automatically generated by Pandoc 2.9.2.1
+.\" Automatically generated by Pandoc 3.1.3
.\"
+.\" Define V font for inline verbatim, using C font in formats
+.\" that render this, and otherwise B font.
+.ie "\f[CB]x\f[]"x" \{\
+. ftr V B
+. ftr VI BI
+. ftr VB B
+. ftr VBI BI
+.\}
+.el \{\
+. ftr V CR
+. ftr VI CI
+. ftr VB CB
+. ftr VBI CBI
+.\}
.TH "Hyprland" "1" "" "" "Hyprland User Manual"
.hy
.SH NAME
@@ -10,8 +24,8 @@ Hyprland - Dynamic tiling Wayland compositor
\f[B]Hyprland\f[R] [\f[I]arg [...]\f[R]].
.SH DESCRIPTION
.PP
-\f[B]Hyprland\f[R] is a dynamic tiling Wayland compositor based on
-wlroots that doesn\[aq]t sacrifice on its looks.
+\f[B]Hyprland\f[R] is an independent, highly customizable, dynamic
+tiling Wayland compositor that doesn\[aq]t sacrifice on its looks.
.PP
You can launch Hyprland by either going into a TTY and executing
\f[B]Hyprland\f[R], or with a login manager.
@@ -32,6 +46,12 @@ Show command usage.
.TP
\f[B]-c\f[R], \f[B]--config\f[R]
Specify config file to use.
+.TP
+\f[B]--socket\f[R]
+Sets the Wayland socket name (for Wayland socket handover)
+.TP
+\f[B]--wayland-fd\f[R]
+Sets the Wayland socket file descriptor (for Wayland socket handover)
.SH BUGS
.TP
Submit bug reports and request features online at:
diff --git a/docs/Hyprland.1.rst b/docs/Hyprland.1.rst
index 54126501..e10d9c6a 100644
--- a/docs/Hyprland.1.rst
+++ b/docs/Hyprland.1.rst
@@ -14,8 +14,8 @@ SYNOPSIS
DESCRIPTION
===========
-**Hyprland** is a dynamic tiling Wayland compositor based on
-wlroots that doesn't sacrifice on its looks.
+**Hyprland** is an independent, highly customizable,
+dynamic tiling Wayland compositor that doesn't sacrifice on its looks.
You can launch Hyprland by either going into a TTY and
executing **Hyprland**, or with a login manager.
@@ -41,6 +41,12 @@ OPTIONS
**-c**, **--config**
Specify config file to use.
+**--socket**
+ Sets the Wayland socket name (for Wayland socket handover)
+
+**--wayland-fd**
+ Sets the Wayland socket file descriptor (for Wayland socket handover)
+
BUGS
====
diff --git a/docs/ISSUE_GUIDELINES.md b/docs/ISSUE_GUIDELINES.md
index 2f6cbbf8..060b27a0 100644
--- a/docs/ISSUE_GUIDELINES.md
+++ b/docs/ISSUE_GUIDELINES.md
@@ -2,15 +2,15 @@
First of all, please remember to:
- Check that your issue is not a duplicate
-- Read the [FAQ](https://wiki.hyprland.org/FAQ/)
-- Read the [Configuring Page](https://wiki.hyprland.org/Configuring/Configuring-Hyprland)
+- Read the [FAQ](https://wiki.hypr.land/FAQ/)
+- Read the [Configuring Page](https://wiki.hypr.land/Configuring/)
# Reporting suggestions
Suggestions are welcome.
-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.
+Many features can be implemented using bash scripts and Hyprland sockets, read up on those [Here](https://wiki.hypr.land/IPC). Please do not suggest features that can be implemented as such.
@@ -70,7 +70,7 @@ A debug coredump provides more information for debugging and may speed up the pr
Make sure you're on latest git. Run `git pull --recurse-submodules` to sync everything.
-1. [Compile Hyprland with debug mode](http://wiki.hyprland.org/Contributing-and-Debugging/#build-in-debug-mode)
+1. [Compile Hyprland with debug mode](http://wiki.hypr.land/Contributing-and-Debugging/#build-in-debug-mode)
> Note: The config file used will be `hyprlandd.conf` instead of `hyprland.conf`
2. `cd ~`
diff --git a/docs/hyprctl.1 b/docs/hyprctl.1
index 8c9f3a23..61cb84fd 100644
--- a/docs/hyprctl.1
+++ b/docs/hyprctl.1
@@ -1,5 +1,19 @@
-.\" Automatically generated by Pandoc 2.9.2.1
+.\" Automatically generated by Pandoc 3.1.3
.\"
+.\" Define V font for inline verbatim, using C font in formats
+.\" that render this, and otherwise B font.
+.ie "\f[CB]x\f[]"x" \{\
+. ftr V B
+. ftr VI BI
+. ftr VB B
+. ftr VBI BI
+.\}
+.el \{\
+. ftr V CR
+. ftr VI CI
+. ftr VB CB
+. ftr VBI CBI
+.\}
.TH "hyprctl" "1" "" "" "hyprctl User Manual"
.hy
.SH NAME
diff --git a/docs/meson.build b/docs/meson.build
deleted file mode 100644
index a5d7e737..00000000
--- a/docs/meson.build
+++ /dev/null
@@ -1,2 +0,0 @@
-install_man ('Hyprland.1')
-install_man ('hyprctl.1')
diff --git a/example/hyprland.conf b/example/hyprland.conf
index f0ee8b25..15b0e4f7 100644
--- a/example/hyprland.conf
+++ b/example/hyprland.conf
@@ -1,6 +1,6 @@
# This is an example Hyprland config file.
# Refer to the wiki for more information.
-# https://wiki.hyprland.org/Configuring/Configuring-Hyprland/
+# https://wiki.hypr.land/Configuring/
# Please note not all available settings / options are set here.
# For a full list, see the wiki
@@ -14,7 +14,7 @@
### MONITORS ###
################
-# See https://wiki.hyprland.org/Configuring/Monitors/
+# See https://wiki.hypr.land/Configuring/Monitors/
monitor=,preferred,auto,auto
@@ -22,12 +22,12 @@ monitor=,preferred,auto,auto
### MY PROGRAMS ###
###################
-# See https://wiki.hyprland.org/Configuring/Keywords/
+# See https://wiki.hypr.land/Configuring/Keywords/
# Set programs that you use
$terminal = kitty
$fileManager = dolphin
-$menu = wofi --show drun
+$menu = hyprlauncher
#################
@@ -46,90 +46,150 @@ $menu = wofi --show drun
### ENVIRONMENT VARIABLES ###
#############################
-# See https://wiki.hyprland.org/Configuring/Environment-variables/
+# See https://wiki.hypr.land/Configuring/Environment-variables/
env = XCURSOR_SIZE,24
env = HYPRCURSOR_SIZE,24
+###################
+### PERMISSIONS ###
+###################
+
+# See https://wiki.hypr.land/Configuring/Permissions/
+# Please note permission changes here require a Hyprland restart and are not applied on-the-fly
+# for security reasons
+
+# ecosystem {
+# enforce_permissions = 1
+# }
+
+# permission = /usr/(bin|local/bin)/grim, screencopy, allow
+# permission = /usr/(lib|libexec|lib64)/xdg-desktop-portal-hyprland, screencopy, allow
+# permission = /usr/(bin|local/bin)/hyprpm, plugin, allow
+
+
#####################
### LOOK AND FEEL ###
#####################
-# Refer to https://wiki.hyprland.org/Configuring/Variables/
+# Refer to https://wiki.hypr.land/Configuring/Variables/
-# https://wiki.hyprland.org/Configuring/Variables/#general
-general {
+# https://wiki.hypr.land/Configuring/Variables/#general
+general {
gaps_in = 5
gaps_out = 20
border_size = 2
- # https://wiki.hyprland.org/Configuring/Variables/#variable-types for info about colors
+ # https://wiki.hypr.land/Configuring/Variables/#variable-types for info about colors
col.active_border = rgba(33ccffee) rgba(00ff99ee) 45deg
col.inactive_border = rgba(595959aa)
# Set to true enable resizing windows by clicking and dragging on borders and gaps
- resize_on_border = false
+ resize_on_border = false
- # Please see https://wiki.hyprland.org/Configuring/Tearing/ before you turn this on
+ # Please see https://wiki.hypr.land/Configuring/Tearing/ before you turn this on
allow_tearing = false
layout = dwindle
}
-# https://wiki.hyprland.org/Configuring/Variables/#decoration
+# https://wiki.hypr.land/Configuring/Variables/#decoration
decoration {
rounding = 10
+ rounding_power = 2
# Change transparency of focused and unfocused windows
active_opacity = 1.0
inactive_opacity = 1.0
- drop_shadow = true
- shadow_range = 4
- shadow_render_power = 3
- col.shadow = rgba(1a1a1aee)
+ shadow {
+ enabled = true
+ range = 4
+ render_power = 3
+ color = rgba(1a1a1aee)
+ }
- # https://wiki.hyprland.org/Configuring/Variables/#blur
+ # https://wiki.hypr.land/Configuring/Variables/#blur
blur {
enabled = true
size = 3
passes = 1
-
+
vibrancy = 0.1696
}
}
-# https://wiki.hyprland.org/Configuring/Variables/#animations
+# https://wiki.hypr.land/Configuring/Variables/#animations
animations {
- enabled = true
+ enabled = yes, please :)
- # Default animations, see https://wiki.hyprland.org/Configuring/Animations/ for more
+ # Default curves, see https://wiki.hypr.land/Configuring/Animations/#curves
+ # NAME, X0, Y0, X1, Y1
+ bezier = easeOutQuint, 0.23, 1, 0.32, 1
+ bezier = easeInOutCubic, 0.65, 0.05, 0.36, 1
+ bezier = linear, 0, 0, 1, 1
+ bezier = almostLinear, 0.5, 0.5, 0.75, 1
+ bezier = quick, 0.15, 0, 0.1, 1
- bezier = myBezier, 0.05, 0.9, 0.1, 1.05
-
- animation = windows, 1, 7, myBezier
- animation = windowsOut, 1, 7, default, popin 80%
- animation = border, 1, 10, default
- animation = borderangle, 1, 8, default
- animation = fade, 1, 7, default
- animation = workspaces, 1, 6, default
+ # Default animations, see https://wiki.hypr.land/Configuring/Animations/
+ # NAME, ONOFF, SPEED, CURVE, [STYLE]
+ animation = global, 1, 10, default
+ animation = border, 1, 5.39, easeOutQuint
+ animation = windows, 1, 4.79, easeOutQuint
+ animation = windowsIn, 1, 4.1, easeOutQuint, popin 87%
+ animation = windowsOut, 1, 1.49, linear, popin 87%
+ animation = fadeIn, 1, 1.73, almostLinear
+ animation = fadeOut, 1, 1.46, almostLinear
+ animation = fade, 1, 3.03, quick
+ animation = layers, 1, 3.81, easeOutQuint
+ animation = layersIn, 1, 4, easeOutQuint, fade
+ animation = layersOut, 1, 1.5, linear, fade
+ animation = fadeLayersIn, 1, 1.79, almostLinear
+ animation = fadeLayersOut, 1, 1.39, almostLinear
+ animation = workspaces, 1, 1.94, almostLinear, fade
+ animation = workspacesIn, 1, 1.21, almostLinear, fade
+ animation = workspacesOut, 1, 1.94, almostLinear, fade
+ animation = zoomFactor, 1, 7, quick
}
-# See https://wiki.hyprland.org/Configuring/Dwindle-Layout/ for more
+# Ref https://wiki.hypr.land/Configuring/Workspace-Rules/
+# "Smart gaps" / "No gaps when only"
+# uncomment all if you wish to use that.
+# workspace = w[tv1], gapsout:0, gapsin:0
+# workspace = f[1], gapsout:0, gapsin:0
+# windowrule {
+# name = no-gaps-wtv1
+# match:float = false
+# match:workspace = w[tv1]
+#
+# border_size = 0
+# rounding = 0
+# }
+#
+# windowrule {
+# name = no-gaps-f1
+# match:float = false
+# match:workspace = f[1]
+#
+# border_size = 0
+# rounding = 0
+# }
+
+# See https://wiki.hypr.land/Configuring/Dwindle-Layout/ for more
dwindle {
pseudotile = true # Master switch for pseudotiling. Enabling is bound to mainMod + P in the keybinds section below
preserve_split = true # You probably want this
}
-# See https://wiki.hyprland.org/Configuring/Master-Layout/ for more
+# See https://wiki.hypr.land/Configuring/Master-Layout/ for more
master {
- new_is_master = true
+ new_status = master
}
-# https://wiki.hyprland.org/Configuring/Variables/#misc
-misc {
+# https://wiki.hypr.land/Configuring/Variables/#misc
+misc {
force_default_wallpaper = -1 # Set to 0 or 1 to disable the anime mascot wallpapers
disable_hyprland_logo = false # If true disables the random hyprland logo / anime girl background. :(
}
@@ -139,7 +199,7 @@ misc {
### INPUT ###
#############
-# https://wiki.hyprland.org/Configuring/Variables/#input
+# https://wiki.hypr.land/Configuring/Variables/#input
input {
kb_layout = us
kb_variant =
@@ -156,35 +216,33 @@ input {
}
}
-# https://wiki.hyprland.org/Configuring/Variables/#gestures
-gestures {
- workspace_swipe = false
-}
+# See https://wiki.hypr.land/Configuring/Gestures
+gesture = 3, horizontal, workspace
# Example per-device config
-# See https://wiki.hyprland.org/Configuring/Keywords/#per-device-input-configs for more
+# See https://wiki.hypr.land/Configuring/Keywords/#per-device-input-configs for more
device {
name = epic-mouse-v1
sensitivity = -0.5
}
-####################
-### KEYBINDINGSS ###
-####################
+###################
+### KEYBINDINGS ###
+###################
-# See https://wiki.hyprland.org/Configuring/Keywords/
+# See https://wiki.hypr.land/Configuring/Keywords/
$mainMod = SUPER # Sets "Windows" key as main modifier
-# Example binds, see https://wiki.hyprland.org/Configuring/Binds/ for more
+# Example binds, see https://wiki.hypr.land/Configuring/Binds/ for more
bind = $mainMod, Q, exec, $terminal
bind = $mainMod, C, killactive,
-bind = $mainMod, M, exit,
+bind = $mainMod, M, exec, command -v hyprshutdown >/dev/null 2>&1 && hyprshutdown || hyprctl dispatch exit
bind = $mainMod, E, exec, $fileManager
bind = $mainMod, V, togglefloating,
bind = $mainMod, R, exec, $menu
bind = $mainMod, P, pseudo, # dwindle
-bind = $mainMod, J, togglesplit, # dwindle
+bind = $mainMod, J, layoutmsg, togglesplit # dwindle
# Move focus with mainMod + arrow keys
bind = $mainMod, left, movefocus, l
@@ -228,18 +286,56 @@ bind = $mainMod, mouse_up, workspace, e-1
bindm = $mainMod, mouse:272, movewindow
bindm = $mainMod, mouse:273, resizewindow
+# Laptop multimedia keys for volume and LCD brightness
+bindel = ,XF86AudioRaiseVolume, exec, wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+
+bindel = ,XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-
+bindel = ,XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle
+bindel = ,XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle
+bindel = ,XF86MonBrightnessUp, exec, brightnessctl -e4 -n2 set 5%+
+bindel = ,XF86MonBrightnessDown, exec, brightnessctl -e4 -n2 set 5%-
+
+# Requires playerctl
+bindl = , XF86AudioNext, exec, playerctl next
+bindl = , XF86AudioPause, exec, playerctl play-pause
+bindl = , XF86AudioPlay, exec, playerctl play-pause
+bindl = , XF86AudioPrev, exec, playerctl previous
##############################
### WINDOWS AND WORKSPACES ###
##############################
-# See https://wiki.hyprland.org/Configuring/Window-Rules/ for more
-# See https://wiki.hyprland.org/Configuring/Workspace-Rules/ for workspace rules
+# See https://wiki.hypr.land/Configuring/Window-Rules/ for more
+# See https://wiki.hypr.land/Configuring/Workspace-Rules/ for workspace rules
-# Example windowrule v1
-# windowrule = float, ^(kitty)$
+# Example windowrules that are useful
-# Example windowrule v2
-# windowrulev2 = float,class:^(kitty)$,title:^(kitty)$
+windowrule {
+ # Ignore maximize requests from all apps. You'll probably like this.
+ name = suppress-maximize-events
+ match:class = .*
-windowrulev2 = suppressevent maximize, class:.* # You'll probably like this.
+ suppress_event = maximize
+}
+
+windowrule {
+ # Fix some dragging issues with XWayland
+ name = fix-xwayland-drags
+ match:class = ^$
+ match:title = ^$
+ match:xwayland = true
+ match:float = true
+ match:fullscreen = false
+ match:pin = false
+
+ no_focus = true
+}
+
+# Hyprland-run windowrule
+windowrule {
+ name = move-hyprland-run
+
+ match:class = hyprland-run
+
+ move = 20 monitor_h-120
+ float = yes
+}
diff --git a/example/hyprland.desktop b/example/hyprland.desktop
deleted file mode 100644
index 57ad076f..00000000
--- a/example/hyprland.desktop
+++ /dev/null
@@ -1,5 +0,0 @@
-[Desktop Entry]
-Name=Hyprland
-Comment=An intelligent dynamic tiling Wayland compositor
-Exec=Hyprland
-Type=Application
\ No newline at end of file
diff --git a/example/hyprland.desktop.in b/example/hyprland.desktop.in
new file mode 100644
index 00000000..d8e87d60
--- /dev/null
+++ b/example/hyprland.desktop.in
@@ -0,0 +1,7 @@
+[Desktop Entry]
+Name=Hyprland
+Comment=An intelligent dynamic tiling Wayland compositor
+Exec=@PREFIX@/@CMAKE_INSTALL_BINDIR@/start-hyprland
+Type=Application
+DesktopNames=Hyprland
+Keywords=tiling;wayland;compositor;
diff --git a/example/launch.json b/example/launch.json
index c47bdb72..e60cc900 100644
--- a/example/launch.json
+++ b/example/launch.json
@@ -22,5 +22,6 @@
}
]
},
+
]
}
\ No newline at end of file
diff --git a/example/meson.build b/example/meson.build
deleted file mode 100644
index ccfc4e00..00000000
--- a/example/meson.build
+++ /dev/null
@@ -1,2 +0,0 @@
-install_data('hyprland.conf', install_dir: join_paths(get_option('datadir'), 'hyprland'), install_tag: 'runtime')
-install_data('hyprland.desktop', install_dir: join_paths(get_option('datadir'), 'wayland-sessions'), install_tag: 'runtime')
diff --git a/example/screenShader.frag b/example/screenShader.frag
index 5eeac17a..71598e51 100644
--- a/example/screenShader.frag
+++ b/example/screenShader.frag
@@ -1,16 +1,19 @@
//
// Example blue light filter shader.
-//
+//
+
+#version 300 es
precision mediump float;
-varying vec2 v_texcoord;
+in vec2 v_texcoord;
+layout(location = 0) out vec4 fragColor;
uniform sampler2D tex;
void main() {
- vec4 pixColor = texture2D(tex, v_texcoord);
+ vec4 pixColor = texture(tex, v_texcoord);
pixColor[2] *= 0.8;
- gl_FragColor = pixColor;
+ fragColor = pixColor;
}
diff --git a/flake.lock b/flake.lock
index 477db69b..4a89c0fc 100644
--- a/flake.lock
+++ b/flake.lock
@@ -1,5 +1,71 @@
{
"nodes": {
+ "aquamarine": {
+ "inputs": {
+ "hyprutils": [
+ "hyprutils"
+ ],
+ "hyprwayland-scanner": [
+ "hyprwayland-scanner"
+ ],
+ "nixpkgs": [
+ "nixpkgs"
+ ],
+ "systems": [
+ "systems"
+ ]
+ },
+ "locked": {
+ "lastModified": 1772292445,
+ "narHash": "sha256-4F1Q7U313TKUDDovCC96m/Za4wZcJ3yqtu4eSrj8lk8=",
+ "owner": "hyprwm",
+ "repo": "aquamarine",
+ "rev": "1dbbba659c1cef0b0202ce92cadfe13bae550e8f",
+ "type": "github"
+ },
+ "original": {
+ "owner": "hyprwm",
+ "repo": "aquamarine",
+ "type": "github"
+ }
+ },
+ "flake-compat": {
+ "flake": false,
+ "locked": {
+ "lastModified": 1767039857,
+ "narHash": "sha256-vNpUSpF5Nuw8xvDLj2KCwwksIbjua2LZCqhV1LNRDns=",
+ "owner": "NixOS",
+ "repo": "flake-compat",
+ "rev": "5edf11c44bc78a0d334f6334cdaf7d60d732daab",
+ "type": "github"
+ },
+ "original": {
+ "owner": "NixOS",
+ "repo": "flake-compat",
+ "type": "github"
+ }
+ },
+ "gitignore": {
+ "inputs": {
+ "nixpkgs": [
+ "pre-commit-hooks",
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1709087332,
+ "narHash": "sha256-HG2cCnktfHsKV0s4XW83gU3F57gaTljL9KNSuG6bnQs=",
+ "owner": "hercules-ci",
+ "repo": "gitignore.nix",
+ "rev": "637db329424fd7e46cf4185293b9cc8c88c95394",
+ "type": "github"
+ },
+ "original": {
+ "owner": "hercules-ci",
+ "repo": "gitignore.nix",
+ "type": "github"
+ }
+ },
"hyprcursor": {
"inputs": {
"hyprlang": [
@@ -13,11 +79,11 @@
]
},
"locked": {
- "lastModified": 1717181720,
- "narHash": "sha256-yv+QZWsusu/NWjydkxixHC2g+tIJ9v+xkE2EiVpJj6g=",
+ "lastModified": 1753964049,
+ "narHash": "sha256-lIqabfBY7z/OANxHoPeIrDJrFyYy9jAM4GQLzZ2feCM=",
"owner": "hyprwm",
"repo": "hyprcursor",
- "rev": "9e27a2c2ceb1e0b85bd55b0afefad196056fe87c",
+ "rev": "44e91d467bdad8dcf8bbd2ac7cf49972540980a5",
"type": "github"
},
"original": {
@@ -26,23 +92,86 @@
"type": "github"
}
},
- "hyprland-protocols": {
+ "hyprgraphics": {
"inputs": {
+ "hyprutils": [
+ "hyprutils"
+ ],
"nixpkgs": [
- "xdph",
"nixpkgs"
],
"systems": [
- "xdph",
"systems"
]
},
"locked": {
- "lastModified": 1691753796,
- "narHash": "sha256-zOEwiWoXk3j3+EoF3ySUJmberFewWlagvewDRuWYAso=",
+ "lastModified": 1770511807,
+ "narHash": "sha256-suKmSbSk34uPOJDTg/GbPrKEJutzK08vj0VoTvAFBCA=",
+ "owner": "hyprwm",
+ "repo": "hyprgraphics",
+ "rev": "7c75487edd43a71b61adb01cae8326d277aab683",
+ "type": "github"
+ },
+ "original": {
+ "owner": "hyprwm",
+ "repo": "hyprgraphics",
+ "type": "github"
+ }
+ },
+ "hyprland-guiutils": {
+ "inputs": {
+ "aquamarine": [
+ "aquamarine"
+ ],
+ "hyprgraphics": [
+ "hyprgraphics"
+ ],
+ "hyprlang": [
+ "hyprlang"
+ ],
+ "hyprtoolkit": "hyprtoolkit",
+ "hyprutils": [
+ "hyprutils"
+ ],
+ "hyprwayland-scanner": [
+ "hyprwayland-scanner"
+ ],
+ "nixpkgs": [
+ "nixpkgs"
+ ],
+ "systems": [
+ "systems"
+ ]
+ },
+ "locked": {
+ "lastModified": 1767023960,
+ "narHash": "sha256-R2HgtVS1G3KSIKAQ77aOZ+Q0HituOmPgXW9nBNkpp3Q=",
+ "owner": "hyprwm",
+ "repo": "hyprland-guiutils",
+ "rev": "c2e906261142f5dd1ee0bfc44abba23e2754c660",
+ "type": "github"
+ },
+ "original": {
+ "owner": "hyprwm",
+ "repo": "hyprland-guiutils",
+ "type": "github"
+ }
+ },
+ "hyprland-protocols": {
+ "inputs": {
+ "nixpkgs": [
+ "nixpkgs"
+ ],
+ "systems": [
+ "systems"
+ ]
+ },
+ "locked": {
+ "lastModified": 1765214753,
+ "narHash": "sha256-P9zdGXOzToJJgu5sVjv7oeOGPIIwrd9hAUAP3PsmBBs=",
"owner": "hyprwm",
"repo": "hyprland-protocols",
- "rev": "0c2ce70625cb30aef199cb388f99e19a61a6ce03",
+ "rev": "3f3860b869014c00e8b9e0528c7b4ddc335c21ab",
"type": "github"
},
"original": {
@@ -64,11 +193,11 @@
]
},
"locked": {
- "lastModified": 1717881852,
- "narHash": "sha256-XeeVoKHQgfKuXoP6q90sUqKyl7EYy3ol2dVZGM+Jj94=",
+ "lastModified": 1771866172,
+ "narHash": "sha256-fYFoXhQLrm1rD8vSFKQBOEX4OGCuJdLt1amKfHd5GAw=",
"owner": "hyprwm",
"repo": "hyprlang",
- "rev": "ec6938c66253429192274d612912649a0cfe4d28",
+ "rev": "0b219224910e7642eb0ed49f0db5ec3d008e3e41",
"type": "github"
},
"original": {
@@ -77,6 +206,51 @@
"type": "github"
}
},
+ "hyprtoolkit": {
+ "inputs": {
+ "aquamarine": [
+ "hyprland-guiutils",
+ "aquamarine"
+ ],
+ "hyprgraphics": [
+ "hyprland-guiutils",
+ "hyprgraphics"
+ ],
+ "hyprlang": [
+ "hyprland-guiutils",
+ "hyprlang"
+ ],
+ "hyprutils": [
+ "hyprland-guiutils",
+ "hyprutils"
+ ],
+ "hyprwayland-scanner": [
+ "hyprland-guiutils",
+ "hyprwayland-scanner"
+ ],
+ "nixpkgs": [
+ "hyprland-guiutils",
+ "nixpkgs"
+ ],
+ "systems": [
+ "hyprland-guiutils",
+ "systems"
+ ]
+ },
+ "locked": {
+ "lastModified": 1764592794,
+ "narHash": "sha256-7CcO+wbTJ1L1NBQHierHzheQGPWwkIQug/w+fhTAVuU=",
+ "owner": "hyprwm",
+ "repo": "hyprtoolkit",
+ "rev": "5cfe0743f0e608e1462972303778d8a0859ee63e",
+ "type": "github"
+ },
+ "original": {
+ "owner": "hyprwm",
+ "repo": "hyprtoolkit",
+ "type": "github"
+ }
+ },
"hyprutils": {
"inputs": {
"nixpkgs": [
@@ -87,11 +261,11 @@
]
},
"locked": {
- "lastModified": 1717881334,
- "narHash": "sha256-a0inRgJhPL6v9v7RPM/rx1kbXdfe3xJA1c9z0ZkYnh4=",
+ "lastModified": 1771271487,
+ "narHash": "sha256-41gEiUS0Pyw3L/ge1l8MXn61cK14VAhgWB/JV8s/oNI=",
"owner": "hyprwm",
"repo": "hyprutils",
- "rev": "0693f9398ab693d89c9a0aa3b3d062dd61b7a60e",
+ "rev": "340a792e3b3d482c4ae5f66d27a9096bdee6d76d",
"type": "github"
},
"original": {
@@ -110,11 +284,11 @@
]
},
"locked": {
- "lastModified": 1717784906,
- "narHash": "sha256-YxmfxHfWed1fosaa7fC1u7XoKp1anEZU+7Lh/ojRKoM=",
+ "lastModified": 1770501770,
+ "narHash": "sha256-NWRM6+YxTRv+bT9yvlhhJ2iLae1B1pNH3mAL5wi2rlQ=",
"owner": "hyprwm",
"repo": "hyprwayland-scanner",
- "rev": "0f30f9eca6e404130988554accbb64d1c9ec877d",
+ "rev": "0bd8b6cde9ec27d48aad9e5b4deefb3746909d40",
"type": "github"
},
"original": {
@@ -123,13 +297,39 @@
"type": "github"
}
},
+ "hyprwire": {
+ "inputs": {
+ "hyprutils": [
+ "hyprutils"
+ ],
+ "nixpkgs": [
+ "nixpkgs"
+ ],
+ "systems": [
+ "systems"
+ ]
+ },
+ "locked": {
+ "lastModified": 1771606233,
+ "narHash": "sha256-F3PLUqQ/TwgR70U+UeOqJnihJZ2EuunzojYC4g5xHr0=",
+ "owner": "hyprwm",
+ "repo": "hyprwire",
+ "rev": "06c7f1f8c4194786c8400653c4efc49dc14c0f3a",
+ "type": "github"
+ },
+ "original": {
+ "owner": "hyprwm",
+ "repo": "hyprwire",
+ "type": "github"
+ }
+ },
"nixpkgs": {
"locked": {
- "lastModified": 1717974879,
- "narHash": "sha256-GTO3C88+5DX171F/gVS3Qga/hOs/eRMxPFpiHq2t+D8=",
+ "lastModified": 1772198003,
+ "narHash": "sha256-I45esRSssFtJ8p/gLHUZ1OUaaTaVLluNkABkk6arQwE=",
"owner": "NixOS",
"repo": "nixpkgs",
- "rev": "c7b821ba2e1e635ba5a76d299af62821cbcb09f3",
+ "rev": "dd9b079222d43e1943b6ebd802f04fd959dc8e61",
"type": "github"
},
"original": {
@@ -139,13 +339,41 @@
"type": "github"
}
},
+ "pre-commit-hooks": {
+ "inputs": {
+ "flake-compat": "flake-compat",
+ "gitignore": "gitignore",
+ "nixpkgs": [
+ "nixpkgs"
+ ]
+ },
+ "locked": {
+ "lastModified": 1772024342,
+ "narHash": "sha256-+eXlIc4/7dE6EcPs9a2DaSY3fTA9AE526hGqkNID3Wg=",
+ "owner": "cachix",
+ "repo": "git-hooks.nix",
+ "rev": "6e34e97ed9788b17796ee43ccdbaf871a5c2b476",
+ "type": "github"
+ },
+ "original": {
+ "owner": "cachix",
+ "repo": "git-hooks.nix",
+ "type": "github"
+ }
+ },
"root": {
"inputs": {
+ "aquamarine": "aquamarine",
"hyprcursor": "hyprcursor",
+ "hyprgraphics": "hyprgraphics",
+ "hyprland-guiutils": "hyprland-guiutils",
+ "hyprland-protocols": "hyprland-protocols",
"hyprlang": "hyprlang",
"hyprutils": "hyprutils",
"hyprwayland-scanner": "hyprwayland-scanner",
+ "hyprwire": "hyprwire",
"nixpkgs": "nixpkgs",
+ "pre-commit-hooks": "pre-commit-hooks",
"systems": "systems",
"xdph": "xdph"
}
@@ -167,10 +395,18 @@
},
"xdph": {
"inputs": {
- "hyprland-protocols": "hyprland-protocols",
+ "hyprland-protocols": [
+ "hyprland-protocols"
+ ],
"hyprlang": [
"hyprlang"
],
+ "hyprutils": [
+ "hyprutils"
+ ],
+ "hyprwayland-scanner": [
+ "hyprwayland-scanner"
+ ],
"nixpkgs": [
"nixpkgs"
],
@@ -179,11 +415,11 @@
]
},
"locked": {
- "lastModified": 1717918856,
- "narHash": "sha256-I38bmPLqamvOfVSArd1hhZtkVRAYBK38fOHZCU1P9Qg=",
+ "lastModified": 1761431178,
+ "narHash": "sha256-xzjC1CV3+wpUQKNF+GnadnkeGUCJX+vgaWIZsnz9tzI=",
"owner": "hyprwm",
"repo": "xdg-desktop-portal-hyprland",
- "rev": "72907822c19afc0983c69d59d299204381623725",
+ "rev": "4b8801228ff958d028f588f0c2b911dbf32297f9",
"type": "github"
},
"original": {
diff --git a/flake.nix b/flake.nix
index c1be8720..6d695bfb 100644
--- a/flake.nix
+++ b/flake.nix
@@ -7,6 +7,14 @@
#
systems.url = "github:nix-systems/default-linux";
+ aquamarine = {
+ url = "github:hyprwm/aquamarine";
+ inputs.nixpkgs.follows = "nixpkgs";
+ inputs.systems.follows = "systems";
+ inputs.hyprutils.follows = "hyprutils";
+ inputs.hyprwayland-scanner.follows = "hyprwayland-scanner";
+ };
+
hyprcursor = {
url = "github:hyprwm/hyprcursor";
inputs.nixpkgs.follows = "nixpkgs";
@@ -14,6 +22,30 @@
inputs.hyprlang.follows = "hyprlang";
};
+ hyprgraphics = {
+ url = "github:hyprwm/hyprgraphics";
+ inputs.nixpkgs.follows = "nixpkgs";
+ inputs.systems.follows = "systems";
+ inputs.hyprutils.follows = "hyprutils";
+ };
+
+ hyprland-protocols = {
+ url = "github:hyprwm/hyprland-protocols";
+ inputs.nixpkgs.follows = "nixpkgs";
+ inputs.systems.follows = "systems";
+ };
+
+ hyprland-guiutils = {
+ url = "github:hyprwm/hyprland-guiutils";
+ inputs.nixpkgs.follows = "nixpkgs";
+ inputs.systems.follows = "systems";
+ inputs.aquamarine.follows = "aquamarine";
+ inputs.hyprgraphics.follows = "hyprgraphics";
+ inputs.hyprutils.follows = "hyprutils";
+ inputs.hyprlang.follows = "hyprlang";
+ inputs.hyprwayland-scanner.follows = "hyprwayland-scanner";
+ };
+
hyprlang = {
url = "github:hyprwm/hyprlang";
inputs.nixpkgs.follows = "nixpkgs";
@@ -33,72 +65,145 @@
inputs.systems.follows = "systems";
};
+ hyprwire = {
+ url = "github:hyprwm/hyprwire";
+ inputs.nixpkgs.follows = "nixpkgs";
+ inputs.systems.follows = "systems";
+ inputs.hyprutils.follows = "hyprutils";
+ };
+
xdph = {
url = "github:hyprwm/xdg-desktop-portal-hyprland";
inputs.nixpkgs.follows = "nixpkgs";
inputs.systems.follows = "systems";
+ inputs.hyprland-protocols.follows = "hyprland-protocols";
inputs.hyprlang.follows = "hyprlang";
+ inputs.hyprutils.follows = "hyprutils";
+ inputs.hyprwayland-scanner.follows = "hyprwayland-scanner";
+ };
+
+ pre-commit-hooks = {
+ url = "github:cachix/git-hooks.nix";
+ inputs.nixpkgs.follows = "nixpkgs";
};
};
- outputs = inputs @ {
- self,
- nixpkgs,
- systems,
- ...
- }: let
- inherit (nixpkgs) lib;
- eachSystem = lib.genAttrs (import systems);
- pkgsFor = eachSystem (system:
- import nixpkgs {
- localSystem = system;
- overlays = with self.overlays; [
- hyprland-packages
- hyprland-extras
- ];
- });
- in {
- overlays = import ./nix/overlays.nix {inherit self lib inputs;};
+ outputs =
+ inputs@{
+ self,
+ nixpkgs,
+ systems,
+ ...
+ }:
+ let
+ inherit (nixpkgs) lib;
+ eachSystem = lib.genAttrs (import systems);
+ pkgsFor = eachSystem (
+ system:
+ import nixpkgs {
+ localSystem = system;
+ overlays = with self.overlays; [
+ hyprland-packages
+ hyprland-extras
+ ];
+ }
+ );
+ pkgsCrossFor = eachSystem (
+ system: crossSystem:
+ import nixpkgs {
+ localSystem = system;
+ inherit crossSystem;
+ overlays = with self.overlays; [
+ hyprland-packages
+ hyprland-extras
+ ];
+ }
+ );
+ pkgsDebugFor = eachSystem (
+ system:
+ import nixpkgs {
+ localSystem = system;
+ overlays = with self.overlays; [
+ hyprland-debug
+ ];
+ }
+ );
+ pkgsDebugCrossFor = eachSystem (
+ system: crossSystem:
+ import nixpkgs {
+ localSystem = system;
+ inherit crossSystem;
+ overlays = with self.overlays; [
+ hyprland-debug
+ ];
+ }
+ );
+ in
+ {
+ overlays = import ./nix/overlays.nix { inherit self lib inputs; };
- checks = eachSystem (system:
- (lib.filterAttrs
- (n: _: (lib.hasPrefix "hyprland" n) && !(lib.hasSuffix "debug" n))
- self.packages.${system})
- // {
- inherit (self.packages.${system}) xdg-desktop-portal-hyprland;
+ checks = eachSystem (
+ system:
+ (lib.filterAttrs (
+ n: _: (lib.hasPrefix "hyprland" n) && !(lib.hasSuffix "debug" n)
+ ) self.packages.${system})
+ // {
+ inherit (self.packages.${system}) xdg-desktop-portal-hyprland;
+ pre-commit-check = inputs.pre-commit-hooks.lib.${system}.run {
+ src = ./.;
+ hooks = {
+ hyprland-treewide-formatter = {
+ enable = true;
+ entry = "${self.formatter.${system}}/bin/hyprland-treewide-formatter";
+ pass_filenames = false;
+ excludes = [ "subprojects" ];
+ always_run = true;
+ };
+ };
+ };
+ }
+ // (import ./nix/tests inputs pkgsFor.${system})
+ );
+
+ packages = eachSystem (system: {
+ default = self.packages.${system}.hyprland;
+ inherit (pkgsFor.${system})
+ # hyprland-packages
+ hyprland
+ hyprland-unwrapped
+ hyprland-with-tests
+ # hyprland-extras
+ xdg-desktop-portal-hyprland
+ ;
+ inherit (pkgsDebugFor.${system}) hyprland-debug;
+ hyprland-cross = (pkgsCrossFor.${system} "aarch64-linux").hyprland;
+ hyprland-debug-cross = (pkgsDebugCrossFor.${system} "aarch64-linux").hyprland-debug;
});
- packages = eachSystem (system: {
- default = self.packages.${system}.hyprland;
- inherit
- (pkgsFor.${system})
- # hyprland-packages
-
- hyprland
- hyprland-debug
- hyprland-legacy-renderer
- hyprland-unwrapped
- # hyprland-extras
-
- xdg-desktop-portal-hyprland
- ;
- });
+ devShells = eachSystem (system: {
+ default =
+ pkgsFor.${system}.mkShell.override
+ {
+ inherit (self.packages.${system}.default) stdenv;
+ }
+ {
+ name = "hyprland-shell";
+ hardeningDisable = [ "fortify" ];
+ inputsFrom = [ pkgsFor.${system}.hyprland ];
+ packages = [ pkgsFor.${system}.clang-tools ];
+ inherit (self.checks.${system}.pre-commit-check) shellHook;
+ };
+ });
- devShells = eachSystem (system: {
- default =
- pkgsFor.${system}.mkShell.override {
- stdenv = pkgsFor.${system}.gcc13Stdenv;
- } {
- name = "hyprland-shell";
- nativeBuildInputs = with pkgsFor.${system}; [expat libxml2];
- hardeningDisable = ["fortify"];
- inputsFrom = [pkgsFor.${system}.hyprland];
- };
- });
+ formatter = eachSystem (system: pkgsFor.${system}.callPackage ./nix/formatter.nix { });
- formatter = eachSystem (system: nixpkgs.legacyPackages.${system}.alejandra);
+ nixosModules.default = import ./nix/module.nix inputs;
+ homeManagerModules.default = import ./nix/hm-module.nix self;
- nixosModules.default = import ./nix/module.nix inputs;
- homeManagerModules.default = import ./nix/hm-module.nix self;
- };
+ # Hydra build jobs
+ # Recent versions of Hydra can aggregate jobsets from 'hydraJobs' instead of a release.nix
+ # or similar. Remember to filter large or incompatible attributes here. More eval jobs can
+ # be added by merging, e.g., self.packages // self.devShells.
+ hydraJobs = self.packages;
+ };
}
diff --git a/hyprctl/CMakeLists.txt b/hyprctl/CMakeLists.txt
index 64b983e6..7071ede9 100644
--- a/hyprctl/CMakeLists.txt
+++ b/hyprctl/CMakeLists.txt
@@ -5,11 +5,32 @@ project(
DESCRIPTION "Control utility for Hyprland"
)
-pkg_check_modules(deps REQUIRED IMPORTED_TARGET hyprutils>=0.1.1)
+pkg_check_modules(hyprctl_deps REQUIRED IMPORTED_TARGET hyprutils>=0.2.4 hyprwire re2)
-add_executable(hyprctl "main.cpp")
+file(GLOB_RECURSE HYPRCTL_SRCFILES CONFIGURE_DEPENDS "src/*.cpp" "hw-protocols/*.cpp" "include/*.hpp")
-target_link_libraries(hyprctl PUBLIC PkgConfig::deps)
+add_executable(hyprctl ${HYPRCTL_SRCFILES})
+
+target_link_libraries(hyprctl PUBLIC PkgConfig::hyprctl_deps)
+target_include_directories(hyprctl PRIVATE "hw-protocols")
+
+# Hyprwire
+
+function(hyprprotocol protoPath protoName)
+ set(path ${CMAKE_CURRENT_SOURCE_DIR}/${protoPath})
+ add_custom_command(
+ OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/hw-protocols/${protoName}-client.cpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/hw-protocols/${protoName}-client.hpp
+ ${CMAKE_CURRENT_SOURCE_DIR}/hw-protocols/${protoName}-spec.hpp
+ COMMAND hyprwire-scanner --client ${path}/${protoName}.xml
+ ${CMAKE_CURRENT_SOURCE_DIR}/hw-protocols/
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
+ target_sources(hyprctl PRIVATE hw-protocols/${protoName}-client.cpp
+ hw-protocols/${protoName}-client.hpp
+ hw-protocols/${protoName}-spec.hpp)
+endfunction()
+
+hyprprotocol(hw-protocols hyprpaper_core)
# binary
install(TARGETS hyprctl)
diff --git a/hyprctl/Makefile b/hyprctl/Makefile
deleted file mode 100644
index 9798320c..00000000
--- a/hyprctl/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-all:
- $(CXX) $(CXXFLAGS) -std=c++2b ./main.cpp -o ./hyprctl
-clean:
- rm ./hyprctl
diff --git a/hyprctl/hw-protocols/hyprpaper_core.xml b/hyprctl/hw-protocols/hyprpaper_core.xml
new file mode 100644
index 00000000..3d26a102
--- /dev/null
+++ b/hyprctl/hw-protocols/hyprpaper_core.xml
@@ -0,0 +1,172 @@
+
+
+
+ BSD 3-Clause License
+
+ Copyright (c) 2025, Hypr Development
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ 3. Neither the name of the copyright holder nor the names of its
+ contributors may be used to endorse or promote products derived from
+ this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hyprctl/hyprctl.bash b/hyprctl/hyprctl.bash
index 8386cfbc..ba541653 100644
--- a/hyprctl/hyprctl.bash
+++ b/hyprctl/hyprctl.bash
@@ -1,17 +1,17 @@
-_hyprctl_cmd_2 () {
- hyprctl monitors | grep Monitor | awk '{ print $2 }'
+_hyprctl_cmd_1 () {
+ hyprctl monitors | awk '/Monitor/{ print $2 }'
}
_hyprctl_cmd_3 () {
- hyprpm list | grep "Plugin" | awk '{print $4}'
+ hyprctl clients | awk '/class/{print $2}'
+}
+
+_hyprctl_cmd_2 () {
+ hyprctl devices | sed -n '/Keyboard at/{n; s/^\s\+//; p}'
}
_hyprctl_cmd_0 () {
- hyprctl clients | grep class | awk '{print $2}'
-}
-
-_hyprctl_cmd_1 () {
- hyprctl devices | sed -n '/Keyboard at/{n; s/^\s\+//; p}'
+ hyprpm list | awk '/Plugin/{print $4}'
}
_hyprctl () {
@@ -23,25 +23,25 @@ _hyprctl () {
local words cword
_get_comp_words_by_ref -n "$COMP_WORDBREAKS" words cword
- local -a literals=("cyclenext" "globalshortcuts" "cursorpos" "bordersize" "renameworkspace" "animationstyle" "focuswindow" "0" "auto" "swapnext" "forceallowsinput" "moveactive" "activebordercolor" "alphafullscreen" "wayland" "layers" "minsize" "monitors" "1" "kill" "settiled" "3" "focusmonitor" "swapwindow" "moveoutofgroup" "notify" "movecursor" "setcursor" "seterror" "movecurrentworkspacetomonitor" "4" "nomaxsize" "forcenoanims" "setprop" "-i" "-q" "togglefloating" "workspacerules" "movetoworkspace" "disable" "setignoregrouplock" "workspaces" "movegroupwindow" "closewindow" "0" "--instance" "binds" "movewindow" "splitratio" "alpha" "denywindowfromgroup" "workspace" "configerrors" "togglegroup" "getoption" "forceopaque" "keepaspectratio" "killactive" "pass" "decorations" "devices" "focuscurrentorlast" "submap" "global" "alphafullscreenoverride" "forcerendererreload" "movewindowpixel" "headless" "version" "dpms" "resizeactive" "moveintogroup" "5" "alphaoverride" "setfloating" "rollinglog" "::=" "rounding" "layouts" "moveworkspacetomonitor" "exec" "alphainactiveoverride" "alterzorder" "fakefullscreen" "nofocus" "keyword" "forcenoborder" "forcenodim" "--quiet" "pin" "output" "forcenoblur" "togglespecialworkspace" "fullscreen" "toggleopaque" "focusworkspaceoncurrentmonitor" "next" "changegroupactive" "-j" "instances" "execr" "exit" "clients" "all" "--batch" "dismissnotify" "inactivebordercolor" "switchxkblayout" "movetoworkspacesilent" "tagwindow" "movewindoworgroup" "-r" "movefocus" "focusurgentorlast" "remove" "activeworkspace" "dispatch" "create" "centerwindow" "2" "hyprpaper" "-1" "reload" "alphainactive" "systeminfo" "plugin" "dimaround" "activewindow" "swapactiveworkspaces" "splash" "sendshortcut" "maxsize" "lockactivegroup" "windowdancecompat" "forceopaqueoverriden" "lockgroups" "movecursortocorner" "x11" "prev" "1" "resizewindowpixel" "forcenoshadow")
-
+ declare -a literals=(resizeactive 2 changegroupactive -r moveintogroup forceallowsinput 4 ::= systeminfo all layouts setprop animationstyle switchxkblayout create denywindowfromgroup headless activebordercolor exec setcursor wayland focusurgentorlast workspacerules movecurrentworkspacetomonitor movetoworkspacesilent hyprpaper alpha inactivebordercolor movegroupwindow movecursortocorner movewindowpixel prev movewindow globalshortcuts clients dimaround setignoregrouplock splash execr monitors 0 forcenoborder -q animations 1 nomaxsize splitratio moveactive pass swapnext devices layers rounding lockactivegroup 5 moveworkspacetomonitor -f -i --quiet forcenodim pin 0 1 forceopaque forcenoshadow setfloating minsize alphaoverride sendshortcut workspaces cyclenext alterzorder togglegroup lockgroups bordersize dpms focuscurrentorlast -1 --batch notify remove instances 1 3 moveoutofgroup killactive 2 movetoworkspace movecursor configerrors closewindow swapwindow tagwindow forcerendererreload centerwindow auto focuswindow seterror nofocus alphafullscreen binds version -h togglespecialworkspace fullscreen windowdancecompat 0 keyword toggleopaque 3 --instance togglefloating renameworkspace alphafullscreenoverride activeworkspace x11 kill forceopaqueoverriden output global dispatch reload forcenoblur -j event --help disable -1 activewindow keepaspectratio dismissnotify focusmonitor movefocus plugin exit workspace fullscreenstate getoption alphainactiveoverride alphainactive decorations settiled config-only descriptions resizewindowpixel fakefullscreen rollinglog swapactiveworkspaces submap next movewindoworgroup cursorpos forcenoanims focusworkspaceoncurrentmonitor maxsize sendkeystate)
declare -A literal_transitions
- literal_transitions[0]="([105]=1 [75]=2 [33]=3 [35]=4 [1]=2 [2]=2 [78]=2 [107]=5 [37]=2 [111]=4 [41]=2 [46]=2 [115]=2 [85]=6 [116]=8 [52]=2 [88]=4 [54]=2 [90]=9 [120]=2 [122]=2 [124]=2 [15]=2 [59]=10 [60]=2 [17]=11 [125]=12 [19]=2 [127]=2 [129]=2 [25]=13 [68]=2 [98]=4 [99]=2 [27]=2 [28]=14 [102]=2 [104]=4)"
- literal_transitions[3]="([73]=17 [13]=2 [32]=17 [55]=17 [56]=17 [91]=17 [106]=2 [123]=2 [77]=1 [16]=2 [126]=17 [3]=1 [5]=2 [64]=17 [131]=2 [133]=17 [81]=17 [134]=17 [84]=17 [31]=17 [49]=2 [12]=2 [86]=17 [10]=17 [87]=17 [141]=17)"
- literal_transitions[7]="([105]=1 [75]=2 [33]=3 [1]=2 [2]=2 [78]=2 [107]=5 [37]=2 [41]=2 [46]=2 [115]=2 [85]=6 [116]=8 [52]=2 [54]=2 [90]=9 [120]=2 [122]=2 [124]=2 [15]=2 [59]=10 [60]=2 [17]=11 [125]=12 [19]=2 [127]=2 [129]=2 [25]=13 [68]=2 [99]=2 [27]=2 [28]=14 [102]=2)"
- literal_transitions[8]="([101]=2 [130]=2 [132]=2 [0]=2 [74]=2 [36]=2 [108]=2 [109]=2 [38]=2 [110]=2 [4]=2 [79]=2 [40]=2 [80]=2 [113]=2 [6]=2 [42]=2 [43]=2 [82]=2 [83]=2 [47]=2 [48]=2 [9]=2 [50]=2 [51]=2 [53]=2 [11]=2 [112]=2 [89]=2 [118]=2 [57]=2 [92]=2 [58]=2 [93]=2 [94]=2 [61]=2 [62]=2 [128]=2 [95]=2 [63]=2 [20]=2 [97]=2 [22]=2 [23]=2 [65]=2 [66]=2 [135]=2 [136]=2 [24]=2 [26]=2 [69]=2 [100]=2 [70]=2 [140]=2 [29]=2 [71]=2)"
- literal_transitions[9]="([117]=20 [114]=16)"
- literal_transitions[11]="([103]=2)"
- literal_transitions[13]="([21]=1 [119]=1 [30]=1 [139]=1 [121]=1 [44]=1 [72]=1)"
- literal_transitions[14]="([39]=2)"
- literal_transitions[15]="([138]=2 [96]=2)"
- literal_transitions[17]="([18]=2 [7]=2)"
- literal_transitions[18]="([76]=19)"
- literal_transitions[19]="([34]=4 [45]=4)"
- literal_transitions[20]="([8]=2 [67]=2 [14]=2 [137]=2)"
-
- declare -A match_anything_transitions
- match_anything_transitions=([1]=2 [0]=7 [6]=2 [15]=2 [10]=2 [5]=15 [14]=18 [7]=7 [2]=18 [16]=2 [12]=2 [11]=18)
+ literal_transitions[0]="([120]=14 [43]=2 [125]=21 [81]=2 [3]=21 [51]=2 [50]=2 [128]=2 [89]=2 [58]=21 [8]=2 [10]=2 [11]=3 [130]=4 [13]=5 [97]=6 [101]=2 [102]=21 [133]=7 [100]=2 [137]=2 [22]=2 [19]=2 [140]=8 [25]=2 [143]=2 [107]=9 [146]=10 [69]=2 [33]=2 [34]=2 [78]=21 [114]=2 [37]=2 [151]=2 [116]=2 [121]=13 [123]=21 [39]=11 [42]=21 [79]=15 [118]=12)"
+ literal_transitions[1]="([81]=2 [51]=2 [50]=2 [128]=2 [8]=2 [89]=2 [10]=2 [11]=3 [130]=4 [13]=5 [97]=6 [101]=2 [133]=7 [100]=2 [22]=2 [19]=2 [137]=2 [140]=8 [25]=2 [143]=2 [107]=9 [146]=10 [69]=2 [33]=2 [34]=2 [114]=2 [37]=2 [151]=2 [116]=2 [39]=11 [118]=12 [121]=13 [120]=14 [79]=15 [43]=2)"
+ literal_transitions[3]="([139]=2 [63]=16 [64]=16 [45]=16 [105]=16 [27]=2 [26]=2 [52]=4 [5]=16 [66]=2 [67]=16 [129]=16 [113]=16 [12]=2 [74]=4 [99]=2 [35]=16 [152]=16 [98]=16 [59]=16 [117]=16 [41]=16 [17]=2 [138]=16 [154]=2 [122]=16)"
+ literal_transitions[6]="([126]=2)"
+ literal_transitions[10]="([56]=2)"
+ literal_transitions[11]="([9]=2)"
+ literal_transitions[12]="([14]=19 [80]=22)"
+ literal_transitions[13]="([142]=2)"
+ literal_transitions[14]="([0]=2 [84]=2 [2]=2 [85]=2 [4]=2 [87]=2 [88]=2 [90]=2 [91]=2 [92]=2 [93]=2 [94]=2 [96]=2 [15]=2 [18]=2 [103]=2 [21]=2 [104]=2 [23]=2 [24]=2 [28]=2 [29]=2 [30]=2 [108]=2 [111]=2 [32]=2 [112]=2 [36]=2 [38]=2 [119]=2 [124]=2 [46]=2 [47]=2 [48]=2 [49]=2 [53]=2 [55]=2 [131]=2 [132]=2 [134]=2 [135]=2 [60]=2 [136]=20 [141]=2 [65]=2 [144]=2 [145]=2 [68]=2 [147]=2 [70]=2 [71]=2 [72]=2 [73]=2 [148]=2 [75]=2 [76]=2 [150]=2 [153]=2)"
+ literal_transitions[15]="([86]=4 [6]=4 [109]=4 [61]=4 [77]=4 [54]=4 [62]=4)"
+ literal_transitions[16]="([40]=2 [44]=2)"
+ literal_transitions[17]="([7]=23)"
+ literal_transitions[18]="([31]=2 [149]=2)"
+ literal_transitions[19]="([95]=2 [16]=2 [115]=2 [20]=2)"
+ literal_transitions[20]="([106]=2 [82]=2 [127]=2 [1]=2 [83]=2)"
+ literal_transitions[23]="([57]=21 [110]=21)"
+ declare -A match_anything_transitions=([6]=17 [7]=2 [0]=1 [22]=2 [5]=18 [4]=2 [2]=17 [18]=2 [11]=17 [8]=2 [9]=2 [13]=17 [10]=17 [1]=1)
declare -A subword_transitions
local state=0
@@ -79,21 +79,9 @@ _hyprctl () {
done
+ local -a matches=()
+
local prefix="${words[$cword]}"
-
- local shortest_suffix="$word"
- for ((i=0; i < ${#COMP_WORDBREAKS}; i++)); do
- local char="${COMP_WORDBREAKS:$i:1}"
- local candidate="${word##*$char}"
- if [[ ${#candidate} -lt ${#shortest_suffix} ]]; then
- shortest_suffix=$candidate
- fi
- done
- local superfluous_prefix=""
- if [[ "$shortest_suffix" != "$word" ]]; then
- local superfluous_prefix=${word%$shortest_suffix}
- fi
-
if [[ -v "literal_transitions[$state]" ]]; then
local state_transitions_initializer=${literal_transitions[$state]}
declare -A state_transitions
@@ -102,25 +90,38 @@ _hyprctl () {
for literal_id in "${!state_transitions[@]}"; do
local literal="${literals[$literal_id]}"
if [[ $literal = "${prefix}"* ]]; then
- local completion=${literal#"$superfluous_prefix"}
- COMPREPLY+=("$completion ")
+ matches+=("$literal ")
fi
done
fi
declare -A commands
- commands=([5]=1 [16]=2 [12]=3 [10]=0)
+ commands=([7]=0 [22]=1 [8]=3 [5]=2)
if [[ -v "commands[$state]" ]]; then
local command_id=${commands[$state]}
local completions=()
- mapfile -t completions < <(_hyprctl_cmd_${command_id} "$prefix" | cut -f1)
+ readarray -t completions < <(_hyprctl_cmd_${command_id} "$prefix" | cut -f1)
for item in "${completions[@]}"; do
if [[ $item = "${prefix}"* ]]; then
- COMPREPLY+=("$item")
+ matches+=("$item")
fi
done
fi
+ local shortest_suffix="$prefix"
+ for ((i=0; i < ${#COMP_WORDBREAKS}; i++)); do
+ local char="${COMP_WORDBREAKS:$i:1}"
+ local candidate=${prefix##*$char}
+ if [[ ${#candidate} -lt ${#shortest_suffix} ]]; then
+ shortest_suffix=$candidate
+ fi
+ done
+ local superfluous_prefix=""
+ if [[ "$shortest_suffix" != "$prefix" ]]; then
+ local superfluous_prefix=${prefix%$shortest_suffix}
+ fi
+ COMPREPLY=("${matches[@]#$superfluous_prefix}")
+
return 0
}
diff --git a/hyprctl/hyprctl.fish b/hyprctl/hyprctl.fish
index 2a75eb12..6ad32041 100644
--- a/hyprctl/hyprctl.fish
+++ b/hyprctl/hyprctl.fish
@@ -1,21 +1,21 @@
-function _hyprctl_3
+function _hyprctl_2
set 1 $argv[1]
- hyprctl monitors | grep Monitor | awk '{ print $2 }'
+ hyprctl monitors | awk '/Monitor/{ print $2 }'
end
function _hyprctl_4
set 1 $argv[1]
- hyprpm list | grep "Plugin" | awk '{print $4}'
+ hyprctl clients | awk '/class/{print $2}'
+end
+
+function _hyprctl_3
+ set 1 $argv[1]
+ hyprctl devices | sed -n '/Keyboard at/{n; s/^\s\+//; p}'
end
function _hyprctl_1
set 1 $argv[1]
- hyprctl clients | grep class | awk '{print $2}'
-end
-
-function _hyprctl_2
- set 1 $argv[1]
- hyprctl devices | sed -n '/Keyboard at/{n; s/^\s\+//; p}'
+ hyprpm list | awk '/Plugin/{print $4}'
end
function _hyprctl
@@ -29,145 +29,160 @@ function _hyprctl
set COMP_CWORD (count $COMP_WORDS)
end
- set --local literals "cyclenext" "globalshortcuts" "cursorpos" "bordersize" "renameworkspace" "animationstyle" "focuswindow" "0" "auto" "swapnext" "forceallowsinput" "moveactive" "activebordercolor" "alphafullscreen" "wayland" "layers" "minsize" "monitors" "1" "kill" "settiled" "3" "focusmonitor" "swapwindow" "moveoutofgroup" "notify" "movecursor" "setcursor" "seterror" "movecurrentworkspacetomonitor" "4" "nomaxsize" "forcenoanims" "setprop" "-i" "-q" "togglefloating" "workspacerules" "movetoworkspace" "disable" "setignoregrouplock" "workspaces" "movegroupwindow" "closewindow" "0" "--instance" "binds" "movewindow" "splitratio" "alpha" "denywindowfromgroup" "workspace" "configerrors" "togglegroup" "getoption" "forceopaque" "keepaspectratio" "killactive" "pass" "decorations" "devices" "focuscurrentorlast" "submap" "global" "alphafullscreenoverride" "forcerendererreload" "movewindowpixel" "headless" "version" "dpms" "resizeactive" "moveintogroup" "5" "alphaoverride" "setfloating" "rollinglog" "::=" "rounding" "layouts" "moveworkspacetomonitor" "exec" "alphainactiveoverride" "alterzorder" "fakefullscreen" "nofocus" "keyword" "forcenoborder" "forcenodim" "--quiet" "pin" "output" "forcenoblur" "togglespecialworkspace" "fullscreen" "toggleopaque" "focusworkspaceoncurrentmonitor" "next" "changegroupactive" "-j" "instances" "execr" "exit" "clients" "all" "--batch" "dismissnotify" "inactivebordercolor" "switchxkblayout" "movetoworkspacesilent" "tagwindow" "movewindoworgroup" "-r" "movefocus" "focusurgentorlast" "remove" "activeworkspace" "dispatch" "create" "centerwindow" "2" "hyprpaper" "-1" "reload" "alphainactive" "systeminfo" "plugin" "dimaround" "activewindow" "swapactiveworkspaces" "splash" "sendshortcut" "maxsize" "lockactivegroup" "windowdancecompat" "forceopaqueoverriden" "lockgroups" "movecursortocorner" "x11" "prev" "1" "resizewindowpixel" "forcenoshadow"
+ set literals "resizeactive" "2" "changegroupactive" "-r" "moveintogroup" "forceallowsinput" "4" "::=" "systeminfo" "all" "layouts" "setprop" "animationstyle" "switchxkblayout" "create" "denywindowfromgroup" "headless" "activebordercolor" "exec" "setcursor" "wayland" "focusurgentorlast" "workspacerules" "movecurrentworkspacetomonitor" "movetoworkspacesilent" "hyprpaper" "alpha" "inactivebordercolor" "movegroupwindow" "movecursortocorner" "movewindowpixel" "prev" "movewindow" "globalshortcuts" "clients" "dimaround" "setignoregrouplock" "splash" "execr" "monitors" "0" "forcenoborder" "-q" "animations" "1" "nomaxsize" "splitratio" "moveactive" "pass" "swapnext" "devices" "layers" "rounding" "lockactivegroup" "5" "moveworkspacetomonitor" "-f" "-i" "--quiet" "forcenodim" "pin" "0" "1" "forceopaque" "forcenoshadow" "setfloating" "minsize" "alphaoverride" "sendshortcut" "workspaces" "cyclenext" "alterzorder" "togglegroup" "lockgroups" "bordersize" "dpms" "focuscurrentorlast" "-1" "--batch" "notify" "remove" "instances" "1" "3" "moveoutofgroup" "killactive" "2" "movetoworkspace" "movecursor" "configerrors" "closewindow" "swapwindow" "tagwindow" "forcerendererreload" "centerwindow" "auto" "focuswindow" "seterror" "nofocus" "alphafullscreen" "binds" "version" "-h" "togglespecialworkspace" "fullscreen" "windowdancecompat" "0" "keyword" "toggleopaque" "3" "--instance" "togglefloating" "renameworkspace" "alphafullscreenoverride" "activeworkspace" "x11" "kill" "forceopaqueoverriden" "output" "global" "dispatch" "reload" "forcenoblur" "-j" "event" "--help" "disable" "-1" "activewindow" "keepaspectratio" "dismissnotify" "focusmonitor" "movefocus" "plugin" "exit" "workspace" "fullscreenstate" "getoption" "alphainactiveoverride" "alphainactive" "decorations" "settiled" "config-only" "descriptions" "resizewindowpixel" "fakefullscreen" "rollinglog" "swapactiveworkspaces" "submap" "next" "movewindoworgroup" "cursorpos" "forcenoanims" "focusworkspaceoncurrentmonitor" "maxsize" "sendkeystate"
- set --local descriptions
- set descriptions[1] "Focus the next window on a workspace"
- set descriptions[3] "Get the current cursor pos in global layout coordinates"
- set descriptions[5] "Rename a workspace"
- set descriptions[7] "Focus the first window matching"
- set descriptions[10] "Swap the focused window with the next window"
- set descriptions[12] "Move the active window"
- set descriptions[16] "List the layers"
- set descriptions[18] "List active outputs with their properties"
- set descriptions[20] "Get into a kill mode, where you can kill an app by clicking on it"
- set descriptions[21] "Set the current window's floating state to false"
- set descriptions[22] "ERROR"
- set descriptions[23] "Focus a monitor"
- set descriptions[24] "Swap the active window with another window"
- set descriptions[25] "Move the active window out of a group"
- set descriptions[26] "Send a notification using the built-in Hyprland notification system"
- set descriptions[27] "Move the cursor to a specified position"
- set descriptions[28] "Set the cursor theme and reloads the cursor manager"
- set descriptions[29] "Set the hyprctl error string"
- set descriptions[30] "Move the active workspace to a monitor"
- set descriptions[31] "CONFUSED"
- set descriptions[34] "Set a property of a window"
- set descriptions[35] "Specify the Hyprland instance"
- set descriptions[36] "Disable output"
- set descriptions[37] "Toggle the current window's floating state"
- set descriptions[38] "Get the list of defined workspace rules"
- set descriptions[39] "Move the focused window to a workspace"
- set descriptions[41] "Temporarily enable or disable binds:ignore_group_lock"
- set descriptions[42] "List all workspaces with their properties"
- set descriptions[43] "Swap the active window with the next or previous in a group"
- set descriptions[44] "Close a specified window"
- set descriptions[45] "WARNING"
- set descriptions[46] "Specify the Hyprland instance"
- set descriptions[47] "List all registered binds"
- set descriptions[48] "Move the active window in a direction or to a monitor"
- set descriptions[49] "Change the split ratio"
- set descriptions[51] "Prohibit the active window from becoming or being inserted into group"
- set descriptions[52] "Change the workspace"
- set descriptions[53] "List all current config parsing errors"
- set descriptions[54] "Toggle the current active window into a group"
- set descriptions[55] "Get the config option status (values)"
- set descriptions[58] "Close the active window"
- set descriptions[59] "Pass the key to a specified window"
- set descriptions[60] "List all decorations and their info"
- set descriptions[61] "List all connected keyboards and mice"
- set descriptions[62] "Switch focus from current to previously focused window"
- set descriptions[63] "Change the current mapping group"
- set descriptions[64] "Execute a Global Shortcut using the GlobalShortcuts portal"
- set descriptions[66] "Force the renderer to reload all resources and outputs"
- set descriptions[67] "Move a selected window"
- set descriptions[69] "Print the Hyprland version: flags, commit and branch of build"
- set descriptions[70] "Set all monitors' DPMS status"
- set descriptions[71] "Resize the active window"
- set descriptions[72] "Move the active window into a group"
- set descriptions[73] "OK"
- set descriptions[75] "Set the current window's floating state to true"
- set descriptions[76] "Print tail of the log"
- set descriptions[79] "List all layouts available (including plugin ones)"
- set descriptions[80] "Move a workspace to a monitor"
- set descriptions[81] "Execute a shell command"
- set descriptions[83] "Modify the window stack order of the active or specified window"
- set descriptions[84] "Toggle the focused window's internal fullscreen state"
- set descriptions[86] "Issue a keyword to call a config keyword dynamically"
- set descriptions[89] "Disable output"
- set descriptions[90] "Pin a window"
- set descriptions[91] "Allows adding/removing fake outputs to a specific backend"
- set descriptions[93] "Toggle a special workspace on/off"
- set descriptions[94] "Toggle the focused window's fullscreen state"
- set descriptions[95] "Toggle the current window to always be opaque"
- set descriptions[96] "Focus the requested workspace"
- set descriptions[98] "Switch to the next window in a group"
- set descriptions[99] "Output in JSON format"
- set descriptions[100] "List all running Hyprland instances and their info"
- set descriptions[101] "Execute a raw shell command"
- set descriptions[102] "Exit the compositor with no questions asked"
- set descriptions[103] "List all windows with their properties"
- set descriptions[105] "Execute a batch of commands separated by ;"
- set descriptions[106] "Dismiss all or up to amount of notifications"
- set descriptions[108] "Set the xkb layout index for a keyboard"
- set descriptions[109] "Move window doesnt switch to the workspace"
- set descriptions[110] "Apply a tag to the window"
- set descriptions[111] "Behave as moveintogroup"
- set descriptions[112] "Refresh state after issuing the command"
- set descriptions[113] "Move the focus in a direction"
- set descriptions[114] "Focus the urgent window or the last window"
- set descriptions[116] "Get the active workspace name and its properties"
- set descriptions[117] "Issue a dispatch to call a keybind dispatcher with an arg"
- set descriptions[119] "Center the active window"
- set descriptions[120] "HINT"
- set descriptions[121] "Interact with hyprpaper if present"
- set descriptions[122] "No Icon"
- set descriptions[123] "Force reload the config"
- set descriptions[125] "Print system info"
- set descriptions[126] "Interact with a plugin"
- set descriptions[128] "Get the active window name and its properties"
- set descriptions[129] "Swap the active workspaces between two monitors"
- set descriptions[130] "Print the current random splash"
- set descriptions[131] "On shortcut X sends shortcut Y to a specified window"
- set descriptions[133] "Lock the focused group"
- set descriptions[136] "Lock the groups"
- set descriptions[137] "Move the cursor to the corner of the active window"
- set descriptions[140] "INFO"
- set descriptions[141] "Resize a selected window"
+ set descriptions
+ set descriptions[1] "Resize the active window"
+ set descriptions[2] "Fullscreen"
+ set descriptions[3] "Switch to the next window in a group"
+ set descriptions[4] "Refresh state after issuing the command"
+ set descriptions[5] "Move the active window into a group"
+ set descriptions[7] "CONFUSED"
+ set descriptions[9] "Print system info"
+ set descriptions[11] "List all layouts available (including plugin ones)"
+ set descriptions[12] "Set a property of a window"
+ set descriptions[14] "Set the xkb layout index for a keyboard"
+ set descriptions[16] "Prohibit the active window from becoming or being inserted into group"
+ set descriptions[19] "Execute a shell command"
+ set descriptions[20] "Set the cursor theme and reloads the cursor manager"
+ set descriptions[22] "Focus the urgent window or the last window"
+ set descriptions[23] "Get the list of defined workspace rules"
+ set descriptions[24] "Move the active workspace to a monitor"
+ set descriptions[25] "Move window doesn't switch to the workspace"
+ set descriptions[26] "Interact with hyprpaper if present"
+ set descriptions[29] "Swap the active window with the next or previous in a group"
+ set descriptions[30] "Move the cursor to the corner of the active window"
+ set descriptions[31] "Move a selected window"
+ set descriptions[33] "Move the active window in a direction or to a monitor"
+ set descriptions[34] "Lists all global shortcuts"
+ set descriptions[35] "List all windows with their properties"
+ set descriptions[37] "Temporarily enable or disable binds:ignore_group_lock"
+ set descriptions[38] "Print the current random splash"
+ set descriptions[39] "Execute a raw shell command"
+ set descriptions[40] "List active outputs with their properties"
+ set descriptions[43] "Disable output"
+ set descriptions[44] "Gets the current config info about animations and beziers"
+ set descriptions[47] "Change the split ratio"
+ set descriptions[48] "Move the active window"
+ set descriptions[49] "Pass the key to a specified window"
+ set descriptions[50] "Swap the focused window with the next window"
+ set descriptions[51] "List all connected keyboards and mice"
+ set descriptions[52] "List the layers"
+ set descriptions[54] "Lock the focused group"
+ set descriptions[55] "OK"
+ set descriptions[56] "Move a workspace to a monitor"
+ set descriptions[58] "Specify the Hyprland instance"
+ set descriptions[59] "Disable output"
+ set descriptions[61] "Pin a window"
+ set descriptions[62] "WARNING"
+ set descriptions[63] "INFO"
+ set descriptions[66] "Set the current window's floating state to true"
+ set descriptions[69] "On shortcut X sends shortcut Y to a specified window"
+ set descriptions[70] "List all workspaces with their properties"
+ set descriptions[71] "Focus the next window on a workspace"
+ set descriptions[72] "Modify the window stack order of the active or specified window"
+ set descriptions[73] "Toggle the current active window into a group"
+ set descriptions[74] "Lock the groups"
+ set descriptions[76] "Set all monitors' DPMS status"
+ set descriptions[77] "Switch focus from current to previously focused window"
+ set descriptions[78] "No Icon"
+ set descriptions[79] "Execute a batch of commands separated by ;"
+ set descriptions[80] "Send a notification using the built-in Hyprland notification system"
+ set descriptions[82] "List all running Hyprland instances and their info"
+ set descriptions[83] "Maximize no fullscreen"
+ set descriptions[84] "Maximize and fullscreen"
+ set descriptions[85] "Move the active window out of a group"
+ set descriptions[86] "Close the active window"
+ set descriptions[87] "HINT"
+ set descriptions[88] "Move the focused window to a workspace"
+ set descriptions[89] "Move the cursor to a specified position"
+ set descriptions[90] "List all current config parsing errors"
+ set descriptions[91] "Close a specified window"
+ set descriptions[92] "Swap the active window with another window"
+ set descriptions[93] "Apply a tag to the window"
+ set descriptions[94] "Force the renderer to reload all resources and outputs"
+ set descriptions[95] "Center the active window"
+ set descriptions[97] "Focus the first window matching"
+ set descriptions[98] "Set the hyprctl error string"
+ set descriptions[101] "List all registered binds"
+ set descriptions[102] "Print the Hyprland version: flags, commit and branch of build"
+ set descriptions[103] "Prints the help message"
+ set descriptions[104] "Toggle a special workspace on/off"
+ set descriptions[105] "Toggle the focused window's fullscreen state"
+ set descriptions[107] "None"
+ set descriptions[108] "Issue a keyword to call a config keyword dynamically"
+ set descriptions[109] "Toggle the current window to always be opaque"
+ set descriptions[110] "ERROR"
+ set descriptions[111] "Specify the Hyprland instance"
+ set descriptions[112] "Toggle the current window's floating state"
+ set descriptions[113] "Rename a workspace"
+ set descriptions[115] "Get the active workspace name and its properties"
+ set descriptions[117] "Get into a kill mode, where you can kill an app by clicking on it"
+ set descriptions[119] "Allows adding/removing fake outputs to a specific backend"
+ set descriptions[120] "Execute a Global Shortcut using the GlobalShortcuts portal"
+ set descriptions[121] "Issue a dispatch to call a keybind dispatcher with an arg"
+ set descriptions[122] "Force reload the config"
+ set descriptions[124] "Output in JSON format"
+ set descriptions[125] "Emits a custom event to socket2"
+ set descriptions[126] "Prints the help message"
+ set descriptions[128] "Current"
+ set descriptions[129] "Get the active window name and its properties"
+ set descriptions[131] "Dismiss all or up to amount of notifications"
+ set descriptions[132] "Focus a monitor"
+ set descriptions[133] "Move the focus in a direction"
+ set descriptions[134] "Interact with a plugin"
+ set descriptions[135] "Exit the compositor with no questions asked"
+ set descriptions[136] "Change the workspace"
+ set descriptions[137] "Sets the focused window’s fullscreen mode and the one sent to the client"
+ set descriptions[138] "Get the config option status (values)"
+ set descriptions[141] "List all decorations and their info"
+ set descriptions[142] "Set the current window's floating state to false"
+ set descriptions[144] "Return a parsable JSON with all the config options, descriptions, value types and ranges"
+ set descriptions[145] "Resize a selected window"
+ set descriptions[146] "Toggle the focused window's internal fullscreen state"
+ set descriptions[147] "Print tail of the log"
+ set descriptions[148] "Swap the active workspaces between two monitors"
+ set descriptions[149] "Change the current mapping group"
+ set descriptions[151] "Behave as moveintogroup"
+ set descriptions[152] "Get the current cursor pos in global layout coordinates"
+ set descriptions[154] "Focus the requested workspace"
- set --local literal_transitions
- set literal_transitions[1] "set inputs 106 76 34 36 2 3 79 108 38 112 42 47 116 86 117 53 89 55 91 121 123 125 16 60 61 18 126 20 128 130 26 69 99 100 28 29 103 105; set tos 2 3 4 5 3 3 3 6 3 5 3 3 3 7 9 3 5 3 10 3 3 3 3 11 3 12 13 3 3 3 14 3 5 3 3 15 3 5"
- set literal_transitions[4] "set inputs 74 14 33 56 57 92 107 124 78 17 127 4 6 65 132 134 82 135 85 32 50 13 87 11 88 142; set tos 18 3 18 18 18 18 3 3 2 3 18 2 3 18 3 18 18 18 18 18 3 3 18 18 18 18"
- set literal_transitions[8] "set inputs 106 76 34 2 3 79 108 38 42 47 116 86 117 53 55 91 121 123 125 16 60 61 18 126 20 128 130 26 69 100 28 29 103; set tos 2 3 4 3 3 3 6 3 3 3 3 7 9 3 3 10 3 3 3 3 11 3 12 13 3 3 3 14 3 3 3 15 3"
- set literal_transitions[9] "set inputs 102 131 133 1 75 37 109 110 39 111 5 80 41 81 114 7 43 44 83 84 48 49 10 51 52 54 12 113 90 119 58 93 59 94 95 62 63 129 96 64 21 98 23 24 66 67 136 137 25 27 70 101 71 141 30 72; set tos 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3"
- set literal_transitions[10] "set inputs 118 115; set tos 21 17"
- set literal_transitions[12] "set inputs 104; set tos 3"
- set literal_transitions[14] "set inputs 22 120 31 140 122 45 73; set tos 2 2 2 2 2 2 2"
- set literal_transitions[15] "set inputs 40; set tos 3"
- set literal_transitions[16] "set inputs 139 97; set tos 3 3"
- set literal_transitions[18] "set inputs 19 8; set tos 3 3"
- set literal_transitions[19] "set inputs 77; set tos 20"
- set literal_transitions[20] "set inputs 35 46; set tos 5 5"
- set literal_transitions[21] "set inputs 9 68 15 138; set tos 3 3 3 3"
+ set literal_transitions
+ set literal_transitions[1] "set inputs 121 44 126 82 4 52 51 129 90 59 9 11 12 131 14 98 102 103 134 101 138 23 20 141 26 144 108 147 70 34 35 79 115 38 152 117 122 124 40 43 80 119; set tos 15 3 22 3 22 3 3 3 3 22 3 3 4 5 6 7 3 22 8 3 3 3 3 9 3 3 10 11 3 3 3 22 3 3 3 3 14 22 12 22 16 13"
+ set literal_transitions[2] "set inputs 82 52 51 129 9 90 11 12 131 14 98 102 134 101 23 20 138 141 26 144 108 147 70 34 35 115 38 152 117 40 119 122 121 80 44; set tos 3 3 3 3 3 3 3 4 5 6 7 3 8 3 3 3 3 9 3 3 10 11 3 3 3 3 3 3 3 12 13 14 15 16 3"
+ set literal_transitions[4] "set inputs 140 64 65 46 106 28 27 53 6 67 68 130 114 13 75 100 36 153 99 60 118 42 18 139 155 123; set tos 3 17 17 17 17 3 3 5 17 3 17 17 17 3 5 3 17 17 17 17 17 17 3 17 3 17"
+ set literal_transitions[7] "set inputs 127; set tos 3"
+ set literal_transitions[11] "set inputs 57; set tos 3"
+ set literal_transitions[12] "set inputs 10; set tos 3"
+ set literal_transitions[13] "set inputs 15 81; set tos 20 23"
+ set literal_transitions[14] "set inputs 143; set tos 3"
+ set literal_transitions[15] "set inputs 1 85 3 86 5 88 89 91 92 93 94 95 97 16 19 104 22 105 24 25 29 30 31 109 112 33 113 37 39 120 125 47 48 49 50 54 56 132 133 135 136 61 137 142 66 145 146 69 148 71 72 73 74 149 76 77 151 154; set tos 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 21 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3"
+ set literal_transitions[16] "set inputs 87 7 110 62 78 55 63; set tos 5 5 5 5 5 5 5"
+ set literal_transitions[17] "set inputs 41 45; set tos 3 3"
+ set literal_transitions[18] "set inputs 8; set tos 24"
+ set literal_transitions[19] "set inputs 32 150; set tos 3 3"
+ set literal_transitions[20] "set inputs 96 17 116 21; set tos 3 3 3 3"
+ set literal_transitions[21] "set inputs 107 83 128 2 84; set tos 3 3 3 3 3"
+ set literal_transitions[24] "set inputs 58 111; set tos 22 22"
- set --local match_anything_transitions_from 2 1 7 16 11 6 15 8 3 17 13 12
- set --local match_anything_transitions_to 3 8 3 3 3 16 19 8 19 3 3 19
+ set match_anything_transitions_from 7 8 1 23 6 5 3 19 12 9 10 14 11 2
+ set match_anything_transitions_to 18 3 2 3 19 3 18 3 18 3 3 18 18 2
- set --local state 1
- set --local word_index 2
+ set state 1
+ set word_index 2
while test $word_index -lt $COMP_CWORD
- set --local -- word $COMP_WORDS[$word_index]
+ set -- word $COMP_WORDS[$word_index]
if set --query literal_transitions[$state] && test -n $literal_transitions[$state]
- set --local --erase inputs
- set --local --erase tos
+ set --erase inputs
+ set --erase tos
eval $literal_transitions[$state]
if contains -- $word $literals
- set --local literal_matched 0
+ set literal_matched 0
for literal_id in (seq 1 (count $literals))
if test $literals[$literal_id] = $word
- set --local index (contains --index -- $literal_id $inputs)
+ set index (contains --index -- $literal_id $inputs)
set state $tos[$index]
set word_index (math $word_index + 1)
set literal_matched 1
@@ -181,7 +196,7 @@ function _hyprctl
end
if set --query match_anything_transitions_from[$state] && test -n $match_anything_transitions_from[$state]
- set --local index (contains --index -- $state $match_anything_transitions_from)
+ set index (contains --index -- $state $match_anything_transitions_from)
set state $match_anything_transitions_to[$index]
set word_index (math $word_index + 1)
continue
@@ -191,8 +206,8 @@ function _hyprctl
end
if set --query literal_transitions[$state] && test -n $literal_transitions[$state]
- set --local --erase inputs
- set --local --erase tos
+ set --erase inputs
+ set --erase tos
eval $literal_transitions[$state]
for literal_id in $inputs
if test -n $descriptions[$literal_id]
@@ -203,14 +218,14 @@ function _hyprctl
end
end
- set command_states 6 17 13 11
- set command_ids 2 3 4 1
+ set command_states 8 23 9 6
+ set command_ids 1 2 4 3
if contains $state $command_states
- set --local index (contains --index $state $command_states)
- set --local function_id $command_ids[$index]
- set --local function_name _hyprctl_$function_id
- set --local --erase inputs
- set --local --erase tos
+ set index (contains --index $state $command_states)
+ set function_id $command_ids[$index]
+ set function_name _hyprctl_$function_id
+ set --erase inputs
+ set --erase tos
$function_name "$COMP_WORDS[$COMP_CWORD]"
end
diff --git a/hyprctl/hyprctl.usage b/hyprctl/hyprctl.usage
index 64cbbb80..e13fc9d5 100644
--- a/hyprctl/hyprctl.usage
+++ b/hyprctl/hyprctl.usage
@@ -1,21 +1,22 @@
-# This is a file feeded to complgen to generate bash/fish/zsh completions
+# This is a file fed to complgen to generate bash/fish/zsh completions
# Repo: https://github.com/adaszko/complgen
# Generate completion scripts: "complgen aot --bash-script hyprctl.bash --fish-script hyprctl.fish --zsh-script hyprctl.zsh ./hyprctl.usage"
-hyprctl []...
+hyprctl []... ::= (-i | --instance) "Specify the Hyprland instance"
| (-j) "Output in JSON format"
| (-r) "Refresh state after issuing the command"
| (--batch) "Execute a batch of commands separated by ;"
| (-q | --quiet) "Disable output"
+ | (-h | --help) "Prints the help message"
;
- ::= {{{ hyprctl clients | grep class | awk '{print $2}' }}};
+ ::= {{{ hyprctl clients | awk '/class/{print $2}' }}};
- ::= {{{ hyprpm list | grep "Plugin" | awk '{print $4}' }}};
+ ::= {{{ hyprpm list | awk '/Plugin/{print $4}' }}};
- ::= {{{ hyprctl monitors | grep Monitor | awk '{ print $2 }' }}};
+ ::= {{{ hyprctl monitors | awk '/Monitor/{ print $2 }' }}};
::= {{{ hyprctl devices | sed -n '/Keyboard at/{n; s/^\s\+//; p}' }}};
@@ -59,16 +60,18 @@ hyprctl []... ::= (activewindow) "Get the active window name and its properties"
| (activeworkspace) "Get the active workspace name and its properties"
+ | (animations) "Gets the current config info about animations and beziers"
| (binds) "List all registered binds"
| (clients) "List all windows with their properties"
| (configerrors) "List all current config parsing errors"
| (cursorpos) "Get the current cursor pos in global layout coordinates"
| (decorations ) "List all decorations and their info"
+ | (descriptions) "Return a parsable JSON with all the config options, descriptions, value types and ranges"
| (devices) "List all connected keyboards and mice"
| (dismissnotify ) "Dismiss all or up to amount of notifications"
| (dispatch ) "Issue a dispatch to call a keybind dispatcher with an arg"
| (getoption) "Get the config option status (values)"
- | (globalshortcuts) ""
+ | (globalshortcuts) "Lists all global shortcuts"
| (hyprpaper) "Interact with hyprpaper if present"
| (instances) "List all running Hyprland instances and their info"
| (keyword ) "Issue a keyword to call a config keyword dynamically"
@@ -79,8 +82,8 @@ hyprctl []...
| (notify ) "Send a notification using the built-in Hyprland notification system"
| (output (create (wayland | x11 | headless | auto) | remove )) "Allows adding/removing fake outputs to a specific backend"
| (plugin ) "Interact with a plugin"
- | (reload) "Force reload the config"
- | (rollinglog) "Print tail of the log"
+ | (reload [config-only]) "Force reload the config"
+ | (rollinglog [-f]) "Print tail of the log"
| (setcursor) "Set the cursor theme and reloads the cursor manager"
| (seterror [disable]) "Set the hyprctl error string"
| (setprop ) "Set a property of a window"
@@ -92,20 +95,29 @@ hyprctl []...
| (workspaces) "List all workspaces with their properties"
;
+ ::= (-1) "Current"
+ | (0) "None"
+ | (1) "Maximize no fullscreen"
+ | (2) "Fullscreen"
+ | (3) "Maximize and fullscreen"
+ ;
+
::= (exec) "Execute a shell command"
| (execr) "Execute a raw shell command"
| (pass) "Pass the key to a specified window"
| (sendshortcut) "On shortcut X sends shortcut Y to a specified window"
+ | (sendkeystate) "Send a key with specific state (down/repeat/up) to a specified window (window must keep focus for events to continue)"
| (killactive) "Close the active window"
| (closewindow) "Close a specified window"
| (workspace) "Change the workspace"
| (movetoworkspace) "Move the focused window to a workspace"
- | (movetoworkspacesilent) "Move window doesnt switch to the workspace"
+ | (movetoworkspacesilent) "Move window doesn't switch to the workspace"
| (togglefloating) "Toggle the current window's floating state"
| (setfloating) "Set the current window's floating state to true"
| (settiled) "Set the current window's floating state to false"
| (fullscreen) "Toggle the focused window's fullscreen state"
| (fakefullscreen) "Toggle the focused window's internal fullscreen state"
+ | (fullscreenstate ) "Sets the focused window’s fullscreen mode and the one sent to the client"
| (dpms) "Set all monitors' DPMS status"
| (pin) "Pin a window"
| (movefocus) "Move the focus in a direction"
@@ -148,4 +160,5 @@ hyprctl []...
| (setignoregrouplock) "Temporarily enable or disable binds:ignore_group_lock"
| (global) "Execute a Global Shortcut using the GlobalShortcuts portal"
| (submap) "Change the current mapping group"
+ | (event) "Emits a custom event to socket2"
;
diff --git a/hyprctl/hyprctl.zsh b/hyprctl/hyprctl.zsh
index 6babd835..e0c48ab0 100644
--- a/hyprctl/hyprctl.zsh
+++ b/hyprctl/hyprctl.zsh
@@ -1,143 +1,160 @@
-_hyprctl_cmd_2 () {
- hyprctl monitors | grep Monitor | awk '{ print $2 }'
+#compdef hyprctl
+
+_hyprctl_cmd_1 () {
+ hyprctl monitors | awk '/Monitor/{ print $2 }'
}
_hyprctl_cmd_3 () {
- hyprpm list | grep "Plugin" | awk '{print $4}'
+ hyprctl clients | awk '/class/{print $2}'
}
-_hyprctl_cmd_0 () {
- hyprctl clients | grep class | awk '{print $2}'
-}
-
-_hyprctl_cmd_1 () {
+_hyprctl_cmd_2 () {
hyprctl devices | sed -n '/Keyboard at/{n; s/^\s\+//; p}'
}
+_hyprctl_cmd_0 () {
+ hyprpm list | awk '/Plugin/{print $4}'
+}
+
_hyprctl () {
- local -a literals=("cyclenext" "globalshortcuts" "cursorpos" "bordersize" "renameworkspace" "animationstyle" "focuswindow" "0" "auto" "swapnext" "forceallowsinput" "moveactive" "activebordercolor" "alphafullscreen" "wayland" "layers" "minsize" "monitors" "1" "kill" "settiled" "3" "focusmonitor" "swapwindow" "moveoutofgroup" "notify" "movecursor" "setcursor" "seterror" "movecurrentworkspacetomonitor" "4" "nomaxsize" "forcenoanims" "setprop" "-i" "-q" "togglefloating" "workspacerules" "movetoworkspace" "disable" "setignoregrouplock" "workspaces" "movegroupwindow" "closewindow" "0" "--instance" "binds" "movewindow" "splitratio" "alpha" "denywindowfromgroup" "workspace" "configerrors" "togglegroup" "getoption" "forceopaque" "keepaspectratio" "killactive" "pass" "decorations" "devices" "focuscurrentorlast" "submap" "global" "alphafullscreenoverride" "forcerendererreload" "movewindowpixel" "headless" "version" "dpms" "resizeactive" "moveintogroup" "5" "alphaoverride" "setfloating" "rollinglog" "::=" "rounding" "layouts" "moveworkspacetomonitor" "exec" "alphainactiveoverride" "alterzorder" "fakefullscreen" "nofocus" "keyword" "forcenoborder" "forcenodim" "--quiet" "pin" "output" "forcenoblur" "togglespecialworkspace" "fullscreen" "toggleopaque" "focusworkspaceoncurrentmonitor" "next" "changegroupactive" "-j" "instances" "execr" "exit" "clients" "all" "--batch" "dismissnotify" "inactivebordercolor" "switchxkblayout" "movetoworkspacesilent" "tagwindow" "movewindoworgroup" "-r" "movefocus" "focusurgentorlast" "remove" "activeworkspace" "dispatch" "create" "centerwindow" "2" "hyprpaper" "-1" "reload" "alphainactive" "systeminfo" "plugin" "dimaround" "activewindow" "swapactiveworkspaces" "splash" "sendshortcut" "maxsize" "lockactivegroup" "windowdancecompat" "forceopaqueoverriden" "lockgroups" "movecursortocorner" "x11" "prev" "1" "resizewindowpixel" "forcenoshadow")
+ local -a literals=("resizeactive" "2" "changegroupactive" "-r" "moveintogroup" "forceallowsinput" "4" "::=" "systeminfo" "all" "layouts" "setprop" "animationstyle" "switchxkblayout" "create" "denywindowfromgroup" "headless" "activebordercolor" "exec" "setcursor" "wayland" "focusurgentorlast" "workspacerules" "movecurrentworkspacetomonitor" "movetoworkspacesilent" "hyprpaper" "alpha" "inactivebordercolor" "movegroupwindow" "movecursortocorner" "movewindowpixel" "prev" "movewindow" "globalshortcuts" "clients" "dimaround" "setignoregrouplock" "splash" "execr" "monitors" "0" "forcenoborder" "-q" "animations" "1" "nomaxsize" "splitratio" "moveactive" "pass" "swapnext" "devices" "layers" "rounding" "lockactivegroup" "5" "moveworkspacetomonitor" "-f" "-i" "--quiet" "forcenodim" "pin" "0" "1" "forceopaque" "forcenoshadow" "setfloating" "minsize" "alphaoverride" "sendshortcut" "workspaces" "cyclenext" "alterzorder" "togglegroup" "lockgroups" "bordersize" "dpms" "focuscurrentorlast" "-1" "--batch" "notify" "remove" "instances" "1" "3" "moveoutofgroup" "killactive" "2" "movetoworkspace" "movecursor" "configerrors" "closewindow" "swapwindow" "tagwindow" "forcerendererreload" "centerwindow" "auto" "focuswindow" "seterror" "nofocus" "alphafullscreen" "binds" "version" "-h" "togglespecialworkspace" "fullscreen" "windowdancecompat" "0" "keyword" "toggleopaque" "3" "--instance" "togglefloating" "renameworkspace" "alphafullscreenoverride" "activeworkspace" "x11" "kill" "forceopaqueoverriden" "output" "global" "dispatch" "reload" "forcenoblur" "-j" "event" "--help" "disable" "-1" "activewindow" "keepaspectratio" "dismissnotify" "focusmonitor" "movefocus" "plugin" "exit" "workspace" "fullscreenstate" "getoption" "alphainactiveoverride" "alphainactive" "decorations" "settiled" "config-only" "descriptions" "resizewindowpixel" "fakefullscreen" "rollinglog" "swapactiveworkspaces" "submap" "next" "movewindoworgroup" "cursorpos" "forcenoanims" "focusworkspaceoncurrentmonitor" "maxsize" "sendkeystate")
local -A descriptions
- descriptions[1]="Focus the next window on a workspace"
- descriptions[3]="Get the current cursor pos in global layout coordinates"
- descriptions[5]="Rename a workspace"
- descriptions[7]="Focus the first window matching"
- descriptions[10]="Swap the focused window with the next window"
- descriptions[12]="Move the active window"
- descriptions[16]="List the layers"
- descriptions[18]="List active outputs with their properties"
- descriptions[20]="Get into a kill mode, where you can kill an app by clicking on it"
- descriptions[21]="Set the current window's floating state to false"
- descriptions[22]="ERROR"
- descriptions[23]="Focus a monitor"
- descriptions[24]="Swap the active window with another window"
- descriptions[25]="Move the active window out of a group"
- descriptions[26]="Send a notification using the built-in Hyprland notification system"
- descriptions[27]="Move the cursor to a specified position"
- descriptions[28]="Set the cursor theme and reloads the cursor manager"
- descriptions[29]="Set the hyprctl error string"
- descriptions[30]="Move the active workspace to a monitor"
- descriptions[31]="CONFUSED"
- descriptions[34]="Set a property of a window"
- descriptions[35]="Specify the Hyprland instance"
- descriptions[36]="Disable output"
- descriptions[37]="Toggle the current window's floating state"
- descriptions[38]="Get the list of defined workspace rules"
- descriptions[39]="Move the focused window to a workspace"
- descriptions[41]="Temporarily enable or disable binds:ignore_group_lock"
- descriptions[42]="List all workspaces with their properties"
- descriptions[43]="Swap the active window with the next or previous in a group"
- descriptions[44]="Close a specified window"
- descriptions[45]="WARNING"
- descriptions[46]="Specify the Hyprland instance"
- descriptions[47]="List all registered binds"
- descriptions[48]="Move the active window in a direction or to a monitor"
- descriptions[49]="Change the split ratio"
- descriptions[51]="Prohibit the active window from becoming or being inserted into group"
- descriptions[52]="Change the workspace"
- descriptions[53]="List all current config parsing errors"
- descriptions[54]="Toggle the current active window into a group"
- descriptions[55]="Get the config option status (values)"
- descriptions[58]="Close the active window"
- descriptions[59]="Pass the key to a specified window"
- descriptions[60]="List all decorations and their info"
- descriptions[61]="List all connected keyboards and mice"
- descriptions[62]="Switch focus from current to previously focused window"
- descriptions[63]="Change the current mapping group"
- descriptions[64]="Execute a Global Shortcut using the GlobalShortcuts portal"
- descriptions[66]="Force the renderer to reload all resources and outputs"
- descriptions[67]="Move a selected window"
- descriptions[69]="Print the Hyprland version: flags, commit and branch of build"
- descriptions[70]="Set all monitors' DPMS status"
- descriptions[71]="Resize the active window"
- descriptions[72]="Move the active window into a group"
- descriptions[73]="OK"
- descriptions[75]="Set the current window's floating state to true"
- descriptions[76]="Print tail of the log"
- descriptions[79]="List all layouts available (including plugin ones)"
- descriptions[80]="Move a workspace to a monitor"
- descriptions[81]="Execute a shell command"
- descriptions[83]="Modify the window stack order of the active or specified window"
- descriptions[84]="Toggle the focused window's internal fullscreen state"
- descriptions[86]="Issue a keyword to call a config keyword dynamically"
- descriptions[89]="Disable output"
- descriptions[90]="Pin a window"
- descriptions[91]="Allows adding/removing fake outputs to a specific backend"
- descriptions[93]="Toggle a special workspace on/off"
- descriptions[94]="Toggle the focused window's fullscreen state"
- descriptions[95]="Toggle the current window to always be opaque"
- descriptions[96]="Focus the requested workspace"
- descriptions[98]="Switch to the next window in a group"
- descriptions[99]="Output in JSON format"
- descriptions[100]="List all running Hyprland instances and their info"
- descriptions[101]="Execute a raw shell command"
- descriptions[102]="Exit the compositor with no questions asked"
- descriptions[103]="List all windows with their properties"
- descriptions[105]="Execute a batch of commands separated by ;"
- descriptions[106]="Dismiss all or up to amount of notifications"
- descriptions[108]="Set the xkb layout index for a keyboard"
- descriptions[109]="Move window doesnt switch to the workspace"
- descriptions[110]="Apply a tag to the window"
- descriptions[111]="Behave as moveintogroup"
- descriptions[112]="Refresh state after issuing the command"
- descriptions[113]="Move the focus in a direction"
- descriptions[114]="Focus the urgent window or the last window"
- descriptions[116]="Get the active workspace name and its properties"
- descriptions[117]="Issue a dispatch to call a keybind dispatcher with an arg"
- descriptions[119]="Center the active window"
- descriptions[120]="HINT"
- descriptions[121]="Interact with hyprpaper if present"
- descriptions[122]="No Icon"
- descriptions[123]="Force reload the config"
- descriptions[125]="Print system info"
- descriptions[126]="Interact with a plugin"
- descriptions[128]="Get the active window name and its properties"
- descriptions[129]="Swap the active workspaces between two monitors"
- descriptions[130]="Print the current random splash"
- descriptions[131]="On shortcut X sends shortcut Y to a specified window"
- descriptions[133]="Lock the focused group"
- descriptions[136]="Lock the groups"
- descriptions[137]="Move the cursor to the corner of the active window"
- descriptions[140]="INFO"
- descriptions[141]="Resize a selected window"
+ descriptions[1]="Resize the active window"
+ descriptions[2]="Fullscreen"
+ descriptions[3]="Switch to the next window in a group"
+ descriptions[4]="Refresh state after issuing the command"
+ descriptions[5]="Move the active window into a group"
+ descriptions[7]="CONFUSED"
+ descriptions[9]="Print system info"
+ descriptions[11]="List all layouts available (including plugin ones)"
+ descriptions[12]="Set a property of a window"
+ descriptions[14]="Set the xkb layout index for a keyboard"
+ descriptions[16]="Prohibit the active window from becoming or being inserted into group"
+ descriptions[19]="Execute a shell command"
+ descriptions[20]="Set the cursor theme and reloads the cursor manager"
+ descriptions[22]="Focus the urgent window or the last window"
+ descriptions[23]="Get the list of defined workspace rules"
+ descriptions[24]="Move the active workspace to a monitor"
+ descriptions[25]="Move window doesn't switch to the workspace"
+ descriptions[26]="Interact with hyprpaper if present"
+ descriptions[29]="Swap the active window with the next or previous in a group"
+ descriptions[30]="Move the cursor to the corner of the active window"
+ descriptions[31]="Move a selected window"
+ descriptions[33]="Move the active window in a direction or to a monitor"
+ descriptions[34]="Lists all global shortcuts"
+ descriptions[35]="List all windows with their properties"
+ descriptions[37]="Temporarily enable or disable binds:ignore_group_lock"
+ descriptions[38]="Print the current random splash"
+ descriptions[39]="Execute a raw shell command"
+ descriptions[40]="List active outputs with their properties"
+ descriptions[43]="Disable output"
+ descriptions[44]="Gets the current config info about animations and beziers"
+ descriptions[47]="Change the split ratio"
+ descriptions[48]="Move the active window"
+ descriptions[49]="Pass the key to a specified window"
+ descriptions[50]="Swap the focused window with the next window"
+ descriptions[51]="List all connected keyboards and mice"
+ descriptions[52]="List the layers"
+ descriptions[54]="Lock the focused group"
+ descriptions[55]="OK"
+ descriptions[56]="Move a workspace to a monitor"
+ descriptions[58]="Specify the Hyprland instance"
+ descriptions[59]="Disable output"
+ descriptions[61]="Pin a window"
+ descriptions[62]="WARNING"
+ descriptions[63]="INFO"
+ descriptions[66]="Set the current window's floating state to true"
+ descriptions[69]="On shortcut X sends shortcut Y to a specified window"
+ descriptions[70]="List all workspaces with their properties"
+ descriptions[71]="Focus the next window on a workspace"
+ descriptions[72]="Modify the window stack order of the active or specified window"
+ descriptions[73]="Toggle the current active window into a group"
+ descriptions[74]="Lock the groups"
+ descriptions[76]="Set all monitors' DPMS status"
+ descriptions[77]="Switch focus from current to previously focused window"
+ descriptions[78]="No Icon"
+ descriptions[79]="Execute a batch of commands separated by ;"
+ descriptions[80]="Send a notification using the built-in Hyprland notification system"
+ descriptions[82]="List all running Hyprland instances and their info"
+ descriptions[83]="Maximize no fullscreen"
+ descriptions[84]="Maximize and fullscreen"
+ descriptions[85]="Move the active window out of a group"
+ descriptions[86]="Close the active window"
+ descriptions[87]="HINT"
+ descriptions[88]="Move the focused window to a workspace"
+ descriptions[89]="Move the cursor to a specified position"
+ descriptions[90]="List all current config parsing errors"
+ descriptions[91]="Close a specified window"
+ descriptions[92]="Swap the active window with another window"
+ descriptions[93]="Apply a tag to the window"
+ descriptions[94]="Force the renderer to reload all resources and outputs"
+ descriptions[95]="Center the active window"
+ descriptions[97]="Focus the first window matching"
+ descriptions[98]="Set the hyprctl error string"
+ descriptions[101]="List all registered binds"
+ descriptions[102]="Print the Hyprland version: flags, commit and branch of build"
+ descriptions[103]="Prints the help message"
+ descriptions[104]="Toggle a special workspace on/off"
+ descriptions[105]="Toggle the focused window's fullscreen state"
+ descriptions[107]="None"
+ descriptions[108]="Issue a keyword to call a config keyword dynamically"
+ descriptions[109]="Toggle the current window to always be opaque"
+ descriptions[110]="ERROR"
+ descriptions[111]="Specify the Hyprland instance"
+ descriptions[112]="Toggle the current window's floating state"
+ descriptions[113]="Rename a workspace"
+ descriptions[115]="Get the active workspace name and its properties"
+ descriptions[117]="Get into a kill mode, where you can kill an app by clicking on it"
+ descriptions[119]="Allows adding/removing fake outputs to a specific backend"
+ descriptions[120]="Execute a Global Shortcut using the GlobalShortcuts portal"
+ descriptions[121]="Issue a dispatch to call a keybind dispatcher with an arg"
+ descriptions[122]="Force reload the config"
+ descriptions[124]="Output in JSON format"
+ descriptions[125]="Emits a custom event to socket2"
+ descriptions[126]="Prints the help message"
+ descriptions[128]="Current"
+ descriptions[129]="Get the active window name and its properties"
+ descriptions[131]="Dismiss all or up to amount of notifications"
+ descriptions[132]="Focus a monitor"
+ descriptions[133]="Move the focus in a direction"
+ descriptions[134]="Interact with a plugin"
+ descriptions[135]="Exit the compositor with no questions asked"
+ descriptions[136]="Change the workspace"
+ descriptions[137]="Sets the focused window’s fullscreen mode and the one sent to the client"
+ descriptions[138]="Get the config option status (values)"
+ descriptions[141]="List all decorations and their info"
+ descriptions[142]="Set the current window's floating state to false"
+ descriptions[144]="Return a parsable JSON with all the config options, descriptions, value types and ranges"
+ descriptions[145]="Resize a selected window"
+ descriptions[146]="Toggle the focused window's internal fullscreen state"
+ descriptions[147]="Print tail of the log"
+ descriptions[148]="Swap the active workspaces between two monitors"
+ descriptions[149]="Change the current mapping group"
+ descriptions[151]="Behave as moveintogroup"
+ descriptions[152]="Get the current cursor pos in global layout coordinates"
+ descriptions[154]="Focus the requested workspace"
local -A literal_transitions
- literal_transitions[1]="([106]=2 [76]=3 [34]=4 [36]=5 [2]=3 [3]=3 [79]=3 [108]=6 [38]=3 [112]=5 [42]=3 [47]=3 [116]=3 [86]=7 [117]=9 [53]=3 [89]=5 [55]=3 [91]=10 [121]=3 [123]=3 [125]=3 [16]=3 [60]=11 [61]=3 [18]=12 [126]=13 [20]=3 [128]=3 [130]=3 [26]=14 [69]=3 [99]=5 [100]=3 [28]=3 [29]=15 [103]=3 [105]=5)"
- literal_transitions[4]="([74]=18 [14]=3 [33]=18 [56]=18 [57]=18 [92]=18 [107]=3 [124]=3 [78]=2 [17]=3 [127]=18 [4]=2 [6]=3 [65]=18 [132]=3 [134]=18 [82]=18 [135]=18 [85]=18 [32]=18 [50]=3 [13]=3 [87]=18 [11]=18 [88]=18 [142]=18)"
- literal_transitions[8]="([106]=2 [76]=3 [34]=4 [2]=3 [3]=3 [79]=3 [108]=6 [38]=3 [42]=3 [47]=3 [116]=3 [86]=7 [117]=9 [53]=3 [55]=3 [91]=10 [121]=3 [123]=3 [125]=3 [16]=3 [60]=11 [61]=3 [18]=12 [126]=13 [20]=3 [128]=3 [130]=3 [26]=14 [69]=3 [100]=3 [28]=3 [29]=15 [103]=3)"
- literal_transitions[9]="([102]=3 [131]=3 [133]=3 [1]=3 [75]=3 [37]=3 [109]=3 [110]=3 [39]=3 [111]=3 [5]=3 [80]=3 [41]=3 [81]=3 [114]=3 [7]=3 [43]=3 [44]=3 [83]=3 [84]=3 [48]=3 [49]=3 [10]=3 [51]=3 [52]=3 [54]=3 [12]=3 [113]=3 [90]=3 [119]=3 [58]=3 [93]=3 [59]=3 [94]=3 [95]=3 [62]=3 [63]=3 [129]=3 [96]=3 [64]=3 [21]=3 [98]=3 [23]=3 [24]=3 [66]=3 [67]=3 [136]=3 [137]=3 [25]=3 [27]=3 [70]=3 [101]=3 [71]=3 [141]=3 [30]=3 [72]=3)"
- literal_transitions[10]="([118]=21 [115]=17)"
- literal_transitions[12]="([104]=3)"
- literal_transitions[14]="([22]=2 [120]=2 [31]=2 [140]=2 [122]=2 [45]=2 [73]=2)"
- literal_transitions[15]="([40]=3)"
- literal_transitions[16]="([139]=3 [97]=3)"
- literal_transitions[18]="([19]=3 [8]=3)"
- literal_transitions[19]="([77]=20)"
- literal_transitions[20]="([35]=5 [46]=5)"
- literal_transitions[21]="([9]=3 [68]=3 [15]=3 [138]=3)"
+ literal_transitions[1]="([121]=15 [44]=3 [126]=22 [82]=3 [4]=22 [52]=3 [51]=3 [129]=3 [90]=3 [59]=22 [9]=3 [11]=3 [12]=4 [131]=5 [14]=6 [98]=7 [102]=3 [103]=22 [134]=8 [101]=3 [138]=3 [23]=3 [20]=3 [141]=9 [26]=3 [144]=3 [108]=10 [147]=11 [70]=3 [34]=3 [35]=3 [79]=22 [115]=3 [38]=3 [152]=3 [117]=3 [122]=14 [124]=22 [40]=12 [43]=22 [80]=16 [119]=13)"
+ literal_transitions[2]="([82]=3 [52]=3 [51]=3 [129]=3 [9]=3 [90]=3 [11]=3 [12]=4 [131]=5 [14]=6 [98]=7 [102]=3 [134]=8 [101]=3 [23]=3 [20]=3 [138]=3 [141]=9 [26]=3 [144]=3 [108]=10 [147]=11 [70]=3 [34]=3 [35]=3 [115]=3 [38]=3 [152]=3 [117]=3 [40]=12 [119]=13 [122]=14 [121]=15 [80]=16 [44]=3)"
+ literal_transitions[4]="([140]=3 [64]=17 [65]=17 [46]=17 [106]=17 [28]=3 [27]=3 [53]=5 [6]=17 [67]=3 [68]=17 [130]=17 [114]=17 [13]=3 [75]=5 [100]=3 [36]=17 [153]=17 [99]=17 [60]=17 [118]=17 [42]=17 [18]=3 [139]=17 [155]=3 [123]=17)"
+ literal_transitions[7]="([127]=3)"
+ literal_transitions[11]="([57]=3)"
+ literal_transitions[12]="([10]=3)"
+ literal_transitions[13]="([15]=20 [81]=23)"
+ literal_transitions[14]="([143]=3)"
+ literal_transitions[15]="([1]=3 [85]=3 [3]=3 [86]=3 [5]=3 [88]=3 [89]=3 [91]=3 [92]=3 [93]=3 [94]=3 [95]=3 [97]=3 [16]=3 [19]=3 [104]=3 [22]=3 [105]=3 [24]=3 [25]=3 [29]=3 [30]=3 [31]=3 [109]=3 [112]=3 [33]=3 [113]=3 [37]=3 [39]=3 [120]=3 [125]=3 [47]=3 [48]=3 [49]=3 [50]=3 [54]=3 [56]=3 [132]=3 [133]=3 [135]=3 [136]=3 [61]=3 [137]=21 [142]=3 [66]=3 [145]=3 [146]=3 [69]=3 [148]=3 [71]=3 [72]=3 [73]=3 [74]=3 [149]=3 [76]=3 [77]=3 [151]=3 [154]=3)"
+ literal_transitions[16]="([87]=5 [7]=5 [110]=5 [62]=5 [78]=5 [55]=5 [63]=5)"
+ literal_transitions[17]="([41]=3 [45]=3)"
+ literal_transitions[18]="([8]=24)"
+ literal_transitions[19]="([32]=3 [150]=3)"
+ literal_transitions[20]="([96]=3 [17]=3 [116]=3 [21]=3)"
+ literal_transitions[21]="([107]=3 [83]=3 [128]=3 [2]=3 [84]=3)"
+ literal_transitions[24]="([58]=22 [111]=22)"
local -A match_anything_transitions
- match_anything_transitions=([2]=3 [1]=8 [7]=3 [16]=3 [11]=3 [6]=16 [15]=19 [8]=8 [3]=19 [17]=3 [13]=3 [12]=19)
+ match_anything_transitions=([7]=18 [8]=3 [1]=2 [23]=3 [6]=19 [5]=3 [3]=18 [19]=3 [12]=18 [9]=3 [10]=3 [14]=18 [11]=18 [2]=2)
declare -A subword_transitions
@@ -197,7 +214,7 @@ _hyprctl () {
fi
done
fi
- local -A commands=([6]=1 [17]=2 [13]=3 [11]=0)
+ local -A commands=([8]=0 [23]=1 [9]=3 [6]=2)
if [[ -v "commands[$state]" ]]; then
local command_id=${commands[$state]}
@@ -250,4 +267,8 @@ _hyprctl () {
return 0
}
-compdef _hyprctl hyprctl
+if [[ $ZSH_EVAL_CONTEXT =~ :file$ ]]; then
+ compdef _hyprctl hyprctl
+else
+ _hyprctl
+fi
diff --git a/hyprctl/main.cpp b/hyprctl/main.cpp
deleted file mode 100644
index 8fb9194c..00000000
--- a/hyprctl/main.cpp
+++ /dev/null
@@ -1,430 +0,0 @@
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-using namespace Hyprutils::String;
-
-#include "Strings.hpp"
-
-#define PAD
-
-std::string instanceSignature;
-bool quiet = false;
-
-struct SInstanceData {
- std::string id;
- uint64_t time;
- uint64_t pid;
- std::string wlSocket;
- bool valid = true;
-};
-
-void log(std::string str) {
- if (quiet)
- return;
-
- std::cout << str;
-}
-
-std::string getRuntimeDir() {
- const auto XDG = getenv("XDG_RUNTIME_DIR");
-
- if (!XDG) {
- const std::string USERID = std::to_string(getpwuid(getuid())->pw_uid);
- return "/run/user/" + USERID + "/hypr";
- }
-
- return std::string{XDG} + "/hypr";
-}
-
-std::vector instances() {
- std::vector result;
-
- for (const auto& el : std::filesystem::directory_iterator(getRuntimeDir())) {
- if (!el.is_directory() || !std::filesystem::exists(el.path().string() + "/hyprland.lock"))
- continue;
-
- // read lock
- SInstanceData* data = &result.emplace_back();
- data->id = el.path().filename().string();
-
- try {
- data->time = std::stoull(data->id.substr(data->id.find_first_of('_') + 1, data->id.find_last_of('_') - (data->id.find_first_of('_') + 1)));
- } catch (std::exception& e) { continue; }
-
- // read file
- std::ifstream ifs(el.path().string() + "/hyprland.lock");
-
- int i = 0;
- for (std::string line; std::getline(ifs, line); ++i) {
- if (i == 0) {
- try {
- data->pid = std::stoull(line);
- } catch (std::exception& e) { continue; }
- } else if (i == 1) {
- data->wlSocket = line;
- } else
- break;
- }
-
- ifs.close();
- }
-
- std::erase_if(result, [&](const auto& el) { return kill(el.pid, 0) != 0 && errno == ESRCH; });
-
- std::sort(result.begin(), result.end(), [&](const auto& a, const auto& b) { return a.time < b.time; });
-
- return result;
-}
-
-int request(std::string arg, int minArgs = 0) {
- const auto SERVERSOCKET = socket(AF_UNIX, SOCK_STREAM, 0);
-
- const auto ARGS = std::count(arg.begin(), arg.end(), ' ');
-
- if (ARGS < minArgs) {
- log("Not enough arguments, expected at least " + minArgs);
- return -1;
- }
-
- if (SERVERSOCKET < 0) {
- log("Couldn't open a socket (1)");
- return 1;
- }
-
- if (instanceSignature.empty()) {
- log("HYPRLAND_INSTANCE_SIGNATURE was not set! (Is Hyprland running?)");
- return 2;
- }
-
- const std::string USERID = std::to_string(getpwuid(getuid())->pw_uid);
-
- sockaddr_un serverAddress = {0};
- serverAddress.sun_family = AF_UNIX;
-
- std::string socketPath = getRuntimeDir() + "/" + instanceSignature + "/.socket.sock";
-
- strncpy(serverAddress.sun_path, socketPath.c_str(), sizeof(serverAddress.sun_path) - 1);
-
- if (connect(SERVERSOCKET, (sockaddr*)&serverAddress, SUN_LEN(&serverAddress)) < 0) {
- log("Couldn't connect to " + socketPath + ". (3)");
- return 3;
- }
-
- auto sizeWritten = write(SERVERSOCKET, arg.c_str(), arg.length());
-
- if (sizeWritten < 0) {
- log("Couldn't write (4)");
- return 4;
- }
-
- std::string reply = "";
- char buffer[8192] = {0};
-
- sizeWritten = read(SERVERSOCKET, buffer, 8192);
-
- if (sizeWritten < 0) {
- log("Couldn't read (5)");
- return 5;
- }
-
- reply += std::string(buffer, sizeWritten);
-
- while (sizeWritten == 8192) {
- sizeWritten = read(SERVERSOCKET, buffer, 8192);
- if (sizeWritten < 0) {
- log("Couldn't read (5)");
- return 5;
- }
- reply += std::string(buffer, sizeWritten);
- }
-
- close(SERVERSOCKET);
-
- log(reply);
-
- return 0;
-}
-
-int requestHyprpaper(std::string arg) {
- const auto SERVERSOCKET = socket(AF_UNIX, SOCK_STREAM, 0);
-
- if (SERVERSOCKET < 0) {
- log("Couldn't open a socket (1)");
- return 1;
- }
-
- if (instanceSignature.empty()) {
- log("HYPRLAND_INSTANCE_SIGNATURE was not set! (Is Hyprland running?)");
- return 2;
- }
-
- sockaddr_un serverAddress = {0};
- serverAddress.sun_family = AF_UNIX;
-
- const std::string USERID = std::to_string(getpwuid(getuid())->pw_uid);
-
- std::string socketPath = getRuntimeDir() + "/" + instanceSignature + "/.hyprpaper.sock";
-
- strncpy(serverAddress.sun_path, socketPath.c_str(), sizeof(serverAddress.sun_path) - 1);
-
- if (connect(SERVERSOCKET, (sockaddr*)&serverAddress, SUN_LEN(&serverAddress)) < 0) {
- log("Couldn't connect to " + socketPath + ". (3)");
- return 3;
- }
-
- arg = arg.substr(arg.find_first_of('/') + 1); // strip flags
- arg = arg.substr(arg.find_first_of(' ') + 1); // strip "hyprpaper"
-
- auto sizeWritten = write(SERVERSOCKET, arg.c_str(), arg.length());
-
- if (sizeWritten < 0) {
- log("Couldn't write (4)");
- return 4;
- }
-
- char buffer[8192] = {0};
-
- sizeWritten = read(SERVERSOCKET, buffer, 8192);
-
- if (sizeWritten < 0) {
- log("Couldn't read (5)");
- return 5;
- }
-
- close(SERVERSOCKET);
-
- log(std::string(buffer));
-
- return 0;
-}
-
-void batchRequest(std::string arg, bool json) {
- std::string commands = arg.substr(arg.find_first_of(" ") + 1);
-
- if (json) {
- commands = "j/" + std::regex_replace(commands, std::regex(";\\s*"), ";j/");
- }
-
- std::string rq = "[[BATCH]]" + commands;
- request(rq);
-}
-
-void instancesRequest(bool json) {
- std::string result = "";
-
- // gather instance data
- std::vector inst = instances();
-
- if (!json) {
- for (auto& el : inst) {
- result += std::format("instance {}:\n\ttime: {}\n\tpid: {}\n\twl socket: {}\n\n", el.id, el.time, el.pid, el.wlSocket);
- }
- } else {
- result += '[';
- for (auto& el : inst) {
- result += std::format(R"#(
-{{
- "instance": "{}",
- "time": {},
- "pid": {},
- "wl_socket": "{}"
-}},)#",
- el.id, el.time, el.pid, el.wlSocket);
- }
-
- result.pop_back();
- result += "\n]";
- }
-
- log(result + "\n");
-}
-
-std::deque splitArgs(int argc, char** argv) {
- std::deque result;
-
- for (auto i = 1 /* skip the executable */; i < argc; ++i)
- result.push_back(std::string(argv[i]));
-
- return result;
-}
-
-int main(int argc, char** argv) {
- bool parseArgs = true;
-
- if (argc < 2) {
- std::cout << USAGE << std::endl;
- return 1;
- }
-
- std::string fullRequest = "";
- std::string fullArgs = "";
- const auto ARGS = splitArgs(argc, argv);
- bool json = false;
- std::string overrideInstance = "";
-
- for (std::size_t i = 0; i < ARGS.size(); ++i) {
- if (ARGS[i] == "--") {
- // Stop parsing arguments after --
- parseArgs = false;
- continue;
- }
- if (parseArgs && (ARGS[i][0] == '-') && !isNumber(ARGS[i], true) /* For stuff like -2 */) {
- // parse
- if (ARGS[i] == "-j" && !fullArgs.contains("j")) {
- fullArgs += "j";
- json = true;
- } else if (ARGS[i] == "-r" && !fullArgs.contains("r")) {
- fullArgs += "r";
- } else if (ARGS[i] == "-a" && !fullArgs.contains("a")) {
- fullArgs += "a";
- } else if ((ARGS[i] == "-c" || ARGS[i] == "--config") && !fullArgs.contains("c")) {
- fullArgs += "c";
- } else if (ARGS[i] == "--batch") {
- fullRequest = "--batch ";
- } else if (ARGS[i] == "--instance" || ARGS[i] == "-i") {
- ++i;
-
- if (i >= ARGS.size()) {
- std::cout << USAGE << std::endl;
- return 1;
- }
-
- overrideInstance = ARGS[i];
- } else if (ARGS[i] == "-q" || ARGS[i] == "--quiet") {
- quiet = true;
- } else if (ARGS[i] == "--help") {
- const std::string& cmd = ARGS[0];
-
- if (cmd == "hyprpaper") {
- std::cout << HYPRPAPER_HELP << std::endl;
- } else if (cmd == "notify") {
- std::cout << NOTIFY_HELP << std::endl;
- } else if (cmd == "output") {
- std::cout << OUTPUT_HELP << std::endl;
- } else if (cmd == "plugin") {
- std::cout << PLUGIN_HELP << std::endl;
- } else if (cmd == "setprop") {
- std::cout << SETPROP_HELP << std::endl;
- } else if (cmd == "switchxkblayout") {
- std::cout << SWITCHXKBLAYOUT_HELP << std::endl;
- } else {
- std::cout << USAGE << std::endl;
- }
-
- return 1;
- } else {
- std::cout << USAGE << std::endl;
- return 1;
- }
-
- continue;
- }
-
- fullRequest += ARGS[i] + " ";
- }
-
- if (fullRequest.empty()) {
- std::cout << USAGE << std::endl;
- return 1;
- }
-
- fullRequest.pop_back(); // remove trailing space
-
- fullRequest = fullArgs + "/" + fullRequest;
-
- // instances is HIS-independent
- if (fullRequest.contains("/instances")) {
- instancesRequest(json);
- return 0;
- }
-
- if (overrideInstance.contains("_"))
- instanceSignature = overrideInstance;
- else if (!overrideInstance.empty()) {
- if (!isNumber(overrideInstance, false)) {
- log("instance invalid\n");
- return 1;
- }
-
- const auto INSTANCENO = std::stoi(overrideInstance);
-
- const auto INSTANCES = instances();
-
- if (INSTANCENO < 0 || static_cast(INSTANCENO) >= INSTANCES.size()) {
- log("no such instance\n");
- return 1;
- }
-
- instanceSignature = INSTANCES[INSTANCENO].id;
- } else {
- const auto ISIG = getenv("HYPRLAND_INSTANCE_SIGNATURE");
-
- if (!ISIG) {
- log("HYPRLAND_INSTANCE_SIGNATURE not set! (is hyprland running?)\n");
- return 1;
- }
-
- instanceSignature = ISIG;
- }
-
- int exitStatus = 0;
-
- if (fullRequest.contains("/--batch"))
- batchRequest(fullRequest, json);
- else if (fullRequest.contains("/hyprpaper"))
- exitStatus = requestHyprpaper(fullRequest);
- else if (fullRequest.contains("/switchxkblayout"))
- exitStatus = request(fullRequest, 2);
- else if (fullRequest.contains("/seterror"))
- exitStatus = request(fullRequest, 1);
- else if (fullRequest.contains("/setprop"))
- exitStatus = request(fullRequest, 3);
- else if (fullRequest.contains("/plugin"))
- exitStatus = request(fullRequest, 1);
- else if (fullRequest.contains("/dismissnotify"))
- exitStatus = request(fullRequest, 0);
- else if (fullRequest.contains("/notify"))
- exitStatus = request(fullRequest, 2);
- else if (fullRequest.contains("/output"))
- exitStatus = request(fullRequest, 2);
- else if (fullRequest.contains("/setcursor"))
- exitStatus = request(fullRequest, 1);
- else if (fullRequest.contains("/dispatch"))
- exitStatus = request(fullRequest, 1);
- else if (fullRequest.contains("/keyword"))
- exitStatus = request(fullRequest, 2);
- else if (fullRequest.contains("/decorations"))
- exitStatus = request(fullRequest, 1);
- else if (fullRequest.contains("/--help"))
- std::cout << USAGE << std::endl;
- else {
- exitStatus = request(fullRequest);
- }
-
- std::cout << std::flush;
- return exitStatus;
-}
diff --git a/hyprctl/meson.build b/hyprctl/meson.build
deleted file mode 100644
index 5488845f..00000000
--- a/hyprctl/meson.build
+++ /dev/null
@@ -1,10 +0,0 @@
-executable('hyprctl', 'main.cpp',
- dependencies: [
- dependency('hyprutils', version: '>= 0.1.1'),
- ],
- install: true
-)
-
-install_data('hyprctl.bash', install_dir: join_paths(get_option('datadir'), 'bash-completion/completions'), install_tag: 'runtime', rename: 'hyprctl')
-install_data('hyprctl.fish', install_dir: join_paths(get_option('datadir'), 'fish/vendor_completions.d'), install_tag: 'runtime')
-install_data('hyprctl.zsh', install_dir: join_paths(get_option('datadir'), 'zsh/site-functions'), install_tag: 'runtime', rename: '_hyprctl')
diff --git a/hyprctl/Strings.hpp b/hyprctl/src/Strings.hpp
similarity index 85%
rename from hyprctl/Strings.hpp
rename to hyprctl/src/Strings.hpp
index 76e87ecb..549d84bb 100644
--- a/hyprctl/Strings.hpp
+++ b/hyprctl/src/Strings.hpp
@@ -1,5 +1,7 @@
#pragma once
+#include
+
const std::string_view USAGE = R"#(usage: hyprctl [flags] [args...|--help]
commands:
@@ -20,6 +22,7 @@ commands:
getoption