1{ config, lib, pkgs, ... }:
2
3with lib;
4
5let
6
7 cfg = config.services.redshift;
8
9in {
10
11 options.services.redshift = {
12 enable = mkOption {
13 type = types.bool;
14 default = false;
15 description = ''
16 Enable Redshift to change your screen's colour temperature depending on
17 the time of day.
18 '';
19 };
20
21 latitude = mkOption {
22 type = types.nullOr types.str;
23 default = null;
24 description = ''
25 Your current latitude, between
26 <literal>-90.0</literal> and <literal>90.0</literal>. Must be provided
27 along with longitude.
28 '';
29 };
30
31 longitude = mkOption {
32 type = types.nullOr types.str;
33 default = null;
34 description = ''
35 Your current longitude, between
36 between <literal>-180.0</literal> and <literal>180.0</literal>. Must be
37 provided along with latitude.
38 '';
39 };
40
41 provider = mkOption {
42 type = types.enum [ "manual" "geoclue2" ];
43 default = "manual";
44 description = ''
45 The location provider to use for determining your location. If set to
46 <literal>manual</literal> you must also provide latitude/longitude.
47 '';
48 };
49
50 temperature = {
51 day = mkOption {
52 type = types.int;
53 default = 5500;
54 description = ''
55 Colour temperature to use during the day, between
56 <literal>1000</literal> and <literal>25000</literal> K.
57 '';
58 };
59 night = mkOption {
60 type = types.int;
61 default = 3700;
62 description = ''
63 Colour temperature to use at night, between
64 <literal>1000</literal> and <literal>25000</literal> K.
65 '';
66 };
67 };
68
69 brightness = {
70 day = mkOption {
71 type = types.str;
72 default = "1";
73 description = ''
74 Screen brightness to apply during the day,
75 between <literal>0.1</literal> and <literal>1.0</literal>.
76 '';
77 };
78 night = mkOption {
79 type = types.str;
80 default = "1";
81 description = ''
82 Screen brightness to apply during the night,
83 between <literal>0.1</literal> and <literal>1.0</literal>.
84 '';
85 };
86 };
87
88 package = mkOption {
89 type = types.package;
90 default = pkgs.redshift;
91 defaultText = "pkgs.redshift";
92 description = ''
93 redshift derivation to use.
94 '';
95 };
96
97 extraOptions = mkOption {
98 type = types.listOf types.str;
99 default = [];
100 example = [ "-v" "-m randr" ];
101 description = ''
102 Additional command-line arguments to pass to
103 <command>redshift</command>.
104 '';
105 };
106 };
107
108 config = mkIf cfg.enable {
109 assertions = [
110 {
111 assertion =
112 if cfg.provider == "manual"
113 then (cfg.latitude != null && cfg.longitude != null)
114 else (cfg.latitude == null && cfg.longitude == null);
115 message = "Latitude and longitude must be provided together, and with provider set to null.";
116 }
117 ];
118
119 # needed so that .desktop files are installed, which geoclue cares about
120 environment.systemPackages = [ cfg.package ];
121
122 services.geoclue2.enable = mkIf (cfg.provider == "geoclue2") true;
123
124 systemd.user.services.redshift =
125 let
126 providerString =
127 if cfg.provider == "manual"
128 then "${cfg.latitude}:${cfg.longitude}"
129 else cfg.provider;
130 in
131 {
132 description = "Redshift colour temperature adjuster";
133 wantedBy = [ "graphical-session.target" ];
134 partOf = [ "graphical-session.target" ];
135 serviceConfig = {
136 ExecStart = ''
137 ${cfg.package}/bin/redshift \
138 -l ${providerString} \
139 -t ${toString cfg.temperature.day}:${toString cfg.temperature.night} \
140 -b ${toString cfg.brightness.day}:${toString cfg.brightness.night} \
141 ${lib.strings.concatStringsSep " " cfg.extraOptions}
142 '';
143 RestartSec = 3;
144 Restart = "always";
145 };
146 };
147 };
148
149}