aboutsummaryrefslogtreecommitdiffstats
path: root/libgamma_x_randr_partition_initialise.c
diff options
context:
space:
mode:
Diffstat (limited to 'libgamma_x_randr_partition_initialise.c')
-rw-r--r--libgamma_x_randr_partition_initialise.c161
1 files changed, 161 insertions, 0 deletions
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;
+}