2008-04-20

LCD screen brightness control program for Linux

This program cycles through the screen brightness levels and shows the current value using an OSD (on screen display) field.

I map this to Meta-B since the native one only goes to "brightest" and
there is no other way to adjust it.

This has been used on linux kernels 2.6.22 and 2.6.24.




#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <errno.h>

#include <unistd.h>

#include <time.h>

//

// can use debian package for libxosd-dev

//  

// compile with:

//   gcc -Wall -DXOSD `xosd-config --cflags --libs` brightness_lcd.c -o brightness_lcd

//

// set sticky:

//   sudo chown root:root brightness_lcd

//   sudo chmod u+s brightness_lcd

//

//  execute:

//   ./brightness_lcd

//



#ifdef XOSD

#include <xosd.h>

#endif //XOSD









#define LEVELS "levels:"

#define CURRENT "current:"





static int lcmp(const void *a, const void *b)

{

  long x = *((long *)a), y = *((long *)b);

  return (x > y) - (x < y);

}



void help(int argc, char *argv[])

{

  // ======= args =========

  if (argc>1 && !strcmp(argv[1], "-h"))  {

    fprintf(stderr,

      "By default, move to next brightness level\n"

      "Options are device and/or value, e.g.:\n"

      "\t%s 37 /proc/acpi/video/VGA/LCD/brightness\n" 

      "\t%s 37\n",

      argv[0], argv[0] );

    exit(-1);

  }

}



int main(int argc, char *argv[])

{

  FILE *fp=NULL;

  char *devname = "/proc/acpi/video/VGA/LCD/brightness";

  int NS=1024;

  char s[NS];

  int NL = 256;

  long levels[NL], nlevels = 0;

  long current = 0;

  int i, j, c=0;

  struct timespec ts = {0, 1000000*250};



#ifdef XOSD

  xosd *osd;

#endif //XOSD





  help(argc, argv);

  

  // ======= read =========

  if (argc>2)

    devname = argv[2];



  if ( !(fp = fopen(devname, "r")) ) {

    fprintf(stderr,

      "Could not open device '%s' for reading.\n",

      devname);

    return -1;

  }



  while (fgets(s, NS, fp)) {

    if ( !strncmp(LEVELS, s, strlen(LEVELS)) ) {

      char *sp, *sp1 = s + strlen(LEVELS);

      errno = 0;

      do {

        sp = sp1;

        levels[nlevels++] = strtol(sp, &sp1, 10);

      } while (sp!=sp1) ;

      nlevels--;

      // printf("levels: ... %ld %ld %ld x%ld\n",

      //         levels[8], levels[9], levels[10], nlevels);

    }

    else if ( !strncmp(CURRENT, s, strlen(CURRENT)) ) {

      char *sp = s + strlen(CURRENT);

      current = strtol(sp, &sp, 10);

      // printf("current: %ld\n", current);

    }

  }



  if (fp)

    fclose(fp);



  // ======= sort and remove duplicates =========

  qsort(levels, nlevels, sizeof(long), lcmp);

  for (i=1; i<nlevels; i++) {

    if (levels[i]==levels[i-1]) {

      for (j=i+1; j<nlevels; j++) {

        levels[j-1] = levels[j];

      }

      nlevels--;

    }

  }

  

  // for (i=0; i<nlevels; i++) {

  //   printf("  level: %ld\n", levels[i]);

  // }



  // ======= find current, go to next =========

  // printf("current: %ld\n", current);

  for (i=0; i<nlevels; i++) {

    if (current<=levels[i]) {

      c = i;

      break;

    }

  }



  c++;

  c%=nlevels;

  // printf("c: %d, level: %ld, x%ld\n", c, levels[c], nlevels);



  if (argc>1)

    sprintf(s, "%s", argv[1]);

  else {

    sprintf(s, "%ld", levels[c]);

  }



  // ======= write =========

  printf("Writing '%s' to '%s'\n", s, devname);

  

  if ( !(fp = fopen(devname, "w")) ) {

    fprintf(stderr, "Could not open device '%s' for writing.\n", devname);

    return -1;

  }



  fwrite(s, 1, strlen(s), fp);



  if (fp)

    fclose(fp);



#ifdef XOSD

  osd = xosd_create (1);

  if (osd == NULL) {

    perror ("Could not create \"osd\"");

    exit (1);

  }



  xosd_set_font (osd, "-adobe-helvetica-bold-r-normal-*-*-320-*-*-p-*-iso8859-1");

  xosd_set_pos (osd, XOSD_bottom);

  xosd_set_align (osd, XOSD_left);

  xosd_display (osd, 0, XOSD_string, s);

  xosd_set_shadow_offset (osd, 2);

  //sleep (1);

  nanosleep (&ts, NULL);

  xosd_destroy (osd);

#endif //XOSD



  return 0;

}





No comments: