mirror of
https://github.com/hyprwm/hyprlock.git
synced 2026-05-20 11:48:07 +02:00
Merge edb9ec890f into ca2aa5e5e3
This commit is contained in:
commit
8d2354ecca
18 changed files with 975 additions and 90 deletions
|
|
@ -1,8 +1,13 @@
|
|||
name: Build
|
||||
name: Build (Nix)
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
secrets:
|
||||
CACHIX_AUTH_TOKEN:
|
||||
required: false
|
||||
|
||||
on: [push, pull_request, workflow_dispatch]
|
||||
jobs:
|
||||
nix:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
|
@ -42,7 +47,6 @@ jobs:
|
|||
# with:
|
||||
# name: hyprland
|
||||
# authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
|
||||
|
||||
#
|
||||
- name: Build
|
||||
run: nix flake check --print-build-logs --keep-going
|
||||
|
||||
run: nix build 'github:${{ github.repository }}?ref=${{ github.ref }}' -L --extra-substituters "https://hyprland.cachix.org"
|
||||
15
.github/workflows/nix-ci.yml
vendored
Normal file
15
.github/workflows/nix-ci.yml
vendored
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
name: Nix
|
||||
|
||||
on: [push, pull_request, workflow_dispatch]
|
||||
|
||||
jobs:
|
||||
hyprlock:
|
||||
if: (github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork)
|
||||
uses: ./.github/workflows/nix-build.yml
|
||||
secrets: inherit
|
||||
|
||||
test:
|
||||
if: (github.event_name != 'pull_request' || github.event.pull_request.head.repo.fork)
|
||||
needs: hyprlock
|
||||
uses: ./.github/workflows/nix-test.yml
|
||||
secrets: inherit
|
||||
66
.github/workflows/nix-test.yml
vendored
Normal file
66
.github/workflows/nix-test.yml
vendored
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
name: Test (Nix)
|
||||
|
||||
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
|
||||
primary-key: nix-${{ runner.os }}
|
||||
# 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
|
||||
# 1G = 1073741824
|
||||
gc-max-store-size-linux: 5G
|
||||
# do purge caches
|
||||
purge: true
|
||||
# purge all versions of the cache
|
||||
purge-prefixes: nix-${{ runner.os }}
|
||||
# created more than this number of seconds ago
|
||||
purge-created: 0
|
||||
# or, last accessed more than this number of seconds ago
|
||||
# relative to the start of the `Post Restore and save Nix store` phase
|
||||
purge-last-accessed: 0
|
||||
# except any version with the key that is the same as the `primary-key`
|
||||
purge-primary-key: never
|
||||
|
||||
#- 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 logs
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: logs
|
||||
path: result/logs
|
||||
|
||||
- name: Upload traces
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: traces
|
||||
path: result/traces
|
||||
|
|
@ -163,3 +163,13 @@ install(
|
|||
FILES ${CMAKE_SOURCE_DIR}/assets/example.conf
|
||||
DESTINATION ${CMAKE_INSTALL_FULL_DATAROOTDIR}/hypr
|
||||
RENAME hyprlock.conf)
|
||||
|
||||
if(TESTS)
|
||||
include(CTest)
|
||||
message(STATUS "Building hyprlock test meta package")
|
||||
|
||||
enable_testing()
|
||||
add_custom_target(tests)
|
||||
|
||||
add_subdirectory(tests)
|
||||
endif()
|
||||
|
|
|
|||
12
flake.lock
generated
12
flake.lock
generated
|
|
@ -62,11 +62,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1772459870,
|
||||
"narHash": "sha256-xxkK2Cvqxpf/4UGcJ/TyCwrvmiNWsKsJfFzHMp2bxis=",
|
||||
"lastModified": 1774534854,
|
||||
"narHash": "sha256-grFWyjph17nSuIGE+eh9oPEW5prXRzyWsQ4xCvXTzWc=",
|
||||
"owner": "hyprwm",
|
||||
"repo": "hyprutils",
|
||||
"rev": "e63f3a79334dec49f8eb1691f66f18115df04085",
|
||||
"rev": "762166b516432ce4b02bfbae365f1daa6f88f76d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
@ -100,11 +100,11 @@
|
|||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1772433332,
|
||||
"narHash": "sha256-izhTDFKsg6KeVBxJS9EblGeQ8y+O8eCa6RcW874vxEc=",
|
||||
"lastModified": 1774386573,
|
||||
"narHash": "sha256-4hAV26quOxdC6iyG7kYaZcM3VOskcPUrdCQd/nx8obc=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "cf59864ef8aa2e178cccedbe2c178185b0365705",
|
||||
"rev": "46db2e09e1d3f113a13c0d7b81e2f221c63b8ce9",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
|
|||
59
flake.nix
59
flake.nix
|
|
@ -32,39 +32,42 @@
|
|||
};
|
||||
};
|
||||
|
||||
outputs =
|
||||
{
|
||||
self,
|
||||
nixpkgs,
|
||||
systems,
|
||||
...
|
||||
}@inputs:
|
||||
let
|
||||
inherit (nixpkgs) lib;
|
||||
eachSystem = lib.genAttrs (import systems);
|
||||
pkgsFor = eachSystem (
|
||||
system:
|
||||
outputs = {
|
||||
self,
|
||||
nixpkgs,
|
||||
systems,
|
||||
...
|
||||
} @ inputs: let
|
||||
inherit (nixpkgs) lib;
|
||||
eachSystem = lib.genAttrs (import systems);
|
||||
pkgsFor = eachSystem (
|
||||
system:
|
||||
import nixpkgs {
|
||||
localSystem.system = system;
|
||||
overlays = with self.overlays; [ hyprlock-with-deps ];
|
||||
overlays = with self.overlays; [hyprlock-with-deps];
|
||||
}
|
||||
);
|
||||
in
|
||||
{
|
||||
overlays = import ./nix/overlays.nix { inherit inputs lib self; };
|
||||
|
||||
packages = eachSystem (system: {
|
||||
default = self.packages.${system}.hyprlock;
|
||||
inherit (pkgsFor.${system}) hyprlock;
|
||||
);
|
||||
pkgsDebugFor = eachSystem (system:
|
||||
import nixpkgs {
|
||||
localSystem = system;
|
||||
overlays = with self.overlays; [hyprlock-debug hyprlock-with-deps];
|
||||
});
|
||||
in {
|
||||
overlays = import ./nix/overlays.nix {inherit inputs lib self;};
|
||||
|
||||
homeManagerModules = {
|
||||
default = self.homeManagerModules.hyprlock;
|
||||
hyprlock = builtins.throw "hyprlock: the flake HM module has been removed. Use the module from Home Manager upstream.";
|
||||
};
|
||||
packages = eachSystem (system: {
|
||||
default = self.packages.${system}.hyprlock;
|
||||
inherit (pkgsFor.${system}) hyprlock;
|
||||
inherit (pkgsDebugFor.${system}) hyprlock-debug hyprlock-test-meta;
|
||||
});
|
||||
|
||||
checks = eachSystem (system: self.packages.${system});
|
||||
|
||||
formatter = eachSystem (system: pkgsFor.${system}.nixfmt-tree);
|
||||
homeManagerModules = {
|
||||
default = self.homeManagerModules.hyprlock;
|
||||
hyprlock = builtins.throw "hyprlock: the flake HM module has been removed. Use the module from Home Manager upstream.";
|
||||
};
|
||||
|
||||
checks = eachSystem (system: self.packages.${system} // (import ./nix/tests/default.nix inputs pkgsFor.${system}));
|
||||
|
||||
formatter = eachSystem (system: pkgsFor.${system}.nixfmt-tree);
|
||||
};
|
||||
}
|
||||
|
|
|
|||
103
nix/default.nix
103
nix/default.nix
|
|
@ -1,6 +1,7 @@
|
|||
{
|
||||
lib,
|
||||
stdenv,
|
||||
stdenvAdapters,
|
||||
cmake,
|
||||
pkg-config,
|
||||
cairo,
|
||||
|
|
@ -19,49 +20,73 @@
|
|||
wayland,
|
||||
wayland-protocols,
|
||||
wayland-scanner,
|
||||
debug ? false,
|
||||
version ? "git",
|
||||
shortRev ? "",
|
||||
}:
|
||||
stdenv.mkDerivation {
|
||||
pname = "hyprlock";
|
||||
inherit version;
|
||||
}: let
|
||||
inherit (builtins) foldl';
|
||||
inherit (lib.lists) flatten;
|
||||
inherit (lib.sources) cleanSourceWith cleanSource;
|
||||
inherit (lib.strings) hasSuffix optionalString;
|
||||
|
||||
src = ../.;
|
||||
|
||||
nativeBuildInputs = [
|
||||
cmake
|
||||
pkg-config
|
||||
hyprwayland-scanner
|
||||
wayland-scanner
|
||||
adapters = flatten [
|
||||
stdenvAdapters.useMoldLinker
|
||||
(lib.optional debug stdenvAdapters.keepDebugInfo)
|
||||
];
|
||||
|
||||
buildInputs = [
|
||||
cairo
|
||||
libdrm
|
||||
libGL
|
||||
libxkbcommon
|
||||
libgbm
|
||||
hyprgraphics
|
||||
hyprlang
|
||||
hyprutils
|
||||
pam
|
||||
pango
|
||||
sdbus-cpp_2
|
||||
systemdLibs
|
||||
wayland
|
||||
wayland-protocols
|
||||
];
|
||||
customStdenv = foldl' (acc: adapter: adapter acc) stdenv adapters;
|
||||
in
|
||||
customStdenv.mkDerivation {
|
||||
pname = "hyprlock${optionalString debug "-debug"}";
|
||||
inherit version;
|
||||
|
||||
cmakeFlags = lib.mapAttrsToList lib.cmakeFeature {
|
||||
HYPRLOCK_COMMIT = shortRev;
|
||||
HYPRLOCK_VERSION_COMMIT = ""; # Intentionally left empty (hyprlock --version will always print the commit)
|
||||
};
|
||||
src = cleanSourceWith {
|
||||
filter = name: _type: let
|
||||
baseName = baseNameOf (toString name);
|
||||
in
|
||||
! (hasSuffix ".nix" baseName);
|
||||
src = cleanSource ../.;
|
||||
};
|
||||
|
||||
meta = {
|
||||
homepage = "https://github.com/hyprwm/hyprlock";
|
||||
description = "A gpu-accelerated screen lock for Hyprland";
|
||||
license = lib.licenses.bsd3;
|
||||
platforms = lib.platforms.linux;
|
||||
mainProgram = "hyprlock";
|
||||
};
|
||||
}
|
||||
nativeBuildInputs = [
|
||||
cmake
|
||||
pkg-config
|
||||
hyprwayland-scanner
|
||||
wayland-scanner
|
||||
];
|
||||
|
||||
buildInputs = [
|
||||
cairo
|
||||
libdrm
|
||||
libGL
|
||||
libxkbcommon
|
||||
libgbm
|
||||
hyprgraphics
|
||||
hyprlang
|
||||
hyprutils
|
||||
pam
|
||||
pango
|
||||
sdbus-cpp_2
|
||||
systemdLibs
|
||||
wayland
|
||||
wayland-protocols
|
||||
];
|
||||
|
||||
cmakeFlags = lib.mapAttrsToList lib.cmakeFeature {
|
||||
HYPRLOCK_COMMIT = shortRev;
|
||||
HYPRLOCK_VERSION_COMMIT = ""; # Intentionally left empty (hyprlock --version will always print the commit)
|
||||
};
|
||||
|
||||
cmakeBuildType =
|
||||
if debug
|
||||
then "Debug"
|
||||
else "Release";
|
||||
|
||||
meta = {
|
||||
homepage = "https://github.com/hyprwm/hyprlock";
|
||||
description = "A gpu-accelerated screen lock for Hyprland";
|
||||
license = lib.licenses.bsd3;
|
||||
platforms = lib.platforms.linux;
|
||||
mainProgram = "hyprlock";
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,19 +2,15 @@
|
|||
lib,
|
||||
inputs,
|
||||
self,
|
||||
}:
|
||||
let
|
||||
mkDate =
|
||||
longDate:
|
||||
(lib.concatStringsSep "-" [
|
||||
(builtins.substring 0 4 longDate)
|
||||
(builtins.substring 4 2 longDate)
|
||||
(builtins.substring 6 2 longDate)
|
||||
]);
|
||||
}: let
|
||||
mkDate = longDate: (lib.concatStringsSep "-" [
|
||||
(builtins.substring 0 4 longDate)
|
||||
(builtins.substring 4 2 longDate)
|
||||
(builtins.substring 6 2 longDate)
|
||||
]);
|
||||
|
||||
version = lib.removeSuffix "\n" (builtins.readFile ../VERSION);
|
||||
in
|
||||
{
|
||||
in {
|
||||
default = inputs.self.overlays.hyprlock;
|
||||
|
||||
hyprlock-with-deps = lib.composeManyExtensions [
|
||||
|
|
@ -37,4 +33,18 @@ in
|
|||
shortRev = self.sourceInfo.shortRev or "dirty";
|
||||
};
|
||||
};
|
||||
|
||||
hyprlock-debug = lib.composeManyExtensions [
|
||||
self.overlays.hyprlock
|
||||
# Dependencies
|
||||
(final: prev: {
|
||||
hyprutils = prev.hyprutils.override {debug = true;};
|
||||
hyprgraphics = prev.hyprgraphics.override {debug = true;};
|
||||
hyprlock-debug = prev.hyprlock.override {debug = true;};
|
||||
hyprlock-test-meta = prev.callPackage ./test-meta.nix {
|
||||
stdenv = prev.gcc15Stdenv;
|
||||
version = version + "+date=" + (mkDate (inputs.self.lastModifiedDate or "19700101")) + "_" + (inputs.self.shortRev or "dirty");
|
||||
};
|
||||
})
|
||||
];
|
||||
}
|
||||
|
|
|
|||
45
nix/test-meta.nix
Normal file
45
nix/test-meta.nix
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
{
|
||||
cmake,
|
||||
egl-wayland,
|
||||
hyprland-protocols,
|
||||
hyprlock,
|
||||
hyprwayland-scanner,
|
||||
lib,
|
||||
pkg-config,
|
||||
stdenv,
|
||||
stdenvAdapters,
|
||||
wayland-scanner,
|
||||
version ? "git",
|
||||
}: let
|
||||
inherit (lib.sources) cleanSourceWith cleanSource;
|
||||
inherit (lib.strings) hasSuffix;
|
||||
in
|
||||
stdenv.mkDerivation (finalAttrs: {
|
||||
pname = "hyprlock-test-meta";
|
||||
inherit version;
|
||||
|
||||
src = cleanSourceWith {
|
||||
filter = name: _type: let
|
||||
baseName = baseNameOf (toString name);
|
||||
in
|
||||
! (hasSuffix ".nix" baseName);
|
||||
src = cleanSource ../tests;
|
||||
};
|
||||
|
||||
nativeBuildInputs = [
|
||||
cmake
|
||||
hyprland-protocols
|
||||
hyprwayland-scanner
|
||||
pkg-config
|
||||
wayland-scanner
|
||||
];
|
||||
|
||||
buildInputs = hyprlock.buildInputs;
|
||||
|
||||
meta = {
|
||||
homepage = "https://github.com/hyprwm/hyprlock";
|
||||
description = "Hyprlock testing utility";
|
||||
license = lib.licenses.bsd3;
|
||||
platforms = hyprlock.meta.platforms;
|
||||
};
|
||||
})
|
||||
164
nix/tests/default.nix
Normal file
164
nix/tests/default.nix
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
inputs: pkgs: let
|
||||
inherit (pkgs) lib;
|
||||
inherit (lib.lists) flatten;
|
||||
flake = inputs.self.packages.${pkgs.stdenv.hostPlatform.system};
|
||||
|
||||
env = {
|
||||
#"AQ_TRACE" = "1";
|
||||
#"HYPRLAND_TRACE" = "1";
|
||||
"HYPRLAND_HEADLESS_ONLY" = "1";
|
||||
"XDG_RUNTIME_DIR" = "/tmp";
|
||||
"XDG_CACHE_HOME" = "/tmp";
|
||||
};
|
||||
|
||||
envAddToSystemdRun = lib.concatStringsSep " " (
|
||||
lib.mapAttrsToList (k: v: "--setenv ${k}=${v} ") env
|
||||
);
|
||||
|
||||
APITRACE_RECORD = true;
|
||||
APITRACE_RECORD_PY = if APITRACE_RECORD then "True" else "False";
|
||||
in {
|
||||
tests = pkgs.testers.runNixOSTest {
|
||||
name = "hyprlock-tests";
|
||||
|
||||
nodes.machine = {pkgs, ...}: {
|
||||
environment.systemPackages = with pkgs; flatten [
|
||||
# Programs needed for tests
|
||||
coreutils # date command
|
||||
procps # pidof
|
||||
(lib.optional APITRACE_RECORD apitrace)
|
||||
];
|
||||
|
||||
# Enabled by default for some reason
|
||||
services.speechd.enable = false;
|
||||
|
||||
environment.variables = env;
|
||||
|
||||
programs.hyprland = {
|
||||
enable = true;
|
||||
#withUWSM = true
|
||||
};
|
||||
|
||||
programs.hyprlock = {
|
||||
enable = true;
|
||||
package = flake.hyprlock;
|
||||
};
|
||||
|
||||
networking.dhcpcd.enable = false;
|
||||
|
||||
# Disable portals
|
||||
xdg.portal.enable = lib.mkForce false;
|
||||
|
||||
# Autologin root into tty
|
||||
services.getty.autologinUser = "alice";
|
||||
|
||||
system.stateVersion = "24.11";
|
||||
|
||||
environment.etc."hyprlock/assets".source = "${flake.hyprlock-test-meta}/share/hypr/assets/";
|
||||
|
||||
users.users.alice = {
|
||||
isNormalUser = true;
|
||||
# password: abcdefghijklmnopqrstuvwxyz1234567890-=!@#$%^&*()_+[]{};\':\\"]\\|,./<>?`~äöüćńóśź
|
||||
hashedPassword = "$y$j9T$s.atBE5..ISB2OoPWrXnU1$.8yaRmR9iBV9e.Q9wM1hG0ciMMYLGhpmDqsJo8Sjiv2";
|
||||
};
|
||||
|
||||
virtualisation = {
|
||||
cores = 4;
|
||||
# Might crash with less
|
||||
memorySize = 8192;
|
||||
resolution = {
|
||||
x = 1920;
|
||||
y = 1080;
|
||||
};
|
||||
|
||||
# Doesn't seem to do much, thought it would fix XWayland crashing
|
||||
qemu.options = ["-vga none -device virtio-gpu-pci"];
|
||||
};
|
||||
};
|
||||
|
||||
testScript = ''
|
||||
from pathlib import Path
|
||||
# Wait for tty to be up
|
||||
machine.wait_for_unit("multi-user.target")
|
||||
# Startup Hyprland as the test compositor for hyprlock
|
||||
print("Running Hyprland")
|
||||
machine.execute("systemd-run -q -u hyprland --uid $(id -u alice) -p RuntimeMaxSec=60 ${envAddToSystemdRun} --setenv PATH=$PATH ${pkgs.hyprland}/bin/Hyprland -c ${flake.hyprlock-test-meta}/share/hypr/hyprland.conf")
|
||||
machine.wait_for_file("/tmp/hyprland_exec_once_notification")
|
||||
machine.execute("sleep 1") # slack just to be save
|
||||
|
||||
_, systeminfo = machine.execute("hyprctl --instance 0 systeminfo")
|
||||
print(systeminfo)
|
||||
|
||||
test_files = [Path("${flake.hyprlock}/share/hypr/hyprlock.conf")] # also test the example configuration
|
||||
test_files += list(Path("${flake.hyprlock-test-meta}/share/hypr/configs/").iterdir())
|
||||
for hyprlock_config in test_files:
|
||||
print(f"Testing configuration file {hyprlock_config}")
|
||||
log_file_path = "/tmp/hyprlock_test_" + hyprlock_config.stem
|
||||
|
||||
hyprlock_cmd = f"hyprlock --config {str(hyprlock_config)} -v 2>&1 >{log_file_path}; echo $? > /tmp/exit_status"
|
||||
if ${APITRACE_RECORD_PY}:
|
||||
hyprlock_cmd = f"${lib.getExe' pkgs.apitrace "apitrace"} trace --output {log_file_path}.trace --api egl {hyprlock_cmd}"
|
||||
machine.execute(f"hyprctl --instance 0 dispatch exec '{hyprlock_cmd}'")
|
||||
|
||||
wait_for_lock_exit_status, out = machine.execute("WAYLAND_DISPLAY=wayland-1 ${lib.getExe' flake.hyprlock-test-meta "wait-for-lock"}")
|
||||
print(f"Wait for lock exit code: {wait_for_lock_exit_status}")
|
||||
if wait_for_lock_exit_status != 0:
|
||||
break
|
||||
|
||||
_, hyprlock_pid = machine.execute("pidof hyprlock")
|
||||
print(f"Hyprlock pid {hyprlock_pid}")
|
||||
|
||||
# wrong password
|
||||
machine.send_chars("asdf\n")
|
||||
|
||||
machine.execute("sleep 3") # default fail_timeout is 2 seconds
|
||||
|
||||
# correct password
|
||||
machine.send_chars("abcdefghijklmnopqrstuvwxyz1234567890-=!@#$%^&*()_+[]{};':\"]\\|,./<>?`~")
|
||||
machine.send_key("alt_r-a")
|
||||
machine.send_key("alt_r-o")
|
||||
machine.send_key("alt_r-u")
|
||||
machine.send_key("alt_r-apostrophe")
|
||||
machine.send_key("c")
|
||||
machine.send_key("alt_r-apostrophe")
|
||||
machine.send_key("n")
|
||||
machine.send_key("alt_r-apostrophe")
|
||||
machine.send_key("o")
|
||||
machine.send_key("alt_r-apostrophe")
|
||||
machine.send_key("s")
|
||||
machine.send_key("alt_r-apostrophe")
|
||||
machine.send_key("z")
|
||||
machine.send_chars("\n")
|
||||
|
||||
machine.execute(f"waitpid {hyprlock_pid}")
|
||||
_, exit_status = machine.execute("cat /tmp/exit_status")
|
||||
print(f"Hyprlock exited with {exit_status}")
|
||||
|
||||
machine.copy_from_vm(log_file_path, "logs")
|
||||
if ${APITRACE_RECORD_PY}:
|
||||
machine.copy_from_vm(log_file_path + ".trace", "traces")
|
||||
|
||||
_, out = machine.execute(f"cat {log_file_path}")
|
||||
print(f"Hyprlock log:\n{out}")
|
||||
_, out = machine.execute(f"cat {log_file_path}")
|
||||
|
||||
if not exit_status or int(exit_status) != 0:
|
||||
break
|
||||
|
||||
|
||||
machine.execute("hyprctl --instance 0 dispatch exit")
|
||||
|
||||
_, exit_status = machine.execute("cat /tmp/exit_status")
|
||||
# For the github runner, just to make sure wen don't accidentally succeed
|
||||
if not exit_status.strip():
|
||||
_, __ = machine.execute("echo 99 >/tmp/exit_status")
|
||||
exit_status = "99"
|
||||
|
||||
machine.copy_from_vm("/tmp/exit_status")
|
||||
assert int(exit_status) == 0, f"hyprlock exit code != 0 (exited with {exit_status})"
|
||||
|
||||
# Finally - shutdown
|
||||
machine.shutdown()
|
||||
'';
|
||||
};
|
||||
}
|
||||
57
tests/CMakeLists.txt
Normal file
57
tests/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
cmake_minimum_required(VERSION 3.27)
|
||||
|
||||
project(hyprlock-test-meta DESCRIPTION "Package files used for hyprlock's integration tests")
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
find_package(hyprwayland-scanner 0.4.4 REQUIRED)
|
||||
|
||||
pkg_check_modules(wfldeps REQUIRED IMPORTED_TARGET
|
||||
hyprland-protocols>=0.6.0
|
||||
hyprutils>=0.11.0
|
||||
wayland-client
|
||||
wayland-protocols>=1.35
|
||||
)
|
||||
|
||||
add_executable(wait-for-lock "waitForLock.cpp")
|
||||
|
||||
target_link_libraries(wait-for-lock PRIVATE PkgConfig::wfldeps)
|
||||
|
||||
# protocols
|
||||
pkg_get_variable(WAYLAND_PROTOCOLS_DIR wayland-protocols pkgdatadir)
|
||||
pkg_get_variable(WAYLAND_SCANNER_PKGDATA_DIR wayland-scanner pkgdatadir)
|
||||
pkg_get_variable(HYPRLAND_PROTOCOLS hyprland-protocols pkgdatadir)
|
||||
message(STATUS "Found hyprland-protocols at ${HYPRLAND_PROTOCOLS}")
|
||||
|
||||
make_directory(${CMAKE_SOURCE_DIR}/protocols)
|
||||
target_include_directories(wait-for-lock PRIVATE ${CMAKE_SOURCE_DIR}/protocols)
|
||||
|
||||
# wayland client
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_SOURCE_DIR}/protocols/wayland.cpp
|
||||
${CMAKE_SOURCE_DIR}/protocols/wayland.hpp
|
||||
COMMAND hyprwayland-scanner --wayland-enums --client
|
||||
${WAYLAND_SCANNER_PKGDATA_DIR}/wayland.xml ${CMAKE_SOURCE_DIR}/protocols/)
|
||||
target_sources(wait-for-lock PRIVATE ${CMAKE_SOURCE_DIR}/protocols/wayland.cpp)
|
||||
|
||||
# hyprland-lock-notify-v1
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_SOURCE_DIR}/protocols/hyprland-lock-notify-v1.cpp
|
||||
${CMAKE_SOURCE_DIR}/protocols/hyprland-lock-notify-v1.hpp
|
||||
COMMAND hyprwayland-scanner --client ${HYPRLAND_PROTOCOLS}/protocols/hyprland-lock-notify-v1.xml
|
||||
${CMAKE_SOURCE_DIR}/protocols/)
|
||||
target_sources(wait-for-lock PRIVATE ${CMAKE_SOURCE_DIR}/protocols/hyprland-lock-notify-v1.cpp)
|
||||
|
||||
install(TARGETS wait-for-lock)
|
||||
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/hyprland.conf
|
||||
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/hypr)
|
||||
|
||||
file(GLOB_RECURSE TESTCONFIGS CONFIGURE_DEPENDS "configs/*.conf")
|
||||
install(FILES ${TESTCONFIGS} DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/hypr/configs)
|
||||
|
||||
file(GLOB_RECURSE TESTCONFIGS CONFIGURE_DEPENDS "assets/*.png")
|
||||
install(FILES ${TESTCONFIGS} DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/hypr/assets)
|
||||
BIN
tests/assets/avatar.png
Normal file
BIN
tests/assets/avatar.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 10 KiB |
BIN
tests/assets/background.png
Normal file
BIN
tests/assets/background.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 202 KiB |
64
tests/configs/images.conf
Normal file
64
tests/configs/images.conf
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
background {
|
||||
monitor=
|
||||
path=/etc/hyprlock/assets/background.png
|
||||
}
|
||||
|
||||
image {
|
||||
monitor=
|
||||
path=/etc/hyprlock/assets/avatar.png
|
||||
size=150
|
||||
position=0, 50
|
||||
halign=center
|
||||
valign=center
|
||||
border_size=3
|
||||
shadow_passes=1
|
||||
shadow_size=5
|
||||
shadow_boost=0.5
|
||||
}
|
||||
|
||||
general {
|
||||
hide_cursor=true
|
||||
}
|
||||
|
||||
input-field {
|
||||
monitor=
|
||||
size=50, 50
|
||||
capslock_color=rgb(CB7459)
|
||||
dots_rounding=0
|
||||
dots_size=0.35
|
||||
dots_spacing=0.1
|
||||
dots_text_format=*
|
||||
fade_on_empty=true
|
||||
font_color=rgb(8F8F8F)
|
||||
font_family=Noto Sans
|
||||
inner_color=rgba(00000000)
|
||||
outer_color=rgba(FFF7EDa0)
|
||||
outline_thickness=4
|
||||
position=0, -5%
|
||||
rounding=-1
|
||||
halign=center
|
||||
valign=center
|
||||
}
|
||||
|
||||
label {
|
||||
monitor=
|
||||
color=rgb(FFF7ED)
|
||||
font_family=Noto Sans
|
||||
font_size=40
|
||||
position=0, 10%
|
||||
text=$TIME $FAIL
|
||||
halign=center
|
||||
valign=center
|
||||
}
|
||||
|
||||
label {
|
||||
monitor=
|
||||
color=rgba(BEBEBEA0)
|
||||
font_family=Noto Sans
|
||||
font_size=24
|
||||
position=0, 15%
|
||||
text=cmd[update:10000] date '+%A %d %B %Y'
|
||||
halign=center
|
||||
valign=center
|
||||
}
|
||||
|
||||
90
tests/configs/layout_and_shape.conf
Normal file
90
tests/configs/layout_and_shape.conf
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
background {
|
||||
color=rgba(255, 255, 255, 0)
|
||||
}
|
||||
|
||||
shape {
|
||||
size = 90%, 90%
|
||||
position = 0, 0
|
||||
color = rgba(0, 0, 0, 0.5)
|
||||
border_color = rgba(255, 255, 0, 1.0)
|
||||
rounding = 5
|
||||
border_size = 10
|
||||
halign = center
|
||||
valign = center
|
||||
}
|
||||
|
||||
shape {
|
||||
size = 50%, 50%
|
||||
position = -10, -10
|
||||
color = rgb(0, 0, 255)
|
||||
rounding = 5
|
||||
border_size = 0
|
||||
halign = center
|
||||
valign = center
|
||||
}
|
||||
|
||||
shape {
|
||||
size = 50%, 50%
|
||||
position = +10, +10
|
||||
color = rgb(00ff00)
|
||||
color = rgba(00ff00ff)
|
||||
rounding = 5
|
||||
border_size = 0
|
||||
halign = center
|
||||
valign = center
|
||||
}
|
||||
|
||||
# Top left corner
|
||||
shape {
|
||||
size = 10%, 10%
|
||||
position = 10, -10
|
||||
color = rgba(0, 255, 0, 1.0)
|
||||
rounding = 5
|
||||
border_size = 0
|
||||
halign = left
|
||||
valign = top
|
||||
}
|
||||
|
||||
# Top right corner
|
||||
shape {
|
||||
size = 10%, 10%
|
||||
position = -10, -10
|
||||
color = rgba(0, 255, 0, 1.0)
|
||||
rounding = 5
|
||||
border_size = 0
|
||||
halign = right
|
||||
valign = top
|
||||
}
|
||||
|
||||
# Bottom left corner
|
||||
shape {
|
||||
size = 10%, 10%
|
||||
position = 10, 10
|
||||
color = rgba(0, 255, 0, 1.0)
|
||||
rounding = 5
|
||||
border_size = 0
|
||||
halign = left
|
||||
valign = bottom
|
||||
}
|
||||
|
||||
# Bottom right corner
|
||||
shape {
|
||||
size = 10%, 10%
|
||||
position = -10, 10
|
||||
color = rgba(0, 255, 0, 1.0)
|
||||
rounding = 5
|
||||
border_size = 0
|
||||
halign = right
|
||||
valign = bottom
|
||||
}
|
||||
|
||||
# Origin of shape centered
|
||||
shape {
|
||||
size = 10%, 10%
|
||||
position = 50%, 50%
|
||||
color = rgb(ff0000)
|
||||
rounding = 5
|
||||
border_size = 0
|
||||
halign = left
|
||||
valign = bottom
|
||||
}
|
||||
221
tests/configs/lots_of_label_updates.conf
Normal file
221
tests/configs/lots_of_label_updates.conf
Normal file
|
|
@ -0,0 +1,221 @@
|
|||
background {
|
||||
monitor=
|
||||
blur_passes=2
|
||||
blur_size=10
|
||||
path=screenshot
|
||||
}
|
||||
|
||||
general {
|
||||
hide_cursor=true
|
||||
}
|
||||
|
||||
input-field {
|
||||
monitor=
|
||||
size=50, 50
|
||||
capslock_color=rgb(CB7459)
|
||||
dots_rounding=0
|
||||
dots_size=0.35
|
||||
dots_spacing=0.1
|
||||
dots_text_format=*
|
||||
fade_on_empty=false
|
||||
font_color=rgb(8F8F8F)
|
||||
font_family=Noto Sans
|
||||
inner_color=rgba(00000000)
|
||||
outer_color=rgba(FFF7EDa0)
|
||||
outline_thickness=4
|
||||
placeholder_text=$PROMPT
|
||||
fail_text=$FAIL <b>($ATTEMPTS)</b>
|
||||
position=0, -5%
|
||||
rounding=-1
|
||||
halign=center
|
||||
valign=center
|
||||
}
|
||||
|
||||
label {
|
||||
monitor=
|
||||
color=rgb(FFF7ED)
|
||||
font_family=Noto Sans
|
||||
font_size=40
|
||||
position=0, 10%
|
||||
text=$TIME $FAIL
|
||||
halign=center
|
||||
valign=center
|
||||
}
|
||||
|
||||
label {
|
||||
monitor=
|
||||
color=rgba(BEBEBEA0)
|
||||
font_family=Noto Sans
|
||||
font_size=24
|
||||
position=0, 15%
|
||||
text=cmd[update:10000] date '+%A %d %B %Y'
|
||||
halign=center
|
||||
valign=center
|
||||
}
|
||||
|
||||
label {
|
||||
text = cmd[update:200] date +'%H:%M:%S:%N'
|
||||
color = rgba(129, 162, 190, 1.0)
|
||||
font_size = 35
|
||||
font_family = Noto Sans
|
||||
|
||||
position = 150, -200
|
||||
halign = left
|
||||
valign = center
|
||||
}
|
||||
|
||||
label {
|
||||
text = cmd[update:200] date +'%H:%M:%S:%N'
|
||||
color = rgba(129, 162, 190, 1.0)
|
||||
font_size = 35
|
||||
font_family = Noto Sans
|
||||
|
||||
position = 150, -150
|
||||
halign = left
|
||||
valign = center
|
||||
}
|
||||
|
||||
label {
|
||||
text = cmd[update:200] date +'%H:%M:%S:%N'
|
||||
color = rgba(129, 162, 190, 1.0)
|
||||
font_size = 35
|
||||
font_family = Noto Sans
|
||||
|
||||
position = 150, -100
|
||||
halign = left
|
||||
valign = center
|
||||
}
|
||||
|
||||
label {
|
||||
text = cmd[update:200] date +'%H:%M:%S:%N'
|
||||
color = rgba(129, 162, 190, 1.0)
|
||||
font_size = 35
|
||||
font_family = Noto Sans
|
||||
|
||||
position = 150, -50
|
||||
halign = left
|
||||
valign = center
|
||||
}
|
||||
|
||||
label {
|
||||
text = cmd[update:200] date +'%H:%M:%S'
|
||||
color = rgba(129, 162, 190, 1.0)
|
||||
font_size = 35
|
||||
font_family = Noto Sans
|
||||
|
||||
position = 150, 0
|
||||
halign = left
|
||||
valign = center
|
||||
}
|
||||
|
||||
label {
|
||||
text = cmd[update:200] date +'%H:%M:%S'
|
||||
color = rgba(129, 162, 190, 1.0)
|
||||
font_size = 35
|
||||
font_family = Noto Sans
|
||||
|
||||
position = 150, 50
|
||||
halign = left
|
||||
valign = center
|
||||
}
|
||||
|
||||
label {
|
||||
text = cmd[update:200] date +'%H:%M:%S'
|
||||
color = rgba(129, 162, 190, 1.0)
|
||||
font_size = 35
|
||||
font_family = Noto Sans
|
||||
|
||||
position = 150, 100
|
||||
halign = left
|
||||
valign = center
|
||||
}
|
||||
|
||||
label {
|
||||
text = cmd[update:200] date +'%H:%M:%S'
|
||||
color = rgba(129, 162, 190, 1.0)
|
||||
font_size = 35
|
||||
font_family = Noto Sans
|
||||
|
||||
position = 150, 150
|
||||
halign = left
|
||||
valign = center
|
||||
}
|
||||
|
||||
label {
|
||||
text = cmd[update:200] date +'%H:%M:%S'
|
||||
color = rgba(129, 162, 190, 1.0)
|
||||
font_size = 35
|
||||
font_family = Noto Sans
|
||||
|
||||
position = 150, 200
|
||||
halign = left
|
||||
valign = center
|
||||
}
|
||||
|
||||
label {
|
||||
text = cmd[update:200] date +'%H:%M:%S'
|
||||
color = rgba(129, 162, 190, 1.0)
|
||||
font_size = 35
|
||||
font_family = Noto Sans
|
||||
|
||||
position = 150, 250
|
||||
halign = left
|
||||
valign = center
|
||||
}
|
||||
|
||||
label {
|
||||
text = cmd[update:200] date +'%H:%M:%S'
|
||||
color = rgba(129, 162, 190, 1.0)
|
||||
font_size = 35
|
||||
font_family = Noto Sans
|
||||
|
||||
position = 150, 300
|
||||
halign = left
|
||||
valign = center
|
||||
}
|
||||
|
||||
label {
|
||||
text = cmd[update:200] date +'%H:%M:%S'
|
||||
color = rgba(129, 162, 190, 1.0)
|
||||
font_size = 35
|
||||
font_family = Noto Sans
|
||||
|
||||
position = 150, 350
|
||||
halign = left
|
||||
valign = center
|
||||
}
|
||||
|
||||
label {
|
||||
text = cmd[update:200] date +'%H:%M:%S'
|
||||
color = rgba(129, 162, 190, 1.0)
|
||||
font_size = 35
|
||||
font_family = Noto Sans
|
||||
|
||||
position = 150, 400
|
||||
halign = left
|
||||
valign = center
|
||||
}
|
||||
|
||||
label {
|
||||
text = cmd[update:200] date +'%H:%M:%S'
|
||||
color = rgba(129, 162, 190, 1.0)
|
||||
font_size = 35
|
||||
font_family = Noto Sans
|
||||
|
||||
position = 150, 450
|
||||
halign = left
|
||||
valign = center
|
||||
}
|
||||
|
||||
label {
|
||||
text = cmd[update:200] date +'%H:%M:%S'
|
||||
color = rgba(129, 162, 190, 1.0)
|
||||
font_size = 35
|
||||
font_family = Noto Sans
|
||||
|
||||
position = 150, 500
|
||||
halign = left
|
||||
valign = center
|
||||
}
|
||||
|
||||
|
||||
41
tests/hyprland.conf
Normal file
41
tests/hyprland.conf
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
monitor = Virtual-1,1920x1080@60,auto-right,1
|
||||
monitor = ,disabled
|
||||
|
||||
input {
|
||||
# to type german and polish specific letters via compose keys
|
||||
kb_layout = eu
|
||||
}
|
||||
|
||||
render {
|
||||
ctm_animation = 0
|
||||
cm_enabled = 0
|
||||
cm_fs_passthrough = 0
|
||||
}
|
||||
|
||||
animations {
|
||||
enabled = 0
|
||||
}
|
||||
|
||||
decoration {
|
||||
shadow {
|
||||
enabled = 0
|
||||
}
|
||||
}
|
||||
|
||||
xwayland {
|
||||
enabled = 0
|
||||
}
|
||||
|
||||
misc {
|
||||
disable_hyprland_logo = 1
|
||||
disable_splash_rendering = 1
|
||||
force_default_wallpaper = 0
|
||||
key_press_enables_dpms = 1
|
||||
}
|
||||
|
||||
debug {
|
||||
disable_logs = 0
|
||||
}
|
||||
|
||||
# we use this in nix/tests/default.nix to be able to wait for hyprland startup
|
||||
exec-once = echo "startup" > /tmp/hyprland_exec_once_notification
|
||||
70
tests/waitForLock.cpp
Normal file
70
tests/waitForLock.cpp
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
// This program exits when the wayland session gets locked, or 10 seconds have passed.
|
||||
// In case it is already locked, it shall return immediatly.
|
||||
// It uses hyprland-lock-notify to accomplish that.
|
||||
#include "hyprland-lock-notify-v1.hpp"
|
||||
#include "wayland.hpp"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <print>
|
||||
#include <hyprutils/memory/SharedPtr.hpp>
|
||||
#include <thread>
|
||||
|
||||
using namespace Hyprutils::Memory;
|
||||
|
||||
#define SP CSharedPointer
|
||||
|
||||
struct SSessionLockState {
|
||||
SP<CCHyprlandLockNotifierV1> m_lockNotifier = nullptr;
|
||||
SP<CCHyprlandLockNotificationV1> m_lockNotification = nullptr;
|
||||
bool m_didLock = false;
|
||||
};
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
auto wlDisplay = wl_display_connect(nullptr);
|
||||
if (!wlDisplay) {
|
||||
std::println(stderr, "Failed to connect to Wayland display");
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto state = makeShared<SSessionLockState>();
|
||||
|
||||
auto wlRegistry = makeShared<CCWlRegistry>((wl_proxy*)wl_display_get_registry(wlDisplay));
|
||||
wlRegistry->setGlobal([state](CCWlRegistry* r, uint32_t name, const char* interface, uint32_t version) {
|
||||
const std::string IFACE = interface;
|
||||
|
||||
if (IFACE == hyprland_lock_notifier_v1_interface.name)
|
||||
state->m_lockNotifier =
|
||||
makeShared<CCHyprlandLockNotifierV1>((wl_proxy*)wl_registry_bind((wl_registry*)r->resource(), name, &hyprland_lock_notifier_v1_interface, version));
|
||||
});
|
||||
|
||||
wl_display_roundtrip(wlDisplay);
|
||||
|
||||
if (!state->m_lockNotifier) {
|
||||
std::print(stderr, "Failed to bind to lock notifier\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
state->m_lockNotification = makeShared<CCHyprlandLockNotificationV1>(state->m_lockNotifier->sendGetLockNotification());
|
||||
state->m_lockNotification->setLocked([state](auto) { state->m_didLock = true; });
|
||||
|
||||
wl_display_flush(wlDisplay);
|
||||
|
||||
const auto STARTTP = std::chrono::system_clock::now();
|
||||
while (!state->m_didLock) {
|
||||
if (wl_display_prepare_read(wlDisplay) == 0) {
|
||||
wl_display_read_events(wlDisplay);
|
||||
wl_display_dispatch_pending(wlDisplay);
|
||||
} else {
|
||||
wl_display_dispatch(wlDisplay);
|
||||
}
|
||||
|
||||
if (std::chrono::system_clock::now() - STARTTP > std::chrono::seconds(10)) {
|
||||
std::print(stderr, "Timeout waiting for the lock event\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue