diff --git a/.clang-tidy b/.clang-tidy index f0dfdf1b..db499035 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,4 +1,111 @@ -WarningsAsErrors: '*' +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: > diff --git a/.github/actions/setup_base/action.yml b/.github/actions/setup_base/action.yml index 7eab5649..9fcaabfb 100644 --- a/.github/actions/setup_base/action.yml +++ b/.github/actions/setup_base/action.yml @@ -24,6 +24,7 @@ runs: glm \ glslang \ go \ + gtest \ hyprlang \ hyprcursor \ jq \ @@ -45,6 +46,7 @@ runs: libxkbfile \ lld \ meson \ + muparser \ ninja \ pango \ pixman \ @@ -74,16 +76,25 @@ runs: cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` cmake --install build - - name: Get hyprgraphics-git + - name: Get hyprwire-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 + 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: | 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 fda97f57..75b4b7c5 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,6 +1,8 @@ diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 06c1e197..2ec558ed 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -21,22 +21,19 @@ jobs: - name: Build Hyprland run: | - CFLAGS=-Werror CXXFLAGS=-Werror 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@v4 @@ -44,86 +41,43 @@ jobs: name: Build archive path: Hyprland.tar.xz - meson: - if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork - 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: - if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork - 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: - if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork - 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: permissions: read-all if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork - name: "Code Style (Arch)" + 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 index e935a605..505829e3 100644 --- a/.github/workflows/clang-format.yml +++ b/.github/workflows/clang-format.yml @@ -4,43 +4,23 @@ jobs: clang-format: permissions: write-all if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork - name: "Code Style (Arch)" + 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: Configure - run: meson setup build -Ddefault_library=static - name: clang-format check - run: ninja -C build clang-format-check + uses: jidicula/clang-format-action@v4.16.0 + with: + exclude-regex: ^subprojects$ - - name: clang-format apply - if: ${{ failure() && github.event_name == 'pull_request' }} - run: ninja -C build clang-format - - - name: Create patch + - 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), or directly apply this patch:' > clang-format.patch - echo '
' >> clang-format.patch - echo 'clang-format.patch' >> clang-format.patch - echo >> clang-format.patch - echo '```diff' >> clang-format.patch - git diff >> clang-format.patch - echo '```' >> clang-format.patch - echo >> clang-format.patch - echo '
' >> clang-format.patch + 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: Comment patch + - name: Post comment if: ${{ failure() && github.event_name == 'pull_request' }} uses: mshick/add-pr-comment@v2 with: 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 5b2e81cf..00000000 --- a/.github/workflows/nix-build.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: Nix (Build) - -on: - workflow_call: - secrets: - CACHIX_AUTH_TOKEN: - required: false - -jobs: - build: - strategy: - matrix: - package: - - hyprland - # - hyprland-cross # cross compiling fails due to qt - # failure chain: hyprland-qtutils -> qt6.qtsvg -> qt6.qtbase -> psqlodbc & qt6.qttranslations - - xdg-desktop-portal-hyprland - - runs-on: ubuntu-latest - steps: - - uses: DeterminateSystems/nix-installer-action@main - - - uses: cachix/cachix-action@v15 - with: - name: hyprland - authToken: "${{ secrets.CACHIX_AUTH_TOKEN }}" - - - run: nix build 'github:hyprwm/Hyprland?ref=${{ github.ref }}#${{ matrix.package }}' -L --extra-substituters "https://hyprland.cachix.org" diff --git a/.github/workflows/nix-ci.yml b/.github/workflows/nix-ci.yml index 75c19790..5b22e992 100644 --- a/.github/workflows/nix-ci.yml +++ b/.github/workflows/nix-ci.yml @@ -1,4 +1,4 @@ -name: Nix (CI) +name: Nix on: [push, pull_request, workflow_dispatch] @@ -8,7 +8,22 @@ jobs: uses: ./.github/workflows/nix-update-inputs.yml secrets: inherit - build: + hyprland: if: (github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork) - uses: ./.github/workflows/nix-build.yml + 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 c9a094a2..a3084b27 100644 --- a/.github/workflows/nix-update-inputs.yml +++ b/.github/workflows/nix-update-inputs.yml @@ -17,7 +17,24 @@ jobs: 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 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 44baff97..09aae111 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -9,17 +9,36 @@ jobs: source-tarball: runs-on: ubuntu-latest steps: - - name: Checkout Hyprland - id: checkout - uses: actions/checkout@v4 + - 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 + 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/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 4ced1678..4e5c2323 100644 --- a/.gitignore +++ b/.gitignore @@ -32,6 +32,8 @@ src/render/shaders/*.inc src/render/shaders/Shaders.hpp hyprctl/hyprctl +hyprctl/hw-protocols/*.c* +hyprctl/hw-protocols/*.h* gmon.out *.out @@ -42,6 +44,7 @@ PKGBUILD src/version.h hyprpm/Makefile hyprctl/Makefile +example/hyprland.desktop **/.#*.* **/#*.*# diff --git a/CMakeLists.txt b/CMakeLists.txt index bc016d85..87574b82 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,6 +9,7 @@ project( DESCRIPTION "A Modern C++ Wayland Compositor" VERSION ${VER}) +include(CTest) include(CheckIncludeFile) include(GNUInstallDirs) @@ -16,18 +17,21 @@ set(HYPRLAND_VERSION ${VER}) set(PREFIX ${CMAKE_INSTALL_PREFIX}) set(INCLUDEDIR ${CMAKE_INSTALL_INCLUDEDIR}) set(BINDIR ${CMAKE_INSTALL_BINDIR}) -configure_file(hyprland.pc.in hyprland.pc @ONLY) 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}) # Make shader files includable execute_process(COMMAND ./scripts/generateShaderIncludes.sh - WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) + 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() find_package(PkgConfig REQUIRED) @@ -35,11 +39,23 @@ find_package(PkgConfig REQUIRED) # provide a .pc file and won't be detected this way pkg_check_modules(udis_dep IMPORTED_TARGET udis86>=1.7.2) -# Fallback to subproject +# Find non-pkgconfig udis86, otherwise fallback to subproject if(NOT udis_dep_FOUND) - add_subdirectory("subprojects/udis86") - include_directories("subprojects/udis86") - message(STATUS "udis86 dependency not found, falling back to subproject") + 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() + +find_library(librt rt) +if("${librt}" MATCHES "librt-NOTFOUND") + unset(LIBRT) +else() + set(LIBRT rt) endif() if(CMAKE_BUILD_TYPE) @@ -70,9 +86,11 @@ message( 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}") @@ -84,14 +102,20 @@ 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) @@ -99,55 +123,158 @@ 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(aquamarine_dep REQUIRED IMPORTED_TARGET aquamarine>=0.8.0) -pkg_check_modules(hyprlang_dep REQUIRED IMPORTED_TARGET hyprlang>=0.3.2) -pkg_check_modules(hyprcursor_dep REQUIRED IMPORTED_TARGET hyprcursor>=0.1.7) -pkg_check_modules(hyprutils_dep REQUIRED IMPORTED_TARGET hyprutils>=0.7.0) -pkg_check_modules(hyprgraphics_dep REQUIRED IMPORTED_TARGET hyprgraphics>=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) -add_compile_definitions(AQUAMARINE_VERSION="${aquamarine_dep_VERSION}") -add_compile_definitions(AQUAMARINE_VERSION_MAJOR=${AQ_VERSION_MAJOR}) -add_compile_definitions(AQUAMARINE_VERSION_MINOR=${AQ_VERSION_MINOR}) -add_compile_definitions(AQUAMARINE_VERSION_PATCH=${AQ_VERSION_PATCH}) -add_compile_definitions(HYPRLANG_VERSION="${hyprlang_dep_VERSION}") -add_compile_definitions(HYPRUTILS_VERSION="${hyprutils_dep_VERSION}") -add_compile_definitions(HYPRCURSOR_VERSION="${hyprcursor_dep_VERSION}") -add_compile_definitions(HYPRGRAPHICS_VERSION="${hyprgraphics_dep_VERSION}") +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 - xkbcommon + IMPORTED_TARGET GLOBAL + xkbcommon>=${XKBCOMMON_MINIMUM_VERSION} uuid - wayland-server>=1.22.90 - wayland-protocols>=1.43 + wayland-server>=${WAYLAND_SERVER_MINIMUM_VERSION} + wayland-protocols>=${WAYLAND_SERVER_PROTOCOLS_MINIMUM_VERSION} cairo pango pangocairo pixman-1 xcursor libdrm - libinput + libinput>=${LIBINPUT_MINIMUM_VERSION} gbm gio-2.0 - re2) + 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) @@ -155,9 +282,14 @@ if(USE_TRACY) message(STATUS "Tracy enabled, TRACY_CPP_FILES: " ${TRACY_CPP_FILES}) endif() -add_executable(Hyprland ${SRCFILES} ${TRACY_CPP_FILES}) +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") @@ -165,23 +297,8 @@ if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG) if(WITH_ASAN) message(STATUS "Enabling ASan") - target_link_libraries(Hyprland asan) - target_compile_options(Hyprland PUBLIC -fsanitize=address) - endif() - - if(USE_TRACY) - message(STATUS "Tracy is turned on") - - option(TRACY_ENABLE "" ON) - option(TRACY_ON_DEMAND "" ON) - add_subdirectory(subprojects/tracy) - - target_link_libraries(Hyprland Tracy::TracyClient) - - if(USE_TRACY_GPU) - message(STATUS "Tracy GPU Profiling is turned on") - add_compile_definitions(USE_TRACY_GPU) - endif() + target_link_libraries(hyprland_lib PUBLIC asan) + target_compile_options(hyprland_lib PUBLIC -fsanitize=address) endif() add_compile_options(-fno-pie -fno-builtin) @@ -192,6 +309,27 @@ if(CMAKE_BUILD_TYPE MATCHES Debug OR CMAKE_BUILD_TYPE MATCHES DEBUG) endif() endif() +if(USE_TRACY) + message(STATUS "Tracy is turned on") + + option(TRACY_ENABLE "" ON) + option(TRACY_ON_DEMAND "" ON) + add_subdirectory(subprojects/tracy) + + add_compile_options(-fno-omit-frame-pointer) + + 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") @@ -201,24 +339,19 @@ 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() 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 PkgConfig::inotify) -endif() - -if(LEGACY_RENDERER) - message(STATUS "Using the legacy GLES2 renderer!") - add_compile_definitions(LEGACY_RENDERER) + target_link_libraries(hyprland_lib PUBLIC PkgConfig::inotify) endif() if(NO_XWAYLAND) @@ -226,10 +359,7 @@ if(NO_XWAYLAND) add_compile_definitions(NO_XWAYLAND) else() message(STATUS "XWAYLAND Enabled (NO_XWAYLAND not defined) checking deps...") - pkg_check_modules( - xdeps - REQUIRED - IMPORTED_TARGET + set(XWAYLAND_DEPENDENCIES xcb xcb-render xcb-xfixes @@ -237,9 +367,21 @@ else() xcb-composite xcb-res xcb-errors) - target_link_libraries(Hyprland PkgConfig::xdeps) + + 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...") else() @@ -260,30 +402,42 @@ 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 + hyprland_lib + PUBLIC PkgConfig::aquamarine_dep PkgConfig::hyprlang_dep PkgConfig::hyprutils_dep PkgConfig::hyprcursor_dep PkgConfig::hyprgraphics_dep - PkgConfig::deps) + PkgConfig::deps +) + +target_link_libraries( + Hyprland + ${LIBRT} + hyprland_lib) if(udis_dep_FOUND) - target_link_libraries(Hyprland PkgConfig::udis_dep) + 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 libudis86) + 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(protocolnew protoPath protoName external) if(external) @@ -297,10 +451,15 @@ function(protocolnew protoPath protoName external) COMMAND hyprwayland-scanner ${path}/${protoName}.xml ${CMAKE_SOURCE_DIR}/protocols/ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) - target_sources(Hyprland PRIVATE protocols/${protoName}.cpp + target_sources(hyprland_lib 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( @@ -310,12 +469,21 @@ function(protocolWayland) hyprwayland-scanner --wayland-enums ${WAYLAND_SCANNER_PKGDATA_DIR}/wayland.xml ${CMAKE_SOURCE_DIR}/protocols/ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}) - target_sources(Hyprland PRIVATE protocols/wayland.cpp protocols/wayland.hpp) + 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 OpenGL::EGL OpenGL::GL Threads::Threads) +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() pkg_check_modules(hyprland_protocols_dep hyprland-protocols>=0.6.4) if(hyprland_protocols_dep_FOUND) @@ -343,13 +511,12 @@ 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" "xx-color-management-v4" true) -protocolnew("protocols" "frog-color-management-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) +protocolnew("${HYPRLAND_PROTOCOLS}/protocols" "hyprland-toplevel-mapping-v1" + true) protocolnew("staging/tearing-control" "tearing-control-v1" false) protocolnew("staging/fractional-scale" "fractional-scale-v1" false) @@ -386,11 +553,19 @@ 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(start) if(NO_HYPRPM) message(STATUS "hyprpm is disabled") @@ -409,6 +584,11 @@ install( \"\$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_DATAROOTDIR}/wayland-sessions) @@ -417,7 +597,6 @@ add_compile_definitions(DATAROOTDIR="${CMAKE_INSTALL_FULL_DATAROOTDIR}") # installable assets file(GLOB_RECURSE INSTALLABLE_ASSETS "assets/install/*") -list(FILTER INSTALLABLE_ASSETS EXCLUDE REGEX "meson.build") install(FILES ${INSTALLABLE_ASSETS} DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/hypr) @@ -453,5 +632,49 @@ install( FILES_MATCHING PATTERN "*.h" PATTERN "*.hpp" - PATTERN "*.inc" - ) + 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 7405cfad..852fcddf 100644 --- a/Makefile +++ b/Makefile @@ -3,20 +3,12 @@ PREFIX = /usr/local stub: @echo "Do not run $(MAKE) directly without any arguments. Please refer to the wiki on how to compile Hyprland." -legacyrenderer: - cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Release -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./build - cmake --build ./build --config Release --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` - -legacyrendererdebug: - cmake --no-warn-unused-cli -DCMAKE_BUILD_TYPE:STRING=Debug -DCMAKE_INSTALL_PREFIX:STRING=${PREFIX} -DLEGACY_RENDERER:BOOL=true -S . -B ./build - cmake --build ./build --config Debug --target all -j`nproc 2>/dev/null || getconf NPROCESSORS_CONF` - release: 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 + 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: @@ -26,6 +18,7 @@ nopch: clear: rm -rf build rm -f ./protocols/*.h ./protocols/*.c ./protocols/*.cpp ./protocols/*.hpp + rm -f ./hyprctl/hw-protocols/*.cpp ./hyprctl/hw-protocols/*.hpp all: $(MAKE) clear @@ -95,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 0970819c..bb74c4e4 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@
-![Badge Workflow] +[![Badge Workflow]][Workflow] [![Badge License]][License] ![Badge Language] [![Badge Pull Requests]][Pull Requests] @@ -100,7 +100,7 @@ easy IPC, much more QoL stuff than other compositors and more... -[Configure]: https://wiki.hyprland.org/Configuring/ +[Configure]: https://wiki.hypr.land/Configuring/ [Stars]: https://starchart.cc/hyprwm/Hyprland [Hypr]: https://github.com/hyprwm/Hypr @@ -108,9 +108,10 @@ easy IPC, much more QoL stuff than other 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 @@ -125,9 +126,9 @@ easy IPC, much more QoL stuff than other compositors and more... -[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/VERSION b/VERSION index 5c4503b7..524456c7 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.49.0 +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 @@ - - -
- - - -

Hyprland

-
-
-
-
+ .st4 { + fill: url(#e); + } + + .st5 { + fill: url(#f); + } + + .st6 { + fill: url(#g); + } + + .st7 { + fill: url(#h); + } + + .st8 { + fill: url(#i); + } +