summaryrefslogtreecommitdiff
path: root/src/main.c
blob: bcd76db1f770ab26ab4b8689ca8735081e470907 (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 #include <sys/file.h>
   23 
   24 #include "config.h"
   25 
   26 #define CONF "/etc/luminous.conf"
   27 
   28 // For string macros
   29 #define xstr(s) str(s)
   30 #define str(s) #s
   31 
   32 
   33 struct props {
   34   int lvl;  // Destination brightness
   35   int step; // Step size
   36   int rate; // Time in milliseconds between steps
   37   int max;  // Maximum brightness of screen device
   38   int cur;  // Current brightness prior to fade operation
   39   char filebrightness[512]; // Path to the sysfs ent for brightness
   40   char filemax_bright[512]; // Path to the sysfs ent for max brightness
   41 };
   42 
   43 
   44 void props_new(struct props* p) {
   45   p->lvl  = -1;
   46   p->step = -1;
   47   p->rate = -1;
   48   p->max  = -1;
   49   p->cur  = -1;
   50   p->filebrightness[0] = '\0';
   51   p->filemax_bright[0] = '\0';
   52 }
   53 
   54 
   55 /**
   56  * version_print:
   57  * @fd File descriptor to print version information to
   58  *
   59  * Prints version information for the current build to the specified file
   60  * descriptor.
   61  * NOTE: Version information is pulled from a macro defined by the Makefile.
   62  */
   63 void version_print(FILE* fd) {
   64   fprintf(fd, "luminous %s (compiled: %s)\n", xstr(VERSTR), xstr(DATESTR));
   65 }
   66 
   67 
   68 /**
   69  * fgeti:
   70  * @path Path to the file from which to read the integer
   71  *
   72  * Reads integer from the specified file. If the file does not contain only an
   73  * integer, returns -1.
   74  *
   75  * returns: Integer read from file, otherwise -1.
   76  */
   77 int fgeti(char* path) {
   78   FILE* fd;
   79   char buf[64];
   80 
   81   fd = fopen(path, "r");
   82   if(! fd)
   83     return -1;
   84 
   85   fgets(buf, 64, fd);
   86   fclose(fd);
   87   return atoi(buf);
   88 }
   89 
   90 
   91 /**
   92  * fade:
   93  * @props Props struct containing runtime parameters
   94  *
   95  * Fades brightness up or down, based on positive (fade up) or negative value
   96  * (fade down) contained in `step` property. Rate of fade is controled by
   97  * `props->rate`.
   98  *
   99  * returns: Success (0) or failure (-1)
  100  */
  101 int fade(struct props* props) {
  102   struct timespec tim, tim2;
  103   int sec;  // Number of seconds to sleep
  104   int msec; // Number of milliseconds to sleep (less than 1 second)
  105   int direction = 0; // Direction of fade. Positive for up, negative for down
  106   int opcount   = 0;
  107 
  108   sec = props->rate / 1000;
  109   msec = props->rate - (sec * 1000);
  110 
  111   tim.tv_sec = sec;
  112   tim.tv_nsec = 1000000 * msec;
  113 
  114   // Determine direction
  115   if(props->lvl > props->cur) {
  116     // Dest brightness is higher than current
  117     direction = 1;
  118     opcount = (props->lvl - props->cur) / props->step;
  119   } else if(props->lvl < props->cur) {
  120     // Dest brightness is lower than current
  121     direction = -1;
  122     opcount = (props->cur - props->lvl) / props->step;
  123   }
  124 
  125   FILE* fd = fopen(props->filebrightness, "w");
  126   if(! fd) {
  127     if(errno == EACCES) {
  128       fprintf(stderr, "Permission denied: %s\n", props->filebrightness);
  129     } else {
  130       fprintf(stderr, "Could not open file %s\n", props->filebrightness);
  131     }
  132     return -1;
  133   }
  134 
  135   // Lock the file descriptor so we can't have conflicting brightness change
  136   // operations
  137   if(flock(fileno(fd), LOCK_EX | LOCK_NB) != 0) {
  138     fprintf(stderr, "Could not obtain brightness file lock\n");
  139     fclose(fd);
  140     return -1;
  141   }
  142 
  143   while(opcount > 0) {
  144     nanosleep(&tim, &tim2);
  145 
  146     // Write the new brightness to the brightness file
  147     fprintf(fd, "%d\n", props->cur);
  148 
  149     // Flush the toil...er...buffer!
  150     fflush(fd);
  151 
  152     props->cur += props->step * direction;
  153     opcount--;
  154   }
  155 
  156   // Do not need to explicitly release the file lock
  157   fclose(fd);
  158   return 0;
  159 }
  160 
  161 
  162 /**
  163  * usage:
  164  *
  165  * Nothing to see here. Just the help text printer.
  166  */
  167 void usage() {
  168   printf(
  169 "Luminous is a backlight manager that supports fading the backlight at\n"
  170 "varying rates and steps. It manages backlight via the kenerl interfaces\n"
  171 "provided in /sys to adjust screen backlight levels. Consequently, it\n"
  172 "requires write access to the brightness property in \n"
  173 "/sys/class/backlight/<device>/brightness.\n"
  174 "\n"
  175 "Usage:\n"
  176 "  luminous --rate 10 --step 8 --level [+-]400\n"
  177 "\n"
  178 "Arguments:\n"
  179 "  -h,--help    Print this helptext\n"
  180 "  -s,--step    Fade step (default: 6)\n"
  181 "  -r,--rate    Time in milliseconds between fade steps (default: 10)\n"
  182 "  -l,--level   Brightness level to change to. Supports absolute values and\n"
  183 "               relative values prefixed with + and -.\n"
  184 "  -V,--version Print program version"
  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], "-V") == 0 || strcmp(argv[i], "--version") == 0) {
  230       version_print(stdout);
  231       return -2;
  232     } else if(strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) {
  233       usage();
  234       return -2;
  235     }
  236   }
  237 
  238   // Some defaults, if no values are set yet
  239   if(out->rate < 0)
  240    out->rate = 20;
  241   if(out->step < 0)
  242    out->step = 12;
  243   if(out->lvl == -1)
  244     out->lvl = 200;
  245 
  246   // Ensure min and max thresholds are respected
  247   if(out->lvl > out->max) {
  248     out->lvl = out->max;
  249   } else if(out->lvl < 0) {
  250     out->lvl = 0;
  251   }
  252   return 0;
  253 }
  254 
  255 
  256 int config_to_props(char* confpath, struct props* p) {
  257   struct config c;
  258   char lvlbuf[32];  // Buffer to store config value for "level" if found
  259   char ratebuf[32]; // Buffer to store config value for "rate" if found
  260   char stepbuf[32]; // Buffer to store config value for "step" if found
  261 
  262   if(config_new(&c, confpath) == 0) {
  263     config_load(&c);
  264   } else {
  265     // Config file not found, return -2 code
  266     return -2;
  267   }
  268 
  269   // If the config specifies a "level" key, set it to the props object
  270   if(config_get(&c, "level", lvlbuf) == 0)
  271     p->lvl = atoi(lvlbuf);
  272 
  273   // If the config specifies a "step" key, set it to the props object
  274   if(config_get(&c, "step", stepbuf) == 0)
  275     p->step = atoi(stepbuf);
  276 
  277   // If the config specifies a "rate" key, set it to the props object
  278   if(config_get(&c, "rate", ratebuf) == 0)
  279     p->rate = atoi(ratebuf);
  280 
  281   // Don't forget to clean up!
  282   config_free(&c);
  283 
  284   return 0;
  285 }
  286 
  287 
  288 /**
  289  * Ye olde main
  290  */
  291 int main(int argc, char* argv[]) {
  292   int r = 0;
  293   struct props p;
  294 
  295   props_new(&p);
  296 
  297   // Load configs into properties struct
  298   config_to_props(CONF, &p);
  299 
  300   // Parse cli arguments (overriding any configs if specified at runtime)
  301   if(parseargs(&p, argc, argv) != 0)
  302     return 1;
  303 
  304   // Determine if we should fade up or fade down
  305   if(p.lvl < 0) {
  306     printf("%d\n", p.cur);
  307   } else {
  308     r = fade(&p);
  309   }
  310 
  311   if(r < 0) {
  312     fprintf(stderr, "ERROR: Could not open brightness file\n");
  313     return 1;
  314   }
  315   return 0;
  316 }

Generated by cgit