From f52513b09580c1533e6c48a4162d3d5f61f3b081 Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Fri, 5 Mar 2021 18:23:13 +0100 Subject: misc MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- libgamma_x_randr_partition_initialise.c | 161 ++++++++++++++++++++++++++++++++ 1 file changed, 161 insertions(+) create mode 100644 libgamma_x_randr_partition_initialise.c (limited to 'libgamma_x_randr_partition_initialise.c') diff --git a/libgamma_x_randr_partition_initialise.c b/libgamma_x_randr_partition_initialise.c new file mode 100644 index 0000000..aa5df50 --- /dev/null +++ b/libgamma_x_randr_partition_initialise.c @@ -0,0 +1,161 @@ +/* See LICENSE file for copyright and license details. */ +#define IN_LIBGAMMA_X_RANDR +#include "common.h" + + +/** + * Duplicate a memory area + * + * @param ptr The memory area + * @param bytes The size, in bytes, of the memory area + * @return A duplication of the memory, `NULL` if zero-length or on error + */ +static inline void * +xmemdup(void *restrict ptr, size_t bytes) +{ + char *restrict rc; + if (!bytes) + return NULL; + rc = malloc(bytes); + if (!rc) + return NULL; + memcpy(rc, ptr, bytes); + return rc; +} + + +/** + * Initialise an allocated partition state + * + * @param this The partition state to initialise + * @param site The site state for the site that the partition belongs to. + * @param partition The the index of the partition within the site + * @return Zero on success, otherwise (negative) the value of an + * error identifier provided by this library + */ +int +libgamma_x_randr_partition_initialise(libgamma_partition_state_t *restrict this, + libgamma_site_state_t *restrict site, size_t partition) +{ + int fail_rc = LIBGAMMA_ERRNO_SET; + xcb_connection_t *restrict connection = site->data; + xcb_screen_t *restrict screen = NULL; + xcb_generic_error_t *error = NULL; + const xcb_setup_t *restrict setup; + xcb_screen_iterator_t iter; + xcb_randr_get_screen_resources_current_cookie_t cookie; + xcb_randr_get_screen_resources_current_reply_t *restrict reply; + xcb_randr_crtc_t *restrict crtcs; + xcb_randr_output_t *restrict outputs; + libgamma_x_randr_partition_data_t *restrict data; + xcb_randr_get_output_info_cookie_t out_cookie; + xcb_randr_get_output_info_reply_t *out_reply; + size_t i; + uint16_t j; + + /* Get screen list */ + setup = xcb_get_setup(connection); + if (!setup) + return LIBGAMMA_LIST_PARTITIONS_FAILED; + iter = xcb_setup_roots_iterator(setup); + + /* Get the screen */ + for (i = 0; iter.rem > 0; i++, xcb_screen_next(&iter)) + if (i == partition) { + screen = iter.data; + break; + } + /* Report failure if we did not find the screen */ + if (!iter.rem) + return LIBGAMMA_NO_SUCH_PARTITION; + + /* Check that the screen is not `NULL`. + * (Do not think this can happen, but why not.) */ + if (!screen) + return LIBGAMMA_NULL_PARTITION; + + /* Get the current resources of the screen */ + cookie = xcb_randr_get_screen_resources_current(connection, screen->root); + reply = xcb_randr_get_screen_resources_current_reply(connection, cookie, &error); + if (error) + return libgamma_x_randr_internal_translate_error(error->error_code, LIBGAMMA_LIST_CRTCS_FAILED, 0); + + /* Get the number of available CRTC:s */ + this->crtcs_available = reply->num_crtcs; + /* Get the CRTC and output lists */ + crtcs = xcb_randr_get_screen_resources_current_crtcs(reply); + outputs = xcb_randr_get_screen_resources_current_outputs(reply); + if (!crtcs || !outputs) { + free(reply); + return LIBGAMMA_REPLY_VALUE_EXTRACTION_FAILED; + } + + /* Allocate adjustment method dependent data memory area. + We use `calloc` because we want `data`'s pointers to be `NULL` if not allocated at `fail`. */ + data = calloc(1, sizeof(libgamma_x_randr_partition_data_t)); + if (!data) + goto fail; + + /* Copy the CRTC:s, just so we do not have to keep the reply in memory */ + data->crtcs = xmemdup(crtcs, (size_t)(reply->num_crtcs) * sizeof(xcb_randr_crtc_t)); + if (!data->crtcs && reply->num_crtcs > 0) + goto fail; + + /* Copy the outputs as well */ + data->outputs = xmemdup(outputs, (size_t)reply->num_outputs * sizeof(xcb_randr_output_t)); + if (!data->outputs && reply->num_outputs > 0) + goto fail; + + /* Get the number of available outputs */ + data->outputs_count = (size_t)reply->num_outputs; + + /* Create mapping table from CRTC indices to output indicies. (injection) */ + data->crtc_to_output = malloc((size_t)reply->num_crtcs * sizeof(size_t)); + if (!data->crtc_to_output) + goto fail; + /* All CRTC:s should be mapped, but incase they are not, all unmapped CRTC:s should have + an invalid target, namely `SIZE_MAX`, which is 1 more than the theoretical limit */ + for (i = 0; i < (size_t)reply->num_crtcs; i++) + data->crtc_to_output[i] = SIZE_MAX; + /* Fill the table */ + for (i = 0; i < (size_t)reply->num_outputs; i++) { + /* Query output (target) information */ + out_cookie = xcb_randr_get_output_info(connection, outputs[i], reply->config_timestamp); + out_reply = xcb_randr_get_output_info_reply(connection, out_cookie, &error); + if (error) { + fail_rc = libgamma_x_randr_internal_translate_error(error->error_code, + LIBGAMMA_OUTPUT_INFORMATION_QUERY_FAILED, 0); + goto fail; + } + + /* Find CRTC (source) */ + for (j = 0; j < reply->num_crtcs; j++) { + if (crtcs[j] == out_reply->crtc) { + data->crtc_to_output[j] = i; + break; + } + } + + /* Release output information */ + free(out_reply); + } + + /* Store the configuration timestamp */ + data->config_timestamp = reply->config_timestamp; + /* Store the adjustment method dependent data */ + this->data = data; + /* Release resources and return successfully */ + free(reply); + return 0; + +fail: + /* Release resources and return with an error */ + if (data) { + free(data->crtcs); + free(data->outputs); + free(data->crtc_to_output); + free(data); + } + free(reply); + return fail_rc; +} -- cgit v1.2.3-70-g09d2