aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/cg-base.c121
-rw-r--r--src/cg-base.h24
-rw-r--r--src/cg-negative.c255
3 files changed, 355 insertions, 45 deletions
diff --git a/src/cg-base.c b/src/cg-base.c
index 424c927..77dfe67 100644
--- a/src/cg-base.c
+++ b/src/cg-base.c
@@ -142,22 +142,26 @@ static int crtc_sort_data_cmp(const void* a_, const void* b_)
int make_slaves(void)
{
struct crtc_sort_data* data;
- size_t i, j, master = 0, master_i;
+ size_t i, j, n = 0, master = 0, master_i;
data = alloca(crtcs_n * sizeof(*data));
memset(data, 0, crtcs_n * sizeof(*data));
for (i = 0; i < crtcs_n; i++)
{
- data[i].depth = crtc_updates[i].filter.depth;
- data[i].red_size = crtc_updates[i].filter.ramps.u8.red_size;
- data[i].green_size = crtc_updates[i].filter.ramps.u8.green_size;
- data[i].blue_size = crtc_updates[i].filter.ramps.u8.blue_size;
- data[i].index = i;
+ if (!(crtc_info[i].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, crtcs_n, sizeof(*data), crtc_sort_data_cmp);
+ qsort(data, n, sizeof(*data), crtc_sort_data_cmp);
- for (i = 1; i < crtcs_n; i++)
+ for (i = 1; i < n; i++)
if (memcmp(data + i, data + master, sizeof(*data) - sizeof(data->index)))
{
if (master + 1 < i)
@@ -403,7 +407,7 @@ static int get_crtc_info(void)
{
size_t i, unsynced = 0, selected;
char* synced;
- int saved_errno, need_flush = 0, fail_rc = -1;
+ int saved_errno, need_flush = 0;
struct pollfd pollfd;
synced = alloca(crtcs_n * sizeof(*synced));
@@ -413,7 +417,7 @@ static int get_crtc_info(void)
pollfd.fd = cg.fd;
pollfd.events = POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI;
- for (;;)
+ while ((unsynced > 0) || (i < crtcs_n))
{
wait:
if (i < crtcs_n)
@@ -450,7 +454,7 @@ static int get_crtc_info(void)
}
send_done:
- if (unsynced == 0)
+ if ((unsynced == 0) && (i == crtcs_n))
break;
if (pollfd.revents & (POLLIN | POLLRDNORM | POLLRDBAND | POLLPRI))
@@ -459,7 +463,10 @@ static int get_crtc_info(void)
{
case 0:
if (synced[selected])
- break;
+ {
+ libcoopgamma_skip_message(&cg);
+ break;
+ }
synced[selected] = 1;
unsynced -= 1;
if (libcoopgamma_get_gamma_info_recv(crtc_info + selected, &cg, asyncs + selected) < 0)
@@ -484,10 +491,10 @@ static int get_crtc_info(void)
}
return 0;
- cg_fail:
- fail_rc = -2;
fail:
- return fail_rc;
+ return -1;
+ cg_fail:
+ return -2;
}
@@ -535,6 +542,7 @@ int main(int argc, char* argv[])
char* prio = NULL;
char* rule = NULL;
char* class = default_class;
+ int explicit_crtcs = 0;
argv0 = *argv++, argc--;
@@ -579,6 +587,7 @@ int main(int argc, char* argv[])
if (arg == NULL)
usage();
crtcs[crtcs_i++] = arg;
+ explicit_crtcs = 1;
}
else if (!strcmp(opt, "-p"))
{
@@ -637,6 +646,11 @@ int main(int argc, char* argv[])
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 ((method != NULL) && !strcmp(method, "?"))
@@ -698,6 +712,26 @@ int main(int argc, char* argv[])
if (libcoopgamma_async_context_initialise(asyncs + crtcs_i) < 0)
goto fail;
+ switch (get_crtc_info())
+ {
+ case 0:
+ break;
+ case -1:
+ goto fail;
+ case -2:
+ goto cg_fail;
+ }
+
+ for (crtcs_i = 0; crtcs_i < crtcs_n; crtcs_i++)
+ {
+ if (explicit_crtcs && !(crtc_info[crtcs_i].supported))
+ fprintf(stderr, "%s: warning: gamma adjustments not supported on CRTC: %s\n",
+ argv0, crtcs[crtcs_i]);
+ if (crtc_info[crtcs_i].cooperative == 0)
+ fprintf(stderr, "%s: warning: cooperative gamma server not running for CRTC: %s\n",
+ argv0, crtcs[crtcs_i]);
+ }
+
crtc_updates = alloca(crtcs_n * sizeof(*crtc_updates));
memset(crtc_updates, 0, crtcs_n * sizeof(*crtc_updates));
for (crtcs_i = 0; crtcs_i < crtcs_n; crtcs_i++)
@@ -719,40 +753,19 @@ int main(int argc, char* argv[])
crtc_updates[crtcs_i].filter.ramps.u8.blue_size = crtc_info[crtcs_i].blue_size;
switch (crtc_updates[crtcs_i].filter.depth)
{
- case LIBCOOPGAMMA_UINT8:
- libcoopgamma_ramps_initialise(&(crtc_updates[crtcs_i].filter.ramps.u8));
- break;
- case LIBCOOPGAMMA_UINT16:
- libcoopgamma_ramps_initialise(&(crtc_updates[crtcs_i].filter.ramps.u16));
- break;
- case LIBCOOPGAMMA_UINT32:
- libcoopgamma_ramps_initialise(&(crtc_updates[crtcs_i].filter.ramps.u32));
- break;
- case LIBCOOPGAMMA_UINT64:
- libcoopgamma_ramps_initialise(&(crtc_updates[crtcs_i].filter.ramps.u64));
- break;
- case LIBCOOPGAMMA_FLOAT:
- libcoopgamma_ramps_initialise(&(crtc_updates[crtcs_i].filter.ramps.f));
- break;
- case LIBCOOPGAMMA_DOUBLE:
- libcoopgamma_ramps_initialise(&(crtc_updates[crtcs_i].filter.ramps.d));
+#define X(CONST, MEMBER, MAX, TYPE)\
+ case CONST:\
+ libcoopgamma_ramps_initialise(&(crtc_updates[crtcs_i].filter.ramps.MEMBER));\
break;
+LIST_DEPTHS
+#undef X
default:
- fprintf(stderr, "%s: internal error: gamma ramp type is unrecognised\n", argv0);
+ fprintf(stderr, "%s: internal error: gamma ramp type is unrecognised: %i\n",
+ argv0, crtc_updates[crtcs_i].filter.depth);
goto custom_fail;
}
}
- switch (get_crtc_info())
- {
- case 0:
- break;
- case -1:
- goto fail;
- case -2:
- goto cg_fail;
- }
-
switch (start())
{
case 0:
@@ -765,6 +778,28 @@ int main(int argc, char* argv[])
goto custom_fail;
}
+ for (crtcs_i = 0; crtcs_i < crtcs_n; crtcs_i++)
+ if (crtc_updates[crtcs_i].failed)
+ {
+ const char* side = cg.error.server_side ? "server" : "client";
+ const char* crtc = crtc_updates[crtcs_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);
diff --git a/src/cg-base.h b/src/cg-base.h
index b12d551..848a202 100644
--- a/src/cg-base.h
+++ b/src/cg-base.h
@@ -20,6 +20,26 @@
/**
+ * 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.
*/
@@ -52,7 +72,7 @@ typedef struct filter_update
/**
* If zero, the ramps in `.filter` shall
- * neither be modified nor freed.
+ * neither be modified nor freed
*/
int master;
@@ -62,7 +82,7 @@ typedef struct filter_update
* ramps with this instance
*
* This will only be set if `.master`
- * is true.
+ * is true
*/
size_t* slaves;
diff --git a/src/cg-negative.c b/src/cg-negative.c
new file mode 100644
index 0000000..566b81a
--- /dev/null
+++ b/src/cg-negative.c
@@ -0,0 +1,255 @@
+/**
+ * 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 "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* const default_class = PKGNAME "::cg-negative::standard";
+
+
+
+/**
+ * -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;
+
+/**
+ * +r: do not touch the green channel
+ */
+static int gplus = 0;
+
+/**
+ * +r: 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] (-d | [-p priority] [-x] [+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;
+}
+
+
+/**
+ * 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 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
+ */
+int handle_args(int argc, char* argv[], char* method, char* site,
+ char** crtcs, char* prio, char* rule)
+{
+ int q = dflag + (xflag | rplus | gplus | bplus);
+ q += (method != NULL) && !strcmp(method, "?");
+ q += (prio != NULL) && !strcmp(prio, "?");
+ q += (rule != NULL) && (!strcmp(method, "?") || !strcmp(method, "??"));
+ for (; *crtcs; crtcs++)
+ q += !strcmp(*crtcs, "?");
+ if (argc || q || (dflag && (prio != NULL)))
+ usage();
+}
+
+
+/**
+ * Fill a filter
+ *
+ * @param 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 < 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)
+ if ((r = make_slaves()) < 0)
+ return r;
+
+ for (i = 0, r = 1; i < crtcs_n; i++)
+ {
+ if (!(crtc_updates[i].master) || !(crtc_info[i].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 = update_filter(i, -1)) < 0)
+ return r;
+
+ if (!dflag)
+ return 0;
+
+ 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;
+}
+