main shrub/neuswc / libswc / screen.c
  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}