diff --git a/maintainers/maintainer-list.nix b/maintainers/maintainer-list.nix index 566414bf4439c..b100208e0dab0 100644 --- a/maintainers/maintainer-list.nix +++ b/maintainers/maintainer-list.nix @@ -3501,6 +3501,11 @@ github = "roconnor"; name = "Russell O'Connor"; }; + roelvandijk = { + email = "roel@lambdacube.nl"; + github = "roelvandijk"; + name = "Roel van Dijk"; + }; romildo = { email = "malaquias@gmail.com"; github = "romildo"; diff --git a/nixos/modules/hardware/openrazer.nix b/nixos/modules/hardware/openrazer.nix new file mode 100644 index 0000000000000..77e254c76aca7 --- /dev/null +++ b/nixos/modules/hardware/openrazer.nix @@ -0,0 +1,160 @@ +{ config, pkgs, lib, ... }: + +with lib; + +let + cfg = config.hardware.openrazer; + + toPyBoolStr = b: if b then "True" else "False"; + + daemonExe = "${cfg.daemonPackage}/bin/openrazer-daemon --config ${daemonConfFile}"; + + daemonConfFile = pkgs.writeTextFile { + name = "razer.conf"; + text = '' + [General] + verbose_logging = ${toPyBoolStr cfg.verboseLogging} + + [Startup] + sync_effects_enabled = ${toPyBoolStr cfg.syncEffectsEnabled} + devices_off_on_screensaver = ${toPyBoolStr cfg.devicesOffOnScreensaver} + mouse_battery_notifier = ${toPyBoolStr cfg.mouseBatteryNotifier} + + [Statistics] + key_statistics = ${toPyBoolStr cfg.keyStatistics} + ''; + }; + + dbusServiceFile = pkgs.writeTextFile rec { + name = "org.razer.service"; + destination = "/share/dbus-1/services/${name}"; + text = '' + [D-BUS Service] + Name=org.razer + Exec=${daemonExe} + SystemdService=openrazer-daemon.service + ''; + }; + + drivers = [ + "razerkbd" + "razermouse" + "razerfirefly" + "razerkraken" + "razermug" + "razercore" + ]; +in +{ + options = { + hardware.openrazer = { + enable = mkEnableOption "OpenRazer drivers and userspace daemon."; + + daemonPackage = mkOption { + type = types.package; + default = pkgs.python3Packages.openrazer-daemon; + defaultText = "pkgs.python3Packages.openrazer-daemon"; + description = '' + Which package to use as the openrazer daemon. + ''; + }; + + driverPackage = mkOption { + type = types.package; + default = config.boot.kernelPackages.openrazer; + defaultText = "config.boot.kernelPackages.openrazer"; + description = '' + Which package to use as the openrazer driver. + ''; + }; + + kernelModules = mkOption { + type = types.listOf (types.enum drivers); + default = drivers; + description = '' + List of openrazer drivers to add as modules to the kernel. + ''; + }; + + verboseLogging = mkOption { + type = types.bool; + default = false; + description = '' + Whether to enable verbose logging. Logs debug messages. + ''; + }; + + syncEffectsEnabled = mkOption { + type = types.bool; + default = true; + description = '' + Set the sync effects flag to true so any assignment of + effects will work across devices. + ''; + }; + + devicesOffOnScreensaver = mkOption { + type = types.bool; + default = true; + description = '' + Turn off the devices when the systems screensaver kicks in. + ''; + }; + + mouseBatteryNotifier = mkOption { + type = types.bool; + default = true; + description = '' + Mouse battery notifier. + ''; + }; + + keyStatistics = mkOption { + type = types.bool; + default = false; + description = '' + Collects number of keypresses per hour per key used to + generate a heatmap. + ''; + }; + }; + }; + + config = mkIf cfg.enable { + boot.extraModulePackages = [ cfg.driverPackage ]; + boot.kernelModules = cfg.kernelModules; + + # Makes the man pages available so you can succesfully run + # > systemctl --user help openrazer-daemon + environment.systemPackages = [ cfg.daemonPackage.man ]; + + services.udev.packages = [ cfg.driverPackage ]; + services.dbus.packages = [ dbusServiceFile ]; + + # A user must be a member of the plugdev group in order to start + # the openrazer-daemon. Therefore we make sure that the plugdev + # group exists. + users.groups = { plugdev = {}; }; + + systemd.user.services = { + "openrazer-daemon" = { + description = "Daemon to manage razer devices in userspace"; + unitConfig.Documentation = "man:openrazer-daemon(8)"; + # Requires a graphical session so the daemon knows when the screensaver + # starts. See the 'devicesOffOnScreensaver' option. + wantedBy = [ "graphical-session.target" ]; + partOf = [ "graphical-session.target" ]; + serviceConfig = { + Type = "dbus"; + BusName = "org.razer"; + ExecStart = "${daemonExe} --foreground"; + Restart = "always"; + }; + }; + }; + }; + + meta = { + maintainers = with lib.maintainers; [ roelvandijk ]; + }; +} diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index b128568bdf512..c1d388e3c8edc 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -44,6 +44,7 @@ ./hardware/network/b43.nix ./hardware/nitrokey.nix ./hardware/opengl.nix + ./hardware/openrazer.nix ./hardware/pcmcia.nix ./hardware/raid/hpsa.nix ./hardware/usb-wwan.nix diff --git a/pkgs/os-specific/linux/openrazer/daemon.nix b/pkgs/os-specific/linux/openrazer/daemon.nix new file mode 100644 index 0000000000000..c6a6fc787383f --- /dev/null +++ b/pkgs/os-specific/linux/openrazer/daemon.nix @@ -0,0 +1,76 @@ +{ buildPythonApplication +, daemonize +, dbus-python +, fetchFromGitHub +, fetchpatch +, gobjectIntrospection +, gtk3 +, makeWrapper +, pygobject3 +, pyudev +, setproctitle +, stdenv +}: + +let + openrazerSrc = import ./src.nix; +in +buildPythonApplication rec { + inherit (openrazerSrc) version; + pname = "openrazer_daemon"; + + outputs = [ "out" "man" ]; + + src = fetchFromGitHub openrazerSrc.github; + sourceRoot = "source/daemon"; + patches = [ + # https://github.com/openrazer/openrazer/pull/680 + (fetchpatch { + url = https://github.com/openrazer/openrazer/pull/680/commits/4d7078b6af0cf7de2e4ff0986daff73706ce7eb8.patch; + sha256 = "0v5bp3zw0csxr5day44gi6b38hm74hipbd7gvvain58b521br5fq"; + stripLen = 1; + }) + + # https://github.com/openrazer/openrazer/pull/681 + (fetchpatch { + url = https://github.com/openrazer/openrazer/pull/681/commits/feefb86497af6ff7db827e682ae560c12d0aee2f.patch; + sha256 = "0vfwbdx252lz2v9mswi46jcrzd6pfyyxv1pn21l6a8as9gbakqrm"; + stripLen = 1; + }) + ]; + + buildInputs = [ makeWrapper ]; + + propagatedBuildInputs = [ + daemonize + dbus-python + gobjectIntrospection + gtk3 + pygobject3 + pyudev + setproctitle + ]; + + preBuild = '' + make openrazer-daemon + ''; + + postBuild = '' + DESTDIR="$out" PREFIX="" make manpages + ''; + + # This fixes problems with gi.require_version('Gdk', '3.0') + preFixup = '' + wrapProgram $out/bin/openrazer-daemon \ + --prefix GI_TYPELIB_PATH : "$GI_TYPELIB_PATH" \ + --prefix LD_LIBRARY_PATH ":" "${gtk3.out}/lib" + ''; + + meta = with stdenv.lib; { + description = "An entirely open source driver and user-space daemon that allows you to manage your Razer peripherals on GNU/Linux"; + homepage = https://openrazer.github.io/; + license = licenses.gpl2; + maintainers = with maintainers; [ roelvandijk ]; + platforms = platforms.linux; + }; +} diff --git a/pkgs/os-specific/linux/openrazer/driver.nix b/pkgs/os-specific/linux/openrazer/driver.nix new file mode 100644 index 0000000000000..c7674cc729f03 --- /dev/null +++ b/pkgs/os-specific/linux/openrazer/driver.nix @@ -0,0 +1,49 @@ +{ coreutils +, fetchFromGitHub +, kernel +, stdenv +, utillinux +}: + +let + openrazerSrc = import ./src.nix; +in +stdenv.mkDerivation rec { + inherit (openrazerSrc) version; + name = "openrazer-${version}-${kernel.version}"; + + src = fetchFromGitHub openrazerSrc.github; + + nativeBuildInputs = kernel.moduleBuildDependencies; + + buildFlags = [ + "KERNELDIR=${kernel.dev}/lib/modules/${kernel.version}/build" + ]; + + installPhase = '' + binDir="$out/lib/modules/${kernel.modDirVersion}/kernel/drivers/hid" + mkdir -p "$binDir" + cp -v driver/*.ko "$binDir" + + RAZER_MOUNT_OUT="$out/bin/razer_mount" + RAZER_RULES_OUT="$out/etc/udev/rules.d/99-razer.rules" + + install -m 644 -v -D install_files/udev/99-razer.rules $RAZER_RULES_OUT + install -m 755 -v -D install_files/udev/razer_mount $RAZER_MOUNT_OUT + + substituteInPlace $RAZER_RULES_OUT \ + --replace razer_mount $RAZER_MOUNT_OUT + substituteInPlace $RAZER_MOUNT_OUT \ + --replace /usr/bin/logger ${utillinux}/bin/logger \ + --replace chgrp ${coreutils}/bin/chgrp \ + --replace "PATH='/sbin:/bin:/usr/sbin:/usr/bin'" "" + ''; + + meta = with stdenv.lib; { + description = "An entirely open source driver and user-space daemon that allows you to manage your Razer peripherals on GNU/Linux"; + homepage = https://openrazer.github.io/; + license = licenses.gpl2; + maintainers = with maintainers; [ roelvandijk ]; + platforms = platforms.linux; + }; +} diff --git a/pkgs/os-specific/linux/openrazer/pylib.nix b/pkgs/os-specific/linux/openrazer/pylib.nix new file mode 100644 index 0000000000000..4fef824ff21a6 --- /dev/null +++ b/pkgs/os-specific/linux/openrazer/pylib.nix @@ -0,0 +1,32 @@ +{ buildPythonPackage +, dbus-python +, fetchFromGitHub +, numpy +, stdenv +, openrazer-daemon +}: + +let + openrazerSrc = import ./src.nix; +in +buildPythonPackage rec { + inherit (openrazerSrc) version; + pname = "openrazer"; + + src = fetchFromGitHub openrazerSrc.github; + sourceRoot = "source/pylib"; + + propagatedBuildInputs = [ + dbus-python + numpy + openrazer-daemon + ]; + + meta = with stdenv.lib; { + description = "An entirely open source driver and user-space daemon that allows you to manage your Razer peripherals on GNU/Linux"; + homepage = https://openrazer.github.io/; + license = licenses.gpl2; + maintainers = with maintainers; [ roelvandijk ]; + platforms = platforms.linux; + }; +} diff --git a/pkgs/os-specific/linux/openrazer/src.nix b/pkgs/os-specific/linux/openrazer/src.nix new file mode 100644 index 0000000000000..e812f132f7b1a --- /dev/null +++ b/pkgs/os-specific/linux/openrazer/src.nix @@ -0,0 +1,9 @@ +rec { + version = "2.3.1"; + github = { + owner = "openrazer"; + repo = "openrazer"; + rev = "v${version}"; + sha256 = "0f8f4z89c16swfzhx73369rw097zgw7f1j1v84hnzqhwlzj256x2"; + }; +} diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index 4b02c8d9cb21d..47ef9a151a04a 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -14229,6 +14229,8 @@ with pkgs; netatop = callPackage ../os-specific/linux/netatop { }; + openrazer = callPackage ../os-specific/linux/openrazer/driver.nix { }; + perf = callPackage ../os-specific/linux/kernel/perf.nix { }; phc-intel = callPackage ../os-specific/linux/phc-intel { }; diff --git a/pkgs/top-level/python-packages.nix b/pkgs/top-level/python-packages.nix index 20ba493da1536..3839eb85362ae 100644 --- a/pkgs/top-level/python-packages.nix +++ b/pkgs/top-level/python-packages.nix @@ -3545,6 +3545,9 @@ in { odfpy = callPackage ../development/python-modules/odfpy { }; + openrazer = callPackage ../os-specific/linux/openrazer/pylib.nix { }; + openrazer-daemon = callPackage ../os-specific/linux/openrazer/daemon.nix { }; + oset = callPackage ../development/python-modules/oset { }; pamela = buildPythonPackage rec {