aboutsummaryrefslogblamecommitdiffstats
path: root/libgamma_list_methods.c
blob: 45faff467003db128d995b2bee6156c1258252c8 (plain) (tree)

















































                                                                                        
                                                                  











































































                                                                                                          
                      






                                                                  
/* 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, sizeof(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, ...)\
	if (list_method_test(CONST, operation) && n++ < buf_size)\
		methods[n - 1] = CONST;
	LIST_AVAILABLE_METHODS(X)
#undef X

	return n;
}