diff options
Diffstat (limited to 'libgamma_list_methods.c')
-rw-r--r-- | libgamma_list_methods.c | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/libgamma_list_methods.c b/libgamma_list_methods.c new file mode 100644 index 0000000..6b912e1 --- /dev/null +++ b/libgamma_list_methods.c @@ -0,0 +1,135 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" + + +/** + * Test whether a file descriptor refers to a VT + * + * @param fd The file descriptor + * @return Whether the file descriptor refers to a VT + */ +static int +is_vt_proper(int fd) +{ + char buf[32], digit0; + + /* Get TTY */ + if (ttyname_r(fd, buf, sizeof(buf) / sizeof(char))) + return 0; + + /* Validate TTY path */ + if (!strcmp(buf, "/dev/console")) + return 1; + if (strncmp(buf, "/dev/tty", sizeof("/dev/tty") - 1)) + return 0; + + /* Validate TTY name */ + digit0 = buf[sizeof("/dev/tty") - 1]; + return '1' <= digit0 && digit0 <= '9'; +} + + +/** + * Test the availability of an adjustment method + * + * @param method The adjustment method + * @param operation Allowed values: + * 0: Pass if the environment suggests it will work but is not fake + * 1: Pass if the environment suggests it will work + * 2: Pass if real and not fake + * 3: Pass if real + * 4: Always pass + * Other values invoke undefined behaviour + * @return Whether the test passed + */ +static int +list_method_test(int method, int operation) +{ + libgamma_method_capabilities_t caps; + int fd, r, saved_errno; + + libgamma_method_capabilities(&caps, method); + + switch (operation) { + case 0: + /* Methods that the environment suggests will work, excluding fake */ + if (caps.fake) + return 0; + /* fall through */ + + case 1: + /* Methods that the environment suggests will work, including fake */ + if (!caps.real) + return 0; +#ifdef HAVE_LIBGAMMA_METHOD_LINUX_DRM + if (method == LIBGAMMA_METHOD_LINUX_DRM) { + saved_errno = errno; + if (is_vt_proper(STDIN_FILENO)) { + r = 1; + } else if (is_vt_proper(STDOUT_FILENO)) { + r = 1; + } else if (is_vt_proper(STDERR_FILENO)) { + r = 1; + } else { + r = 0; + fd = open("/dev/tty", O_RDONLY); + if (fd >= 0) { + r = is_vt_proper(fd); + close(fd); + } + } + errno = saved_errno; + return r; + } +#endif +#ifdef HAVE_LIBGAMMA_METHOD_DUMMY + if (method == LIBGAMMA_METHOD_DUMMY) + return 0; +#endif + return caps.default_site_known; + + case 2: + /* All real non-fake methods */ + return caps.real && !caps.fake; + + case 3: + /* All real methods */ + return caps.real; + + default: + /* All methods */ + return 1; + } +} + + +/** + * List available adjustment methods by their order of preference based on the environment + * + * @param methods Output array of methods, should be able to hold `LIBGAMMA_METHOD_COUNT` elements + * @param buf_size The number of elements that fits in `methods`, it should be `LIBGAMMA_METHOD_COUNT`, + * This is used to avoid writing outside the output buffer if this library adds new + * adjustment methods without the users of the library recompiling + * @param operation Allowed values: + * 0: Methods that the environment suggests will work, excluding fake + * 1: Methods that the environment suggests will work, including fake + * 2: All real non-fake methods + * 3: All real methods + * 4: All methods + * Other values invoke undefined behaviour + * @return The number of element that have been stored in `methods`, or should + * have been stored if the buffer was large enough + */ +size_t +libgamma_list_methods(int *restrict methods, size_t buf_size, int operation) +{ + size_t n = 0; + +#define X(CONST, CNAME, DEPTH, RAMPS)\ + if (list_method_test(CONST, operation) && n++ < buf_size)\ + methods[n - 1] = CONST; + LIST_AVAILABLE_METHODS(X) +#undef X + + return n; +} |