main shrub/neuswc / libswc / output.c
  1#include "output.h"
  2#include "drm.h"
  3#include "internal.h"
  4#include "mode.h"
  5#include "screen.h"
  6#include "util.h"
  7
  8#include <drm.h>
  9#include <stdio.h>
 10#include <stdlib.h>
 11#include <string.h>
 12#include <xf86drm.h>
 13
 14static const struct wl_output_interface output_impl = {
 15    .release = destroy_resource,
 16};
 17
 18static void
 19bind_output(struct wl_client *client, void *data, uint32_t version, uint32_t id)
 20{
 21	struct output *output = data;
 22	struct screen *screen = output->screen;
 23	struct mode *mode = &screen->planes.primary.mode;
 24	struct wl_resource *resource;
 25	uint32_t flags;
 26
 27	resource = wl_resource_create(client, &wl_output_interface, version, id);
 28
 29	if (!resource) {
 30		wl_client_post_no_memory(client);
 31		return;
 32	}
 33
 34	output->resource = resource;
 35	wl_resource_set_implementation(resource, &output_impl, output,
 36	                               &remove_resource);
 37	wl_list_insert(&output->resources, wl_resource_get_link(resource));
 38
 39	wl_output_send_geometry(resource, screen->base.geometry.x,
 40	                        screen->base.geometry.y, output->physical_width,
 41	                        output->physical_height, 0, "unknown", "unknown",
 42	                        WL_OUTPUT_TRANSFORM_NORMAL);
 43
 44	wl_array_for_each(mode, &output->modes)
 45	{
 46		flags = 0;
 47		if (mode->preferred) {
 48			flags |= WL_OUTPUT_MODE_PREFERRED;
 49		}
 50		if (mode_equal(&screen->planes.primary.mode, mode)) {
 51			flags |= WL_OUTPUT_MODE_CURRENT;
 52		}
 53
 54		wl_output_send_mode(resource, flags, mode->width, mode->height,
 55		                    mode->refresh);
 56	}
 57
 58	if (version >= 4) {
 59		wl_output_send_name(resource, output->name);
 60		wl_output_send_description(resource, output->name);
 61	}
 62
 63	if (version >= 2) {
 64		wl_output_send_done(resource);
 65	}
 66}
 67
 68struct output *
 69output_new(drmModeConnectorPtr connector)
 70{
 71	struct output *output;
 72	struct mode *modes;
 73	const char *name;
 74	uint32_t i;
 75
 76	if (!(output = malloc(sizeof(*output)))) {
 77		ERROR("Failed to allocate output\n");
 78		goto error0;
 79	}
 80
 81	output->global = wl_global_create(swc.display, &wl_output_interface, 4,
 82	                                  output, &bind_output);
 83
 84	if (!output->global) {
 85		ERROR("Failed to create output global\n");
 86		goto error1;
 87	}
 88
 89	output->physical_width = connector->mmWidth;
 90	output->physical_height = connector->mmHeight;
 91	output->preferred_mode = NULL;
 92
 93	wl_list_init(&output->resources);
 94	wl_array_init(&output->modes);
 95	pixman_region32_init(&output->current_damage);
 96	pixman_region32_init(&output->previous_damage);
 97
 98	output->connector = connector->connector_id;
 99
100	if (connector->count_modes == 0) {
101		goto error2;
102	}
103
104	modes =
105	    wl_array_add(&output->modes, connector->count_modes * sizeof(*modes));
106	if (!modes) {
107		goto error2;
108	}
109
110	for (i = 0; i < connector->count_modes; ++i) {
111		mode_initialize(&modes[i], &connector->modes[i]);
112
113		if (modes[i].preferred) {
114			output->preferred_mode = &modes[i];
115		}
116	}
117
118	if (!output->preferred_mode) {
119		output->preferred_mode = &modes[0];
120	}
121
122	if (!(name = drmModeGetConnectorTypeName(connector->connector_type)))
123		name = "UNKNOWN";
124	snprintf(output->name, sizeof(output->name), "%s-%d", name, connector->connector_type_id);
125
126	return output;
127
128error2:
129	wl_global_destroy(output->global);
130error1:
131	free(output);
132error0:
133	return NULL;
134}
135
136void
137output_destroy(struct output *output)
138{
139	struct wl_resource *resource, *tmp;
140
141	wl_list_for_each_safe(resource, tmp, &output->resources, link)
142		wl_resource_destroy(resource);
143	pixman_region32_fini(&output->current_damage);
144	pixman_region32_fini(&output->previous_damage);
145	wl_array_release(&output->modes);
146	wl_global_destroy(output->global);
147	free(output);
148}