main 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#include "drm.h"
 26#include "event.h"
 27#include "internal.h"
 28#include "mode.h"
 29#include "output.h"
 30#include "plane.h"
 31#include "pointer.h"
 32#include "util.h"
 33
 34#include "swc-server-protocol.h"
 35#include <stdlib.h>
 36
 37#define INTERNAL(s) ((struct screen *)(s))
 38
 39static struct screen *active_screen;
 40static const struct swc_screen_handler null_handler;
 41
 42static bool
 43handle_motion(struct pointer_handler *handler,
 44              uint32_t time,
 45              wl_fixed_t x,
 46              wl_fixed_t y);
 47
 48struct pointer_handler screens_pointer_handler = {
 49    .motion = handle_motion,
 50};
 51
 52EXPORT void
 53swc_screen_set_handler(struct swc_screen *base,
 54                       const struct swc_screen_handler *handler,
 55                       void *data)
 56{
 57	struct screen *screen = INTERNAL(base);
 58
 59	screen->handler = handler;
 60	screen->handler_data = data;
 61}
 62
 63bool
 64screens_initialize(void)
 65{
 66	wl_list_init(&swc.screens);
 67
 68	if (!drm_create_screens(&swc.screens)) {
 69		return false;
 70	}
 71
 72	if (wl_list_empty(&swc.screens)) {
 73		return false;
 74	}
 75
 76	return true;
 77}
 78
 79void
 80screens_finalize(void)
 81{
 82	struct screen *screen, *tmp;
 83
 84	wl_list_for_each_safe(screen, tmp, &swc.screens, link)
 85	    screen_destroy(screen);
 86}
 87
 88static void
 89bind_screen(struct wl_client *client, void *data, uint32_t version, uint32_t id)
 90{
 91	struct screen *screen = data;
 92	struct wl_resource *resource;
 93
 94	resource = wl_resource_create(client, &swc_screen_interface, version, id);
 95
 96	if (!resource) {
 97		wl_client_post_no_memory(client);
 98		return;
 99	}
100
101	wl_resource_set_implementation(resource, NULL, screen, &remove_resource);
102	wl_list_insert(&screen->resources, wl_resource_get_link(resource));
103}
104
105struct screen *
106screen_new(uint32_t crtc, struct output *output, struct plane *cursor_plane)
107{
108	struct screen *screen;
109	int32_t x = 0;
110
111	/* Simple heuristic for initial screen positioning. */
112	wl_list_for_each(screen, &swc.screens, link) x =
113	    MAX(x, screen->base.geometry.x + screen->base.geometry.width);
114
115	if (!(screen = malloc(sizeof(*screen)))) {
116		goto error0;
117	}
118
119	screen->global = wl_global_create(
120	    swc.display, &swc_screen_interface, 1, screen, &bind_screen);
121
122	if (!screen->global) {
123		ERROR("Failed to create screen global\n");
124		goto error1;
125	}
126
127	screen->crtc = crtc;
128
129	if (!primary_plane_initialize(&screen->planes.primary,
130	                              crtc,
131	                              output->preferred_mode,
132	                              &output->connector,
133	                              1)) {
134		ERROR("Failed to initialize primary plane\n");
135		goto error2;
136	}
137
138	cursor_plane->screen = screen;
139	screen->planes.cursor = cursor_plane;
140
141	screen->handler = &null_handler;
142	wl_signal_init(&screen->destroy_signal);
143	wl_list_init(&screen->resources);
144	wl_list_init(&screen->outputs);
145	wl_list_insert(&screen->outputs, &output->link);
146	wl_list_init(&screen->modifiers);
147
148	view_move(&screen->planes.primary.view, x, 0);
149	screen->base.geometry = screen->planes.primary.view.geometry;
150	screen->base.usable_geometry = screen->base.geometry;
151
152	swc.manager->new_screen(&screen->base);
153
154	return screen;
155
156error2:
157	wl_global_destroy(screen->global);
158error1:
159	free(screen);
160error0:
161	return NULL;
162}
163
164void
165screen_destroy(struct screen *screen)
166{
167	struct output *output, *next;
168
169	if (active_screen == screen) {
170		active_screen = NULL;
171	}
172	if (screen->handler->destroy) {
173		screen->handler->destroy(screen->handler_data);
174	}
175	wl_signal_emit(&screen->destroy_signal, NULL);
176	wl_list_for_each_safe(output, next, &screen->outputs, link)
177	    output_destroy(output);
178	primary_plane_finalize(&screen->planes.primary);
179	plane_destroy(screen->planes.cursor);
180	free(screen);
181}
182
183void
184screen_update_usable_geometry(struct screen *screen)
185{
186	pixman_region32_t total_usable, usable;
187	pixman_box32_t *extents;
188	struct screen_modifier *modifier;
189	struct swc_rectangle *geom = &screen->base.geometry;
190
191	DEBUG("Updating usable geometry\n");
192
193	pixman_region32_init_rect(
194	    &total_usable, geom->x, geom->y, geom->width, geom->height);
195	pixman_region32_init(&usable);
196
197	wl_list_for_each(modifier, &screen->modifiers, link)
198	{
199		modifier->modify(modifier, geom, &usable);
200		pixman_region32_intersect(&total_usable, &total_usable, &usable);
201	}
202
203	extents = pixman_region32_extents(&total_usable);
204
205	if (extents->x1 != screen->base.usable_geometry.x ||
206	    extents->y1 != screen->base.usable_geometry.y ||
207	    (extents->x2 - extents->x1) != screen->base.usable_geometry.width ||
208	    (extents->y2 - extents->y1) != screen->base.usable_geometry.height) {
209		screen->base.usable_geometry.x = extents->x1;
210		screen->base.usable_geometry.y = extents->y1;
211		screen->base.usable_geometry.width = extents->x2 - extents->x1;
212		screen->base.usable_geometry.height = extents->y2 - extents->y1;
213
214		if (screen->handler->usable_geometry_changed) {
215			screen->handler->usable_geometry_changed(screen->handler_data);
216		}
217	}
218}
219
220bool
221handle_motion(struct pointer_handler *handler,
222              uint32_t time,
223              wl_fixed_t fx,
224              wl_fixed_t fy)
225{
226	struct screen *screen;
227	int32_t x = wl_fixed_to_int(fx), y = wl_fixed_to_int(fy);
228
229	wl_list_for_each(screen, &swc.screens, link)
230	{
231		if (rectangle_contains_point(&screen->base.geometry, x, y)) {
232			if (screen != active_screen) {
233				active_screen = screen;
234
235				if (screen->handler->entered) {
236					screen->handler->entered(screen->handler_data);
237				}
238			}
239			break;
240		}
241	}
242
243	return false;
244}