summaryrefslogtreecommitdiff
path: root/src/main.c
blob: 0e6762397cfe55f298dabb73f6a3ff4693ca37ca (plain)
    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 }

Generated by cgit