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