1 /**
2 * Copyright (C) 2017 Aaron Ball <nullspoon@oper.io>
3 *
4 * Luminous is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * Luminous is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with noteless. If not, see <http://www.gnu.org/licenses/>.
16 */
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <time.h>
21 #include <errno.h>
22
23 #include "config.h"
24
25 #define CONF "/etc/luminous.conf"
26
27
28 struct props {
29 int lvl; // Destination brightness
30 int step; // Step size
31 int rate; // Time in milliseconds between steps
32 int max; // Maximum brightness of screen device
33 int cur; // Current brightness prior to fade operation
34 char filebrightness[512]; // Path to the sysfs ent for brightness
35 char filemax_bright[512]; // Path to the sysfs ent for max brightness
36 };
37
38
39 void props_new(struct props* p) {
40 p->lvl = -1;
41 p->step = -1;
42 p->rate = -1;
43 p->max = -1;
44 p->cur = -1;
45 p->filebrightness[0] = '\0';
46 p->filemax_bright[0] = '\0';
47 }
48
49
50 /**
51 * fgeti:
52 * @path Path to the file from which to read the integer
53 *
54 * Reads integer from the specified file. If the file does not contain only an
55 * integer, returns -1.
56 *
57 * returns: Integer read from file, otherwise -1.
58 */
59 int fgeti(char* path) {
60 FILE* fd;
61 char buf[64];
62
63 fd = fopen(path, "r");
64 if(! fd)
65 return -1;
66
67 fgets(buf, 64, fd);
68 fclose(fd);
69 return atoi(buf);
70 }
71
72
73 /**
74 * fade:
75 * @props Props struct containing runtime parameters
76 *
77 * Fades brightness up or down, based on positive (fade up) or negative value
78 * (fade down) contained in `step` property. Rate of fade is controled by
79 * `props->rate`.
80 *
81 * returns: Success (0) or failure (-1)
82 */
83 int fade(struct props* props) {
84 struct timespec tim, tim2;
85 int sec; // Number of seconds to sleep
86 int msec; // Number of milliseconds to sleep (less than 1 second)
87 int direction = 0; // Direction of fade. Positive for up, negative for down
88 int opcount = 0;
89
90 sec = props->rate / 1000;
91 msec = props->rate - (sec * 1000);
92
93 tim.tv_sec = sec;
94 tim.tv_nsec = 1000000 * msec;
95
96 // Determine direction
97 if(props->lvl > props->cur) {
98 // Dest brightness is higher than current
99 direction = 1;
100 opcount = (props->lvl - props->cur) / props->step;
101 } else if(props->lvl < props->cur) {
102 // Dest brightness is lower than current
103 direction = -1;
104 opcount = (props->cur - props->lvl) / props->step;
105 }
106
107 FILE* fd = fopen(props->filebrightness, "w");
108 if(! fd) {
109 if(errno == EACCES) {
110 fprintf(stderr, "Permission denied: %s\n", props->filebrightness);
111 } else {
112 fprintf(stderr, "Could not open file %s\n", props->filebrightness);
113 }
114 return -1;
115 }
116
117 while(opcount > 0) {
118 nanosleep(&tim, &tim2);
119
120 // Write the new brightness to the brightness file
121 fprintf(fd, "%d\n", props->cur);
122
123 // Flush the toil...er...buffer!
124 fflush(fd);
125
126 props->cur += props->step * direction;
127 opcount--;
128 }
129
130 fclose(fd);
131 return 0;
132 }
133
134
135 /**
136 * usage:
137 *
138 * Nothing to see here. Just the help text printer.
139 */
140 void usage() {
141 printf(
142 "Luminous is a backlight manager that supports fading the backlight at\n"
143 "varying rates and steps. It manages backlight via the kenerl interfaces\n"
144 "provided in /sys to adjust screen backlight levels. Consequently, it\n"
145 "requires write access to the brightness property in \n"
146 "/sys/class/backlight/<device>/brightness.\n"
147 "\n"
148 "Usage:\n"
149 " luminous --rate 10 --step 8 --level [+-]400\n"
150 "\n"
151 "Arguments:\n"
152 " -h,--help Print this helptext\n"
153 " -s,--step Fade step (default: 6)\n"
154 " -r,--rate Time in milliseconds between fade steps (default: 10)\n"
155 " -l,--level Brightness level to change to. Supports absolute values and\n"
156 " relative values prefixed with + and -."
157 "\n\n"
158 );
159 }
160
161
162 /**
163 * parseargs:
164 * @out Output properties struct
165 * @argc Number of arguments passed
166 * @argv Arguments char array
167 *
168 * Parses command line arguments into a props struct.
169 *
170 * returns: Success (0), failure (-1), or incomplete (-2)
171 */
172 int parseargs(struct props* out, int argc, char* argv[]) {
173 int i;
174
175 strcpy(out->filebrightness,
176 "/sys/class/backlight/intel_backlight/brightness");
177 strcpy(out->filemax_bright,
178 "/sys/class/backlight/intel_backlight/max_brightness");
179
180 // Read the system values for current and maximum brightness
181 out->cur = fgeti(out->filebrightness);
182 out->max = fgeti(out->filemax_bright);
183
184 for(i = 0; i < argc; i++) {
185 if(strcmp(argv[i], "-r") == 0 || strcmp(argv[i], "--rate") == 0) {
186 i++;
187 out->rate = atoi(argv[i]);
188 } else if(strcmp(argv[i], "-s") == 0 || strcmp(argv[i], "--step") == 0) {
189 i++;
190 out->step = atoi(argv[i]);
191 } else if(strcmp(argv[i], "-l") == 0 || strcmp(argv[i], "--level") == 0) {
192 i++;
193 // Account for relative and absolute increments and decrements
194 if(argv[i][0] == '+') {
195 out->lvl = out->cur + atoi(&argv[i][1]);
196 } else if(argv[i][0] == '-') {
197 out->lvl = out->cur - atoi(&argv[i][1]);
198 } else {
199 out->lvl = atoi(argv[i]);
200 }
201 } else if(strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) {
202 usage();
203 return -2;
204 }
205 }
206
207 // Some defaults, if no values are set yet
208 if(out->rate < 0)
209 out->rate = 20;
210 if(out->step < 0)
211 out->step = 12;
212 if(out->lvl == -1)
213 out->lvl = 200;
214
215 // Ensure min and max thresholds are respected
216 if(out->lvl > out->max) {
217 out->lvl = out->max;
218 } else if(out->lvl < 0) {
219 out->lvl = 0;
220 }
221 return 0;
222 }
223
224
225 int config_to_props(char* confpath, struct props* p) {
226 struct config c;
227 char lvlbuf[32]; // Buffer to store config value for "level" if found
228 char ratebuf[32]; // Buffer to store config value for "rate" if found
229 char stepbuf[32]; // Buffer to store config value for "step" if found
230
231 if(config_new(&c, confpath) == 0) {
232 config_load(&c);
233 } else {
234 // Config file not found, return -2 code
235 return -2;
236 }
237
238 // If the config specifies a "level" key, set it to the props object
239 if(config_get(&c, "level", lvlbuf) == 0)
240 p->lvl = atoi(lvlbuf);
241
242 // If the config specifies a "step" key, set it to the props object
243 if(config_get(&c, "step", stepbuf) == 0)
244 p->step = atoi(stepbuf);
245
246 // If the config specifies a "rate" key, set it to the props object
247 if(config_get(&c, "rate", ratebuf) == 0)
248 p->rate = atoi(ratebuf);
249
250 // Don't forget to clean up!
251 config_free(&c);
252
253 return 0;
254 }
255
256
257 /**
258 * Ye olde main
259 */
260 int main(int argc, char* argv[]) {
261 int r = 0;
262 struct props p;
263
264 props_new(&p);
265
266 // Load configs into properties struct
267 config_to_props(CONF, &p);
268
269 // Parse cli arguments (overriding any configs if specified at runtime)
270 if(parseargs(&p, argc, argv) != 0)
271 return 1;
272
273 // Determine if we should fade up or fade down
274 if(p.lvl < 0) {
275 printf("%d\n", p.cur);
276 } else {
277 r = fade(&p);
278 }
279
280 if(r < 0) {
281 fprintf(stderr, "ERROR: Could not open brightness file\n");
282 return 1;
283 }
284 return 0;
285 }
|