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