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