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}