diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/arg.h | 65 | ||||
-rw-r--r-- | src/cg-base.c | 927 | ||||
-rw-r--r-- | src/cg-base.h | 254 | ||||
-rw-r--r-- | src/cg-brilliance.c | 313 | ||||
-rw-r--r-- | src/cg-darkroom.c | 316 | ||||
-rw-r--r-- | src/cg-gamma.c | 541 | ||||
-rw-r--r-- | src/cg-icc.c | 945 | ||||
-rw-r--r-- | src/cg-limits.c | 731 | ||||
-rw-r--r-- | src/cg-linear.c | 280 | ||||
-rw-r--r-- | src/cg-negative.c | 255 | ||||
-rw-r--r-- | src/cg-query.c | 514 | ||||
-rw-r--r-- | src/cg-rainbow.c | 279 | ||||
-rw-r--r-- | src/cg-remove.c | 403 | ||||
-rw-r--r-- | src/cg-shallow.c | 279 | ||||
-rw-r--r-- | src/cg-sleepmode.c | 460 |
15 files changed, 0 insertions, 6562 deletions
diff --git a/src/arg.h b/src/arg.h deleted file mode 100644 index 0b23c53..0000000 --- a/src/arg.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copy me if you can. - * by 20h - */ - -#ifndef ARG_H__ -#define ARG_H__ - -extern char *argv0; - -/* use main(int argc, char *argv[]) */ -#define ARGBEGIN for (argv0 = *argv, argv++, argc--;\ - argv[0] && argv[0][0] == '-'\ - && argv[0][1];\ - argc--, argv++) {\ - char argc_;\ - char **argv_;\ - int brk_;\ - if (argv[0][1] == '-' && argv[0][2] == '\0') {\ - argv++;\ - argc--;\ - break;\ - }\ - for (brk_ = 0, argv[0]++, argv_ = argv;\ - argv[0][0] && !brk_;\ - argv[0]++) {\ - if (argv_ != argv)\ - break;\ - argc_ = argv[0][0];\ - switch (argc_) - -/* Handles obsolete -NUM syntax */ -#define ARGNUM case '0':\ - case '1':\ - case '2':\ - case '3':\ - case '4':\ - case '5':\ - case '6':\ - case '7':\ - case '8':\ - case '9' - -#define ARGEND }\ - } - -#define ARGC() argc_ - -#define ARGNUMF() (brk_ = 1, estrtonum(argv[0], 0, INT_MAX)) - -#define EARGF(x) ((argv[0][1] == '\0' && argv[1] == NULL)?\ - ((x), abort(), (char *)0) :\ - (brk_ = 1, (argv[0][1] != '\0')?\ - (&argv[0][1]) :\ - (argc--, argv++, argv[0]))) - -#define ARGF() ((argv[0][1] == '\0' && argv[1] == NULL)?\ - (char *)0 :\ - (brk_ = 1, (argv[0][1] != '\0')?\ - (&argv[0][1]) :\ - (argc--, argv++, argv[0]))) - -#define LNGARG() &argv[0][0] - -#endif diff --git a/src/cg-base.c b/src/cg-base.c deleted file mode 100644 index 9f77937..0000000 --- a/src/cg-base.c +++ /dev/null @@ -1,927 +0,0 @@ -/** - * cg-tools -- Cooperative gamma-enabled tools - * Copyright (C) 2016, 2018 Mattias Andrée (maandree@kth.se) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#include "cg-base.h" - -#include <libclut.h> - -#include <alloca.h> -#include <errno.h> -#include <inttypes.h> -#include <poll.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - - - -/** - * The process's name - */ -const char* argv0 = NULL; - -/** - * The libcoopgamma context - */ -libcoopgamma_context_t cg; - -/** - * The names of the selected CRTC:s - */ -char** crtcs = NULL; - -/** - * Gamma ramp updates for each CRTC - */ -filter_update_t* crtc_updates = NULL; - -/** - * CRTC and monitor information about - * each selected CRTC and connect monitor - */ -libcoopgamma_crtc_info_t* crtc_info = NULL; - -/** - * The number of selected CRTC:s - */ -size_t crtcs_n = 0; - -/** - * The number of filters - */ -size_t filters_n = 0; - - -/** - * Contexts for asynchronous ramp updates - */ -static libcoopgamma_async_context_t* asyncs = NULL; - -/** - * The number of pending receives - */ -static size_t pending_recvs = 0; - -/** - * Whether message must be flushed - */ -static int flush_pending = 0; - - - -/** - * Data used to sort CRTC:s - */ -struct crtc_sort_data -{ - /** - * The gamma ramp type - */ - libcoopgamma_depth_t depth; - - /** - * Should be 0 - */ - int __padding; - - /** - * The size of the red gamma ramp - */ - size_t red_size; - - /** - * The size of the green gamma ramp - */ - size_t green_size; - - /** - * The size of the blue gamma ramp - */ - size_t blue_size; - - /** - * The index of the CRTC - */ - size_t index; -}; - - - -/** - * Compare two strings - * - * @param a Return -1 if this string is `NULL` or less than `b` - * @param b Return +1 if this string is less than `a` - * @return See `a` and `b`, 0 is returned if `a` and `b` are equal - */ -static int nulstrcmp(const char *a, const char *b) -{ - return (a == NULL) ? -1 : strcmp(a, b); -} - - -/** - * Compare two instances of `crtc_sort_data` - * - * @param a_ Return -1 if this one is lower - * @param b_ Return +1 if this one is higher - * @return See `a_` and `b_`, only -1 or +1 can be returned - */ -static int crtc_sort_data_cmp(const void* a_, const void* b_) -{ - const struct crtc_sort_data* a = a_; - const struct crtc_sort_data* b = b_; - int cmp = memcmp(a, b, sizeof(*a) - sizeof(a->index)); - return cmp ? cmp : a->index < b->index ? -1 : +1; -} - - -/** - * Make elements in `crtc_updates` slaves where appropriate - * - * @return Zero on success, -1 on error - */ -int make_slaves(void) -{ - struct crtc_sort_data* data; - size_t i, j, n = 0, master = 0, master_i; - - data = alloca(filters_n * sizeof(*data)); - memset(data, 0, filters_n * sizeof(*data)); - for (i = 0; i < filters_n; i++) - { - if (!(crtc_info[crtc_updates[i].crtc].supported)) - continue; - - data[n].depth = crtc_updates[i].filter.depth; - data[n].red_size = crtc_updates[i].filter.ramps.u8.red_size; - data[n].green_size = crtc_updates[i].filter.ramps.u8.green_size; - data[n].blue_size = crtc_updates[i].filter.ramps.u8.blue_size; - data[n].index = i; - n++; - } - - qsort(data, n, sizeof(*data), crtc_sort_data_cmp); - if (n == 0) - return 0; - - master_i = data[0].index; - for (i = 1; i < n; i++) - if (memcmp(data + i, data + master, sizeof(*data) - sizeof(data->index))) - { - if (master + 1 < i) - { - crtc_updates[master_i].slaves = calloc(i - master, sizeof(size_t)); - if (crtc_updates[master_i].slaves == NULL) - return -1; - for (j = 1; master + j < i; j++) - crtc_updates[master_i].slaves[j - 1] = data[master + j].index; - } - master = i; - master_i = data[master].index; - } - else - { - libcoopgamma_ramps_destroy(&(crtc_updates[data[i].index].filter.ramps.u8)); - crtc_updates[data[i].index].master = 0; - crtc_updates[data[i].index].filter.ramps.u8 = crtc_updates[master_i].filter.ramps.u8; - } - - if (master + 1 < i) - { - crtc_updates[master_i].slaves = calloc(i - master, sizeof(size_t)); - if (crtc_updates[master_i].slaves == NULL) - return -1; - for (j = 1; master + j < i; j++) - crtc_updates[master_i].slaves[j - 1] = data[master + j].index; - } - - return 0; -} - - -/** - * Update a filter and synchronise calls - * - * @param index The index of the CRTC - * @param timeout The number of milliseconds a call to `poll` may block, - * -1 if it may block forever - * @return 1: Success, no pending synchronisations - * 0: Success, with still pending synchronisations - * -1: Error, `errno` set - * -2: Error, `cg.error` set - * - * @throws EINTR Call to `poll` was interrupted by a signal - * @throws EAGAIN Call to `poll` timed out - */ -int update_filter(size_t index, int timeout) -{ - filter_update_t* filter = crtc_updates + index; - - if (!(filter->synced) || filter->failed) - abort(); - - pending_recvs += 1; - - if (libcoopgamma_set_gamma_send(&(filter->filter), &cg, asyncs + index) < 0) - switch (errno) - { - case EINTR: - case EAGAIN: -#if EAGAIN != EWOULDBLOCK - case EWOULDBLOCK: -#endif - flush_pending = 1; - break; - default: - return -1; - } - - filter->synced = 0; - return synchronise(timeout); -} - - -/** - * Synchronised calls - * - * @param timeout The number of milliseconds a call to `poll` may block, - * -1 if it may block forever - * @return 1: Success, no pending synchronisations - * 0: Success, with still pending synchronisations - * -1: Error, `errno` set - * -2: Error, `cg.error` set - * - * @throws EINTR Call to `poll` was interrupted by a signal - * @throws EAGAIN Call to `poll` timed out - */ -int synchronise(int timeout) -{ - struct pollfd pollfd; - size_t selected; - - pollfd.fd = cg.fd; - pollfd.events = POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI; - if (flush_pending > 0) - pollfd.events |= POLLOUT; - - pollfd.revents = 0; - if (poll(&pollfd, (nfds_t)1, timeout) < 0) - return -1; - - if (pollfd.revents & (POLLOUT | POLLERR | POLLHUP | POLLNVAL)) - { - if (libcoopgamma_flush(&cg) < 0) - goto sync; - flush_pending = 0; - } - - if ((timeout < 0) && (pending_recvs > 0)) - if (!(pollfd.revents & (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI))) - { - pollfd.revents = 0; - if (poll(&pollfd, (nfds_t)1, -1) < 0) - return -1; - } - - sync: - if (pollfd.revents & (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI | POLLERR | POLLHUP | POLLNVAL)) - for (;;) - { - if (libcoopgamma_synchronise(&cg, asyncs, filters_n, &selected) < 0) - { - if (errno == 0) - continue; - else - goto fail; - } - if (crtc_updates[selected].synced) - continue; - crtc_updates[selected].synced = 1; - pending_recvs -= 1; - if (libcoopgamma_set_gamma_recv(&cg, asyncs + selected) < 0) - { - if (cg.error.server_side) - { - crtc_updates[selected].error = cg.error; - crtc_updates[selected].failed = 1; - memset(&(cg.error), 0, sizeof(cg.error)); - } - else - goto cg_fail; - } - } - - return pending_recvs == 0; - cg_fail: - return -2; - fail: - switch (errno) - { - case EINTR: - case EAGAIN: -#if EAGAIN != EWOULDBLOCK - case EWOULDBLOCK: -#endif - return pending_recvs == 0; - default: - return -1; - } -} - - -/** - * Initialise the process, specifically - * reset the signal mask and signal handlers - * - * @return Zero on success, -1 on error - */ -static int initialise_proc(void) -{ - sigset_t sigmask; - int sig; - - for (sig = 1; sig < _NSIG; sig++) - if (signal(sig, SIG_DFL) == SIG_ERR) - if (sig == SIGCHLD) - return -1; - - if (sigemptyset(&sigmask) < 0) - return -1; - if (sigprocmask(SIG_SETMASK, &sigmask, NULL) < 0) - return -1; - - return 0; -} - - -/** - * Print, to stdout, a list of all - * recognised adjustment methods - * - * @return Zero on success, -1 on error - */ -static int list_methods(void) -{ - char** list; - size_t i; - - list = libcoopgamma_get_methods(); - if (list == NULL) - return -1; - for (i = 0; list[i]; i++) - printf("%s\n", list[i]); - free(list); - if (fflush(stdout) < 0) - return -1; - - return 0; -} - - -/** - * Print, to stdout, a list of all CRTC:s - * - * A connection to the coopgamma server - * must have been made - * - * @return Zero on success, -1 on error, -2 - * on libcoopgamma error - */ -static int list_crtcs(void) -{ - char** list; - size_t i; - - list = libcoopgamma_get_crtcs_sync(&cg); - if (list == NULL) - return -2; - for (i = 0; list[i]; i++) - printf("%s\n", list[i]); - free(list); - if (fflush(stdout) < 0) - return -1; - - return 0; -} - - -/** - * Fill the list of CRTC information - * - * @return Zero on success, -1 on error, -2 - * on libcoopgamma error - */ -static int get_crtc_info(void) -{ - size_t i, unsynced = 0, selected; - char* synced; - int need_flush = 0; - struct pollfd pollfd; - - synced = alloca(crtcs_n * sizeof(*synced)); - memset(synced, 0, crtcs_n * sizeof(*synced)); - - i = 0; - pollfd.fd = cg.fd; - pollfd.events = POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI; - - while ((unsynced > 0) || (i < crtcs_n)) - { - wait: - if (i < crtcs_n) - pollfd.events |= POLLOUT; - else - pollfd.events &= ~POLLOUT; - - pollfd.revents = 0; - if (poll(&pollfd, (nfds_t)1, -1) < 0) - goto fail; - - if (pollfd.revents & (POLLOUT | POLLERR | POLLHUP | POLLNVAL)) - { - if (need_flush && (libcoopgamma_flush(&cg) < 0)) - goto send_fail; - need_flush = 0; - for (; i < crtcs_n; i++) - if (unsynced++, libcoopgamma_get_gamma_info_send(crtcs[i], &cg, asyncs + i) < 0) - goto send_fail; - goto send_done; - send_fail: - switch (errno) - { - case EINTR: - case EAGAIN: -#if EAGAIN != EWOULDBLOCK - case EWOULDBLOCK: -#endif - i++; - need_flush = 1; - break; - default: - goto fail; - } - } - send_done: - - if ((unsynced == 0) && (i == crtcs_n)) - break; - - if (pollfd.revents & (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) - while (unsynced > 0) - switch (libcoopgamma_synchronise(&cg, asyncs, i, &selected)) - { - case 0: - if (synced[selected]) - { - libcoopgamma_skip_message(&cg); - break; - } - synced[selected] = 1; - unsynced -= 1; - if (libcoopgamma_get_gamma_info_recv(crtc_info + selected, &cg, asyncs + selected) < 0) - goto cg_fail; - break; - case -1: - switch (errno) - { - case 0: - break; - case EINTR: - case EAGAIN: -#if EAGAIN != EWOULDBLOCK - case EWOULDBLOCK: -#endif - goto wait; - default: - goto fail; - } - break; - } - } - - return 0; - fail: - return -1; - cg_fail: - return -2; -} - - -/** - * -M METHOD - * Select adjustment method. If METHOD is "?", - * available methods will be printed to stdout. - * - * -S SITE - * Select site (display server instance). - * - * -c CRTC - * Select CRT controller. If CRTC is "?", CRTC:s - * will be printed to stdout. - * - * This option can be used multiple times. If it - * is not used at all, all CRTC:s will be selected. - * - * -p PRIORITY - * Select the priority for the filter, this should - * be a signed two's-complement integer. If - * PRIORITY is "?", the default priority for the - * program is printed to stdout. - * - * -R RULE - * The rule of the filter, that is, the last part - * of the class which is its identifier. If RULE - * is "?" the default rule is printed to stdout, - * if RULE is "??" the default class is printed - * to stdout. - * - * @param argc The number of command line arguments - * @param argv The command line arguments - * @return 0 on success, 1 on error - */ -int main(int argc, char* argv[]) -{ - int stage = 0; - int dealloc_crtcs = 0; - int rc = 0; - char* method = NULL; - char* site = NULL; - size_t crtc_i = 0; - int64_t priority = default_priority; - char* prio = NULL; - char* rule = NULL; - char* class = default_class; - char** classes = NULL; - size_t classes_n = 0; - int explicit_crtcs = 0; - int have_crtc_q = 0; - size_t i, filter_i; - - argv0 = *argv++, argc--; - - if (initialise_proc() < 0) - goto fail; - - crtcs = alloca(argc * sizeof(*crtcs)); - - for (; *argv; argv++, argc--) - { - char* args = *argv; - char opt[3]; - if (!strcmp(args, "--")) - { - argv++, argc--; - break; - } - opt[0] = *args++; - opt[2] = '\0'; - if ((*opt != '-') && (*opt != '+')) - break; - while (*args) - { - char* arg; - int at_end; - opt[1] = *args++; - arg = args; - if ((at_end = !*arg)) - arg = argv[1]; - if (!strcmp(opt, "-M")) - { - if ((method != NULL) || ((method = arg) == NULL)) - usage(); - } - else if (!strcmp(opt, "-S")) - { - if ((site != NULL) || ((site = arg) == NULL)) - usage(); - } - else if (!strcmp(opt, "-c")) - { - if (arg == NULL) - usage(); - crtcs[crtc_i++] = arg; - explicit_crtcs = 1; - if (!have_crtc_q && !strcmp(arg, "?")) - have_crtc_q = 1; - } - else if (!strcmp(opt, "-p")) - { - if ((prio != NULL) || ((prio = arg) == NULL)) - usage(); - } - else if (!strcmp(opt, "-R")) - { - if ((rule != NULL) || ((rule = arg) == NULL)) - usage(); - } - else - switch (handle_opt(opt, arg)) - { - case 0: - goto next_opt; - case 1: - break; - default: - goto fail; - } - argv += at_end; - argc -= at_end; - break; - next_opt:; - } - } - - crtcs_n = crtc_i; - crtcs[crtc_i] = NULL; - if (!have_crtc_q && nulstrcmp(method, "?") && - nulstrcmp(rule, "?") && nulstrcmp(rule, "??") && - ((default_priority == NO_DEFAULT_PRIORITY) || nulstrcmp(prio, "?"))) - if (handle_args(argc, argv, prio) < 0) - goto fail; - - if (default_priority != NO_DEFAULT_PRIORITY) - { - if (!nulstrcmp(prio, "?")) - { - printf("%" PRIi64 "\n", priority); - return 0; - } - else if (prio != NULL) - { - char *end; - errno = 0; - priority = (int64_t)strtoll(prio, &end, 10); - if (errno || *end || !*prio) - usage(); - } - } - - if (!nulstrcmp(rule, "??")) - { - size_t i; - if (*class_suffixes == NULL) - printf("%s\n", class); - else - for (i = 0; class_suffixes[i] != NULL; i++) - printf("%s%s\n", class, class_suffixes[i]); - return 0; - } - else if (!nulstrcmp(rule, "?")) - { - printf("%s\n", strstr(strstr(class, "::") + 2, "::") + 2); - return 0; - } - else if (rule != NULL) - { - char* p = strstr(strstr(class, "::") + 2, "::") + 2; - size_t n = (size_t)(p - class); - class = alloca(strlen(rule) + n + (size_t)1); - memcpy(class, default_class, n); - strcpy(class + n, rule); - if (strchr(class, '\n')) - { - fprintf(stderr, "%s: LF character is not allowed in the filter's class\n", argv0); - goto custom_fail; - } - } - - if (!nulstrcmp(method, "?")) - { - if (list_methods() < 0) - goto fail; - return 0; - } - - if (libcoopgamma_context_initialise(&cg) < 0) - goto fail; - stage++; - if (libcoopgamma_connect(method, site, &cg) < 0) - { - fprintf(stderr, "%s: server failed to initialise\n", argv0); - goto custom_fail; - } - stage++; - - if (have_crtc_q) - switch (list_crtcs()) - { - case 0: - goto done; - case -1: - goto fail; - default: - goto cg_fail; - } - - if (crtcs_n == 0) - { - crtcs = libcoopgamma_get_crtcs_sync(&cg); - if (crtcs == NULL) - goto cg_fail; - dealloc_crtcs = 1; - for (; crtcs[crtcs_n] != NULL; crtcs_n++); - } - - if (crtcs_n == 0) - { - fprintf(stderr, "%s: no CRTC:s are available\n", argv0); - goto custom_fail; - } - - if (*class_suffixes == NULL) - { - classes = &class; - classes_n = 1; - } - else - { - size_t len = strlen(class); - while (class_suffixes[classes_n]) - classes_n++; - classes = alloca(classes_n * sizeof(*classes)); - for (i = 0; i < classes_n; i++) - { - classes[i] = alloca(len + strlen(class_suffixes[i]) + sizeof(":")); - stpcpy(stpcpy(stpcpy(classes[i], class), ":"), class_suffixes[i]); - } - } - filters_n = classes_n * crtcs_n; - - crtc_info = alloca(crtcs_n * sizeof(*crtc_info)); - memset(crtc_info, 0, crtcs_n * sizeof(*crtc_info)); - for (crtc_i = 0; crtc_i < crtcs_n; crtc_i++) - if (libcoopgamma_crtc_info_initialise(crtc_info + crtc_i) < 0) - goto cg_fail; - - if (libcoopgamma_set_nonblocking(&cg, 1) < 0) - goto fail; - - asyncs = alloca(filters_n * sizeof(*asyncs)); - memset(asyncs, 0, filters_n * sizeof(*asyncs)); - for (filter_i = 0; filter_i < filters_n; filter_i++) - if (libcoopgamma_async_context_initialise(asyncs + filter_i) < 0) - goto fail; - - switch (get_crtc_info()) - { - case 0: - break; - case -1: - goto fail; - case -2: - goto cg_fail; - } - - for (crtc_i = 0; crtc_i < crtcs_n; crtc_i++) - { - if (explicit_crtcs && !(crtc_info[crtc_i].supported)) - fprintf(stderr, "%s: warning: gamma adjustments not supported on CRTC: %s\n", - argv0, crtcs[crtc_i]); - if (crtc_info[crtc_i].cooperative == 0) - fprintf(stderr, "%s: warning: cooperative gamma server not running for CRTC: %s\n", - argv0, crtcs[crtc_i]); - } - - crtc_updates = alloca(filters_n * sizeof(*crtc_updates)); - memset(crtc_updates, 0, filters_n * sizeof(*crtc_updates)); - for (filter_i = i = 0; i < classes_n; i++) - for (crtc_i = 0; crtc_i < crtcs_n; crtc_i++, filter_i++) - { - if (libcoopgamma_filter_initialise(&(crtc_updates[filter_i].filter)) < 0) - goto fail; - if (libcoopgamma_error_initialise(&(crtc_updates[filter_i].error)) < 0) - goto fail; - crtc_updates[filter_i].crtc = crtc_i; - crtc_updates[filter_i].synced = 1; - crtc_updates[filter_i].failed = 0; - crtc_updates[filter_i].master = 1; - crtc_updates[filter_i].slaves = NULL; - crtc_updates[filter_i].filter.crtc = crtcs[crtc_i]; - crtc_updates[filter_i].filter.class = classes[i]; - crtc_updates[filter_i].filter.priority = priority; - crtc_updates[filter_i].filter.depth = crtc_info[crtc_i].depth; - crtc_updates[filter_i].filter.ramps.u8.red_size = crtc_info[crtc_i].red_size; - crtc_updates[filter_i].filter.ramps.u8.green_size = crtc_info[crtc_i].green_size; - crtc_updates[filter_i].filter.ramps.u8.blue_size = crtc_info[crtc_i].blue_size; - switch (crtc_updates[filter_i].filter.depth) - { -#define X(CONST, MEMBER, MAX, TYPE)\ - case CONST:\ - libcoopgamma_ramps_initialise(&(crtc_updates[filter_i].filter.ramps.MEMBER));\ - libclut_start_over(&(crtc_updates[filter_i].filter.ramps.MEMBER), MAX, TYPE, 1, 1, 1);\ - break; -LIST_DEPTHS -#undef X - default: - fprintf(stderr, "%s: internal error: gamma ramp type is unrecognised: %i\n", - argv0, crtc_updates[filter_i].filter.depth); - goto custom_fail; - } - } - - switch (start()) - { - case 0: - break; - case -1: - goto fail; - case -2: - goto cg_fail; - case -3: - goto custom_fail; - } - - for (filter_i = 0; filter_i < filters_n; filter_i++) - if (crtc_updates[filter_i].failed) - { - const char* side = cg.error.server_side ? "server" : "client"; - const char* crtc = crtc_updates[filter_i].filter.crtc; - if (cg.error.custom) - { - if ((cg.error.number != 0) && (cg.error.description != NULL)) - fprintf(stderr, "%s: %s-side error number %" PRIu64 " for CRTC %s: %s\n", - argv0, side, cg.error.number, crtc, cg.error.description); - else if (cg.error.number != 0) - fprintf(stderr, "%s: %s-side error number %" PRIu64 " for CRTC %s\n", - argv0, side, cg.error.number, crtc); - else if (cg.error.description != NULL) - fprintf(stderr, "%s: %s-side error for CRTC %s: %s\n", argv0, side, crtc, cg.error.description); - } - else if (cg.error.description != NULL) - fprintf(stderr, "%s: %s-side error for CRTC %s: %s\n", argv0, side, crtc, cg.error.description); - else - fprintf(stderr, "%s: %s-side error for CRTC %s: %s\n", argv0, side, crtc, strerror(cg.error.number)); - } - - done: - if (dealloc_crtcs) - free(crtcs); - if (crtc_info != NULL) - for (crtc_i = 0; crtc_i < crtcs_n; crtc_i++) - libcoopgamma_crtc_info_destroy(crtc_info + crtc_i); - if (asyncs != NULL) - for (filter_i = 0; filter_i < filters_n; filter_i++) - libcoopgamma_async_context_destroy(asyncs + filter_i); - if (stage >= 1) - libcoopgamma_context_destroy(&cg, stage >= 2); - if (crtc_updates != NULL) - for (filter_i = 0; filter_i < filters_n; filter_i++) - { - if (crtc_updates[filter_i].master == 0) - memset(&(crtc_updates[filter_i].filter.ramps.u8), 0, sizeof(crtc_updates[filter_i].filter.ramps.u8)); - crtc_updates[filter_i].filter.crtc = NULL; - crtc_updates[filter_i].filter.class = NULL; - libcoopgamma_filter_destroy(&(crtc_updates[filter_i].filter)); - libcoopgamma_error_destroy(&(crtc_updates[filter_i].error)); - free(crtc_updates[filter_i].slaves); - } - return rc; - - custom_fail: - rc = 1; - goto done; - - fail: - rc = 1; - if (errno) - perror(argv0); - goto done; - - cg_fail: - rc = 1; - { - const char* side = cg.error.server_side ? "server" : "client"; - if (cg.error.custom) - { - if ((cg.error.number != 0) && (cg.error.description != NULL)) - fprintf(stderr, "%s: %s-side error number %" PRIu64 ": %s\n", - argv0, side, cg.error.number, cg.error.description); - else if (cg.error.number != 0) - fprintf(stderr, "%s: %s-side error number %" PRIu64 "\n", argv0, side, cg.error.number); - else if (cg.error.description != NULL) - fprintf(stderr, "%s: %s-side error: %s\n", argv0, side, cg.error.description); - } - else if (cg.error.description != NULL) - fprintf(stderr, "%s: %s-side error: %s\n", argv0, side, cg.error.description); - else - fprintf(stderr, "%s: %s-side error: %s\n", argv0, side, strerror(cg.error.number)); - } - goto done; -} - diff --git a/src/cg-base.h b/src/cg-base.h deleted file mode 100644 index cd885e7..0000000 --- a/src/cg-base.h +++ /dev/null @@ -1,254 +0,0 @@ -/** - * cg-tools -- Cooperative gamma-enabled tools - * Copyright (C) 2016 Mattias Andrée (maandree@kth.se) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#include <libcoopgamma.h> - -#include <inttypes.h> - - - -/** - * Value of `default_priority` that indicates - * that there is no default priority - */ -#define NO_DEFAULT_PRIORITY INT64_MAX - - - -/** - * X-macro that list all gamma ramp types - * - * X will be expanded with 4 arguments: - * 1) The libcoopgamma constant that identifies the type - * 2) The member in `union libcoopgamma_ramps` that - * corresponds to the type - * 3) The max value for the ramp stops - * 4) The type of the ramp stops - */ -#define LIST_DEPTHS\ - X(LIBCOOPGAMMA_UINT8, u8, UINT8_MAX, uint8_t)\ - X(LIBCOOPGAMMA_UINT16, u16, UINT16_MAX, uint16_t)\ - X(LIBCOOPGAMMA_UINT32, u32, UINT32_MAX, uint32_t)\ - X(LIBCOOPGAMMA_UINT64, u64, UINT64_MAX, uint64_t)\ - X(LIBCOOPGAMMA_FLOAT, f, ((float)1), float)\ - X(LIBCOOPGAMMA_DOUBLE, d, ((double)1), double) - - - -/** - * Information (except asynchronous call context) - * required to update the gamma ramps on a CRTC. - */ -typedef struct filter_update -{ - /** - * The filter to update - * - * `.filter.crtc`, `.filter.class`, and - * `.filter.priority` (unless `default_priority` - * is `NO_DEFAULT_PRIORITY`), `.filter.depth` - * are preconfigured, and `.filter.ramps` - * is preinitialised and preset to an - * identity ramp - */ - libcoopgamma_filter_t filter; - - /** - * The index of the CRTC - */ - size_t crtc; - - /** - * Has the update been synchronised? - */ - int synced; - - /** - * Did the update fail? - */ - int failed; - - /** - * Error description if `.failed` is true - */ - libcoopgamma_error_t error; - - /** - * If zero, the ramps in `.filter` shall - * neither be modified nor freed - */ - int master; - - /** - * 0-terminated list of elements in - * `.crtc_updates` which shares gamma - * ramps with this instance - * - * This will only be set if `.master` - * is true - */ - size_t* slaves; - -} filter_update_t; - - - -/** - * The process's name - */ -extern const char* argv0; - -/** - * The libcoopgamma context - */ -extern libcoopgamma_context_t cg; - -/** - * The names of the selected CRTC:s - */ -extern char** crtcs; - -/** - * Gamma ramp updates for each CRTC - */ -extern filter_update_t* crtc_updates; - -/** - * CRTC and monitor information about - * each selected CRTC and connect monitor - */ -extern libcoopgamma_crtc_info_t* crtc_info; - -/** - * The number of selected CRTC:s - */ -extern size_t crtcs_n; - -/** - * The number of filters - */ -extern size_t filters_n; - - - -/** - * The default filter priority for the program - */ -extern const int64_t default_priority; - -/** - * The default class for the program - */ -extern char default_class[]; - -/** - * Class suffixes - */ -extern const char* const* class_suffixes; - - - -/** - * Make elements in `crtc_updates` slaves where appropriate - * - * @return Zero on success, -1 on error - */ -int make_slaves(void); - -/** - * Update a filter and synchronise calls - * - * @param index The index of the CRTC - * @param timeout The number of milliseconds a call to `poll` may block, - * -1 if it may block forever - * @return 1: Success, no pending synchronisations - * 0: Success, with still pending synchronisations - * -1: Error, `errno` set - * -2: Error, `cg.error` set - * - * @throws EINTR Call to `poll` was interrupted by a signal - * @throws EAGAIN Call to `poll` timed out - */ -int update_filter(size_t index, int timeout); - -/** - * Synchronised calls - * - * @param timeout The number of milliseconds a call to `poll` may block, - * -1 if it may block forever - * @return 1: Success, no pending synchronisations - * 0: Success, with still pending synchronisations - * -1: Error, `errno` set - * -2: Error, `cg.error` set - * - * @throws EINTR Call to `poll` was interrupted by a signal - * @throws EAGAIN Call to `poll` timed out - */ -int synchronise(int timeout); - - -/** - * Print usage information and exit - */ -#if defined(__GNUC__) -__attribute__((__noreturn__)) -#endif -extern void usage(void); - -/** - * Handle a command line option - * - * @param opt The option, it is a NUL-terminate two-character - * string starting with either '-' or '+', if the - * argument is not recognised, call `usage`. This - * string will not be "-M", "-S", "-c", "-p", or "-R". - * @param arg The argument associated with `opt`, - * `NULL` there is no next argument, if this - * parameter is `NULL` but needed, call `usage` - * @return 0 if `arg` was not used, - * 1 if `arg` was used, - * -1 on error - */ -#if defined(__GNUC__) -__attribute__((__nonnull__(1))) -#endif -extern int handle_opt(char* opt, char* arg); - -/** - * This function is called after the last - * call to `handle_opt` - * - * @param argc The number of unparsed arguments - * @param argv `NULL` terminated list of unparsed arguments - * @param prio The argument associated with the "-p" option - * @return Zero on success, -1 on error - */ -#if defined(__GNUC__) -__attribute__((__nonnull__(2))) -#endif -extern int handle_args(int argc, char* argv[], char* prio); - -/** - * The main function for the program-specific code - * - * @return 0: Success - * -1: Error, `errno` set - * -2: Error, `cg.error` set - * -3: Error, message already printed - */ -extern int start(void); - diff --git a/src/cg-brilliance.c b/src/cg-brilliance.c deleted file mode 100644 index 3541d03..0000000 --- a/src/cg-brilliance.c +++ /dev/null @@ -1,313 +0,0 @@ -/** - * cg-tools -- Cooperative gamma-enabled tools - * Copyright (C) 2016, 2018 Mattias Andrée (maandree@kth.se) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#include "cg-base.h" - -#include <libclut.h> - -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - - - -/** - * The default filter priority for the program - */ -const int64_t default_priority = (int64_t)1 << 61; - -/** - * The default class for the program - */ -char default_class[] = PKGNAME "::cg-brilliance::standard"; - -/** - * Class suffixes - */ -const char* const* class_suffixes = (const char* const[]){NULL}; - - - -/** - * -d: keep process alive and remove filter on death - */ -static int dflag = 0; - -/** - * -x: remove filter rather than adding it - */ -static int xflag = 0; - -/** - * The brilliance of the red channel - */ -static double rvalue = 0; - -/** - * The brilliance of the green channel - */ -static double gvalue = 0; - -/** - * The brilliance of the blue channel - */ -static double bvalue = 0; - - - -/** - * Print usage information and exit - */ -void usage(void) -{ - fprintf(stderr, - "Usage: %s [-M method] [-S site] [-c crtc]... [-R rule] " - "(-x | [-p priority] [-d] (all | red green blue))\n", - argv0); - exit(1); -} - - -/** - * Handle a command line option - * - * @param opt The option, it is a NUL-terminate two-character - * string starting with either '-' or '+', if the - * argument is not recognised, call `usage`. This - * string will not be "-M", "-S", "-c", "-p", or "-R". - * @param arg The argument associated with `opt`, - * `NULL` there is no next argument, if this - * parameter is `NULL` but needed, call `usage` - * @return 0 if `arg` was not used, - * 1 if `arg` was used, - * -1 on error - */ -int handle_opt(char* opt, char* arg) -{ - if (opt[0] == '-') - switch (opt[1]) - { - case 'd': - if (dflag || xflag) - usage(); - dflag = 1; - break; - case 'x': - if (xflag || dflag) - usage(); - xflag = 1; - break; - default: - usage(); - } - else - usage(); - return 0; - (void) arg; -} - - -/** - * Parse a non-negative double encoded as a string - * - * @param out Output parameter for the value - * @param str The string - * @return Zero on success, -1 if the string is invalid - */ -static int parse_double(double* restrict out, const char* restrict str) -{ - char* end; - errno = 0; - *out = strtod(str, &end); - if (errno || (*out < 0) || isinf(*out) || isnan(*out) || *end) - return -1; - if (!*str || !strchr("0123456789.", *str)) - return -1; - return 0; -} - - -/** - * This function is called after the last - * call to `handle_opt` - * - * @param argc The number of unparsed arguments - * @param argv `NULL` terminated list of unparsed arguments - * @param prio The argument associated with the "-p" option - * @return Zero on success, -1 on error - */ -int handle_args(int argc, char* argv[], char* prio) -{ - char* red = NULL; - char* green = NULL; - char* blue = NULL; - int q = xflag + dflag; - if ((q > 1) || (xflag && (prio != NULL || argc))) - usage(); - if (argc == 1) - red = green = blue = argv[0]; - else if (argc == 3) - { - red = argv[0]; - green = argv[1]; - blue = argv[2]; - } - else if (argc || !xflag) - usage(); - if (argc) - { - if (parse_double(&rvalue, red) < 0) - usage(); - if (parse_double(&gvalue, blue) < 0) - usage(); - if (parse_double(&bvalue, green) < 0) - usage(); - } - return 0; -} - - -/** - * Fill a filter - * - * @param filter The filter to fill - */ -static void fill_filter(libcoopgamma_filter_t* restrict filter) -{ - size_t i; - switch (filter->depth) - { -#define X(CONST, MAX, TYPE, MEMBER) \ - case CONST: \ - for (i = 0; i < filter->ramps.MEMBER.red_size; i++) \ - { \ - double val = (double)(filter->ramps.MEMBER.red[i]); \ - val *= rvalue; \ - if (val < 0) filter->ramps.MEMBER.red[i] = 0; \ - else if (val > (double)(MAX)) filter->ramps.MEMBER.red[i] = MAX; \ - else filter->ramps.MEMBER.red[i] = (TYPE)val; \ - } \ - for (i = 0; i < filter->ramps.MEMBER.green_size; i++) \ - { \ - double val = (double)(filter->ramps.MEMBER.green[i]); \ - val *= gvalue; \ - if (val < 0) filter->ramps.MEMBER.green[i] = 0; \ - else if (val > (double)(MAX)) filter->ramps.MEMBER.green[i] = MAX; \ - else filter->ramps.MEMBER.green[i] = (TYPE)val; \ - } \ - for (i = 0; i < filter->ramps.MEMBER.blue_size; i++) \ - { \ - double val = (double)(filter->ramps.MEMBER.blue[i]); \ - val *= bvalue; \ - if (val < 0) filter->ramps.MEMBER.blue[i] = 0; \ - else if (val > (double)(MAX)) filter->ramps.MEMBER.blue[i] = MAX; \ - else filter->ramps.MEMBER.blue[i] = (TYPE)val; \ - } \ - break - X(LIBCOOPGAMMA_UINT8, UINT8_MAX, uint8_t, u8); - X(LIBCOOPGAMMA_UINT16, UINT16_MAX, uint16_t, u16); - X(LIBCOOPGAMMA_UINT32, UINT32_MAX, uint32_t, u32); - X(LIBCOOPGAMMA_UINT64, UINT64_MAX, uint64_t, u64); -#undef X - case LIBCOOPGAMMA_FLOAT: - libclut_rgb_brightness(&(filter->ramps.f), (float)1, float, rvalue, gvalue, bvalue); - libclut_clip(&(filter->ramps.f), (float)1, float, 1, 1, 1); - break; - case LIBCOOPGAMMA_DOUBLE: - libclut_rgb_brightness(&(filter->ramps.d), (double)1, double, rvalue, gvalue, bvalue); - libclut_clip(&(filter->ramps.d), (double)1, double, 1, 1, 1); - break; - default: - abort(); - } -} - - -/** - * The main function for the program-specific code - * - * @return 0: Success - * -1: Error, `errno` set - * -2: Error, `cg.error` set - * -3: Error, message already printed - */ -int start(void) -{ - int r; - size_t i, j; - - if (xflag) - for (i = 0; i < filters_n; i++) - crtc_updates[i].filter.lifespan = LIBCOOPGAMMA_REMOVE; - else if (dflag) - for (i = 0; i < filters_n; i++) - crtc_updates[i].filter.lifespan = LIBCOOPGAMMA_UNTIL_DEATH; - else - for (i = 0; i < filters_n; i++) - crtc_updates[i].filter.lifespan = LIBCOOPGAMMA_UNTIL_REMOVAL; - - if (!xflag) - if ((r = make_slaves()) < 0) - return r; - - for (i = 0, r = 1; i < filters_n; i++) - { - if (!(crtc_updates[i].master) || !(crtc_info[crtc_updates[i].crtc].supported)) - continue; - if (!xflag) - fill_filter(&(crtc_updates[i].filter)); - r = update_filter(i, 0); - if ((r == -2) || ((r == -1) && (errno != EAGAIN))) - return r; - if (crtc_updates[i].slaves != NULL) - for (j = 0; crtc_updates[i].slaves[j] != 0; j++) - { - r = update_filter(crtc_updates[i].slaves[j], 0); - if ((r == -2) || ((r == -1) && (errno != EAGAIN))) - return r; - } - } - - while (r != 1) - if ((r = synchronise(-1)) < 0) - return r; - - if (!dflag) - return 0; - - if (libcoopgamma_set_nonblocking(&cg, 0) < 0) - return -1; - for (;;) - if (libcoopgamma_synchronise(&cg, NULL, 0, &j) < 0) - switch (errno) - { - case 0: - break; - case ENOTRECOVERABLE: - goto enotrecoverable; - default: - return -1; - } - - enotrecoverable: - for (;;) - if (pause() < 0) - return -1; -} - diff --git a/src/cg-darkroom.c b/src/cg-darkroom.c deleted file mode 100644 index 9990aa3..0000000 --- a/src/cg-darkroom.c +++ /dev/null @@ -1,316 +0,0 @@ -/** - * cg-tools -- Cooperative gamma-enabled tools - * Copyright (C) 2016, 2018 Mattias Andrée (maandree@kth.se) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#include "cg-base.h" - -#include <libclut.h> - -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - - - -/** - * The default filter priority for the program - */ -const int64_t default_priority = (int64_t)3 << 61; - -/** - * The default class for the program - */ -char default_class[] = PKGNAME "::cg-darkroom::standard"; - -/** - * Class suffixes - */ -const char* const* class_suffixes = (const char* const[]){NULL}; - - - -/** - * -d: keep process alive and remove filter on death - */ -static int dflag = 0; - -/** - * -x: remove filter rather than adding it - */ -static int xflag = 0; - -/** - * The brilliance of the red channel - */ -static double value = 0.25; - - - -/** - * Print usage information and exit - */ -void usage(void) -{ - fprintf(stderr, - "Usage: %s [-M method] [-S site] [-c crtc]... [-R rule] " - "(-x | [-p priority] [-d] [brightness])\n", - argv0); - exit(1); -} - - -/** - * Handle a command line option - * - * @param opt The option, it is a NUL-terminate two-character - * string starting with either '-' or '+', if the - * argument is not recognised, call `usage`. This - * string will not be "-M", "-S", "-c", "-p", or "-R". - * @param arg The argument associated with `opt`, - * `NULL` there is no next argument, if this - * parameter is `NULL` but needed, call `usage` - * @return 0 if `arg` was not used, - * 1 if `arg` was used, - * -1 on error - */ -int handle_opt(char* opt, char* arg) -{ - if (opt[0] == '-') - switch (opt[1]) - { - case 'd': - if (dflag || xflag) - usage(); - dflag = 1; - break; - case 'x': - if (xflag || dflag) - usage(); - xflag = 1; - break; - default: - usage(); - } - else - usage(); - return 0; - (void) arg; -} - - -/** - * Parse a non-negative double encoded as a string - * - * @param out Output parameter for the value - * @param str The string - * @return Zero on success, -1 if the string is invalid - */ -static int parse_double(double* restrict out, const char* restrict str) -{ - char* end; - errno = 0; - *out = strtod(str, &end); - if (errno || (*out < 0) || isinf(*out) || isnan(*out) || *end) - return -1; - if (!*str || !strchr("0123456789.", *str)) - return -1; - return 0; -} - - -/** - * This function is called after the last - * call to `handle_opt` - * - * @param argc The number of unparsed arguments - * @param argv `NULL` terminated list of unparsed arguments - * @param prio The argument associated with the "-p" option - * @return Zero on success, -1 on error - */ -int handle_args(int argc, char* argv[], char* prio) -{ - int q = xflag + dflag; - if ((q > 1) || (xflag && (prio != NULL || argc))) - usage(); - if (argc == 1) - { - if (parse_double(&value, argv[0]) < 0) - usage(); - } - else if (argc) - usage(); - return 0; -} - - -/** - * Fill a filter - * - * @param filter The filter to fill - * @return Zero on success, -1 on error - */ -static int fill_filter(libcoopgamma_filter_t* restrict filter) -{ - union libcoopgamma_ramps dramps; - size_t size; - - if ((0 <= value) && (value <= 1)) - { - switch (filter->depth) - { -#define X(CONST, MEMBER, MAX, TYPE)\ - case CONST:\ - libclut_negative(&(filter->ramps.MEMBER), MAX, TYPE, 1, 0, 0);\ - libclut_rgb_brightness(&(filter->ramps.MEMBER), MAX, TYPE, 1, 0, 0);\ - libclut_cie_brightness(&(filter->ramps.MEMBER), MAX, TYPE, value, value, value);\ - break; -LIST_DEPTHS -#undef X - default: - abort(); - } - return 0; - } - if (filter->depth == LIBCOOPGAMMA_DOUBLE) - { - libclut_negative(&(filter->ramps.d), (double)1, double, 1, 0, 0); - libclut_rgb_brightness(&(filter->ramps.d), (double)1, double, 1, 0, 0); - libclut_cie_brightness(&(filter->ramps.d), (double)1, double, value, value, value); - libclut_clip(&(filter->ramps.d), (double)1, double, 1, 0, 0); - return 0; - } - if (filter->depth == LIBCOOPGAMMA_FLOAT) - { - libclut_negative(&(filter->ramps.f), (float)1, float, 1, 0, 0); - libclut_rgb_brightness(&(filter->ramps.f), (float)1, float, 1, 0, 0); - libclut_cie_brightness(&(filter->ramps.f), (float)1, float, value, value, value); - libclut_clip(&(filter->ramps.f), (float)1, float, 1, 0, 0); - return 0; - } - - size = dramps.d.red_size = filter->ramps.d.red_size; - size += dramps.d.green_size = filter->ramps.d.green_size; - size += dramps.d.blue_size = filter->ramps.d.blue_size; - dramps.d.red = calloc(size, sizeof(double)); - if (dramps.d.red == NULL) - return -1; - dramps.d.green = dramps.d.red + dramps.d.red_size; - dramps.d.blue = dramps.d.green + dramps.d.green_size; - - libclut_start_over(&(dramps.d), (double)1, double, 1, 0, 0); - libclut_negative(&(dramps.d), (double)1, double, 1, 0, 0); - libclut_rgb_brightness(&(dramps.d), (double)1, double, 1, 0, 0); - libclut_cie_brightness(&(dramps.d), (double)1, double, value, value, value); - libclut_clip(&(dramps.d), (double)1, double, 1, 0, 0); - - switch (filter->depth) - { - case LIBCOOPGAMMA_UINT8: - libclut_translate(&(filter->ramps.u8), UINT8_MAX, uint8_t, &(dramps.d), (double)1, double); - break; - case LIBCOOPGAMMA_UINT16: - libclut_translate(&(filter->ramps.u16), UINT16_MAX, uint16_t, &(dramps.d), (double)1, double); - break; - case LIBCOOPGAMMA_UINT32: - libclut_translate(&(filter->ramps.u32), UINT32_MAX, uint32_t, &(dramps.d), (double)1, double); - break; - case LIBCOOPGAMMA_UINT64: - libclut_translate(&(filter->ramps.u64), UINT64_MAX, uint64_t, &(dramps.d), (double)1, double); - break; - default: - abort(); - } - - free(dramps.d.red); - return 0; -} - - -/** - * The main function for the program-specific code - * - * @return 0: Success - * -1: Error, `errno` set - * -2: Error, `cg.error` set - * -3: Error, message already printed - */ -int start(void) -{ - int r; - size_t i, j; - - if (xflag) - for (i = 0; i < filters_n; i++) - crtc_updates[i].filter.lifespan = LIBCOOPGAMMA_REMOVE; - else if (dflag) - for (i = 0; i < filters_n; i++) - crtc_updates[i].filter.lifespan = LIBCOOPGAMMA_UNTIL_DEATH; - else - for (i = 0; i < filters_n; i++) - crtc_updates[i].filter.lifespan = LIBCOOPGAMMA_UNTIL_REMOVAL; - - if (!xflag) - if ((r = make_slaves()) < 0) - return r; - - for (i = 0, r = 1; i < filters_n; i++) - { - if (!(crtc_updates[i].master) || !(crtc_info[crtc_updates[i].crtc].supported)) - continue; - if (!xflag) - if ((r = fill_filter(&(crtc_updates[i].filter))) < 0) - return r; - r = update_filter(i, 0); - if ((r == -2) || ((r == -1) && (errno != EAGAIN))) - return r; - if (crtc_updates[i].slaves != NULL) - for (j = 0; crtc_updates[i].slaves[j] != 0; j++) - { - r = update_filter(crtc_updates[i].slaves[j], 0); - if ((r == -2) || ((r == -1) && (errno != EAGAIN))) - return r; - } - } - - while (r != 1) - if ((r = synchronise(-1)) < 0) - return r; - - if (!dflag) - return 0; - - if (libcoopgamma_set_nonblocking(&cg, 0) < 0) - return -1; - for (;;) - if (libcoopgamma_synchronise(&cg, NULL, 0, &j) < 0) - switch (errno) - { - case 0: - break; - case ENOTRECOVERABLE: - goto enotrecoverable; - default: - return -1; - } - - enotrecoverable: - for (;;) - if (pause() < 0) - return -1; -} - diff --git a/src/cg-gamma.c b/src/cg-gamma.c deleted file mode 100644 index 1d24d07..0000000 --- a/src/cg-gamma.c +++ /dev/null @@ -1,541 +0,0 @@ -/** - * cg-tools -- Cooperative gamma-enabled tools - * Copyright (C) 2016, 2018 Mattias Andrée (maandree@kth.se) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#include "cg-base.h" - -#include <libclut.h> - -#include <sys/stat.h> -#include <errno.h> -#include <fcntl.h> -#include <pwd.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - - - -/** - * The default filter priority for the program - */ -const int64_t default_priority = 0; - -/** - * The default class for the program - */ -char default_class[] = PKGNAME "::cg-gamma::standard"; - -/** - * Class suffixes - */ -const char* const* class_suffixes = (const char* const[]){NULL}; - - - -/** - * -d: keep process alive and remove filter on death - */ -static int dflag = 0; - -/** - * -x: remove filter rather than adding it - */ -static int xflag = 0; - -/** - * -f: gamma listing file - */ -static char* fflag = NULL; - -/** - * The gamma of the red channel - */ -static double rgamma = 1; - -/** - * The gamma of the green channel - */ -static double ggamma = 1; - -/** - * The gamma of the blue channel - */ -static double bgamma = 1; - -/** - * `NULL`-terminated list of output - * names listed in the configuration file - */ -static char** names = NULL; - -/** - * The gamma of the red channel on monitor - * with same index in `names` - */ -static double* rgammas = NULL; - -/** - * The gamma of the green channel on monitor - * with same index in `names` - */ -static double* ggammas = NULL; - -/** - * The gamma of the blue channel on monitor - * with same index in `names` - */ -static double* bgammas = NULL; - - - -/** - * Print usage information and exit - */ -void usage(void) -{ - fprintf(stderr, - "Usage: %s [-M method] [-S site] [-c crtc]... [-R rule] " - "(-x | [-p priority] [-d] [-f file | all | red green blue])\n", - argv0); - exit(1); -} - - -/** - * Perform cleanup so valgrind output is clean - * - * @param ret The value to return - * @return `ret` is returned as is - */ -static int cleanup(int ret) -{ - int saved_errno = errno; - if (names != NULL) - { - char** p = names; - while (*p) - free(*p++); - } - free(names); - free(rgammas); - free(ggammas); - free(bgammas); - errno = saved_errno; - return ret; -} - - -/** - * Handle a command line option - * - * @param opt The option, it is a NUL-terminate two-character - * string starting with either '-' or '+', if the - * argument is not recognised, call `usage`. This - * string will not be "-M", "-S", "-c", "-p", or "-R". - * @param arg The argument associated with `opt`, - * `NULL` there is no next argument, if this - * parameter is `NULL` but needed, call `usage` - * @return 0 if `arg` was not used, - * 1 if `arg` was used, - * -1 on error - */ -int handle_opt(char* opt, char* arg) -{ - if (opt[0] == '-') - switch (opt[1]) - { - case 'd': - if (dflag || xflag) - usage(); - dflag = 1; - break; - case 'x': - if (xflag || dflag) - usage(); - xflag = 1; - break; - case 'f': - if (fflag || !(fflag = arg)) - usage(); - return 1; - default: - usage(); - } - return 0; -} - - -/** - * Get the pathname of a configuration file - * - * @param confname The filename (excluding directory) of the configuration file - * @return The full pathname of the configuration file, `NULL` on error - */ -static char* get_conf_file(const char* restrict confname) -{ - struct passwd* pw; - char* path; - - pw = getpwuid(getuid()); - if ((pw == NULL) || (pw->pw_dir == NULL)) - return NULL; - - path = malloc(strlen(pw->pw_dir) + strlen(confname) + sizeof("/.config/")); - if (path == NULL) - return NULL; - - sprintf(path, "%s/.config/%s", pw->pw_dir, confname); - - if (access(path, F_OK) < 0) - sprintf(path, "/etc/%s", confname); - - return path; -} - - -/** - * Parse a non-negative double encoded as a string - * - * @param out Output parameter for the value - * @param str The string - * @return Zero on success, -1 if the string is invalid - */ -static int parse_double(double* restrict out, const char* restrict str) -{ - char* end; - errno = 0; - *out = strtod(str, &end); - if (errno || (*out < 0) || isinf(*out) || isnan(*out) || *end) - return -1; - if (!*str || !strchr("0123456789.", *str)) - return -1; - return 0; -} - - -/** - * Parse gamma configuration file - * - * @param pathname The pathname of the file - * @return Zero on success, -1 on error - */ -static int parse_gamma_file(const char* restrict pathname) -{ - int fd, saved_errno; - char* line = NULL; - size_t size = 0, lineno = 0, ptr = 0, alloc = 0; - ssize_t n; - FILE* f = NULL; - char* p; - char* q; - char* r; - char* g; - char* b; - - fd = open(pathname, O_RDONLY); - if (fd == -1) - return -1; - - f = fdopen(fd, "rb"); - if (f == NULL) - goto fail; - - while (n = getline(&line, &size, f), n >= 0) - { - lineno += 1; - - if ((n > 0) && (line[n - 1] == '\n')) - line[n - 1] = '\0'; - p = line; - while ((*p == ' ') || (*p == '\t')) p++; - if ((!*p) || (*p == '#')) - continue; - - r = strpbrk(line, " \t"); - if (r == NULL) - goto bad; - while (r[1] == ' ' || r[1] == '\t') r++; - g = strpbrk(r + 1, " \t"); - if (g == NULL) - goto bad; - while (g[1] == ' ' || g[1] == '\t') g++; - b = strpbrk(g + 1, " \t"); - if (b == NULL) - goto bad; - while (b[1] == ' ' || b[1] == '\t') b++; - - for (;;) - { - q = strpbrk(b + 1, " \t"); - if (q == NULL) - break; - while (q[1] == ' ' || q[1] == '\t') q++; - if (!*q) - break; - r = g, g = b, b = q; - } - - *r++ = '\0'; - *g++ = '\0'; - *b++ = '\0'; - - q = strpbrk(r, " \t"); - if (q != NULL) - *q = '\0'; - q = strpbrk(g, " \t"); - if (q != NULL) - *q = '\0'; - q = strpbrk(b, " \t"); - if (q != NULL) - *q = '\0'; - - q = strchr(p, '\0'); - while ((q != p) && ((q[-1] == ' ') || (q[-1] == '\t'))) - q--; - *q = '\0'; - - if (ptr == alloc) - { - void* new; - size_t new_size = alloc ? (alloc << 1) : 4; - - new = realloc(rgammas, new_size * sizeof(*rgammas)); - if (new == NULL) - goto fail; - rgammas = new; - - new = realloc(ggammas, new_size * sizeof(*ggammas)); - if (new == NULL) - goto fail; - ggammas = new; - - new = realloc(bgammas, new_size * sizeof(*bgammas)); - if (new == NULL) - goto fail; - bgammas = new; - - new = realloc(names, (new_size + 1) * sizeof(*names)); - if (new == NULL) - goto fail; - names = new; - memset(names + alloc, 0, (new_size + 1 - alloc) * sizeof(*names)); - - alloc = new_size; - } - - if ((parse_double(rgammas + ptr, r) < 0) || - (parse_double(ggammas + ptr, g) < 0) || - (parse_double(bgammas + ptr, b) < 0)) - goto bad; - names[ptr] = malloc(strlen(p) + 1); - if (names[ptr] == NULL) - goto fail; - strcpy(names[ptr], p); - ptr++; - - continue; - bad: - fprintf(stderr, "%s: ignoring malformatted line in %s: %zu\n", argv0, pathname, lineno); - } - - if (fclose(f) < 0) - { - f = NULL; - goto fail; - } - close(fd); - free(line); - return 0; - fail: - saved_errno = errno; - free(line); - if (f != NULL) - fclose(f); - if (fd >= 0) - close(fd); - errno = saved_errno; - return -1; -} - - -/** - * This function is called after the last - * call to `handle_opt` - * - * @param argc The number of unparsed arguments - * @param argv `NULL` terminated list of unparsed arguments - * @param prio The argument associated with the "-p" option - * @return Zero on success, -1 on error - */ -int handle_args(int argc, char* argv[], char* prio) -{ - int free_fflag = 0, saved_errno; - int q = xflag + dflag; - if ((q > 1) || (fflag && argc) || (xflag && ((fflag != NULL) || (argc > 0) || (prio != NULL)))) - usage(); - if (argc == 1) - { - if (parse_double(&rgamma, argv[0]) < 0) - usage(); - bgamma = ggamma = rgamma; - } - else if (argc == 3) - { - if (parse_double(&rgamma, argv[0]) < 0) - usage(); - if (parse_double(&ggamma, argv[1]) < 0) - usage(); - if (parse_double(&bgamma, argv[2]) < 0) - usage(); - } - else if (argc) - usage(); - if (!argc && !fflag && !xflag) - { - fflag = get_conf_file("gamma"); - if (fflag == NULL) - return -1; - free_fflag = 1; - } - if (fflag) - if (parse_gamma_file(fflag) < 0) - goto fail; - if (free_fflag) - free(fflag), fflag = NULL; - return 0; - fail: - saved_errno = errno; - if (free_fflag) - free(fflag), fflag = NULL; - errno = saved_errno; - return cleanup(-1); -} - - -/** - * Fill a filter - * - * @param filter The filter to fill - * @param r The red gamma - * @param g The green gamma - * @param b The blue gamma - */ -static void fill_filter(libcoopgamma_filter_t* restrict filter, double r, double g, double b) -{ - switch (filter->depth) - { -#define X(CONST, MEMBER, MAX, TYPE)\ - case CONST:\ - libclut_gamma(&(filter->ramps.MEMBER), MAX, TYPE, r, g, b);\ - break; -LIST_DEPTHS -#undef X - default: - abort(); - } -} - - -/** - * The main function for the program-specific code - * - * @return 0: Success - * -1: Error, `errno` set - * -2: Error, `cg.error` set - * -3: Error, message already printed - */ -int start(void) -{ - int r; - size_t i, j; - - if (xflag) - for (i = 0; i < filters_n; i++) - crtc_updates[i].filter.lifespan = LIBCOOPGAMMA_REMOVE; - else if (dflag) - for (i = 0; i < filters_n; i++) - crtc_updates[i].filter.lifespan = LIBCOOPGAMMA_UNTIL_DEATH; - else - for (i = 0; i < filters_n; i++) - crtc_updates[i].filter.lifespan = LIBCOOPGAMMA_UNTIL_REMOVAL; - - if (!xflag && (names != NULL)) - if ((r = make_slaves()) < 0) - return cleanup(r); - - if (names == NULL) - for (i = 0, r = 1; i < filters_n; i++) - { - if (!(crtc_updates[i].master) || !(crtc_info[crtc_updates[i].crtc].supported)) - continue; - if (!xflag) - fill_filter(&(crtc_updates[i].filter), rgamma, ggamma, bgamma); - r = update_filter(i, 0); - if ((r == -2) || ((r == -1) && (errno != EAGAIN))) - return cleanup(r); - if (crtc_updates[i].slaves != NULL) - for (j = 0; crtc_updates[i].slaves[j] != 0; j++) - { - r = update_filter(crtc_updates[i].slaves[j], 0); - if ((r == -2) || ((r == -1) && (errno != EAGAIN))) - return cleanup(r); - } - } - else - for (i = 0, r = 1; i < filters_n; i++) - { - if (!(crtc_info[crtc_updates[i].crtc].supported)) - continue; - for (j = 0; names[j] != NULL; j++) - if (!strcasecmp(crtc_updates[i].filter.crtc, names[j])) - { - fill_filter(&(crtc_updates[i].filter), rgammas[j], ggammas[j], bgammas[j]); - r = update_filter(i, 0); - if ((r == -2) || ((r == -1) && (errno != EAGAIN))) - return cleanup(r); - break; - } - } - - while (r != 1) - if ((r = synchronise(-1)) < 0) - return cleanup(r); - - if (!dflag) - return cleanup(0); - - if (libcoopgamma_set_nonblocking(&cg, 0) < 0) - return cleanup(-1); - for (;;) - if (libcoopgamma_synchronise(&cg, NULL, 0, &j) < 0) - switch (errno) - { - case 0: - break; - case ENOTRECOVERABLE: - goto enotrecoverable; - default: - return cleanup(-1); - } - - enotrecoverable: - for (;;) - if (pause() < 0) - return cleanup(-1); -} - diff --git a/src/cg-icc.c b/src/cg-icc.c deleted file mode 100644 index 5970930..0000000 --- a/src/cg-icc.c +++ /dev/null @@ -1,945 +0,0 @@ -/** - * cg-tools -- Cooperative gamma-enabled tools - * Copyright (C) 2016, 2018 Mattias Andrée (maandree@kth.se) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#include "cg-base.h" - -#include <libclut.h> - -#include <sys/stat.h> -#include <errno.h> -#include <fcntl.h> -#include <pwd.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - - - -/* Note, that EDID:s are 256 hexadecimals long, and - * a filename can only be 255 characters long. */ - - - -/** - * Magic number for dual-byte precision lookup table based profiles - */ -#define MLUT_TAG 0x6D4C5554L - -/** - * Magic number for gamma–brightness–contrast based profiles - * and for variable precision lookup table profiles - */ -#define VCGT_TAG 0x76636774L - -/** - * The filename of the configuration file - */ -#define ICCTAB "icctab" - - - -/** - * The default filter priority for the program - */ -const int64_t default_priority = 0; - -/** - * The default class for the program - */ -char default_class[] = PKGNAME "::cg-icc::standard"; - -/** - * Class suffixes - */ -const char* const* class_suffixes = (const char* const[]){NULL}; - - - -/** - * -d: keep process alive and remove filter on death - */ -static int dflag = 0; - -/** - * -x: remove filter rather than adding it - */ -static int xflag = 0; - -/** - * The panhame of the selected ICC profile - */ -static const char* icc_pathname = NULL; - -/** - * Gamma ramps loaded from `icc_pathname` - */ -static libcoopgamma_ramps_t uniramps; - -/** - * The datatype of the stops in the ramps of `uniramps` - */ -static libcoopgamma_depth_t unidepth = 0; - -/** - * Parsed ICC profiles for each CRTC - */ -static libcoopgamma_ramps_t* rampses = NULL; - -/** - * The datatype of the stops in the ramps of - * corresponding element in `rampses` - */ -static libcoopgamma_depth_t* depths = NULL; - -/** - * File descriptor for configuration directory - */ -static int confdirfd = -1; - -/** - * List of CRTC:s - */ -static char** crtc_icc_keys = NULL; - -/** - * List of ICC profile pathnames for corresponding - * CRTC in `crtc_icc_keys` - */ -static char** crtc_icc_values = NULL; - - - -/** - * Print usage information and exit - */ -void usage(void) -{ - fprintf(stderr, - "Usage: %s [-M method] [-S site] [-c crtc]... [-R rule] " - "(-x | [-p priority] [-d] [file])\n", - argv0); - exit(1); -} - - -/** - * Perform cleanup so valgrind output is clean - * - * @param ret The value to return - * @return `ret` is returned as is - */ -static int cleanup(int ret) -{ - int saved_errno = errno; - size_t i; - libcoopgamma_ramps_destroy(&uniramps); - if (confdirfd >= 0) - close(confdirfd); - if (rampses != NULL) - for (i = 0; i < crtcs_n; i++) - libcoopgamma_ramps_destroy(rampses + i); - free(rampses); - free(depths); - if (crtc_icc_keys != NULL) - for (i = 0; crtc_icc_keys[i] != NULL; i++) - free(crtc_icc_keys[i]); - free(crtc_icc_keys); - if (crtc_icc_values != NULL) - for (i = 0; crtc_icc_values[i] != NULL; i++) - free(crtc_icc_values[i]); - free(crtc_icc_values); - errno = saved_errno; - return ret; -} - - -/** - * Handle a command line option - * - * @param opt The option, it is a NUL-terminate two-character - * string starting with either '-' or '+', if the - * argument is not recognised, call `usage`. This - * string will not be "-M", "-S", "-c", "-p", or "-R". - * @param arg The argument associated with `opt`, - * `NULL` there is no next argument, if this - * parameter is `NULL` but needed, call `usage` - * @return 0 if `arg` was not used, - * 1 if `arg` was used, - * -1 on error - */ -int handle_opt(char* opt, char* arg) -{ - if (opt[0] == '-') - switch (opt[1]) - { - case 'd': - if (dflag || xflag) - usage(); - dflag = 1; - break; - case 'x': - if (xflag || dflag) - usage(); - xflag = 1; - break; - default: - usage(); - } - return 0; - (void) arg; -} - - -/** - * Populate `crtc_icc_keys` and `crtc_icc_value` - * - * @path fd File descriptor for the ICC profile table - * @path dirname The dirname of the ICC profile table - * @return Zero on success, -1 on error - */ -static int load_icc_table(int fd, const char *dirname) -{ - FILE *fp; - ssize_t len; - size_t lineno = 1, size = 0; - char *p, *q, *line = NULL; - int saved_errno; - size_t ptr = 0, siz = 0; - void *new; - size_t dirname_len = strlen(dirname); - fp = fdopen(fd, "rb"); - if (fp == NULL) - return -1; - for (; len = getline(&line, &size, fp), len >= 0; lineno++) - { - if (len && line[len - 1] == '\n') - line[--len] = '\0'; - p = line + strspn(line, " \t"); - if (!*p || (*p == '#')) - continue; - q = p + strspn(p, "0123456789abcdefABCDEF"); - if ((*q != ' ' && *q != '\t')) - { - fprintf(stderr, "%s: warning: line %zu is malformated in %s/%s\n", - argv0, lineno, dirname, ICCTAB); - continue; - } - *q = '\0'; - if ((size_t)(q - p) != 256) - fprintf(stderr, "%s: warning: EDID on line %zu in %s/%s looks to be of wrong length: %s\n", - argv0, lineno, dirname, ICCTAB, p); - q++; - q += strspn(p, " \t"); - if (!*q) - { - fprintf(stderr, "%s: warning: line %zu is malformated in %s/%s\n", - argv0, lineno, dirname, ICCTAB); - continue; - } - if (strchr(" \t", strchr(q, '\0')[-1])) - fprintf(stderr, "%s: warning: filename on line %zu in %s/%s ends with white space: %s\n", - argv0, lineno, dirname, ICCTAB, q); - if (ptr == siz) - { - new = realloc(crtc_icc_keys, (siz + 5) * sizeof(*crtc_icc_keys)); - if (new == NULL) - goto fail; - crtc_icc_keys = new; - new = realloc(crtc_icc_values, (siz + 5) * sizeof(*crtc_icc_values)); - if (new == NULL) - goto fail; - crtc_icc_values = new; - siz += 4; - } - crtc_icc_values[ptr] = malloc((*q == '/' ? 1 : dirname_len + sizeof("/")) + strlen(q)); - if (crtc_icc_values[ptr] == NULL) - goto fail; - if (*q == '/') - strcpy(crtc_icc_values[ptr], q); - else - stpcpy(stpcpy(stpcpy(crtc_icc_values[ptr], dirname), "/"), q); - crtc_icc_keys[ptr] = malloc(strlen(p) + 1); - if (crtc_icc_keys[ptr] == NULL) - { - ptr++; - goto fail; - } - strcpy(crtc_icc_keys[ptr], p); - ptr++; - } - if (ferror(fp)) - goto fail; - if (crtc_icc_keys != NULL) - crtc_icc_keys[ptr] = NULL; - if (crtc_icc_values != NULL) - crtc_icc_values[ptr] = NULL; - fclose(fp); - free(line); - return 0; - fail: - saved_errno = errno; - if (crtc_icc_keys != NULL) - crtc_icc_keys[ptr] = NULL; - if (crtc_icc_values != NULL) - crtc_icc_values[ptr] = NULL; - fclose(fp); - free(line); - errno = saved_errno; - return -1; -} - - -/** - * This function is called after the last - * call to `handle_opt` - * - * @param argc The number of unparsed arguments - * @param argv `NULL` terminated list of unparsed arguments - * @param prio The argument associated with the "-p" option - * @return Zero on success, -1 on error - */ -int handle_args(int argc, char* argv[], char* prio) -{ - struct passwd* pw; - char* path = NULL; - int saved_errno; - int fd = -1, q = xflag + dflag; - if ((q > 1) || (xflag && ((argc > 0) || (prio != NULL))) || (argc > 1)) - usage(); - icc_pathname = *argv; - memset(&uniramps, 0, sizeof(uniramps)); - if (!xflag && (icc_pathname == NULL)) - { - pw = getpwuid(getuid()); - if ((pw == NULL) || (pw->pw_dir == NULL)) - goto fail; - - path = malloc(strlen(pw->pw_dir) + sizeof("/.config")); - if (path == NULL) - goto fail; - - sprintf(path, "%s/.config", pw->pw_dir); - - if (access(path, F_OK) < 0) - sprintf(path, "/etc"); - - confdirfd = open(path, O_DIRECTORY); - if (confdirfd < 0) - goto fail; - - fd = openat(confdirfd, ICCTAB, O_RDONLY); - if (fd < 0) - goto fail; - - if (load_icc_table(fd, path) < 0) - goto fail; - - free(path), path = NULL; - close(fd), fd = -1; - } - return 0; - fail: - saved_errno = errno; - free(path), path = NULL; - if (fd >= 0) - close(fd); - errno = saved_errno; - return cleanup(-1); -} - - -/** - * Read an unsigned 64-bit integer - * - * @param content The beginning of the encoded integer - * @return The integer, decoded - */ -static uint64_t icc_uint64(const char* restrict content) -{ - uint64_t rc; - rc = (uint64_t)(unsigned char)(content[0]), rc <<= 8; - rc |= (uint64_t)(unsigned char)(content[1]), rc <<= 8; - rc |= (uint64_t)(unsigned char)(content[2]), rc <<= 8; - rc |= (uint64_t)(unsigned char)(content[3]), rc <<= 8; - rc |= (uint64_t)(unsigned char)(content[4]), rc <<= 8; - rc |= (uint64_t)(unsigned char)(content[5]), rc <<= 8; - rc |= (uint64_t)(unsigned char)(content[6]), rc <<= 8; - rc |= (uint64_t)(unsigned char)(content[7]); - return rc; -} - - -/** - * Read an unsigned 32-bit integer - * - * @param content The beginning of the encoded integer - * @return The integer, decoded - */ -static uint32_t icc_uint32(const char* restrict content) -{ - uint32_t rc; - rc = (uint32_t)(unsigned char)(content[0]), rc <<= 8; - rc |= (uint32_t)(unsigned char)(content[1]), rc <<= 8; - rc |= (uint32_t)(unsigned char)(content[2]), rc <<= 8; - rc |= (uint32_t)(unsigned char)(content[3]); - return rc; -} - - -/** - * Read an unsigned 16-bit integer - * - * @param content The beginning of the encoded integer - * @return The integer, decoded - */ -static uint16_t icc_uint16(const char* restrict content) -{ - uint16_t rc; - rc = (uint16_t)(unsigned char)(content[0]), rc <<= 8; - rc |= (uint16_t)(unsigned char)(content[1]); - return rc; -} - - -/** - * Read an unsigned 8-bit integer - * - * @param content The beginning of the encoded integer - * @return The integer, decoded - */ -static uint16_t icc_uint8(const char* restrict content) -{ - return (uint8_t)(content[0]); -} - - -/** - * Read a floating-point value - * - * @param content The beginning of the encoded value - * @param width The number of bytes with which the value is encoded - * @return The value, decoded - */ -static double icc_double(const char* restrict content, size_t width) -{ - double ret = 0; - size_t i; - for (i = 0; i < width; i++) - { - ret /= 256; - ret += (double)(unsigned char)(content[width - 1 - i]); - } - ret /= 255; - return ret; -} - - -/** - * Parse an ICC profile - * - * @param content The content of the ICC profile file - * @param n The byte-size of `content` - * @param ramps Output parameter for the filter stored in the ICC profile, - * `.red_size`, `.green_size`, `.blue_size` should already be - * set (these values can however be modified.) - * @param depth Output parameter for ramps stop value type - * @return Zero on success, -1 on error, -2 if no usable data is - * available in the profile. - */ -static int parse_icc(const char* restrict content, size_t n, libcoopgamma_ramps_t* ramps, - libcoopgamma_depth_t* depth) -{ - uint32_t i_tag, n_tags; - size_t i, ptr = 0, xptr; - - /* Skip header */ - if (n - ptr < 128) - return -2; - ptr += 128; - - /* Get the number of tags */ - if (n - ptr < 4) - return -2; - n_tags = icc_uint32(content + ptr), ptr += 4; - - for (i_tag = 0, xptr = ptr; i_tag < n_tags; i_tag++, ptr = xptr) - { - uint32_t tag_name, tag_offset, tag_size, gamma_type; - - /* Get profile encoding type, offset to the profile and the encoding size of its data */ - if (n - ptr < 12) - return -2; - tag_name = icc_uint32(content + ptr), ptr += 4; - tag_offset = icc_uint32(content + ptr), ptr += 4; - tag_size = icc_uint32(content + ptr), ptr += 4; - xptr = ptr; - - /* Jump to the profile data */ - if (tag_offset > INT32_MAX - tag_size) - return -2; - if (tag_offset + tag_size > n) - return -2; - ptr = tag_offset; - - if (tag_name == MLUT_TAG) - { - /* The profile is encododed as an dual-byte precision lookup table */ - - /* Initialise ramps */ - *depth = LIBCOOPGAMMA_UINT16; - ramps->u16.red_size = 256; - ramps->u16.green_size = 256; - ramps->u16.blue_size = 256; - if (libcoopgamma_ramps_initialise(&(ramps->u16)) < 0) - return -1; - - /* Get the lookup table */ - if (n - ptr < 3 * 256 * 2) - continue; - for (i = 0; i < 256; i++) - ramps->u16.red[i] = icc_uint16(content + ptr), ptr += 2; - for (i = 0; i < 256; i++) - ramps->u16.green[i] = icc_uint16(content + ptr), ptr += 2; - for (i = 0; i < 256; i++) - ramps->u16.blue[i] = icc_uint16(content + ptr), ptr += 2; - - return 0; - } - else if (tag_name == VCGT_TAG) - { - /* The profile is encoded as with gamma, brightness and contrast values - * or as a variable precision lookup table profile */ - - /* VCGT profiles starts where their magic number */ - if (n - ptr < 4) - continue; - tag_name = icc_uint32(content + ptr), ptr += 4; - if (tag_name != VCGT_TAG) - continue; - - /* Skip four bytes */ - if (n - ptr < 4) - continue; - ptr += 4; - - /* Get the actual encoding type */ - if (n - ptr < 4) - continue; - gamma_type = icc_uint32(content + ptr), ptr += 4; - - if (gamma_type == 0) - { - /* The profile is encoded as a variable precision lookup table */ - uint16_t n_channels, n_entries, entry_size; - - /* Get metadata */ - if (n - ptr < 3 * 4) - continue; - n_channels = icc_uint16(content + ptr), ptr += 2; - n_entries = icc_uint16(content + ptr), ptr += 2; - entry_size = icc_uint16(content + ptr), ptr += 2; - if (tag_size == 1584) - n_channels = 3, n_entries = 256, entry_size = 2; - if (n_channels != 3) - /* Assuming sRGB, can only be an correct assumption if there are exactly three channels */ - continue; - - /* Check data availability */ - if (n_channels > SIZE_MAX / n_entries) - continue; - if (entry_size > SIZE_MAX / (n_entries * n_channels)) - continue; - if (n - ptr < (size_t)n_channels * (size_t)n_entries * (size_t)entry_size) - continue; - - /* Initialise ramps */ - ramps->u8.red_size = (size_t)n_entries; - ramps->u8.green_size = (size_t)n_entries; - ramps->u8.blue_size = (size_t)n_entries; - switch (entry_size) - { - case 1: - *depth = LIBCOOPGAMMA_UINT8; - if (libcoopgamma_ramps_initialise(&(ramps->u8)) < 0) - return -1; - break; - case 2: - *depth = LIBCOOPGAMMA_UINT16; - if (libcoopgamma_ramps_initialise(&(ramps->u16)) < 0) - return -1; - break; - case 4: - *depth = LIBCOOPGAMMA_UINT32; - if (libcoopgamma_ramps_initialise(&(ramps->u32)) < 0) - return -1; - break; - case 8: - *depth = LIBCOOPGAMMA_UINT64; - if (libcoopgamma_ramps_initialise(&(ramps->u64)) < 0) - return -1; - break; - default: - *depth = LIBCOOPGAMMA_DOUBLE; - if (libcoopgamma_ramps_initialise(&(ramps->d)) < 0) - return -1; - break; - } - - /* Get the lookup table */ - switch (*depth) - { - case LIBCOOPGAMMA_UINT8: - for (i = 0; i < ramps->u8.red_size; i++) - ramps->u8.red[i] = icc_uint8(content + ptr), ptr += 1; - for (i = 0; i < ramps->u8.green_size; i++) - ramps->u8.green[i] = icc_uint8(content + ptr), ptr += 1; - for (i = 0; i < ramps->u8.blue_size; i++) - ramps->u8.blue[i] = icc_uint8(content + ptr), ptr += 1; - break; - case LIBCOOPGAMMA_UINT16: - for (i = 0; i < ramps->u16.red_size; i++) - ramps->u16.red[i] = icc_uint16(content + ptr), ptr += 2; - for (i = 0; i < ramps->u16.green_size; i++) - ramps->u16.green[i] = icc_uint16(content + ptr), ptr += 2; - for (i = 0; i < ramps->u16.blue_size; i++) - ramps->u16.blue[i] = icc_uint16(content + ptr), ptr += 2; - break; - case LIBCOOPGAMMA_UINT32: - for (i = 0; i < ramps->u32.red_size; i++) - ramps->u32.red[i] = icc_uint32(content + ptr), ptr += 4; - for (i = 0; i < ramps->u32.green_size; i++) - ramps->u32.green[i] = icc_uint32(content + ptr), ptr += 4; - for (i = 0; i < ramps->u32.blue_size; i++) - ramps->u32.blue[i] = icc_uint32(content + ptr), ptr += 4; - break; - case LIBCOOPGAMMA_UINT64: - for (i = 0; i < ramps->u64.red_size; i++) - ramps->u64.red[i] = icc_uint64(content + ptr), ptr += 8; - for (i = 0; i < ramps->u64.green_size; i++) - ramps->u64.green[i] = icc_uint64(content + ptr), ptr += 8; - for (i = 0; i < ramps->u64.blue_size; i++) - ramps->u64.blue[i] = icc_uint64(content + ptr), ptr += 8; - break; - default: - for (i = 0; i < ramps->d.red_size; i++) - ramps->d.red[i] = icc_double(content + ptr, entry_size), ptr += entry_size; - for (i = 0; i < ramps->d.green_size; i++) - ramps->d.green[i] = icc_double(content + ptr, entry_size), ptr += entry_size; - for (i = 0; i < ramps->d.blue_size; i++) - ramps->d.blue[i] = icc_double(content + ptr, entry_size), ptr += entry_size; - break; - } - - return 0; - } - else if (gamma_type == 1) - { - /* The profile is encoded with gamma, brightness and contrast values */ - double r_gamma, r_min, r_max, g_gamma, g_min, g_max, b_gamma, b_min, b_max; - - /* Get the gamma, brightness and contrast */ - if (n - ptr < 9 * 4) - continue; - r_gamma = icc_uint32(content + ptr), r_gamma /= 65536L, ptr += 4; - r_min = icc_uint32(content + ptr), r_min /= 65536L, ptr += 4; - r_max = icc_uint32(content + ptr), r_max /= 65536L, ptr += 4; - g_gamma = icc_uint32(content + ptr), g_gamma /= 65536L, ptr += 4; - g_min = icc_uint32(content + ptr), g_min /= 65536L, ptr += 4; - g_max = icc_uint32(content + ptr), g_max /= 65536L, ptr += 4; - b_gamma = icc_uint32(content + ptr), b_gamma /= 65536L, ptr += 4; - b_min = icc_uint32(content + ptr), b_min /= 65536L, ptr += 4; - b_max = icc_uint32(content + ptr), b_max /= 65536L, ptr += 4; - - /* Initialise ramps */ - *depth = LIBCOOPGAMMA_DOUBLE; - if (libcoopgamma_ramps_initialise(&(ramps->d)) < 0) - return -1; - - /* Set ramps */ - libclut_start_over(&(ramps->d), (double)1, double, 1, 1, 1); - libclut_gamma(&(ramps->d), (double)1, double, r_gamma, g_gamma, b_gamma); - libclut_rgb_limits(&(ramps->d), (double)1, double, r_min, r_max, g_min, g_max, b_min, b_max); - - return 0; - } - } - } - - return -2; -} - - -/** - * Load an ICC profile - * - * @param file The ICC-profile file - * @param ramps Output parameter for the filter stored in the ICC profile, - * `.red_size`, `.green_size`, `.blue_size` should already be - * set (these values can however be modified.) - * @param depth Output parameter for ramps stop value type - * @return Zero on success, -1 on error, -2 if no usable data is - * available in the profile. - */ -static int load_icc(const char* file, libcoopgamma_ramps_t* ramps, libcoopgamma_depth_t* depth) -{ - char* content = NULL; - size_t ptr = 0, size = 0; - ssize_t got; - int fd = -1, r = -1, saved_errno; - - fd = open(file, O_RDONLY); - if (fd < 0) - { - if (errno == ENOENT) - { - fprintf(stderr, "%s: %s: %s\n", argv0, strerror(ENOENT), file); - errno = 0; - } - goto fail; - } - - for (;;) - { - if (ptr == size) - { - size_t new_size = size ? (size << 1) : 4098; - void* new = realloc(content, new_size); - if (new == NULL) - goto fail; - content = new; - size = new_size; - } - got = read(fd, content + ptr, size - ptr); - if (got < 0) - { - if (errno == EINTR) - continue; - goto fail; - } - if (got == 0) - break; - ptr += (size_t)got; - } - - close(fd), fd = -1; - - r = parse_icc(content, ptr, ramps, depth); - fail: - saved_errno = errno; - if (fd >= 0) - close(fd); - free(content); - errno = saved_errno; - return r; -} - - -/** - * Get the pathname of the ICC profile for a CRTC - * - * @param crtc The CRTC name - * @return The ICC profile file - */ -static const char* get_icc(const char* crtc) -{ - size_t i; - if (crtc_icc_keys != NULL) - for (i = 0; crtc_icc_keys[i] != NULL; i++) - if (!strcasecmp(crtc, crtc_icc_keys[i])) - return crtc_icc_values[i]; - return NULL; -} - - -/** - * Fill a filter - * - * @param filter The filter to fill - * @param ramps The prototype filter - * @param depth The prototype filter's stop datatype - */ -static void fill_filter(libcoopgamma_filter_t* filter, const libcoopgamma_ramps_t* ramps, - libcoopgamma_depth_t depth) -{ - switch (filter->depth) - { -#define X(CONST, MEMBER, MAX, TYPE)\ - case CONST:\ - switch (depth)\ - {\ - case LIBCOOPGAMMA_UINT8:\ - libclut_translate(&(filter->ramps.MEMBER), MAX, TYPE, &(ramps->u8), UINT8_MAX, uint8_t);\ - break;\ - case LIBCOOPGAMMA_UINT16:\ - libclut_translate(&(filter->ramps.MEMBER), MAX, TYPE, &(ramps->u16), UINT16_MAX, uint16_t);\ - break;\ - case LIBCOOPGAMMA_UINT32:\ - libclut_translate(&(filter->ramps.MEMBER), MAX, TYPE, &(ramps->u32), UINT32_MAX, uint32_t);\ - break;\ - case LIBCOOPGAMMA_UINT64:\ - libclut_translate(&(filter->ramps.MEMBER), MAX, TYPE, &(ramps->u64), UINT64_MAX, uint64_t);\ - break;\ - case LIBCOOPGAMMA_FLOAT:\ - libclut_translate(&(filter->ramps.MEMBER), MAX, TYPE, &(ramps->f), (float)1, float);\ - break;\ - case LIBCOOPGAMMA_DOUBLE:\ - libclut_translate(&(filter->ramps.MEMBER), MAX, TYPE, &(ramps->d), (double)1, double);\ - break;\ - }\ - break; -LIST_DEPTHS -#undef X - default: - abort(); - } -} - - -/** - * The main function for the program-specific code - * - * @return 0: Success - * -1: Error, `errno` set - * -2: Error, `cg.error` set - * -3: Error, message already printed - */ -int start(void) -{ - int r; - size_t i, j; - const char* path; - - if (xflag) - for (i = 0; i < crtcs_n; i++) - crtc_updates[i].filter.lifespan = LIBCOOPGAMMA_REMOVE; - else if (dflag) - for (i = 0; i < crtcs_n; i++) - crtc_updates[i].filter.lifespan = LIBCOOPGAMMA_UNTIL_DEATH; - else - for (i = 0; i < crtcs_n; i++) - crtc_updates[i].filter.lifespan = LIBCOOPGAMMA_UNTIL_REMOVAL; - - if (!xflag && (icc_pathname == NULL)) - if ((r = make_slaves()) < 0) - return cleanup(r); - - if (icc_pathname != NULL) - { - uniramps.u8.red_size = uniramps.u8.green_size = uniramps.u8.blue_size = 1; - for (i = 0; i < crtcs_n; i++) - { - if (uniramps.u8.red_size < crtc_updates[i].filter.ramps.u8.red_size) - uniramps. u8.red_size = crtc_updates[i].filter.ramps.u8.red_size; - if (uniramps.u8.green_size < crtc_updates[i].filter.ramps.u8.green_size) - uniramps. u8.green_size = crtc_updates[i].filter.ramps.u8.green_size; - if (uniramps.u8.blue_size < crtc_updates[i].filter.ramps.u8.blue_size) - uniramps. u8.blue_size = crtc_updates[i].filter.ramps.u8.blue_size; - } - switch (load_icc(icc_pathname, &uniramps, &unidepth)) - { - case 0: - break; - case -1: - return cleanup(-1); - case -2: - fprintf(stderr, "%s: unusable ICC profile: %s\n", argv0, icc_pathname); - return cleanup(-3); - } - } - else - { - rampses = calloc(crtcs_n, sizeof(*rampses)); - if (rampses == NULL) - return cleanup(-1); - depths = malloc(crtcs_n * sizeof(*depths)); - if (depths == NULL) - return cleanup(-1); - for (i = 0; i < crtcs_n; i++) - { - rampses[i].u8.red_size = crtc_updates[i].filter.ramps.u8.red_size; - rampses[i].u8.green_size = crtc_updates[i].filter.ramps.u8.green_size; - rampses[i].u8.blue_size = crtc_updates[i].filter.ramps.u8.blue_size; - path = get_icc(crtc_updates[i].filter.crtc); - if (path == NULL) - { - /* TODO remove CRTC */ - } - else - switch (load_icc(path, rampses + i, depths + i)) - { - case 0: - break; - case -1: - return cleanup(-1); - case -2: - fprintf(stderr, "%s: unusable ICC profile: %s\n", argv0, path); - return cleanup(-3); - } - } - } - - for (i = 0, r = 1; i < crtcs_n; i++) - { - if (!(crtc_updates[i].master) || !(crtc_info[i].supported)) - continue; - if (!xflag) - { - if (icc_pathname != NULL) - fill_filter(&(crtc_updates[i].filter), &uniramps, unidepth); - else - fill_filter(&(crtc_updates[i].filter), rampses + i, depths[i]); - } - r = update_filter(i, 0); - if ((r == -2) || ((r == -1) && (errno != EAGAIN))) - return cleanup(r); - if (crtc_updates[i].slaves != NULL) - for (j = 0; crtc_updates[i].slaves[j] != 0; j++) - { - r = update_filter(crtc_updates[i].slaves[j], 0); - if ((r == -2) || ((r == -1) && (errno != EAGAIN))) - return cleanup(r); - } - } - - while (r != 1) - if ((r = synchronise(-1)) < 0) - return cleanup(r); - - if (!dflag) - return cleanup(0); - - if (libcoopgamma_set_nonblocking(&cg, 0) < 0) - return cleanup(-1); - for (;;) - if (libcoopgamma_synchronise(&cg, NULL, 0, &j) < 0) - switch (errno) - { - case 0: - break; - case ENOTRECOVERABLE: - goto enotrecoverable; - default: - return cleanup(-1); - } - - enotrecoverable: - for (;;) - if (pause() < 0) - return cleanup(-1); -} - diff --git a/src/cg-limits.c b/src/cg-limits.c deleted file mode 100644 index 8390385..0000000 --- a/src/cg-limits.c +++ /dev/null @@ -1,731 +0,0 @@ -/** - * cg-tools -- Cooperative gamma-enabled tools - * Copyright (C) 2016, 2018 Mattias Andrée (maandree@kth.se) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#include "cg-base.h" - -#include <libclut.h> - -#include <sys/stat.h> -#include <errno.h> -#include <fcntl.h> -#include <pwd.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - - - -/** - * The default filter priority for the program - */ -const int64_t default_priority = -((int64_t)1 << 62); - -/** - * The default class for the program - */ -char default_class[] = PKGNAME "::cg-limits::standard"; - -/** - * Class suffixes - */ -const char* const* class_suffixes = (const char* const[]){NULL}; - - - -/** - * -d: keep process alive and remove filter on death - */ -static int dflag = 0; - -/** - * -x: remove filter rather than adding it - */ -static int xflag = 0; - -/** - * -B: brightness listing file - */ -static char* Bflag = NULL; - -/** - * -C: constrat listing file - */ -static char* Cflag = NULL; - -/** - * The brightness of the red channel - */ -static double rbrightness = 0; - -/** - * The brightness of the green channel - */ -static double gbrightness = 0; - -/** - * The brightness of the blue channel - */ -static double bbrightness = 0; - -/** - * The contrast of the red channel - */ -static double rcontrast = 1; - -/** - * The contrast of the green channel - */ -static double gcontrast = 1; - -/** - * The contrast of the blue channel - */ -static double bcontrast = 1; - -/** - * `NULL`-terminated list of output names - * listed in the brightness configuration file - */ -static char** brightness_names = NULL; - -/** - * The brightness of the red channel on monitor - * with same index in `brightness_names` - */ -static double* rbrightnesses = NULL; - -/** - * The brightness of the green channel on monitor - * with same index in `brightness_names` - */ -static double* gbrightnesses = NULL; - -/** - * The brightness of the blue channel on monitor - * with same index in `brightness_names` - */ -static double* bbrightnesses = NULL; - -/** - * `NULL`-terminated list of output names - * listed in the contrast configuration file - */ -static char** contrast_names = NULL; - -/** - * The contrast of the red channel on monitor - * with same index in `contrast_names` - */ -static double* rcontrasts = NULL; - -/** - * The contrast of the green channel on monitor - * with same index in `contrast_names` - */ -static double* gcontrasts = NULL; - -/** - * The contrast of the blue channel on monitor - * with same index in `contrast_names` - */ -static double* bcontrasts = NULL; - - - -/** - * Print usage information and exit - */ -void usage(void) -{ - fprintf(stderr, - "Usage: %s [-M method] [-S site] [-c crtc]... [-R rule] (-x | [-p priority] [-d] " - "([-B brightness-file] [-C contrast-file] | brightness-all:contrast-all | " - "brightness-red:contrast-red brightness-green:contrast-green brightness-blue:contrast-blue))\n", - argv0); - exit(1); -} - - -/** - * Perform cleanup so valgrind output is clean - * - * @param ret The value to return - * @return `ret` is returned as is - */ -static int cleanup(int ret) -{ - int saved_errno = errno; - if (brightness_names != NULL) - { - char** p = brightness_names; - while (*p) - free(*p++); - } - free(brightness_names); - free(rbrightnesses); - free(gbrightnesses); - free(bbrightnesses); - if (contrast_names != NULL) - { - char** p = contrast_names; - while (*p) - free(*p++); - } - free(contrast_names); - free(rcontrasts); - free(gcontrasts); - free(bcontrasts); - errno = saved_errno; - return ret; -} - - -/** - * Handle a command line option - * - * @param opt The option, it is a NUL-terminate two-character - * string starting with either '-' or '+', if the - * argument is not recognised, call `usage`. This - * string will not be "-M", "-S", "-c", "-p", or "-R". - * @param arg The argument associated with `opt`, - * `NULL` there is no next argument, if this - * parameter is `NULL` but needed, call `usage` - * @return 0 if `arg` was not used, - * 1 if `arg` was used, - * -1 on error - */ -int handle_opt(char* opt, char* arg) -{ - if (opt[0] == '-') - switch (opt[1]) - { - case 'd': - if (dflag || xflag) - usage(); - dflag = 1; - break; - case 'x': - if (xflag || dflag) - usage(); - xflag = 1; - break; - case 'B': - if (Bflag || !(Bflag = arg)) - usage(); - return 1; - case 'C': - if (Cflag || !(Cflag = arg)) - usage(); - return 1; - default: - usage(); - } - return 0; -} - - -/** - * Get the pathname of a configuration file - * - * @param confname The filename (excluding directory) of the configuration file - * @return The full pathname of the configuration file, `NULL` on error - */ -static char* get_conf_file(const char* restrict confname) -{ - struct passwd* pw; - char* path; - - pw = getpwuid(getuid()); - if ((pw == NULL) || (pw->pw_dir == NULL)) - return NULL; - - path = malloc(strlen(pw->pw_dir) + strlen(confname) + sizeof("/.config/")); - if (path == NULL) - return NULL; - - sprintf(path, "%s/.config/%s", pw->pw_dir, confname); - - if (access(path, F_OK) < 0) - sprintf(path, "/etc/%s", confname); - - return path; -} - - -/** - * Parse a double encoded as a string - * - * @param out Output parameter for the value - * @param str The string - * @return Zero on success, -1 if the string is invalid - */ -static int parse_double(double* restrict out, const char* restrict str) -{ - char* end; - errno = 0; - *out = strtod(str, &end); - if (errno || isinf(*out) || isnan(*out) || *end) - return -1; - if (!*str || !strchr("-0123456789.", *str)) - return -1; - return 0; -} - - -/** - * Parse two doubles encoded as a "%lf:%lf" string - * - * @param left Output parameter for the first value - * @param right Output parameter for the second value - * @param str The string - * @return Zero on success, -1 if the string is invalid - */ -static int parse_twidouble(double* restrict left, double* restrict right, const char* restrict str) -{ - char* p = strchr(str, ':'); - int r; - if (p == NULL) - return -1; - *p = '\0'; - r = -((parse_double(left, str) < 0) || (parse_double(right, p + 1) < 0)); - *p = ':'; - return r; -} - - -/** - * Parse configuration file - * - * @param pathname The pathname of the file - * @param names Reference to the list of names - * @param rs Reference to the list of red values - * @param gs Reference to the list of green values - * @param bs Reference to the list of blue values - * @return Zero on success, -1 on error - */ -static int parse_conf_file(const char* restrict pathname, char*** restrict names, - double** restrict rs, double** restrict gs, double** restrict bs) -{ - int fd, saved_errno; - char* line = NULL; - size_t size = 0, lineno = 0, ptr = 0, alloc = 0; - ssize_t n; - FILE* f = NULL; - char* p; - char* q; - char* r; - char* g; - char* b; - - fd = open(pathname, O_RDONLY); - if (fd == -1) - return -1; - - f = fdopen(fd, "rb"); - if (f == NULL) - goto fail; - - while (n = getline(&line, &size, f), n >= 0) - { - lineno += 1; - - if ((n > 0) && (line[n - 1] == '\n')) - line[n - 1] = '\0'; - p = line; - while ((*p == ' ') || (*p == '\t')) p++; - if ((!*p) || (*p == '#')) - continue; - - r = strpbrk(line, " \t"); - if (r == NULL) - goto bad; - while (r[1] == ' ' || r[1] == '\t') r++; - g = strpbrk(r + 1, " \t"); - if (g == NULL) - goto bad; - while (g[1] == ' ' || g[1] == '\t') g++; - b = strpbrk(g + 1, " \t"); - if (b == NULL) - goto bad; - while (b[1] == ' ' || b[1] == '\t') b++; - - for (;;) - { - q = strpbrk(b + 1, " \t"); - if (q == NULL) - break; - while (q[1] == ' ' || q[1] == '\t') q++; - if (!*q) - break; - r = g, g = b, b = q; - } - - *r++ = '\0'; - *g++ = '\0'; - *b++ = '\0'; - - q = strpbrk(r, " \t"); - if (q != NULL) - *q = '\0'; - q = strpbrk(g, " \t"); - if (q != NULL) - *q = '\0'; - q = strpbrk(b, " \t"); - if (q != NULL) - *q = '\0'; - - q = strchr(p, '\0'); - while ((q != p) && ((q[-1] == ' ') || (q[-1] == '\t'))) - q--; - *q = '\0'; - - if (ptr == alloc) - { - void* new; - size_t new_size = alloc ? (alloc << 1) : 4; - - new = realloc(*rs, new_size * sizeof(**rs)); - if (new == NULL) - goto fail; - *rs = new; - - new = realloc(*gs, new_size * sizeof(**gs)); - if (new == NULL) - goto fail; - *gs = new; - - new = realloc(*bs, new_size * sizeof(**bs)); - if (new == NULL) - goto fail; - *bs = new; - - new = realloc(*names, (new_size + 1) * sizeof(**names)); - if (new == NULL) - goto fail; - *names = new; - memset(*names + alloc, 0, (new_size + 1 - alloc) * sizeof(**names)); - - alloc = new_size; - } - - if ((parse_double((*rs) + ptr, r) < 0) || - (parse_double((*gs) + ptr, g) < 0) || - (parse_double((*bs) + ptr, b) < 0)) - goto bad; - (*names)[ptr] = malloc(strlen(p) + 1); - if ((*names)[ptr] == NULL) - goto fail; - strcpy((*names)[ptr], p); - ptr++; - - continue; - bad: - fprintf(stderr, "%s: ignoring malformatted line in %s: %zu\n", argv0, pathname, lineno); - } - - if (fclose(f) < 0) - { - f = NULL; - goto fail; - } - close(fd); - free(line); - return 0; - fail: - saved_errno = errno; - free(line); - if (f != NULL) - fclose(f); - if (fd >= 0) - close(fd); - errno = saved_errno; - return -1; -} - - -/** - * Parse brightness configuration file - * - * @param pathname The pathname of the file - * @return Zero on success, -1 on error - */ -static int parse_brightness_file(const char* restrict pathname) -{ - return parse_conf_file(pathname, &brightness_names, &rbrightnesses, &gbrightnesses, &bbrightnesses); -} - - -/** - * Parse contrast configuration file - * - * @param pathname The pathname of the file - * @return Zero on success, -1 on error - */ -static int parse_contrast_file(const char* restrict pathname) -{ - return parse_conf_file(pathname, &contrast_names, &rcontrasts, &gcontrasts, &bcontrasts); -} - - -/** - * This function is called after the last - * call to `handle_opt` - * - * @param argc The number of unparsed arguments - * @param argv `NULL` terminated list of unparsed arguments - * @param prio The argument associated with the "-p" option - * @return Zero on success, -1 on error - */ -int handle_args(int argc, char* argv[], char* prio) -{ - int free_Bflag = 0, free_Cflag = 0, saved_errno; - int q = xflag + dflag; - if ((q > 1) || (xflag && ((Bflag != NULL) || (Cflag != NULL) || (argc > 0) || (prio != NULL)))) - usage(); - if ((Bflag || Cflag) && argc) - usage(); - - if (argc == 1) - { - if (parse_twidouble(&rbrightness, &rcontrast, argv[0]) < 0) - usage(); - bbrightness = gbrightness = rbrightness; - bcontrast = gcontrast = rcontrast; - } - else if (argc == 3) - { - if (parse_twidouble(&rbrightness, &rcontrast, argv[0]) < 0) - usage(); - if (parse_twidouble(&gbrightness, &gcontrast, argv[1]) < 0) - usage(); - if (parse_twidouble(&bbrightness, &bcontrast, argv[2]) < 0) - usage(); - } - else if (argc) - usage(); - - if (!argc && !Bflag && !xflag) - { - Bflag = get_conf_file("brightness"); - if (Bflag == NULL) - return -1; - free_Bflag = 1; - } - if (Bflag) - if (parse_brightness_file(Bflag) < 0) - goto fail; - if (free_Bflag) - free(Bflag), Bflag = NULL; - - if (!argc && !Cflag && !xflag) - { - Cflag = get_conf_file("contrast"); - if (Cflag == NULL) - return -1; - free_Cflag = 1; - } - if (Cflag) - if (parse_contrast_file(Cflag) < 0) - goto fail; - if (free_Cflag) - free(Cflag), Cflag = NULL; - - return 0; - fail: - saved_errno = errno; - if (free_Bflag) - free(Bflag), Bflag = NULL; - if (free_Cflag) - free(Cflag), Cflag = NULL; - errno = saved_errno; - return cleanup(-1); -} - - -/** - * Fill a filter - * - * @param filter The filter to fill - * @param rb The red brightness - * @param rc The red contrast - * @param gb The green brightness - * @param gc The green contrast - * @param bb The blue brightness - * @param bc The blue contrast - * @return Zero on success, -1 on error - */ -static int fill_filter(libcoopgamma_filter_t* restrict filter, - double rb, double rc, double gb, double gc, double bb, double bc) -{ - union libcoopgamma_ramps dramps; - size_t size; - - if (filter->depth == LIBCOOPGAMMA_DOUBLE) - { - libclut_rgb_limits(&(filter->ramps.d), (double)1, double, rb, rc, gb, gc, bb, bc); - libclut_clip(&(filter->ramps.d), (double)1, double, 1, 1, 1); - return 0; - } - if (filter->depth == LIBCOOPGAMMA_FLOAT) - { - libclut_rgb_limits(&(filter->ramps.f), (float)1, float, rb, rc, gb, gc, bb, bc); - libclut_clip(&(filter->ramps.f), (float)1, float, 1, 1, 1); - return 0; - } - - size = dramps.d.red_size = filter->ramps.d.red_size; - size += dramps.d.green_size = filter->ramps.d.green_size; - size += dramps.d.blue_size = filter->ramps.d.blue_size; - dramps.d.red = calloc(size, sizeof(double)); - if (dramps.d.red == NULL) - return -1; - dramps.d.green = dramps.d.red + dramps.d.red_size; - dramps.d.blue = dramps.d.green + dramps.d.green_size; - - libclut_start_over(&(dramps.d), (double)1, double, 1, 1, 1); - libclut_rgb_limits(&(dramps.d), (double)1, double, rb, rc, gb, gc, bb, bc); - libclut_clip(&(dramps.d), (double)1, double, 1, 1, 1); - - switch (filter->depth) - { - case LIBCOOPGAMMA_UINT8: - libclut_translate(&(filter->ramps.u8), UINT8_MAX, uint8_t, &(dramps.d), (double)1, double); - break; - case LIBCOOPGAMMA_UINT16: - libclut_translate(&(filter->ramps.u16), UINT16_MAX, uint16_t, &(dramps.d), (double)1, double); - break; - case LIBCOOPGAMMA_UINT32: - libclut_translate(&(filter->ramps.u32), UINT32_MAX, uint32_t, &(dramps.d), (double)1, double); - break; - case LIBCOOPGAMMA_UINT64: - libclut_translate(&(filter->ramps.u64), UINT64_MAX, uint64_t, &(dramps.d), (double)1, double); - break; - default: - abort(); - } - - free(dramps.d.red); - return 0; -} - - -/** - * The main function for the program-specific code - * - * @return 0: Success - * -1: Error, `errno` set - * -2: Error, `cg.error` set - * -3: Error, message already printed - */ -int start(void) -{ - int r; - size_t i, j, k; - - if (xflag) - for (i = 0; i < filters_n; i++) - crtc_updates[i].filter.lifespan = LIBCOOPGAMMA_REMOVE; - else if (dflag) - for (i = 0; i < filters_n; i++) - crtc_updates[i].filter.lifespan = LIBCOOPGAMMA_UNTIL_DEATH; - else - for (i = 0; i < filters_n; i++) - crtc_updates[i].filter.lifespan = LIBCOOPGAMMA_UNTIL_REMOVAL; - - if (!xflag && ((brightness_names != NULL) || (contrast_names != NULL))) - if ((r = make_slaves()) < 0) - return cleanup(r); - - if ((brightness_names == NULL) && (contrast_names == NULL)) - for (i = 0, r = 1; i < filters_n; i++) - { - if (!(crtc_updates[i].master) || !(crtc_info[crtc_updates[i].crtc].supported)) - continue; - if (!xflag) - if ((r = fill_filter(&(crtc_updates[i].filter), rbrightness, rcontrast, - gbrightness, gcontrast, bbrightness, bcontrast)) < 0) - return cleanup(r); - r = update_filter(i, 0); - if ((r == -2) || ((r == -1) && (errno != EAGAIN))) - return cleanup(r); - if (crtc_updates[i].slaves != NULL) - for (j = 0; crtc_updates[i].slaves[j] != 0; j++) - { - r = update_filter(crtc_updates[i].slaves[j], 0); - if ((r == -2) || ((r == -1) && (errno != EAGAIN))) - return cleanup(r); - } - } - else - { - char* empty = NULL; - char** bnames = brightness_names ? brightness_names : ∅ - char** cnames = contrast_names ? contrast_names : ∅ - for (i = 0, r = 1; i < filters_n; i++) - { - if (!(crtc_info[crtc_updates[i].crtc].supported)) - continue; - for (j = 0; bnames[j] != NULL; j++) - if (!strcasecmp(crtc_updates[i].filter.crtc, bnames[j])) - break; - for (k = 0; cnames[k] != NULL; k++) - if (!strcasecmp(crtc_updates[i].filter.crtc, cnames[k])) - break; - if ((bnames[j] != NULL) || (cnames[k] != NULL)) - { - double rb = 0, gb = 0, bb = 0, rc = 1, bc = 1, gc = 1; - if (bnames[j] != NULL) - rb = rbrightnesses[j], gb = gbrightnesses[j], bb = bbrightnesses[j]; - if (cnames[j] != NULL) - rc = rcontrasts[j], gc = gcontrasts[j], bc = bcontrasts[j]; - if ((r = fill_filter(&(crtc_updates[i].filter), rb, rc, gb, gc, bb, bc)) < 0) - return cleanup(r); - r = update_filter(i, 0); - if ((r == -2) || ((r == -1) && (errno != EAGAIN))) - return cleanup(r); - } - } - } - - while (r != 1) - if ((r = synchronise(-1)) < 0) - return cleanup(r); - - if (!dflag) - return cleanup(0); - - if (libcoopgamma_set_nonblocking(&cg, 0) < 0) - return cleanup(-1); - for (;;) - if (libcoopgamma_synchronise(&cg, NULL, 0, &j) < 0) - switch (errno) - { - case 0: - break; - case ENOTRECOVERABLE: - goto enotrecoverable; - default: - return cleanup(-1); - } - - enotrecoverable: - for (;;) - if (pause() < 0) - return cleanup(-1); -} - diff --git a/src/cg-linear.c b/src/cg-linear.c deleted file mode 100644 index 1ce9a5d..0000000 --- a/src/cg-linear.c +++ /dev/null @@ -1,280 +0,0 @@ -/** - * cg-tools -- Cooperative gamma-enabled tools - * Copyright (C) 2016, 2018 Mattias Andrée (maandree@kth.se) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#include "cg-base.h" - -#include <libclut.h> - -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - - - -/** - * The default filter priority for the program - */ -const int64_t default_priority = NO_DEFAULT_PRIORITY; - -/** - * The default class base for the program - */ -char default_class[] = PKGNAME "::cg-linear::standard"; - -/** - * Class suffixes - */ -const char* const* class_suffixes = (const char* const[]){":start", ":stop", NULL}; - - - -/** - * -d: keep process alive and remove filter on death - */ -static int dflag = 0; - -/** - * -x: remove filter rather than adding it - */ -static int xflag = 0; - -/** - * +r: do not touch the red channel - */ -static int rplus = 0; - -/** - * +g: do not touch the green channel - */ -static int gplus = 0; - -/** - * +b: do not touch the blue channel - */ -static int bplus = 0; - -/** - * The priority of the linearisation filter - */ -static int64_t start_priority; - -/** - * The priority of the delinearisation filter - */ -static int64_t stop_priority; - - - -/** - * Print usage information and exit - */ -void usage(void) -{ - fprintf(stderr, - "Usage: %s [-M method] [-S site] [-c crtc]... [-R rule-base] " - "(-x | -p start-priority:stop-priority [-d] [+rgb])\n", - argv0); - exit(1); -} - - -/** - * Handle a command line option - * - * @param opt The option, it is a NUL-terminate two-character - * string starting with either '-' or '+', if the - * argument is not recognised, call `usage`. This - * string will not be "-M", "-S", "-c", "-p", or "-R". - * @param arg The argument associated with `opt`, - * `NULL` there is no next argument, if this - * parameter is `NULL` but needed, call `usage` - * @return 0 if `arg` was not used, - * 1 if `arg` was used, - * -1 on error - */ -int handle_opt(char* opt, char* arg) -{ - if (opt[0] == '-') - switch (opt[1]) - { - case 'd': - if (dflag || xflag) - usage(); - dflag = 1; - break; - case 'x': - if (xflag || dflag) - usage(); - xflag = 1; - break; - default: - usage(); - } - else - switch (opt[1]) - { - case 'r': - if (rplus) - usage(); - rplus = 1; - break; - case 'g': - if (gplus) - usage(); - gplus = 1; - break; - case 'b': - if (bplus) - usage(); - bplus = 1; - break; - default: - usage(); - } - return 0; - (void) arg; -} - - -/** - * This function is called after the last - * call to `handle_opt` - * - * @param argc The number of unparsed arguments - * @param argv `NULL` terminated list of unparsed arguments - * @param prio The argument associated with the "-p" option - * @return Zero on success, -1 on error - */ -int handle_args(int argc, char* argv[], char* prio) -{ - int q = xflag + (dflag | rplus | gplus | bplus); - char *p, *end; - if (argc || (q > 1) || (xflag && (prio != NULL))) - usage(); - if (!xflag && (prio == NULL)) - usage(); - if (prio != NULL) - { - p = strchr(prio, ':'); - if (!p) - usage(); - *p++ = '\0'; - errno = 0; - start_priority = (size_t)strtoul(prio, &end, 10); - if (errno || *end || !*prio) - usage(); - stop_priority = (size_t)strtoul(p, &end, 10); - if (errno || *end || !*prio) - usage(); - p[-1] = ':'; - } - return 0; - (void) argv; -} - - -/** - * Fill a filter - * - * @param filter The filter to fill - * @param is_start If the fitler is a linearisation filter - */ -static void fill_filter(libcoopgamma_filter_t* restrict filter, int is_start) -{ - switch (filter->depth) - { -#define X(CONST, MEMBER, MAX, TYPE)\ - case CONST:\ - if (is_start)\ - libclut_linearise(&(filter->ramps.MEMBER), MAX, TYPE, !rplus, !gplus, !bplus);\ - else\ - libclut_standardise(&(filter->ramps.MEMBER), MAX, TYPE, !rplus, !gplus, !bplus);\ - break; -LIST_DEPTHS -#undef X - default: - abort(); - } -} - - -/** - * The main function for the program-specific code - * - * @return 0: Success - * -1: Error, `errno` set - * -2: Error, `cg.error` set - * -3: Error, message already printed - */ -int start(void) -{ - int r; - size_t i, j; - - if (xflag) - for (i = 0; i < filters_n; i++) - crtc_updates[i].filter.lifespan = LIBCOOPGAMMA_REMOVE; - else if (dflag) - for (i = 0; i < filters_n; i++) - crtc_updates[i].filter.lifespan = LIBCOOPGAMMA_UNTIL_DEATH; - else - for (i = 0; i < filters_n; i++) - crtc_updates[i].filter.lifespan = LIBCOOPGAMMA_UNTIL_REMOVAL; - - for (i = 0, r = 1; i < filters_n; i++) - { - if (!(crtc_info[crtc_updates[i].crtc].supported)) - continue; - if (!xflag) { - int is_start = strchr(crtc_updates[i].filter.class, '\0')[-1] == 't'; - fill_filter(&(crtc_updates[i].filter), is_start); - crtc_updates[i].filter.priority = is_start ? start_priority : stop_priority; - } - r = update_filter(i, 0); - if ((r == -2) || ((r == -1) && (errno != EAGAIN))) - return r; - } - - while (r != 1) - if ((r = synchronise(-1)) < 0) - return r; - - if (!dflag) - return 0; - - if (libcoopgamma_set_nonblocking(&cg, 0) < 0) - return -1; - for (;;) - if (libcoopgamma_synchronise(&cg, NULL, 0, &j) < 0) - switch (errno) - { - case 0: - break; - case ENOTRECOVERABLE: - goto enotrecoverable; - default: - return -1; - } - - enotrecoverable: - for (;;) - if (pause() < 0) - return -1; -} - diff --git a/src/cg-negative.c b/src/cg-negative.c deleted file mode 100644 index 8a98959..0000000 --- a/src/cg-negative.c +++ /dev/null @@ -1,255 +0,0 @@ -/** - * cg-tools -- Cooperative gamma-enabled tools - * Copyright (C) 2016, 2018 Mattias Andrée (maandree@kth.se) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#include "cg-base.h" - -#include <libclut.h> - -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - - - -/** - * The default filter priority for the program - */ -const int64_t default_priority = (int64_t)1 << 62; - -/** - * The default class for the program - */ -char default_class[] = PKGNAME "::cg-negative::standard"; - -/** - * Class suffixes - */ -const char* const* class_suffixes = (const char* const[]){NULL}; - - - -/** - * -d: keep process alive and remove filter on death - */ -static int dflag = 0; - -/** - * -x: remove filter rather than adding it - */ -static int xflag = 0; - -/** - * +r: do not touch the red channel - */ -static int rplus = 0; - -/** - * +g: do not touch the green channel - */ -static int gplus = 0; - -/** - * +b: do not touch the blue channel - */ -static int bplus = 0; - - - -/** - * Print usage information and exit - */ -void usage(void) -{ - fprintf(stderr, - "Usage: %s [-M method] [-S site] [-c crtc]... [-R rule] (-x | [-p priority] [-d] [+rgb])\n", - argv0); - exit(1); -} - - -/** - * Handle a command line option - * - * @param opt The option, it is a NUL-terminate two-character - * string starting with either '-' or '+', if the - * argument is not recognised, call `usage`. This - * string will not be "-M", "-S", "-c", "-p", or "-R". - * @param arg The argument associated with `opt`, - * `NULL` there is no next argument, if this - * parameter is `NULL` but needed, call `usage` - * @return 0 if `arg` was not used, - * 1 if `arg` was used, - * -1 on error - */ -int handle_opt(char* opt, char* arg) -{ - if (opt[0] == '-') - switch (opt[1]) - { - case 'd': - if (dflag || xflag) - usage(); - dflag = 1; - break; - case 'x': - if (xflag || dflag) - usage(); - xflag = 1; - break; - default: - usage(); - } - else - switch (opt[1]) - { - case 'r': - if (rplus) - usage(); - rplus = 1; - break; - case 'g': - if (gplus) - usage(); - gplus = 1; - break; - case 'b': - if (bplus) - usage(); - bplus = 1; - break; - default: - usage(); - } - return 0; - (void) arg; -} - - -/** - * This function is called after the last - * call to `handle_opt` - * - * @param argc The number of unparsed arguments - * @param argv `NULL` terminated list of unparsed arguments - * @param prio The argument associated with the "-p" option - * @return Zero on success, -1 on error - */ -int handle_args(int argc, char* argv[], char* prio) -{ - int q = xflag + (dflag | rplus | gplus | bplus); - if (argc || (q > 1) || (xflag && (prio != NULL))) - usage(); - return 0; - (void) argv; -} - - -/** - * Fill a filter - * - * @param filter The filter to fill - */ -static void fill_filter(libcoopgamma_filter_t* restrict filter) -{ - switch (filter->depth) - { -#define X(CONST, MEMBER, MAX, TYPE)\ - case CONST:\ - libclut_negative(&(filter->ramps.MEMBER), MAX, TYPE, !rplus, !gplus, !bplus);\ - break; -LIST_DEPTHS -#undef X - default: - abort(); - } -} - - -/** - * The main function for the program-specific code - * - * @return 0: Success - * -1: Error, `errno` set - * -2: Error, `cg.error` set - * -3: Error, message already printed - */ -int start(void) -{ - int r; - size_t i, j; - - if (xflag) - for (i = 0; i < filters_n; i++) - crtc_updates[i].filter.lifespan = LIBCOOPGAMMA_REMOVE; - else if (dflag) - for (i = 0; i < filters_n; i++) - crtc_updates[i].filter.lifespan = LIBCOOPGAMMA_UNTIL_DEATH; - else - for (i = 0; i < filters_n; i++) - crtc_updates[i].filter.lifespan = LIBCOOPGAMMA_UNTIL_REMOVAL; - - if (!xflag) - if ((r = make_slaves()) < 0) - return r; - - for (i = 0, r = 1; i < filters_n; i++) - { - if (!(crtc_updates[i].master) || !(crtc_info[crtc_updates[i].crtc].supported)) - continue; - if (!xflag) - fill_filter(&(crtc_updates[i].filter)); - r = update_filter(i, 0); - if ((r == -2) || ((r == -1) && (errno != EAGAIN))) - return r; - if (crtc_updates[i].slaves != NULL) - for (j = 0; crtc_updates[i].slaves[j] != 0; j++) - { - r = update_filter(crtc_updates[i].slaves[j], 0); - if ((r == -2) || ((r == -1) && (errno != EAGAIN))) - return r; - } - } - - while (r != 1) - if ((r = synchronise(-1)) < 0) - return r; - - if (!dflag) - return 0; - - if (libcoopgamma_set_nonblocking(&cg, 0) < 0) - return -1; - for (;;) - if (libcoopgamma_synchronise(&cg, NULL, 0, &j) < 0) - switch (errno) - { - case 0: - break; - case ENOTRECOVERABLE: - goto enotrecoverable; - default: - return -1; - } - - enotrecoverable: - for (;;) - if (pause() < 0) - return -1; -} - diff --git a/src/cg-query.c b/src/cg-query.c deleted file mode 100644 index a24ef11..0000000 --- a/src/cg-query.c +++ /dev/null @@ -1,514 +0,0 @@ -/** - * cg-tools -- Cooperative gamma-enabled tools - * Copyright (C) 2016, 2018 Mattias Andrée (maandree@kth.se) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#include "arg.h" - -#include <libcoopgamma.h> - -#include <errno.h> -#include <inttypes.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - - - -/** - * The libcoopgamma context - */ -static libcoopgamma_context_t cg; - -/** - * Filter query - */ -static libcoopgamma_filter_query_t query; - -/** - * The class of the filter to print - */ -static char* class = NULL; - - - -/** - * Print usage information and exit - */ -static void usage(void) -{ - fprintf(stderr, - "Usage: %s [-M method] [-S site] [-h high] [-l low] [-f class] -c crtc\n", - argv0); - exit(1); -} - - -/** - * Initialise the process, specifically - * reset the signal mask and signal handlers - * - * @return Zero on success, -1 on error - */ -static int initialise_proc(void) -{ - sigset_t sigmask; - int sig; - - for (sig = 1; sig < _NSIG; sig++) - if (signal(sig, SIG_DFL) == SIG_ERR) - if (sig == SIGCHLD) - return -1; - - if (sigemptyset(&sigmask) < 0) - return -1; - if (sigprocmask(SIG_SETMASK, &sigmask, NULL) < 0) - return -1; - - return 0; -} - - -/** - * Print, to stdout, a list of all - * recognised adjustment methods - * - * @return Zero on success, -1 on error - */ -static int list_methods(void) -{ - char** list; - size_t i; - - list = libcoopgamma_get_methods(); - if (list == NULL) - return -1; - for (i = 0; list[i]; i++) - printf("%s\n", list[i]); - free(list); - if (fflush(stdout) < 0) - return -1; - - return 0; -} - - -/** - * Print, to stdout, a list of all CRTC:s - * - * A connection to the coopgamma server - * must have been made - * - * @return Zero on success, -1 on error, -2 - * on libcoopgamma error - */ -static int list_crtcs(void) -{ - char** list; - size_t i; - - list = libcoopgamma_get_crtcs_sync(&cg); - if (list == NULL) - return -2; - for (i = 0; list[i]; i++) - printf("%s\n", list[i]); - free(list); - if (fflush(stdout) < 0) - return -1; - - return 0; -} - - -/** - * Print, to stdout, information about - * the selected CRTC - * - * @return Zero on success, -1 on error, -2 - * on libcoopgamma error, -3 on error - * with error message already printed - */ -static int print_info(void) -{ - libcoopgamma_crtc_info_t info; - libcoopgamma_filter_table_t table; - const char* str; - int saved_errno, ret = 0; - size_t i; - - if (libcoopgamma_crtc_info_initialise(&info) < 0) - return -1; - if (libcoopgamma_filter_table_initialise(&table) < 0) - { - saved_errno = errno; - libcoopgamma_crtc_info_destroy(&info); - errno = saved_errno; - return -1; - } - - if (libcoopgamma_get_gamma_info_sync(query.crtc, &info, &cg) < 0) - goto cg_fail; - - printf("Cooperative gamma server running: %s\n", - info.cooperative ? "yes" : "no"); - - printf("Gamma adjustments supported: %s\n", - info.supported == LIBCOOPGAMMA_MAYBE ? "maybe" : info.supported ? "yes" : "no"); - - printf("Gamma ramps stops (red green blue): %zu %zu %zu\n", - info.red_size, info.green_size, info.blue_size); - - switch (info.depth) - { - case LIBCOOPGAMMA_DOUBLE: str = "double-precision floating-point"; break; - case LIBCOOPGAMMA_FLOAT: str = "single-precision floating-point"; break; - case LIBCOOPGAMMA_UINT8: str = "unsigned 8-bit integer"; break; - case LIBCOOPGAMMA_UINT16: str = "unsigned 16-bit integer"; break; - case LIBCOOPGAMMA_UINT32: str = "unsigned 32-bit integer"; break; - case LIBCOOPGAMMA_UINT64: str = "unsigned 64-bit integer"; break; - default: - errno = EPROTO; - goto fail; - } - printf("Gamma ramps stops value type: %s\n", str); - - if (info.colourspace != LIBCOOPGAMMA_UNKNOWN) - { - switch (info.colourspace) - { - case LIBCOOPGAMMA_SRGB: str = "sRGB"; break; - case LIBCOOPGAMMA_RGB: str = "non-standard RGB"; break; - case LIBCOOPGAMMA_NON_RGB: str = "non-RGB multicolour"; break; - case LIBCOOPGAMMA_GREY: str = "monochrome or singlecolour scale"; break; - default: - errno = EPROTO; - goto fail; - } - printf("Monitor's colourspace: %s\n", str); - } - - if (info.have_gamut) - { - printf("Monitor's red colour (x, y): %lf, %lf\n", - info.red_x / (double)1024, info.red_y / (double)1024); - - printf("Monitor's green colour (x, y): %lf, %lf\n", - info.green_x / (double)1024, info.green_y / (double)1024); - - printf("Monitor's blue colour (x, y): %lf, %lf\n", - info.blue_x / (double)1024, info.blue_y / (double)1024); - - printf("Monitor's white point (x, y): %lf, %lf\n", - info.white_x / (double)1024, info.white_y / (double)1024); - } - - if (libcoopgamma_get_gamma_sync(&query, &table, &cg) < 0) - goto cg_fail; - - if ((table.red_size != info.red_size) || (table.green_size != info.green_size) || - (table.blue_size != info.blue_size) || (table.depth != info.depth)) - { - fprintf(stderr, "%s: gamma ramp structure changed between queries\n", argv0); - goto custom_fail; - } - - printf("Filters: %zu\n", table.filter_count); - for (i = 0; i < table.filter_count; i++) - { - printf(" Filter %zu:\n", i); - printf(" Priority: %" PRIi64 "\n", table.filters[i].priority); - printf(" Class: %s\n", table.filters[i].class); - } - - done: - saved_errno = errno; - libcoopgamma_crtc_info_destroy(&info); - libcoopgamma_filter_table_destroy(&table); - errno = saved_errno; - return ret; - fail: - ret = -1; - goto done; - cg_fail: - ret = -2; - goto done; - custom_fail: - ret = -3; - goto done; -} - - - -/** - * Print, to stdout, the ramps of the select - * filter on the select CRTC - * - * @return Zero on success, -1 on error, -2 - * on libcoopgamma error, -3 on error - * with error message already printed - */ -static int print_filter(void) -{ - libcoopgamma_filter_table_t table; - libcoopgamma_ramps_t* restrict ramps; - int saved_errno, ret = 0; - size_t i, n; - - if (libcoopgamma_filter_table_initialise(&table) < 0) - return -1; - - if (libcoopgamma_get_gamma_sync(&query, &table, &cg) < 0) - goto cg_fail; - - if (query.coalesce) - i = 0; - else - for (i = 0; i < table.filter_count; i++) - if (!strcmp(table.filters[i].class, class)) - break; - if (i == table.filter_count) - { - fprintf(stderr, "%s: selected filter does not exist on selected CRTC\n", argv0); - goto custom_fail; - } - ramps = &(table.filters[i].ramps); - - n = table.red_size; - if (n < table.green_size) - n = table.green_size; - if (n < table.blue_size) - n = table.blue_size; - - switch (table.depth) - { -#define X(CONST, MEMBER, TYPE, FORMAT, DASH) \ - case CONST: \ - for (i = 0; i < n; i++) \ - { \ - if (i < ramps->MEMBER.red_size) \ - printf("%" FORMAT " ", (TYPE)(ramps->MEMBER.red[i])); \ - else \ - printf(DASH " "); \ - if (i < ramps->MEMBER.green_size) \ - printf("%" FORMAT " ", (TYPE)(ramps->MEMBER.green[i])); \ - else \ - printf(DASH " "); \ - if (i < ramps->MEMBER.blue_size) \ - printf("%" FORMAT "\n", (TYPE)(ramps->MEMBER.blue[i])); \ - else \ - printf(DASH "\n"); \ - } \ - break - X(LIBCOOPGAMMA_DOUBLE, d, double, "lf", "----"); - X(LIBCOOPGAMMA_FLOAT, f, double, "lf", "----"); - X(LIBCOOPGAMMA_UINT8, u8, uint8_t, "02" PRIx8, "--"); - X(LIBCOOPGAMMA_UINT16, u16, uint16_t, "04" PRIx16, "----"); - X(LIBCOOPGAMMA_UINT32, u32, uint32_t, "08" PRIx32, "--------"); - X(LIBCOOPGAMMA_UINT64, u64, uint64_t, "016" PRIx64, "----------------"); -#undef X - default: - errno = EPROTO; - goto fail; - } - - done: - saved_errno = errno; - libcoopgamma_filter_table_destroy(&table); - errno = saved_errno; - return ret; - fail: - ret = -1; - goto done; - cg_fail: - ret = -2; - goto done; - custom_fail: - ret = -3; - goto done; -} - - -/** - * -M METHOD - * Select adjustment method. If METHOD is "?", - * available methods will be printed to stdout. - * - * -S SITE - * Select site (display server instance). - * - * -c CRTC - * Select CRT controller. If CRTC is "?", CRTC:s - * will be printed to stdout. - * - * -h HIGH - * Suppress filter with higher priority than HIGH. - * - * -l LOW - * Suppress filter with lower priority than LOW. - * - * -f CLASS - * Print gamma ramps of the filter with class CLASS - * on the selected CRTC. If CLASS is "*" all filters - * with a priority in [LOW, HIGH] are coalesced. - * - * @param argc The number of command line arguments - * @param argv The command line arguments - * @return 0 on success, 1 on error - */ -int main(int argc, char* argv[]) -{ - int stage = 0, haveh = 0, havel = 0; - int rc = 0; - char* method = NULL; - char* site = NULL; - - query.high_priority = INT64_MAX; - query.low_priority = INT64_MIN; - query.crtc = NULL; - query.coalesce = 0; - - ARGBEGIN - { - case 'M': - if (method != NULL) - usage(); - method = EARGF(usage()); - break; - case 'S': - if (site != NULL) - usage(); - site = EARGF(usage()); - break; - case 'c': - if (query.crtc != NULL) - usage(); - query.crtc = EARGF(usage()); - break; - case 'h': - if (haveh++) - usage(); - query.high_priority = (int64_t)atoll(EARGF(usage())); - break; - case 'l': - if (havel++) - usage(); - query.low_priority = (int64_t)atoll(EARGF(usage())); - break; - case 'f': - if (class != NULL) - usage(); - class = EARGF(usage()); - if ((class[0] == '*') && (class[1] == '\0')) - query.coalesce = 1; - break; - default: - usage(); - } - ARGEND; - - if (argc) - usage(); - - if (initialise_proc() < 0) - goto fail; - - if ((method != NULL) && !strcmp(method, "?")) - { - if ((site != NULL) || (query.crtc != NULL)) - usage(); - if (list_methods() < 0) - goto fail; - return 0; - } - - if (libcoopgamma_context_initialise(&cg) < 0) - goto fail; - stage++; - if (libcoopgamma_connect(method, site, &cg) < 0) - { - fprintf(stderr, "%s: server failed to initialise\n", argv0); - goto custom_fail; - } - stage++; - - if (!(query.crtc)) - usage(); - - if (!strcmp(query.crtc, "?")) - switch (list_crtcs()) - { - case 0: - goto done; - case -1: - goto fail; - default: - goto cg_fail; - } - - switch (class ? print_filter() : print_info()) - { - case 0: - goto done; - case -1: - goto fail; - case -2: - goto cg_fail; - default: - goto custom_fail; - } - - fflush(stdout); - if (ferror(stdout)) - goto fail; - if (fclose(stdout) < 0) - goto fail; - - done: - if (stage >= 1) - libcoopgamma_context_destroy(&cg, stage >= 2); - return rc; - - custom_fail: - rc = 1; - goto done; - - fail: - rc = 1; - perror(argv0); - goto done; - - cg_fail: - rc = 1; - { - const char* side = cg.error.server_side ? "server" : "client"; - if (cg.error.custom) - { - if ((cg.error.number != 0) || (cg.error.description != NULL)) - fprintf(stderr, "%s: %s-side error number %" PRIu64 ": %s\n", - argv0, side, cg.error.number, cg.error.description); - else if (cg.error.number != 0) - fprintf(stderr, "%s: %s-side error number %" PRIu64 "\n", argv0, side, cg.error.number); - else if (cg.error.description != NULL) - fprintf(stderr, "%s: %s-side error: %s\n", argv0, side, cg.error.description); - } - else if (cg.error.description != NULL) - fprintf(stderr, "%s: %s-side error: %s\n", argv0, side, cg.error.description); - else - fprintf(stderr, "%s: %s-side error: %s\n", argv0, side, strerror(cg.error.number)); - } - goto done; -} - diff --git a/src/cg-rainbow.c b/src/cg-rainbow.c deleted file mode 100644 index 067785f..0000000 --- a/src/cg-rainbow.c +++ /dev/null @@ -1,279 +0,0 @@ -/** - * cg-tools -- Cooperative gamma-enabled tools - * Copyright (C) 2016, 2018 Mattias Andrée (maandree@kth.se) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#include "cg-base.h" - -#include <libclut.h> - -#include <errno.h> -#include <math.h> -#include <sched.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#include <unistd.h> - - - -/** - * The default filter priority for the program - */ -const int64_t default_priority = (int64_t)1 << 60; - -/** - * The default class for the program - */ -char default_class[] = PKGNAME "::cg-rainbow::standard"; - -/** - * Class suffixes - */ -const char* const* class_suffixes = (const char* const[]){NULL}; - - - -/** - * -s: rainbow-frequency in Hz - */ -static char* sflag = NULL; - -/** - * -l: base luminosity - */ -static char* lflag = NULL; - -/** - * The rainbow-frequency multiplied by 3 - */ -double rainbows_per_third_second = 1; - -/** - * The base luminosity - */ -double luminosity = (double)1 / 3; - - - -/** - * Print usage information and exit - */ -void usage(void) -{ - fprintf(stderr, - "Usage: %s [-M method] [-S site] [-c crtc]... [-R rule] [-p priority]" - " [-l luminosity] [-s rainbowhz]\n", - argv0); - exit(1); -} - - -/** - * Handle a command line option - * - * @param opt The option, it is a NUL-terminate two-character - * string starting with either '-' or '+', if the - * argument is not recognised, call `usage`. This - * string will not be "-M", "-S", "-c", "-p", or "-R". - * @param arg The argument associated with `opt`, - * `NULL` there is no next argument, if this - * parameter is `NULL` but needed, call `usage` - * @return 0 if `arg` was not used, - * 1 if `arg` was used, - * -1 on error - */ -int handle_opt(char* opt, char* arg) -{ - if (opt[0] == '-') - switch (opt[1]) - { - case 'l': - if (lflag || !(lflag = arg)) - usage(); - return 1; - case 's': - if (sflag || !(sflag = arg)) - usage(); - return 1; - default: - usage(); - } - else - usage(); - return 0; -} - - -/** - * Parse a non-negative double encoded as a string - * - * @param out Output parameter for the value - * @param str The string - * @return Zero on success, -1 if the string is invalid - */ -static int parse_double(double* restrict out, const char* restrict str) -{ - char* end; - errno = 0; - *out = strtod(str, &end); - if (errno || (*out < 0) || isinf(*out) || isnan(*out) || *end) - return -1; - if (!*str || !strchr("0123456789.", *str)) - return -1; - return 0; -} - - -/** - * This function is called after the last - * call to `handle_opt` - * - * @param argc The number of unparsed arguments - * @param argv `NULL` terminated list of unparsed arguments - * @param prio The argument associated with the "-p" option - * @return Zero on success, -1 on error - */ -int handle_args(int argc, char* argv[], char* prio) -{ - int q = (lflag || sflag); - if ((q > 1) || argc) - usage(); - if (sflag != NULL) - { - if (parse_double(&rainbows_per_third_second, sflag) < 0) - usage(); - rainbows_per_third_second *= 3; - } - if (lflag != NULL) - { - if (parse_double(&luminosity, lflag) < 0) - usage(); - } - return 0; - (void) argv; - (void) prio; -} - - -/** - * Fill a filter - * - * @param filter The filter to fill - * @param red The red brightness - * @param green The green brightness - * @param blue The blue brightness - */ -static void fill_filter(libcoopgamma_filter_t* restrict filter, double red, double green, double blue) -{ - switch (filter->depth) - { -#define X(CONST, MEMBER, MAX, TYPE)\ - case CONST:\ - libclut_start_over(&(filter->ramps.MEMBER), MAX, TYPE, 1, 1, 1);\ - libclut_rgb_brightness(&(filter->ramps.MEMBER), MAX, TYPE, red, green, blue);\ - break; -LIST_DEPTHS -#undef X - default: - abort(); - } -} - - -/** - * Get the current monotonic time as a double - * - * @param now Output parameter for the current time (monotonic) - * @return Zero on success, -1 on error - */ -static int double_time(double* restrict now) -{ -#ifndef CLOCK_MONOTONIC_RAW -# define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC -#endif - struct timespec ts; - if (clock_gettime(CLOCK_MONOTONIC_RAW, &ts) < 0) - return -1; - *now = (double)(ts.tv_nsec); - *now /= 1000000000L; - *now += (double)(ts.tv_sec); - return 0; -} - - -/** - * The main function for the program-specific code - * - * @return 0: Success - * -1: Error, `errno` set - * -2: Error, `cg.error` set - * -3: Error, message already printed - */ -int start(void) -{ - int r; - size_t i, j; - double pal[3]; - double t, starttime; - - for (i = 0; i < filters_n; i++) - crtc_updates[i].filter.lifespan = LIBCOOPGAMMA_UNTIL_DEATH; - - if ((r = make_slaves()) < 0) - return r; - - if ((r = double_time(&starttime)) < 0) - return r; - - for (;;) - { - if ((r = double_time(&t)) < 0) - return r; - t -= starttime; - t *= rainbows_per_third_second; - pal[0] = pal[1] = pal[2] = luminosity; - pal[((long)t) % 3] += 1 - fmod(t, 1); - pal[((long)t + 1) % 3] += fmod(t, 1); - if (pal[0] > 1) pal[0] = 1; - if (pal[1] > 1) pal[1] = 1; - if (pal[2] > 1) pal[2] = 1; - - for (i = 0, r = 1; i < filters_n; i++) - { - if (!(crtc_updates[i].master) || !(crtc_info[crtc_updates[i].crtc].supported)) - continue; - fill_filter(&(crtc_updates[i].filter), pal[0], pal[1], pal[2]); - r = update_filter(i, 0); - if ((r == -2) || ((r == -1) && (errno != EAGAIN))) - return r; - if (crtc_updates[i].slaves != NULL) - for (j = 0; crtc_updates[i].slaves[j] != 0; j++) - { - r = update_filter(crtc_updates[i].slaves[j], 0); - if ((r == -2) || ((r == -1) && (errno != EAGAIN))) - return r; - } - } - - while (r != 1) - if ((r = synchronise(-1)) < 0) - return r; - - sched_yield(); - } -} - diff --git a/src/cg-remove.c b/src/cg-remove.c deleted file mode 100644 index d942f87..0000000 --- a/src/cg-remove.c +++ /dev/null @@ -1,403 +0,0 @@ -/** - * cg-tools -- Cooperative gamma-enabled tools - * Copyright (C) 2016, 2018 Mattias Andrée (maandree@kth.se) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#include "arg.h" - -#include <libcoopgamma.h> - -#include <errno.h> -#include <inttypes.h> -#include <poll.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - - - -/** - * The libcoopgamma context - */ -static libcoopgamma_context_t cg; - - - -/** - * Print usage information and exit - */ -static void usage(void) -{ - fprintf(stderr, - "Usage: %s [-M method] [-S site] [-c crtc]... class...\n", - argv0); - exit(1); -} - - -/** - * Initialise the process, specifically - * reset the signal mask and signal handlers - * - * @return Zero on success, -1 on error - */ -static int initialise_proc(void) -{ - sigset_t sigmask; - int sig; - - for (sig = 1; sig < _NSIG; sig++) - if (signal(sig, SIG_DFL) == SIG_ERR) - if (sig == SIGCHLD) - return -1; - - if (sigemptyset(&sigmask) < 0) - return -1; - if (sigprocmask(SIG_SETMASK, &sigmask, NULL) < 0) - return -1; - - return 0; -} - - -/** - * Print, to stdout, a list of all - * recognised adjustment methods - * - * @return Zero on success, -1 on error - */ -static int list_methods(void) -{ - char** list; - size_t i; - - list = libcoopgamma_get_methods(); - if (list == NULL) - return -1; - for (i = 0; list[i]; i++) - printf("%s\n", list[i]); - free(list); - if (fflush(stdout) < 0) - return -1; - - return 0; -} - - -/** - * Print, to stdout, a list of all CRTC:s - * - * A connection to the coopgamma server - * must have been made - * - * @return Zero on success, -1 on error, -2 - * on libcoopgamma error - */ -static int list_crtcs(void) -{ - char** list; - size_t i; - - list = libcoopgamma_get_crtcs_sync(&cg); - if (list == NULL) - return -2; - for (i = 0; list[i]; i++) - printf("%s\n", list[i]); - free(list); - if (fflush(stdout) < 0) - return -1; - - return 0; -} - - -/** - * Remove selected filters from selected CRTC:s - * - * @param crtcs `NULL`-terminated list of CRTC names - * @param classes `NULL`-terminated list of filter classes - * @return Zero on success, -1 on error, -2 on - * libcoopgamma error - */ -static int remove_filters(char* const* restrict crtcs, char* const* restrict classes) -{ - size_t n = 0, unsynced = 0, selected, i, j; - char* synced = NULL; - libcoopgamma_async_context_t* asyncs = NULL; - int saved_errno, need_flush = 0, ret = 0; - struct pollfd pollfd; - libcoopgamma_filter_t command; - - for (i = 0; crtcs[i] != NULL; i++); - for (j = 0; classes[j] != NULL; j++); - synced = calloc(i, j * sizeof(*synced)); - if (synced == NULL) - goto fail; - asyncs = calloc(i, j * sizeof(*asyncs)); - if (asyncs == NULL) - goto fail; - - i = j = 0; - command.lifespan = LIBCOOPGAMMA_REMOVE; - pollfd.fd = cg.fd; - pollfd.events = POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI; - - while ((unsynced > 0) || (crtcs[i] != NULL)) - { - wait: - if (crtcs[i] != NULL) - pollfd.events |= POLLOUT; - else - pollfd.events &= ~POLLOUT; - - pollfd.revents = 0; - if (poll(&pollfd, (nfds_t)1, -1) < 0) - goto fail; - - if (pollfd.revents & (POLLOUT | POLLERR | POLLHUP | POLLNVAL)) - { - if (need_flush && (libcoopgamma_flush(&cg) < 0)) - goto send_fail; - need_flush = 0; - for (; crtcs[i] != NULL; i++, j = 0) - { - command.crtc = crtcs[i]; - while (classes[j] != NULL) - { - command.class = classes[j++]; - if (unsynced++, libcoopgamma_set_gamma_send(&command, &cg, asyncs + n++) < 0) - goto send_fail; - } - } - goto send_done; - send_fail: - switch (errno) - { - case EINTR: - case EAGAIN: -#if EAGAIN != EWOULDBLOCK - case EWOULDBLOCK: -#endif - need_flush = 1; - if (classes[j] == NULL) - i++, j = 0; - break; - default: - goto fail; - } - } - send_done: - - if ((unsynced == 0) && (crtcs[i] == NULL)) - break; - - if (pollfd.revents & (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI)) - while (unsynced > 0) - switch (libcoopgamma_synchronise(&cg, asyncs, n, &selected)) - { - case 0: - if (synced[selected]) - { - libcoopgamma_skip_message(&cg); - break; - } - synced[selected] = 1; - unsynced -= 1; - if (libcoopgamma_set_gamma_recv(&cg, asyncs + selected) < 0) - goto cg_fail; - break; - default: - switch (errno) - { - case 0: - break; - case EINTR: - case EAGAIN: -#if EAGAIN != EWOULDBLOCK - case EWOULDBLOCK: -#endif - goto wait; - default: - goto fail; - } - break; - } - } - - done: - saved_errno = errno; - free(synced); - free(asyncs); - errno = saved_errno; - return ret; - fail: - ret = -1; - goto done; - cg_fail: - ret = -2; - goto done; -} - - -/** - * -M METHOD - * Select adjustment method. If METHOD is "?", - * available methods will be printed to stdout. - * - * -S SITE - * Select site (display server instance). - * - * -c CRTC - * Select CRT controller. If CRTC is "?", CRTC:s - * will be printed to stdout. - * - * Can be used multiple times. If not used, all - * CRTC:s are selected. - * - * @param argc The number of command line arguments - * @param argv The command line arguments - * @return 0 on success, 1 on error - */ -int main(int argc, char* argv[]) -{ - int stage = 0; - int rc = 0; - char* method = NULL; - char* site = NULL; - char** crtcs_ = NULL; - char** crtcs = alloca(argc * sizeof(char*)); - size_t i, crtcs_n = 0; - - ARGBEGIN - { - case 'M': - if (method != NULL) - usage(); - method = EARGF(usage()); - break; - case 'S': - if (site != NULL) - usage(); - site = EARGF(usage()); - break; - case 'c': - crtcs[crtcs_n++] = EARGF(usage()); - break; - default: - usage(); - } - ARGEND; - - if (initialise_proc() < 0) - goto fail; - - if ((method != NULL) && !strcmp(method, "?")) - { - if ((site != NULL) || (crtcs_n > 0) || (argc > 0)) - usage(); - if (list_methods() < 0) - goto fail; - return 0; - } - - if (libcoopgamma_context_initialise(&cg) < 0) - goto fail; - stage++; - if (libcoopgamma_connect(method, site, &cg) < 0) - { - fprintf(stderr, "%s: server failed to initialise\n", argv0); - goto custom_fail; - } - stage++; - - for (i = 0; i < crtcs_n; i++) - if (!strcmp(crtcs[i], "?")) - { - if (argc > 0) - usage(); - switch (list_crtcs()) - { - case 0: - goto done; - case -1: - goto fail; - default: - goto cg_fail; - } - } - - if (argc == 0) - usage(); - - if (crtcs_n == 0) - { - crtcs = crtcs_ = libcoopgamma_get_crtcs_sync(&cg); - if (crtcs == NULL) - goto cg_fail; - } - else - crtcs[crtcs_n] = NULL; - - if (libcoopgamma_set_nonblocking(&cg, 1) < 0) - goto fail; - - switch (remove_filters(crtcs, argv)) - { - case 0: - break; - case -1: - goto fail; - default: - goto cg_fail; - } - - done: - if (stage >= 1) - libcoopgamma_context_destroy(&cg, stage >= 2); - free(crtcs_); - return rc; - - custom_fail: - rc = 1; - goto done; - - fail: - rc = 1; - perror(argv0); - goto done; - - cg_fail: - rc = 1; - { - const char* side = cg.error.server_side ? "server" : "client"; - if (cg.error.custom) - { - if ((cg.error.number != 0) || (cg.error.description != NULL)) - fprintf(stderr, "%s: %s-side error number %" PRIu64 ": %s\n", - argv0, side, cg.error.number, cg.error.description); - else if (cg.error.number != 0) - fprintf(stderr, "%s: %s-side error number %" PRIu64 "\n", argv0, side, cg.error.number); - else if (cg.error.description != NULL) - fprintf(stderr, "%s: %s-side error: %s\n", argv0, side, cg.error.description); - } - else if (cg.error.description != NULL) - fprintf(stderr, "%s: %s-side error: %s\n", argv0, side, cg.error.description); - else - fprintf(stderr, "%s: %s-side error: %s\n", argv0, side, strerror(cg.error.number)); - } - goto done; -} - diff --git a/src/cg-shallow.c b/src/cg-shallow.c deleted file mode 100644 index 230da88..0000000 --- a/src/cg-shallow.c +++ /dev/null @@ -1,279 +0,0 @@ -/** - * cg-tools -- Cooperative gamma-enabled tools - * Copyright (C) 2016, 2018 Mattias Andrée (maandree@kth.se) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#include "cg-base.h" - -#include <libclut.h> - -#include <ctype.h> -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - - - -/** - * The default filter priority for the program - */ -const int64_t default_priority = -((int64_t)3 << 61); - -/** - * The default class for the program - */ -char default_class[] = PKGNAME "::cg-shallow::standard"; - -/** - * Class suffixes - */ -const char* const* class_suffixes = (const char* const[]){NULL}; - - - -/** - * -d: keep process alive and remove filter on death - */ -static int dflag = 0; - -/** - * -x: remove filter rather than adding it - */ -static int xflag = 0; - -/** - * The emulated red resolution, 0 for unchanged. - */ -static size_t rres = 2; - -/** - * The emulated green resolution, 0 for unchanged. - */ -static size_t gres = 2; - -/** - * The emulated blue resolution, 0 for unchanged. - */ -static size_t bres = 2; - - -/** - * Print usage information and exit - */ -void usage(void) -{ - fprintf(stderr, - "Usage: %s [-M method] [-S site] [-c crtc]... [-R rule] " - "(-x | [-p priority] [-d] [all | red green blue])\n", - argv0); - exit(1); -} - - -/** - * Handle a command line option - * - * @param opt The option, it is a NUL-terminate two-character - * string starting with either '-' or '+', if the - * argument is not recognised, call `usage`. This - * string will not be "-M", "-S", "-c", "-p", or "-R". - * @param arg The argument associated with `opt`, - * `NULL` there is no next argument, if this - * parameter is `NULL` but needed, call `usage` - * @return 0 if `arg` was not used, - * 1 if `arg` was used, - * -1 on error - */ -int handle_opt(char* opt, char* arg) -{ - if (opt[0] == '-') - switch (opt[1]) - { - case 'd': - if (dflag || xflag) - usage(); - dflag = 1; - break; - case 'x': - if (xflag || dflag) - usage(); - xflag = 1; - break; - default: - usage(); - } - else - usage(); - return 0; - (void) arg; -} - - -/** - * Parse a non-negative integer encoded as a string - * - * @param out Output parameter for the value - * @param str The string - * @return Zero on success, -1 if the string is invalid - */ -static int parse_int(size_t* restrict out, const char* restrict str) -{ - char* end; - errno = 0; - if (!isdigit(*str)) - return -1; - *out = strtoul(str, &end, 10); - if (errno || *end) - return -1; - return 0; -} - - -/** - * This function is called after the last - * call to `handle_opt` - * - * @param argc The number of unparsed arguments - * @param argv `NULL` terminated list of unparsed arguments - * @param prio The argument associated with the "-p" option - * @return Zero on success, -1 on error - */ -int handle_args(int argc, char* argv[], char* prio) -{ - char* red = NULL; - char* green = NULL; - char* blue = NULL; - int q = xflag + (dflag | (argc > 0)); - if ((q > 1) || (xflag && (prio != NULL))) - usage(); - if (argc == 1) - red = green = blue = argv[0]; - else if (argc == 3) - { - red = argv[0]; - green = argv[1]; - blue = argv[2]; - } - else if (argc && !xflag) - usage(); - if (argc) - { - if (parse_int(&rres, red) < 0) - usage(); - if (parse_int(&gres, blue) < 0) - usage(); - if (parse_int(&bres, green) < 0) - usage(); - } - return 0; - (void) argv; -} - - -/** - * Fill a filter - * - * @param filter The filter to fill - */ -static void fill_filter(libcoopgamma_filter_t* restrict filter) -{ - switch (filter->depth) - { -#define X(CONST, MEMBER, MAX, TYPE)\ - case CONST:\ - libclut_lower_resolution(&(filter->ramps.MEMBER), MAX, TYPE, 0, rres, 0, gres, 0, bres);\ - break; -LIST_DEPTHS -#undef X - default: - abort(); - } -} - - -/** - * The main function for the program-specific code - * - * @return 0: Success - * -1: Error, `errno` set - * -2: Error, `cg.error` set - * -3: Error, message already printed - */ -int start(void) -{ - int r; - size_t i, j; - - if (xflag) - for (i = 0; i < filters_n; i++) - crtc_updates[i].filter.lifespan = LIBCOOPGAMMA_REMOVE; - else if (dflag) - for (i = 0; i < filters_n; i++) - crtc_updates[i].filter.lifespan = LIBCOOPGAMMA_UNTIL_DEATH; - else - for (i = 0; i < filters_n; i++) - crtc_updates[i].filter.lifespan = LIBCOOPGAMMA_UNTIL_REMOVAL; - - if (!xflag) - if ((r = make_slaves()) < 0) - return r; - - for (i = 0, r = 1; i < filters_n; i++) - { - if (!(crtc_updates[i].master) || !(crtc_info[crtc_updates[i].crtc].supported)) - continue; - if (!xflag) - fill_filter(&(crtc_updates[i].filter)); - r = update_filter(i, 0); - if ((r == -2) || ((r == -1) && (errno != EAGAIN))) - return r; - if (crtc_updates[i].slaves != NULL) - for (j = 0; crtc_updates[i].slaves[j] != 0; j++) - { - r = update_filter(crtc_updates[i].slaves[j], 0); - if ((r == -2) || ((r == -1) && (errno != EAGAIN))) - return r; - } - } - - while (r != 1) - if ((r = synchronise(-1)) < 0) - return r; - - if (!dflag) - return 0; - - if (libcoopgamma_set_nonblocking(&cg, 0) < 0) - return -1; - for (;;) - if (libcoopgamma_synchronise(&cg, NULL, 0, &j) < 0) - switch (errno) - { - case 0: - break; - case ENOTRECOVERABLE: - goto enotrecoverable; - default: - return -1; - } - - enotrecoverable: - for (;;) - if (pause() < 0) - return -1; -} - diff --git a/src/cg-sleepmode.c b/src/cg-sleepmode.c deleted file mode 100644 index 3248d58..0000000 --- a/src/cg-sleepmode.c +++ /dev/null @@ -1,460 +0,0 @@ -/** - * cg-tools -- Cooperative gamma-enabled tools - * Copyright (C) 2016, 2018 Mattias Andrée (maandree@kth.se) - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ -#include "cg-base.h" - -#include <libclut.h> - -#if defined(_GNU_SOURCE) -# undef _GNU_SOURCE -#endif -#include <errno.h> -#include <sched.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <time.h> -#include <unistd.h> - - - -/** - * The default filter priority for the program - */ -const int64_t default_priority = (int64_t)3 << 59; - -/** - * The default class for the program - */ -char default_class[] = PKGNAME "::cg-sleepmode::standard"; - -/** - * Class suffixes - */ -const char* const* class_suffixes = (const char* const[]){NULL}; - - - -/** - * -r: fade-out time for the red channel - */ -static char* rflag; - -/** - * -g: fade-out time for the green channel - */ -static char* gflag; - -/** - * -b: fade-out time for the blue channel - */ -static char* bflag; - -/** - * The duration, in seconds, of the red channel's fade out - */ -static double red_time = 3; - -/** - * The duration, in seconds, of the green channel's fade out - */ -static double green_time = 2; - -/** - * The duration, in seconds, of the blue channel's fade out - */ -static double blue_time = 1; - -/** - * The luminosity of red channel after the fade out - */ -static double red_target = 0.5; - -/** - * The luminosity of green channel after the fade out - */ -static double green_target = 0; - -/** - * The luminosity of blue channel after the fade out - */ -static double blue_target = 0; - -/** - * Time to fade in? - */ -static volatile sig_atomic_t received_int = 0; - - - -/** - * Print usage information and exit - */ -void usage(void) -{ - fprintf(stderr, - "Usage: %s [-M method] [-S site] [-c crtc]... [-R rule] [-p priority] " - "[-r red-fadeout-time] [-g green-fadeout-time] [-b blue-fadeout-time] " - "[red-luminosity [green-luminosity [blue-luminosity]]]\n", - argv0); - exit(1); -} - - -/** - * Called when a signal is received - * that tells the program to terminate - * - * @param signo The received signal - */ -static void sig_int(int signo) -{ - received_int = 1; - (void) signo; -} - - -/** - * Handle a command line option - * - * @param opt The option, it is a NUL-terminate two-character - * string starting with either '-' or '+', if the - * argument is not recognised, call `usage`. This - * string will not be "-M", "-S", "-c", "-p", or "-R". - * @param arg The argument associated with `opt`, - * `NULL` there is no next argument, if this - * parameter is `NULL` but needed, call `usage` - * @return 0 if `arg` was not used, - * 1 if `arg` was used, - * -1 on error - */ -int handle_opt(char* opt, char* arg) -{ - if (opt[0] == '-') - switch (opt[1]) - { - case 'r': - if (rflag || !(rflag = arg)) - usage(); - return 1; - case 'g': - if (gflag || !(gflag = arg)) - usage(); - return 1; - case 'b': - if (bflag || !(bflag = arg)) - usage(); - return 1; - default: - usage(); - } - else - usage(); - return 0; -} - - -/** - * Parse a non-negative double encoded as a string - * - * @param out Output parameter for the value - * @param str The string - * @return Zero on success, -1 if the string is invalid - */ -static int parse_double(double* restrict out, const char* restrict str) -{ - char* end; - errno = 0; - *out = strtod(str, &end); - if (errno || (*out < 0) || isinf(*out) || isnan(*out) || *end) - return -1; - if (!*str || !strchr("0123456789.", *str)) - return -1; - return 0; -} - - -/** - * This function is called after the last - * call to `handle_opt` - * - * @param argc The number of unparsed arguments - * @param argv `NULL` terminated list of unparsed arguments - * @param prio The argument associated with the "-p" option - * @return Zero on success, -1 on error - */ -int handle_args(int argc, char* argv[], char* prio) -{ - int q = (rflag || gflag || bflag || argc); - if ((q > 1) || (argc > 3)) - usage(); - if (rflag != NULL) - if (parse_double(&red_time, rflag) < 0) - usage(); - if (gflag != NULL) - if (parse_double(&green_time, gflag) < 0) - usage(); - if (bflag != NULL) - if (parse_double(&blue_time, bflag) < 0) - usage(); - if (argc >= 1) - if (parse_double(&red_target, argv[0]) < 0) - usage(); - if (argc >= 2) - if (parse_double(&green_target, argv[1]) < 0) - usage(); - if (argc >= 3) - if (parse_double(&blue_target, argv[2]) < 0) - usage(); - if (red_target >= 1) - red_time = 0; - if (green_target >= 1) - green_time = 0; - if (blue_target >= 1) - blue_time = 0; - return 0; - (void) prio; -} - - -/** - * Fill a filter - * - * @param filter The filter to fill - * @param red The red brightness - * @param green The green brightness - * @param blue The blue brightness - */ -static void fill_filter(libcoopgamma_filter_t* restrict filter, double red, double green, double blue) -{ - switch (filter->depth) - { -#define X(CONST, MEMBER, MAX, TYPE)\ - case CONST:\ - libclut_start_over(&(filter->ramps.MEMBER), MAX, TYPE, 1, 1, 1);\ - libclut_rgb_brightness(&(filter->ramps.MEMBER), MAX, TYPE, red, green, blue);\ - break; -LIST_DEPTHS -#undef X - default: - abort(); - } -} - - -/** - * Get the current monotonic time as a double - * - * @param now Output parameter for the current time (monotonic) - * @return Zero on success, -1 on error - */ -static int double_time(double* restrict now) -{ -#ifndef CLOCK_MONOTONIC_RAW -# define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC -#endif - struct timespec ts; - if (clock_gettime(CLOCK_MONOTONIC_RAW, &ts) < 0) - return -1; - *now = (double)(ts.tv_nsec); - *now /= 1000000000L; - *now += (double)(ts.tv_sec); - return 0; -} - - -/** - * The main function for the program-specific code - * - * @return 0: Success - * -1: Error, `errno` set - * -2: Error, `cg.error` set - * -3: Error, message already printed - */ -int start(void) -{ - int r, fade_red, fade_green, fade_blue; - size_t i, j; - double t, starttime, red, green, blue, redt, greent, bluet; - - redt = (red_target - 1) / red_time; - greent = (green_target - 1) / green_time; - bluet = (blue_target - 1) / blue_time; - fade_red = !isinf(redt) && !isnan(redt); - fade_green = !isinf(greent) && !isnan(greent); - fade_blue = !isinf(bluet) && !isnan(bluet); - - for (i = 0; i < filters_n; i++) - crtc_updates[i].filter.lifespan = LIBCOOPGAMMA_UNTIL_DEATH; - - if ((r = make_slaves()) < 0) - return r; - - if ((r = double_time(&starttime)) < 0) - return r; - - red = red_target < 0 ? 0 : red_target > 1 ? 1 : red_target; - green = green_target < 0 ? 0 : green_target > 1 ? 1 : green_target; - blue = blue_target < 0 ? 0 : blue_target > 1 ? 1 : blue_target; - - for (;;) - { - if ((r = double_time(&t)) < 0) - return r; - t -= starttime; - if (fade_red) - {if (red = 1 + t * redt, red > 1) red = 1; else if (red < 0) red = 0;} - if (fade_green) - {if (green = 1 + t * greent, green > 1) green = 1; else if (green < 0) green = 0;} - if (fade_blue) - {if (blue = 1 + t * bluet, blue > 1) blue = 1; else if (blue < 0) blue = 0;} - - for (i = 0, r = 1; i < filters_n; i++) - { - if (!(crtc_updates[i].master) || !(crtc_info[crtc_updates[i].crtc].supported)) - continue; - fill_filter(&(crtc_updates[i].filter), red, green, blue); - r = update_filter(i, 0); - if ((r == -2) || ((r == -1) && (errno != EAGAIN))) - return r; - if (crtc_updates[i].slaves != NULL) - for (j = 0; crtc_updates[i].slaves[j] != 0; j++) - { - r = update_filter(crtc_updates[i].slaves[j], 0); - if ((r == -2) || ((r == -1) && (errno != EAGAIN))) - return r; - } - } - - while (r != 1) - if ((r = synchronise(-1)) < 0) - return r; - - sched_yield(); - - if ((t >= red_time) && (t >= green_time) && (t >= blue_time)) - break; - } - - if ((signal(SIGINT, sig_int) == SIG_ERR) || - (signal(SIGTERM, sig_int) == SIG_ERR) || - (signal(SIGHUP, sig_int) == SIG_ERR)) - return -1; - - if (libcoopgamma_set_nonblocking(&cg, 0) < 0) - return -1; - for (;;) - if (libcoopgamma_synchronise(&cg, NULL, 0, &j) < 0) - { - if (received_int) - goto fade_in; - switch (errno) - { - case 0: - break; - case ENOTRECOVERABLE: - goto enotrecoverable; - default: - return 1; - } - } - - fade_in: - if (libcoopgamma_set_nonblocking(&cg, 1) < 0) - return -1; - - t = red_time; - t = t > green_time ? t : green_time; - t = t > blue_time ? t : blue_time; - redt = t - red_time; - greent = t - green_time; - bluet = t - blue_time; - t = red_time + green_time + blue_time; - if (red_time > 0) - t = t < red_time ? t : red_time; - if (green_time > 0) - t = t < green_time ? t : green_time; - if (blue_time > 0) - t = t < blue_time ? t : blue_time; - red_time = t + redt; - green_time = t + greent; - blue_time = t + bluet; - - red = green = blue = 1; - - if ((r = double_time(&starttime)) < 0) - return r; - - for (;;) - { - if ((r = double_time(&t)) < 0) - return r; - t -= starttime; - redt = t / red_time; - greent = t / green_time; - bluet = t / blue_time; - if (!isinf(redt) && !isnan(redt)) - { - red = red_target * (1 - redt) + redt; - if (red > 1) red = 1; else if (red < 0) red = 0; - } - if (!isinf(greent) && !isnan(greent)) - { - green = green_target * (1 - greent) + greent; - if (green > 1) green = 1; else if (green < 0) green = 0; - } - if (!isinf(bluet) && !isnan(bluet)) - { - blue = blue_target * (1 - bluet) + bluet; - if (blue > 1) blue = 1; else if (blue < 0) blue = 0; - } - - for (i = 0, r = 1; i < filters_n; i++) - { - if (!(crtc_updates[i].master) || !(crtc_info[crtc_updates[i].crtc].supported)) - continue; - fill_filter(&(crtc_updates[i].filter), red, green, blue); - r = update_filter(i, 0); - if ((r == -2) || ((r == -1) && (errno != EAGAIN))) - return r; - if (crtc_updates[i].slaves != NULL) - for (j = 0; crtc_updates[i].slaves[j] != 0; j++) - { - r = update_filter(crtc_updates[i].slaves[j], 0); - if ((r == -2) || ((r == -1) && (errno != EAGAIN))) - return r; - } - } - - while (r != 1) - if ((r = synchronise(-1)) < 0) - return r; - - sched_yield(); - - if ((t >= red_time) && (t >= green_time) && (t >= blue_time)) - break; - } - - return 0; - enotrecoverable: - for (;;) - if (pause() < 0) - return -1; -} - |