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 // For string macros
28 #define xstr(s) str(s)
29 #define str(s) #s
30
31
32 struct props {
33 int lvl;
34 int step;
35 int rate;
36 int max;
37 int cur;
38 char filebrightness[512];
39 char filemax_bright[512];
40 };
41
42
43 void props_new(struct props* p) {
44 p->lvl = -1;
45 p->step = -1;
46 p->rate = -1;
47 p->max = -1;
48 p->cur = -1;
49 p->filebrightness[0] = '\0';
50 p->filemax_bright[0] = '\0';
51 }
52
53
54 /**
55 * version_print:
56 * @fd File descriptor to print version information to
57 *
58 * Prints version information for the current build to the specified file
59 * descriptor.
60 * NOTE: Version information is pulled from a macro defined by the Makefile.
61 */
62 void version_print(FILE* fd) {
63 fprintf(fd, "luminous %s\n", xstr(VERSTR));
64 }
65
66
67 /**
68 * fgeti:
69 * @path
70 *
71 * Reads integer from the specified file. If the file does not contain only an
72 * integer, returns -1.
73 *
74 * returns: Integer read from file, otherwise -1.
75 */
76 int fgeti(char* path) {
77 FILE* fd;
78 char buf[64];
79
80 fd = fopen(path, "r");
81 if(! fd)
82 return -1;
83
84 fgets(buf, 64, fd);
85 fclose(fd);
86 return atoi(buf);
87 }
88
89
90 /**
91 * fadeup:
92 * @props Props struct containing runtime parameters
93 *
94 * Fades brightness down, incremented by props->step every props->rate
95 * milliseconds
96 *
97 * returns: Success (0) or failure (-1)
98 */
99 int fadeup(struct props* props) {
100 struct timespec tim, tim2;
101 int sec; // Number of seconds to sleep
102 int msec; // Number of milliseconds to sleep (less than 1 second)
103
104 sec = props->rate / 1000;
105 msec = props->rate - (sec * 1000);
106
107 tim.tv_sec = sec;
108 tim.tv_nsec = 1000000 * msec;
109
110 while(props->cur < props->lvl) {
111 nanosleep(&tim, &tim2);
112
113 FILE* fd = fopen(props->filebrightness, "w");
114 if(! fd) {
115 if(errno == EACCES) {
116 fprintf(stderr, "Permission denied: %s\n", props->filebrightness);
117 } else {
118 fprintf(stderr, "Could not open file %s\n", props->filebrightness);
119 }
120 return -1;
121 }
122
123 // Write the new brightness to the brightness file
124 fprintf(fd, "%d\n", props->cur);
125 fclose(fd);
126
127 if(props->cur >= props->max)
128 break;
129 props->cur += props->step;
130 }
131 return 0;
132 }
133
134
135 /**
136 * fadedown:
137 * @props Props struct containing runtime parameters
138 *
139 * Fades brightness down, decremented by props->step every props->rate
140 * milliseconds
141 *
142 * returns: Success (0) or failure (-1)
143 */
144 int fadedown(struct props* props) {
145 struct timespec tim, tim2;
146 int sec; // Number of seconds to sleep
147 int msec; // Number of milliseconds to sleep (less than 1 second)
148
149 sec = props->rate / 1000;
150 msec = props->rate - (sec * 1000);
151
152 tim.tv_sec = sec;
153 tim.tv_nsec = 1000000 * msec;
154
155 while(props->cur > props->lvl) {
156 nanosleep(&tim, &tim2);
157
158 FILE* fd = fopen(props->filebrightness, "w");
159 if(! fd) {
160 if(errno == EACCES) {
161 fprintf(stderr, "Permission denied: %s\n", props->filebrightness);
162 } else {
163 fprintf(stderr, "Could not open file %s\n", props->filebrightness);
164 }
165 return -1;
166 }
167
168 // Write the new brightness to the brightness file
169 fprintf(fd, "%d\n", props->cur);
170 fclose(fd);
171
172 if(props->cur <= 0)
173 break;
174 props->cur -= props->step;
175 }
176 return 0;
177 }
178
179
180 /**
181 * usage:
182 *
183 * Nothing to see here. Just the help text printer.
184 */
185 void usage() {
186 printf(
187 "Luminous is a backlight manager that supports fading the backlight at\n"
188 "varying rates and steps. It manages backlight via the kenerl interfaces\n"
189 "provided in /sys to adjust screen backlight levels. Consequently, it\n"
190 "requires write access to the brightness property in \n"
191 "/sys/class/backlight/<device>/brightness.\n"
192 "\n"
193 "Usage:\n"
194 " luminous --rate 10 --step 8 --level [+-]400\n"
195 "\n"
196 "Arguments:\n"
197 " -h,--help Print this helptext\n"
198 " -s,--step Fade step (default: 6)\n"
199 " -r,--rate Time in milliseconds between fade steps (default: 10)\n"
200 " -l,--level Brightness level to change to. Supports absolute values and\n"
201 " relative values prefixed with + and -.\n"
202 " -V,--version Print program version"
203 "\n\n"
204 );
205 }
206
207
208 /**
209 * parseargs:
210 * @out Output properties struct
211 * @argc Number of arguments passed
212 * @argv Arguments char array
213 *
214 * Parses command line arguments into a props struct.
215 *
216 * returns: Success (0), failure (-1), or incomplete (-2)
217 */
218 int parseargs(struct props* out, int argc, char* argv[]) {
219 int i;
220
221 strcpy(out->filebrightness,
222 "/sys/class/backlight/intel_backlight/brightness");
223 strcpy(out->filemax_bright,
224 "/sys/class/backlight/intel_backlight/max_brightness");
225
226 // Read the system values for current and maximum brightness
227 out->cur = fgeti(out->filebrightness);
228 out->max = fgeti(out->filemax_bright);
229
230 for(i = 0; i < argc; i++) {
231 if(strcmp(argv[i], "-r") == 0 || strcmp(argv[i], "--rate") == 0) {
232 i++;
233 out->rate = atoi(argv[i]);
234 } else if(strcmp(argv[i], "-s") == 0 || strcmp(argv[i], "--step") == 0) {
235 i++;
236 out->step = atoi(argv[i]);
237 } else if(strcmp(argv[i], "-l") == 0 || strcmp(argv[i], "--level") == 0) {
238 i++;
239 // Account for relative and absolute increments and decrements
240 if(argv[i][0] == '+') {
241 out->lvl = out->cur + atoi(&argv[i][1]);
242 } else if(argv[i][0] == '-') {
243 out->lvl = out->cur - atoi(&argv[i][1]);
244 } else {
245 out->lvl = atoi(argv[i]);
246 }
247 } else if(strcmp(argv[i], "-V") == 0 || strcmp(argv[i], "--version") == 0) {
248 version_print(stdout);
249 return -2;
250 } else if(strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) {
251 usage();
252 return -2;
253 }
254 }
255
256 // Some defaults, if no values are set yet
257 if(out->rate < 0)
258 out->rate = 20;
259 if(out->step < 0)
260 out->step = 12;
261 if(out->lvl == -1)
262 out->lvl = 200;
263
264 // Ensure min and max thresholds are respected
265 if(out->lvl > out->max) {
266 out->lvl = out->max;
267 } else if(out->lvl < 0) {
268 out->lvl = 0;
269 }
270 return 0;
271 }
272
273
274 int config_to_props(char* confpath, struct props* p) {
275 struct config c;
276 char lvlbuf[32]; // Buffer to store config value for "level" if found
277 char ratebuf[32]; // Buffer to store config value for "rate" if found
278 char stepbuf[32]; // Buffer to store config value for "step" if found
279
280 if(config_new(&c, confpath) == 0) {
281 config_load(&c);
282 } else {
283 // Config file not found, return -2 code
284 return -2;
285 }
286
287 // If the config specifies a "level" key, set it to the props object
288 if(config_get(&c, "level", lvlbuf) == 0)
289 p->lvl = atoi(lvlbuf);
290
291 // If the config specifies a "step" key, set it to the props object
292 if(config_get(&c, "step", stepbuf) == 0)
293 p->step = atoi(stepbuf);
294
295 // If the config specifies a "rate" key, set it to the props object
296 if(config_get(&c, "rate", ratebuf) == 0)
297 p->rate = atoi(ratebuf);
298
299 // Don't forget to clean up!
300 config_free(&c);
301
302 return 0;
303 }
304
305
306 /**
307 * Ye olde main
308 */
309 int main(int argc, char* argv[]) {
310 int r = 0;
311 struct props p;
312
313 props_new(&p);
314
315 // Load configs into properties struct
316 config_to_props(CONF, &p);
317
318 // Parse cli arguments (overriding any configs if specified at runtime)
319 if(parseargs(&p, argc, argv) != 0)
320 return 1;
321
322 // Determine if we should fade up or fade down
323 if(p.lvl < 0) {
324 printf("%d\n", p.cur);
325 } else if(p.lvl > p.cur) {
326 r = fadeup(&p);
327 } else if (p.lvl < p.cur) {
328 r = fadedown(&p);
329 }
330
331 if(r < 0) {
332 fprintf(stderr, "ERROR: Could not open brightness file\n");
333 return 1;
334 }
335 return 0;
336 }
|