aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/cg-base.c179
-rw-r--r--src/cg-base.h52
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