1/* swc: libswc/screen.c
2 *
3 * Copyright (c) 2013, 2014 Michael Forney
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23
24#include "screen.h"
25#ifdef ENABLE_DRM
26#include "drm.h"
27#else
28#include "fb.h"
29#endif
30#include "event.h"
31#include "internal.h"
32#include "mode.h"
33#include "output.h"
34#ifdef ENABLE_DRM
35#include "plane.h"
36#endif
37#include "pointer.h"
38#include "util.h"
39
40#include "swc-server-protocol.h"
41#include <stdlib.h>
42
43#define INTERNAL(s) ((struct screen *)(s))
44
45static struct screen *active_screen;
46static const struct swc_screen_handler null_handler;
47
48static bool
49handle_motion(struct pointer_handler *handler,
50 uint32_t time,
51 wl_fixed_t x,
52 wl_fixed_t y);
53
54struct pointer_handler screens_pointer_handler = {
55 .motion = handle_motion,
56};
57
58EXPORT void
59swc_screen_set_handler(struct swc_screen *base,
60 const struct swc_screen_handler *handler,
61 void *data)
62{
63 struct screen *screen = INTERNAL(base);
64
65 screen->handler = handler;
66 screen->handler_data = data;
67}
68
69bool
70screens_initialize(void)
71{
72 wl_list_init(&swc.screens);
73
74 if (!
75#ifdef ENABLE_DRM
76 drm_create_screens(&swc.screens)
77#else
78 fb_create_screens(&swc.screens)
79#endif
80 ) {
81 return false;
82 }
83
84 if (wl_list_empty(&swc.screens)) {
85 return false;
86 }
87
88 return true;
89}
90
91void
92screens_finalize(void)
93{
94 struct screen *screen, *tmp;
95
96 wl_list_for_each_safe(screen, tmp, &swc.screens, link)
97 screen_destroy(screen);
98}
99
100static void
101bind_screen(struct wl_client *client, void *data, uint32_t version, uint32_t id)
102{
103 struct screen *screen = data;
104 struct wl_resource *resource;
105
106 resource = wl_resource_create(client, &swc_screen_interface, version, id);
107
108 if (!resource) {
109 wl_client_post_no_memory(client);
110 return;
111 }
112
113 wl_resource_set_implementation(resource, NULL, screen, &remove_resource);
114 wl_list_insert(&screen->resources, wl_resource_get_link(resource));
115}
116
117struct screen *
118#ifdef ENABLE_DRM
119screen_new(uint32_t crtc, struct output *output, struct plane *cursor_plane)
120#else
121screen_new(struct output *output)
122#endif
123{
124 struct screen *screen;
125 int32_t x = 0;
126
127 /* Simple heuristic for initial screen positioning. */
128 wl_list_for_each(screen, &swc.screens, link) x =
129 MAX(x, screen->base.geometry.x + screen->base.geometry.width);
130
131 if (!(screen = malloc(sizeof(*screen)))) {
132 goto error0;
133 }
134
135 screen->global = wl_global_create(
136 swc.display, &swc_screen_interface, 1, screen, &bind_screen);
137
138 if (!screen->global) {
139 ERROR("Failed to create screen global\n");
140 goto error1;
141 }
142
143#ifdef ENABLE_DRM
144 screen->crtc = crtc;
145 if (!primary_plane_initialize(&screen->planes.primary,
146 crtc,
147 output->preferred_mode,
148 &output->connector,
149 1)) {
150 ERROR("Failed to initialize primary plane\n");
151 goto error2;
152 }
153
154 cursor_plane->screen = screen;
155 screen->planes.cursor = cursor_plane;
156#else
157 if (!primary_plane_initialize(&screen->planes.primary,
158 output->preferred_mode)) {
159 ERROR("Failed to initialize primary plane\n");
160 goto error2;
161 }
162 screen->planes.cursor = NULL;
163#endif
164
165 screen->handler = &null_handler;
166 wl_signal_init(&screen->destroy_signal);
167 wl_list_init(&screen->resources);
168 wl_list_init(&screen->outputs);
169 wl_list_insert(&screen->outputs, &output->link);
170 wl_list_init(&screen->modifiers);
171
172 view_move(&screen->planes.primary.view, x, 0);
173 screen->base.geometry = screen->planes.primary.view.geometry;
174 screen->base.usable_geometry = screen->base.geometry;
175
176 swc.manager->new_screen(&screen->base);
177
178 return screen;
179
180error2:
181 wl_global_destroy(screen->global);
182error1:
183 free(screen);
184error0:
185 return NULL;
186}
187
188void
189screen_destroy(struct screen *screen)
190{
191 struct output *output, *next;
192
193 if (active_screen == screen) {
194 active_screen = NULL;
195 }
196 if (screen->handler->destroy) {
197 screen->handler->destroy(screen->handler_data);
198 }
199 wl_signal_emit(&screen->destroy_signal, NULL);
200 wl_list_for_each_safe(output, next, &screen->outputs, link)
201 output_destroy(output);
202 primary_plane_finalize(&screen->planes.primary);
203#ifdef ENABLE_DRM
204 if (screen->planes.cursor) {
205 plane_destroy(screen->planes.cursor);
206 }
207#endif
208 free(screen);
209}
210
211void
212screen_update_usable_geometry(struct screen *screen)
213{
214 pixman_region32_t total_usable, usable;
215 pixman_box32_t *extents;
216 struct screen_modifier *modifier;
217 struct swc_rectangle *geom = &screen->base.geometry;
218
219 DEBUG("Updating usable geometry\n");
220
221 pixman_region32_init_rect(
222 &total_usable, geom->x, geom->y, geom->width, geom->height);
223 pixman_region32_init(&usable);
224
225 wl_list_for_each(modifier, &screen->modifiers, link)
226 {
227 modifier->modify(modifier, geom, &usable);
228 pixman_region32_intersect(&total_usable, &total_usable, &usable);
229 }
230
231 extents = pixman_region32_extents(&total_usable);
232
233 if (extents->x1 != screen->base.usable_geometry.x ||
234 extents->y1 != screen->base.usable_geometry.y ||
235 (extents->x2 - extents->x1) != screen->base.usable_geometry.width ||
236 (extents->y2 - extents->y1) != screen->base.usable_geometry.height) {
237 screen->base.usable_geometry.x = extents->x1;
238 screen->base.usable_geometry.y = extents->y1;
239 screen->base.usable_geometry.width = extents->x2 - extents->x1;
240 screen->base.usable_geometry.height = extents->y2 - extents->y1;
241
242 if (screen->handler->usable_geometry_changed) {
243 screen->handler->usable_geometry_changed(screen->handler_data);
244 }
245 }
246}
247
248bool
249handle_motion(struct pointer_handler *handler,
250 uint32_t time,
251 wl_fixed_t fx,
252 wl_fixed_t fy)
253{
254 struct screen *screen;
255 int32_t x = wl_fixed_to_int(fx), y = wl_fixed_to_int(fy);
256
257 wl_list_for_each(screen, &swc.screens, link)
258 {
259 if (rectangle_contains_point(&screen->base.geometry, x, y)) {
260 if (screen != active_screen) {
261 active_screen = screen;
262
263 if (screen->handler->entered) {
264 screen->handler->entered(screen->handler_data);
265 }
266 }
267 break;
268 }
269 }
270
271 return false;
272}