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}