From 84243cf155bb00c50add124c8b89c853b6033c41 Mon Sep 17 00:00:00 2001 From: bitbloxhub <45184892+bitbloxhub@users.noreply.github.com> Date: Wed, 22 Apr 2026 17:41:21 +0000 Subject: [PATCH 1/2] reframe: init at 1.15.1 --- pkgs/by-name/re/reframe/package.nix | 93 +++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 pkgs/by-name/re/reframe/package.nix diff --git a/pkgs/by-name/re/reframe/package.nix b/pkgs/by-name/re/reframe/package.nix new file mode 100644 index 000000000000..04c49bd6953d --- /dev/null +++ b/pkgs/by-name/re/reframe/package.nix @@ -0,0 +1,93 @@ +{ + lib, + stdenv, + fetchFromGitHub, + pkg-config, + meson, + ninja, + cmake, + systemd, + glib, + gtk4, + libdrm, + libepoxy, + libxkbcommon, + libvncserver, + neatvnc, + aml, + pixman, + zlib, + ffmpeg, + nix-update-script, + + withNeatVNC ? true, +}: + +stdenv.mkDerivation (finalAttrs: { + pname = "reframe"; + version = "1.15.1"; + + src = fetchFromGitHub { + owner = "AlynxZhou"; + repo = "reframe"; + tag = "v${finalAttrs.version}"; + hash = "sha256-3ZCLnmu5Idn4RsypJr+JNqIhT13/pq1Xi4wTidUgCqQ="; + fetchSubmodules = true; + }; + + nativeBuildInputs = [ + meson + ninja + cmake + pkg-config + ]; + + buildInputs = [ + systemd + glib + gtk4 + libdrm + libepoxy + libxkbcommon + libvncserver + ] + ++ lib.optionals withNeatVNC [ + neatvnc + aml + pixman + zlib + ffmpeg + ]; + + passthru = { + updateScript = nix-update-script { }; + }; + + mesonFlags = [ + (lib.mesonOption "systemunitdir" "${placeholder "out"}/lib/systemd/system") + (lib.mesonOption "sysusersdir" "${placeholder "out"}/lib/sysusers.d") + (lib.mesonOption "tmpfilesdir" "${placeholder "out"}/lib/tmpfiles.d") + ] + ++ lib.optionals withNeatVNC [ (lib.mesonOption "neatvnc" "true") ]; + + postPatch = '' + chmod +x meson_post_install.sh + patchShebangs meson_post_install.sh + + # Comment out all commands, all systemd reloading + sed -i '1,2! s/^/# /' meson_post_install.sh + ''; + + strictDeps = true; + __structuredAttrs = true; + + meta = { + homepage = "https://reframe.alynx.one/"; + description = "DRM/KMS based remote desktop for Linux that supports Wayland/NVIDIA/headless/login…"; + license = lib.licenses.asl20; + maintainers = with lib.maintainers; [ + bitbloxhub + ]; + platforms = lib.platforms.linux; + }; +}) From 98831cfb6d67d9e11dbf89b7ab573f75fc906e6e Mon Sep 17 00:00:00 2001 From: bitbloxhub <45184892+bitbloxhub@users.noreply.github.com> Date: Wed, 22 Apr 2026 17:39:12 +0000 Subject: [PATCH 2/2] nixos/reframe: init --- .../manual/release-notes/rl-2605.section.md | 2 + nixos/modules/services/networking/reframe.nix | 190 ++++++++++++++++++ 2 files changed, 192 insertions(+) create mode 100644 nixos/modules/services/networking/reframe.nix diff --git a/nixos/doc/manual/release-notes/rl-2605.section.md b/nixos/doc/manual/release-notes/rl-2605.section.md index f883372fd450..c56c16c4db99 100644 --- a/nixos/doc/manual/release-notes/rl-2605.section.md +++ b/nixos/doc/manual/release-notes/rl-2605.section.md @@ -116,6 +116,8 @@ - [RSSHub](https://github.com/DIYgod/RSSHub), a service to convert many sources into rss. Available as `services.rsshub`. +- [ReFrame](https://github.com/AlynxZhou/reframe), a DRM/KMS based remote desktop for Linux that supports Wayland/NVIDIA/headless/login. + - [Komodo Periphery](https://github.com/moghtech/komodo), a multi-server Docker and Git deployment agent by Komodo. Available as [services.komodo-periphery](#opt-services.komodo-periphery.enable). - [Shoko](https://shokoanime.com), an anime management system. Available as [services.shoko](#opt-services.shoko.enable). diff --git a/nixos/modules/services/networking/reframe.nix b/nixos/modules/services/networking/reframe.nix new file mode 100644 index 000000000000..b05f33772eaa --- /dev/null +++ b/nixos/modules/services/networking/reframe.nix @@ -0,0 +1,190 @@ +{ + lib, + pkgs, + config, + ... +}: +let + cfg = config.services.reframe; + iniFmt = pkgs.formats.ini { }; +in +{ + options.programs.reframe = { + enable = lib.mkEnableOption "DRM/KMS based remote desktop for Linux that supports Wayland/NVIDIA/headless/login…"; + package = lib.mkPackageOption pkgs "reframe" { }; + configs = lib.mkOption { + type = lib.types.attrsOf ( + lib.types.submodule { + options = { + reframe = { + card = lib.mkOption { + type = lib.types.str; + default = ""; + description = "Select monitor via DRM card. All available cards and connectors can be found in `/sys/class/drm/`."; + example = "card0"; + }; + connector = lib.mkOption { + type = lib.types.str; + default = ""; + description = "Select monitor via connector. All available cards and connectors can be found in `/sys/class/drm/`."; + example = "eDP-1"; + }; + rotation = lib.mkOption { + type = lib.types.enum [ + 0 + 90 + 180 + 270 + ]; + default = 0; + description = '' + This is the angle you rotate the monitor, not the angle of display content relative to the monitor! + Valid angles are clockwise `0`, `90`, `180`, `270`. + ''; + }; + desktop-width = lib.mkOption { + type = lib.types.int; + default = 0; + description = '' + If you have more than 1 monitor, set those values to the logical size of the whole virtual desktop. + You can get those value by finding the pointer position of the right most and bottom most border of your monitors. + ''; + }; + desktop-height = lib.mkOption { + type = lib.types.int; + default = 0; + description = '' + If you have more than 1 monitor, set those values to the logical size of the whole virtual desktop. + You can get those value by finding the pointer position of the right most and bottom most border of your monitors. + ''; + }; + monitor-x = lib.mkOption { + type = lib.types.int; + default = 0; + description = '' + If you have more than 1 monitor, set those values to the logical position of the top left corner of your selected monitor. + ''; + }; + monitor-y = lib.mkOption { + type = lib.types.int; + default = 0; + description = '' + If you have more than 1 monitor, set those values to the logical position of the top left corner of your selected monitor. + ''; + }; + default-width = lib.mkOption { + type = lib.types.int; + default = 0; + description = '' + If your client does not support resizing, use those to force a size. Empty or `0` means monitor size. + ''; + }; + default-height = lib.mkOption { + type = lib.types.int; + default = 0; + description = '' + If your client does not support resizing, use those to force a size. Empty or `0` means monitor size. + ''; + }; + resize = lib.mkOption { + type = lib.types.bool; + default = true; + description = '' + Set to `false` to prohibit client resizing. + ''; + }; + cursor = lib.mkOption { + type = lib.types.bool; + default = true; + description = '' + Set to `false` to ignore DRM cursor plane. + ''; + }; + wakeup = lib.mkOption { + type = lib.types.bool; + default = true; + description = '' + Set to `false` if you already disabled automatic screen blank. + ''; + }; + damage = lib.mkOption { + type = lib.types.enum [ + "" + "cpu" + "gpu" + ]; + default = true; + description = '' + Set to `gpu` to use GPU damage region detection, which may be more efficiency but may cause artifacts depending on GPU vendors. + Set to `cpu` to use CPU damage region detection if you get bugs with `gpu`. + Empty to disable damage region detection, which may require higher network bandwidth. + ''; + }; + fps = lib.mkOption { + type = lib.types.int; + default = 30; + }; + }; + vnc = { + ip = lib.mkOption { + type = lib.types.str; + default = ""; + description = '' + Empty means accept all incoming connections. + ''; + }; + port = lib.mkOption { + type = lib.types.port; + default = 5933; + }; + password = lib.mkOption { + type = lib.types.str; + default = ""; + description = '' + Empty means no password. + ''; + }; + type = lib.mkOption { + type = lib.types.enum [ + "libvncserver" + "neatvnc" + ]; + default = "libvncserver"; + description = '' + Set to `neatvnc` to prefer neatvnc, which provides more efficient encoding methods but maybe more unstable. + ''; + }; + }; + }; + } + ); + default = { }; + description = "Configurations for ReFrame"; + }; + }; + + config = lib.mkIf cfg.enable { + environment.systemPackages = [ cfg.package ]; + systemd.packages = [ cfg.package ]; + systemd.tmpfiles.packages = [ cfg.package ]; + users.users.reframe = { + isSystemUser = true; + group = "reframe"; + description = "ReFrame Remote Desktop"; + }; + users.groups.reframe = { }; + environment.etc = builtins.mapAttrs' ( + name: value: + lib.nameValuePair "reframe/${name}.conf" { + mode = "0644"; + user = "root"; + group = "root"; + source = iniFmt.generate "${name}.conf" value; + } + ) cfg.configs; + }; + + meta.maintainers = with lib.maintainers; [ + bitbloxhub + ]; +}