diff options
-rw-r--r-- | src/cg-base.c | 179 | ||||
-rw-r--r-- | src/cg-base.h | 52 |
2 files changed, 216 insertions, 15 deletions
diff --git a/src/cg-base.c b/src/cg-base.c index 6f6f7df..424c927 100644 --- a/src/cg-base.c +++ b/src/cg-base.c @@ -69,14 +69,14 @@ size_t crtcs_n = 0; static libcoopgamma_async_context_t* asyncs = NULL; /** - * The number of pending sends + * The number of pending receives */ -static size_t pending_sends = 0; +static size_t pending_recvs = 0; /** - * The number of pending receives + * Whether message must be flushed */ -static size_t pending_recvs = 0; +static int flush_pending = 0; @@ -192,6 +192,132 @@ 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) +{ + 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; + + 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))) + 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, crtcs_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 * @@ -366,11 +492,11 @@ static int get_crtc_info(void) /** - * -m METHOD + * -M METHOD * Select adjustment method. If METHOD is "?", * available methods will be printed to stdout. * - * -s SITE + * -S SITE * Select site (display server instance). * * -c CRTC @@ -386,6 +512,13 @@ static int get_crtc_info(void) * 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 @@ -400,6 +533,8 @@ int main(int argc, char* argv[]) size_t crtcs_i = 0; int64_t priority = default_priority; char* prio = NULL; + char* rule = NULL; + char* class = default_class; argv0 = *argv++, argc--; @@ -429,12 +564,12 @@ int main(int argc, char* argv[]) arg = args + 1; if ((at_end = !*arg)) arg = argv[1]; - if (!strcmp(opt, "-m")) + if (!strcmp(opt, "-M")) { if ((method != NULL) || ((method = arg) == NULL)) usage(); } - else if (!strcmp(opt, "-s")) + else if (!strcmp(opt, "-S")) { if ((site != NULL) || ((site = arg) == NULL)) usage(); @@ -450,6 +585,11 @@ int main(int argc, char* argv[]) 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)) { @@ -469,7 +609,7 @@ int main(int argc, char* argv[]) crtcs_n = crtcs_i; crtcs[crtcs_i] = NULL; - if (handle_args(argc, argv, method, site, crtcs) < 0) + if (handle_args(argc, argv, method, site, crtcs, prio, rule) < 0) goto fail; if ((prio != NULL) && !strcmp(prio, "?")) @@ -480,6 +620,25 @@ int main(int argc, char* argv[]) else if (prio != NULL) priority = (int64_t)atoll(prio); + if ((rule != NULL) && !strcmp(rule, "??")) + { + printf("%s\n", class); + return 0; + } + else if ((rule != NULL) && !strcmp(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 ((method != NULL) && !strcmp(method, "?")) { if (list_methods() < 0) @@ -552,6 +711,7 @@ int main(int argc, char* argv[]) crtc_updates[crtcs_i].master = 1; crtc_updates[crtcs_i].slaves = NULL; crtc_updates[crtcs_i].filter.crtc = crtcs[crtcs_i]; + crtc_updates[crtcs_i].filter.class = class; crtc_updates[crtcs_i].filter.priority = priority; crtc_updates[crtcs_i].filter.depth = crtc_info[crtcs_i].depth; crtc_updates[crtcs_i].filter.ramps.u8.red_size = crtc_info[crtcs_i].red_size; @@ -622,6 +782,7 @@ int main(int argc, char* argv[]) if (crtc_updates[crtcs_i].master == 0) memset(&(crtc_updates[crtcs_i].filter.ramps.u8), 0, sizeof(crtc_updates[crtcs_i].filter.ramps.u8)); crtc_updates[crtcs_i].filter.crtc = NULL; + crtc_updates[crtcs_i].filter.class = NULL; libcoopgamma_filter_destroy(&(crtc_updates[crtcs_i].filter)); libcoopgamma_error_destroy(&(crtc_updates[crtcs_i].error)); free(crtc_updates[crtcs_i].slaves); diff --git a/src/cg-base.h b/src/cg-base.h index 13667b7..b12d551 100644 --- a/src/cg-base.h +++ b/src/cg-base.h @@ -28,8 +28,10 @@ typedef struct filter_update /** * The filter to update * - * `.filter.crtc` and `.filter.priority` - * are preconfigured + * `.filter.crtc`, `.filter.class`, and + * `.filter.priority`, `.filter.depth` + * are preconfigured, and `.filter.ramps` + * is preinitialised. */ libcoopgamma_filter_t filter; @@ -106,6 +108,11 @@ extern size_t crtcs_n; */ extern const int64_t default_priority; +/** + * The default class for the program + */ +extern char* const default_class; + /** @@ -115,6 +122,36 @@ extern const int64_t default_priority; */ 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); /** @@ -131,7 +168,7 @@ extern void usage(void); * @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", or "-c". + * 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` @@ -150,15 +187,18 @@ extern int handle_opt(char* opt, char* arg); * * @param argc The number of unparsed arguments * @param argv `NULL` terminated list of unparsed arguments - * @param method The argument associated with the "-m" option - * @param site The argument associated with the "-s" option + * @param method The argument associated with the "-M" option + * @param site The argument associated with the "-S" option * @param crtcs The arguments associated with the "-c" options, `NULL`-terminated + * @param prio The argument associated with the "-p" option + * @param rule The argument associated with the "-R" option * @return Zero on success, -1 on error */ #if defined(__GNUC__) __attribute__((__nonnull__(2))) #endif -extern int handle_args(int argc, char* argv[], char* method, char* site, char** crtcs); +extern int handle_args(int argc, char* argv[], char* method, char* site, char** crtcs, + char* prio, char* rule); /** * The main function for the program-specific code |