/* * Copyright © 2007 Keith Packard * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that copyright * notice and this permission notice appear in supporting documentation, and * that the name of the copyright holders not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. The copyright holders make no representations * about the suitability of this software for any purpose. It is provided "as * is" without express or implied warranty. * * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE * OF THIS SOFTWARE. */ #ifdef HAVE_CONFIG_H # include "config.h" #endif #include #include #include #include #include #include #include #include #include #include typedef enum { Get, Set, Inc, Dec } op_t; static char *program_name; static xcb_atom_t backlight, backlight_new, backlight_legacy; static void usage (int exitcode) { fprintf(stderr, "usage: %s [options]\n%s", program_name, " where options are:\n" " -display or -d \n" " -help\n" " -version\n" " -set or = \n" " -inc or + \n" " -dec or - \n" " -get\n" " -time \n" " -steps \n"); exit (exitcode); } static double atof_or_die (char *str) { double retval; errno = 0; retval = strtod(str, NULL); if (errno) usage(1); return retval; } static void missing_arg (const char *option) { fprintf(stderr, "%s: %s requires an argument\n", program_name, option); usage(1); } static long backlight_get (xcb_connection_t *conn, xcb_randr_output_t output) { xcb_generic_error_t *error; xcb_randr_get_output_property_reply_t *prop_reply = NULL; xcb_randr_get_output_property_cookie_t prop_cookie; long value; backlight = backlight_new; if (backlight != XCB_ATOM_NONE) { prop_cookie = xcb_randr_get_output_property (conn, output, backlight, XCB_ATOM_NONE, 0, 4, 0, 0); prop_reply = xcb_randr_get_output_property_reply (conn, prop_cookie, &error); if (error != NULL || prop_reply == NULL) { backlight = backlight_legacy; if (backlight != XCB_ATOM_NONE) { prop_cookie = xcb_randr_get_output_property (conn, output, backlight, XCB_ATOM_NONE, 0, 4, 0, 0); prop_reply = xcb_randr_get_output_property_reply (conn, prop_cookie, &error); if (error != NULL || prop_reply == NULL) { return -1; } } } } if (prop_reply == NULL || prop_reply->type != XCB_ATOM_INTEGER || prop_reply->num_items != 1 || prop_reply->format != 32) { value = -1; } else { value = *((int32_t *) xcb_randr_get_output_property_data (prop_reply)); } free (prop_reply); return value; } static void backlight_set (xcb_connection_t *conn, xcb_randr_output_t output, long value) { xcb_randr_change_output_property (conn, output, backlight, XCB_ATOM_INTEGER, 32, XCB_PROP_MODE_REPLACE, 1, (unsigned char *)&value); } int main (int argc, char **argv) { char *dpy_name = NULL; op_t op = Get; double value = 0; int i; int total_time = 200; /* ms */ int steps = 20; xcb_connection_t *conn; xcb_generic_error_t *error; xcb_randr_query_version_cookie_t ver_cookie; xcb_randr_query_version_reply_t *ver_reply; xcb_intern_atom_cookie_t backlight_cookie[2]; xcb_intern_atom_reply_t *backlight_reply; xcb_screen_iterator_t iter; program_name = argv[0]; for (i = 1; i < argc; i++) { if (!strcmp (argv[i], "-display") || !strcmp ("-d", argv[i])) { if (++i >= argc) missing_arg (argv[i-1]); dpy_name = argv[i]; continue; } if (!strcmp (argv[i], "-set") || !strcmp (argv[i], "=")) { if (++i >= argc) missing_arg (argv[i-1]); op = Set; value = atof_or_die (argv[i]); continue; } if (argv[i][0] == '=' && isdigit (argv[i][1])) { op = Set; value = atof_or_die (argv[i] + 1); continue; } if (!strcmp (argv[i], "-inc") || !strcmp (argv[i], "+")) { if (++i >= argc) missing_arg (argv[i-1]); op = Inc; value = atof_or_die (argv[i]); continue; } if (argv[i][0] == '+' && isdigit (argv[i][1])) { op = Inc; value = atof_or_die (argv[i] + 1); continue; } if (!strcmp (argv[i], "-dec") || !strcmp (argv[i], "-")) { if (++i >= argc) missing_arg (argv[i-1]); op = Dec; value = atof_or_die (argv[i]); continue; } if (argv[i][0] == '-' && isdigit (argv[i][1])) { op = Dec; value = atof_or_die (argv[i] + 1); continue; } if (!strcmp (argv[i], "-get") || !strcmp (argv[i], "-g")) { op = Get; continue; } if (!strcmp (argv[i], "-time")) { if (++i >= argc) missing_arg (argv[i-1]); total_time = atoi (argv[i]); continue; } if (!strcmp (argv[i], "-steps")) { if (++i >= argc) missing_arg (argv[i-1]); steps = atoi (argv[i]); continue; } if (!strcmp (argv[i], "-help") || !strcmp (argv[i], "-?")) { usage (0); } if (!strcmp (argv[i], "-version")) { puts (PACKAGE_STRING); exit (0); } fprintf(stderr, "%s: unrecognized argument '%s'\n", program_name, argv[i]); usage (1); } conn = xcb_connect (dpy_name, NULL); ver_cookie = xcb_randr_query_version (conn, 1, 2); ver_reply = xcb_randr_query_version_reply (conn, ver_cookie, &error); if (error != NULL || ver_reply == NULL) { int ec = error ? error->error_code : -1; fprintf (stderr, "RANDR Query Version returned error %d\n", ec); exit (1); } if (ver_reply->major_version != 1 || ver_reply->minor_version < 2) { fprintf (stderr, "RandR version %d.%d too old\n", ver_reply->major_version, ver_reply->minor_version); exit (1); } free (ver_reply); backlight_cookie[0] = xcb_intern_atom (conn, 1, strlen("Backlight"), "Backlight"); backlight_cookie[1] = xcb_intern_atom (conn, 1, strlen("BACKLIGHT"), "BACKLIGHT"); backlight_reply = xcb_intern_atom_reply (conn, backlight_cookie[0], &error); if (error != NULL || backlight_reply == NULL) { int ec = error ? error->error_code : -1; fprintf (stderr, "Intern Atom returned error %d\n", ec); exit (1); } backlight_new = backlight_reply->atom; free (backlight_reply); backlight_reply = xcb_intern_atom_reply (conn, backlight_cookie[1], &error); if (error != NULL || backlight_reply == NULL) { int ec = error ? error->error_code : -1; fprintf (stderr, "Intern Atom returned error %d\n", ec); exit (1); } backlight_legacy = backlight_reply->atom; free (backlight_reply); if (backlight_new == XCB_NONE && backlight_legacy == XCB_NONE) { fprintf (stderr, "No outputs have backlight property\n"); exit (1); } iter = xcb_setup_roots_iterator (xcb_get_setup (conn)); while (iter.rem) { xcb_screen_t *screen = iter.data; xcb_window_t root = screen->root; xcb_randr_output_t *outputs; xcb_randr_get_screen_resources_current_cookie_t resources_cookie; xcb_randr_get_screen_resources_current_reply_t *resources_reply; resources_cookie = xcb_randr_get_screen_resources_current (conn, root); resources_reply = xcb_randr_get_screen_resources_current_reply (conn, resources_cookie, &error); if (error != NULL || resources_reply == NULL) { int ec = error ? error->error_code : -1; fprintf (stderr, "RANDR Get Screen Resources returned error %d\n", ec); continue; } outputs = xcb_randr_get_screen_resources_current_outputs (resources_reply); for (int o = 0; o < resources_reply->num_outputs; o++) { xcb_randr_output_t output = outputs[o]; double cur, new, step; double min, max; double set; cur = backlight_get (conn, output); if (cur != -1) { xcb_randr_query_output_property_cookie_t prop_cookie; xcb_randr_query_output_property_reply_t *prop_reply; prop_cookie = xcb_randr_query_output_property (conn, output, backlight); prop_reply = xcb_randr_query_output_property_reply (conn, prop_cookie, &error); if (error != NULL || prop_reply == NULL) continue; if (prop_reply->range && xcb_randr_query_output_property_valid_values_length (prop_reply) == 2) { int32_t *values = xcb_randr_query_output_property_valid_values (prop_reply); min = values[0]; max = values[1]; if (op == Get) { printf ("%f\n", (cur - min) * 100 / (max - min)); } else { set = value * (max - min) / 100; switch (op) { case Set: new = min + set; break; case Inc: new = cur + set; break; case Dec: new = cur - set; break; default: xcb_aux_sync (conn); return 1; } if (new > max) new = max; if (new < min) new = min; step = (new - cur) / steps; for (i = 0; i < steps && step != 0; i++) { if (i == steps - 1) cur = new; else cur += step; backlight_set (conn, output, (long) (cur + 0.5)); xcb_flush (conn); usleep (total_time * 1000 / steps); } } } free (prop_reply); } } free (resources_reply); xcb_screen_next (&iter); } xcb_aux_sync (conn); return 0; }