• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2010-2012 Intel Corporation
3  * Copyright 2013 Raspberry Pi Foundation
4  * Copyright 2011-2012,2020 Collabora, Ltd.
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a
7  * copy of this software and associated documentation files (the "Software"),
8  * to deal in the Software without restriction, including without limitation
9  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10  * and/or sell copies of the Software, and to permit persons to whom the
11  * Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the next
14  * paragraph) shall be included in all copies or substantial portions of the
15  * Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23  * DEALINGS IN THE SOFTWARE.
24  */
25 
26 #include <assert.h>
27 #include <linux/input.h>
28 #include <stdbool.h>
29 #include <stdint.h>
30 #include <string.h>
31 
32 #include "kiosk-shell.h"
33 #include "kiosk-shell-grab.h"
34 #include "compositor/weston.h"
35 #include "shared/helpers.h"
36 #include "util.h"
37 
38 static struct kiosk_shell_surface *
get_kiosk_shell_surface(struct weston_surface * surface)39 get_kiosk_shell_surface(struct weston_surface *surface)
40 {
41 	struct weston_desktop_surface *desktop_surface =
42 		weston_surface_get_desktop_surface(surface);
43 
44 	if (desktop_surface)
45 		return weston_desktop_surface_get_user_data(desktop_surface);
46 
47 	return NULL;
48 }
49 
50 static void
51 kiosk_shell_seat_handle_destroy(struct wl_listener *listener, void *data);
52 
53 static struct kiosk_shell_seat *
get_kiosk_shell_seat(struct weston_seat * seat)54 get_kiosk_shell_seat(struct weston_seat *seat)
55 {
56 	struct wl_listener *listener;
57 
58 	listener = wl_signal_get(&seat->destroy_signal,
59 				 kiosk_shell_seat_handle_destroy);
60 	assert(listener != NULL);
61 
62 	return container_of(listener,
63 			    struct kiosk_shell_seat, seat_destroy_listener);
64 }
65 
66 /*
67  * kiosk_shell_surface
68  */
69 
70 static void
71 kiosk_shell_surface_set_output(struct kiosk_shell_surface *shsurf,
72 			       struct weston_output *output);
73 static void
74 kiosk_shell_surface_set_parent(struct kiosk_shell_surface *shsurf,
75 			       struct kiosk_shell_surface *parent);
76 
77 static void
kiosk_shell_surface_notify_parent_destroy(struct wl_listener * listener,void * data)78 kiosk_shell_surface_notify_parent_destroy(struct wl_listener *listener, void *data)
79 {
80 	struct kiosk_shell_surface *shsurf =
81 		container_of(listener,
82 			     struct kiosk_shell_surface, parent_destroy_listener);
83 
84 	kiosk_shell_surface_set_parent(shsurf, shsurf->parent->parent);
85 }
86 
87 static void
kiosk_shell_surface_notify_output_destroy(struct wl_listener * listener,void * data)88 kiosk_shell_surface_notify_output_destroy(struct wl_listener *listener, void *data)
89 {
90 	struct kiosk_shell_surface *shsurf =
91 		container_of(listener,
92 			     struct kiosk_shell_surface, output_destroy_listener);
93 
94 	kiosk_shell_surface_set_output(shsurf, NULL);
95 }
96 
97 static struct kiosk_shell_surface *
kiosk_shell_surface_get_parent_root(struct kiosk_shell_surface * shsurf)98 kiosk_shell_surface_get_parent_root(struct kiosk_shell_surface *shsurf)
99 {
100 	struct kiosk_shell_surface *root = shsurf;
101 	while (root->parent)
102 		root = root->parent;
103 	return root;
104 }
105 
106 static bool
107 kiosk_shell_output_has_app_id(struct kiosk_shell_output *shoutput,
108 			      const char *app_id);
109 
110 static struct weston_output *
kiosk_shell_surface_find_best_output(struct kiosk_shell_surface * shsurf)111 kiosk_shell_surface_find_best_output(struct kiosk_shell_surface *shsurf)
112 {
113 	struct weston_output *output;
114 	struct kiosk_shell_output *shoutput;
115 	struct kiosk_shell_surface *root;
116 	const char *app_id;
117 
118 	/* Always use current output if any. */
119 	if (shsurf->output)
120 		return shsurf->output;
121 
122 	/* Check if we have a designated output for this app. */
123 	app_id = weston_desktop_surface_get_app_id(shsurf->desktop_surface);
124 	if (app_id) {
125 		wl_list_for_each(shoutput, &shsurf->shell->output_list, link) {
126 			if (kiosk_shell_output_has_app_id(shoutput, app_id))
127 				return shoutput->output;
128 		}
129 	}
130 
131 	/* Group all related windows in the same output. */
132 	root = kiosk_shell_surface_get_parent_root(shsurf);
133 	if (root->output)
134 		return root->output;
135 
136 	output = get_focused_output(shsurf->shell->compositor);
137 	if (output)
138 		return output;
139 
140 	output = get_default_output(shsurf->shell->compositor);
141 	if (output)
142 		return output;
143 
144 	return NULL;
145 }
146 
147 static void
kiosk_shell_surface_set_output(struct kiosk_shell_surface * shsurf,struct weston_output * output)148 kiosk_shell_surface_set_output(struct kiosk_shell_surface *shsurf,
149 			       struct weston_output *output)
150 {
151 	shsurf->output = output;
152 
153 	if (shsurf->output_destroy_listener.notify) {
154 		wl_list_remove(&shsurf->output_destroy_listener.link);
155 		shsurf->output_destroy_listener.notify = NULL;
156 	}
157 
158 	if (!shsurf->output)
159 		return;
160 
161 	shsurf->output_destroy_listener.notify =
162 		kiosk_shell_surface_notify_output_destroy;
163 	wl_signal_add(&shsurf->output->destroy_signal,
164 		      &shsurf->output_destroy_listener);
165 }
166 
167 static void
kiosk_shell_surface_set_fullscreen(struct kiosk_shell_surface * shsurf,struct weston_output * output)168 kiosk_shell_surface_set_fullscreen(struct kiosk_shell_surface *shsurf,
169 				   struct weston_output *output)
170 {
171 	if (!output)
172 		output = kiosk_shell_surface_find_best_output(shsurf);
173 
174 	kiosk_shell_surface_set_output(shsurf, output);
175 
176 	weston_desktop_surface_set_fullscreen(shsurf->desktop_surface, true);
177 	if (shsurf->output)
178 		weston_desktop_surface_set_size(shsurf->desktop_surface,
179 						shsurf->output->width,
180 						shsurf->output->height);
181 }
182 
183 static void
kiosk_shell_surface_set_maximized(struct kiosk_shell_surface * shsurf)184 kiosk_shell_surface_set_maximized(struct kiosk_shell_surface *shsurf)
185 {
186 	struct weston_output *output =
187 		kiosk_shell_surface_find_best_output(shsurf);
188 
189 	kiosk_shell_surface_set_output(shsurf, output);
190 
191 	weston_desktop_surface_set_maximized(shsurf->desktop_surface, true);
192 	if (shsurf->output)
193 		weston_desktop_surface_set_size(shsurf->desktop_surface,
194 						shsurf->output->width,
195 						shsurf->output->height);
196 }
197 
198 static void
kiosk_shell_surface_set_normal(struct kiosk_shell_surface * shsurf)199 kiosk_shell_surface_set_normal(struct kiosk_shell_surface *shsurf)
200 {
201 	if (!shsurf->output)
202 		kiosk_shell_surface_set_output(shsurf,
203 			kiosk_shell_surface_find_best_output(shsurf));
204 
205 	weston_desktop_surface_set_fullscreen(shsurf->desktop_surface, false);
206 	weston_desktop_surface_set_maximized(shsurf->desktop_surface, false);
207 	weston_desktop_surface_set_size(shsurf->desktop_surface, 0, 0);
208 }
209 
210 static void
kiosk_shell_surface_set_parent(struct kiosk_shell_surface * shsurf,struct kiosk_shell_surface * parent)211 kiosk_shell_surface_set_parent(struct kiosk_shell_surface *shsurf,
212 			       struct kiosk_shell_surface *parent)
213 {
214 	if (shsurf->parent_destroy_listener.notify) {
215 		wl_list_remove(&shsurf->parent_destroy_listener.link);
216 		shsurf->parent_destroy_listener.notify = NULL;
217 	}
218 
219 	shsurf->parent = parent;
220 
221 	if (shsurf->parent) {
222 		shsurf->parent_destroy_listener.notify =
223 			kiosk_shell_surface_notify_parent_destroy;
224 		wl_signal_add(&shsurf->parent->destroy_signal,
225 			      &shsurf->parent_destroy_listener);
226 		kiosk_shell_surface_set_output(shsurf, NULL);
227 		kiosk_shell_surface_set_normal(shsurf);
228 	} else {
229 		kiosk_shell_surface_set_fullscreen(shsurf, shsurf->output);
230 	}
231 }
232 
233 static void
kiosk_shell_surface_reconfigure_for_output(struct kiosk_shell_surface * shsurf)234 kiosk_shell_surface_reconfigure_for_output(struct kiosk_shell_surface *shsurf)
235 {
236 	struct weston_desktop_surface *desktop_surface;
237 
238 	if (!shsurf->output)
239 		return;
240 
241 	desktop_surface = shsurf->desktop_surface;
242 
243 	if (weston_desktop_surface_get_maximized(desktop_surface) ||
244 	    weston_desktop_surface_get_fullscreen(desktop_surface)) {
245 		weston_desktop_surface_set_size(desktop_surface,
246 						shsurf->output->width,
247 						shsurf->output->height);
248 	}
249 
250 	center_on_output(shsurf->view, shsurf->output);
251 	weston_view_update_transform(shsurf->view);
252 }
253 
254 static void
kiosk_shell_surface_destroy(struct kiosk_shell_surface * shsurf)255 kiosk_shell_surface_destroy(struct kiosk_shell_surface *shsurf)
256 {
257 	wl_signal_emit(&shsurf->destroy_signal, shsurf);
258 
259 	weston_desktop_surface_set_user_data(shsurf->desktop_surface, NULL);
260 	shsurf->desktop_surface = NULL;
261 
262 	weston_desktop_surface_unlink_view(shsurf->view);
263 
264 	weston_view_destroy(shsurf->view);
265 
266 	if (shsurf->output_destroy_listener.notify) {
267 		wl_list_remove(&shsurf->output_destroy_listener.link);
268 		shsurf->output_destroy_listener.notify = NULL;
269 	}
270 
271 	if (shsurf->parent_destroy_listener.notify) {
272 		wl_list_remove(&shsurf->parent_destroy_listener.link);
273 		shsurf->parent_destroy_listener.notify = NULL;
274 		shsurf->parent = NULL;
275 	}
276 
277 	free(shsurf);
278 }
279 
280 static struct kiosk_shell_surface *
kiosk_shell_surface_create(struct kiosk_shell * shell,struct weston_desktop_surface * desktop_surface)281 kiosk_shell_surface_create(struct kiosk_shell *shell,
282 			   struct weston_desktop_surface *desktop_surface)
283 {
284 	struct weston_desktop_client *client =
285 		weston_desktop_surface_get_client(desktop_surface);
286 	struct wl_client *wl_client =
287 		weston_desktop_client_get_client(client);
288 	struct weston_view *view;
289 	struct kiosk_shell_surface *shsurf;
290 
291 	view = weston_desktop_surface_create_view(desktop_surface);
292 	if (!view)
293 		return NULL;
294 
295 	shsurf = zalloc(sizeof *shsurf);
296 	if (!shsurf) {
297 		if (wl_client)
298 			wl_client_post_no_memory(wl_client);
299 		else
300 			weston_log("no memory to allocate shell surface\n");
301 		return NULL;
302 	}
303 
304 	shsurf->desktop_surface = desktop_surface;
305 	shsurf->view = view;
306 	shsurf->shell = shell;
307 
308 	weston_desktop_surface_set_user_data(desktop_surface, shsurf);
309 
310 	wl_signal_init(&shsurf->destroy_signal);
311 
312 	return shsurf;
313 }
314 
315 /*
316  * kiosk_shell_seat
317  */
318 
319 static void
kiosk_shell_seat_handle_keyboard_focus(struct wl_listener * listener,void * data)320 kiosk_shell_seat_handle_keyboard_focus(struct wl_listener *listener, void *data)
321 {
322 	struct weston_keyboard *keyboard = data;
323 	struct kiosk_shell_seat *shseat = get_kiosk_shell_seat(keyboard->seat);
324 
325 	if (shseat->focused_surface) {
326 		struct kiosk_shell_surface *shsurf =
327 			get_kiosk_shell_surface(shseat->focused_surface);
328 		if (shsurf && --shsurf->focus_count == 0)
329 			weston_desktop_surface_set_activated(shsurf->desktop_surface,
330 							     false);
331 	}
332 
333 	shseat->focused_surface = weston_surface_get_main_surface(keyboard->focus);
334 
335 	if (shseat->focused_surface) {
336 		struct kiosk_shell_surface *shsurf =
337 			get_kiosk_shell_surface(shseat->focused_surface);
338 		if (shsurf && shsurf->focus_count++ == 0)
339 			weston_desktop_surface_set_activated(shsurf->desktop_surface,
340 							     true);
341 	}
342 }
343 
344 static void
kiosk_shell_seat_handle_destroy(struct wl_listener * listener,void * data)345 kiosk_shell_seat_handle_destroy(struct wl_listener *listener, void *data)
346 {
347 	struct kiosk_shell_seat *shseat =
348 		container_of(listener,
349 			     struct kiosk_shell_seat, seat_destroy_listener);
350 
351 	wl_list_remove(&shseat->keyboard_focus_listener.link);
352 	wl_list_remove(&shseat->caps_changed_listener.link);
353 	wl_list_remove(&shseat->seat_destroy_listener.link);
354 	free(shseat);
355 }
356 
357 static void
kiosk_shell_seat_handle_caps_changed(struct wl_listener * listener,void * data)358 kiosk_shell_seat_handle_caps_changed(struct wl_listener *listener, void *data)
359 {
360 	struct weston_keyboard *keyboard;
361 	struct kiosk_shell_seat *shseat;
362 
363 	shseat = container_of(listener, struct kiosk_shell_seat,
364 			      caps_changed_listener);
365 	keyboard = weston_seat_get_keyboard(shseat->seat);
366 
367 	if (keyboard &&
368 	    wl_list_empty(&shseat->keyboard_focus_listener.link)) {
369 		wl_signal_add(&keyboard->focus_signal,
370 			      &shseat->keyboard_focus_listener);
371 	} else if (!keyboard) {
372 		wl_list_remove(&shseat->keyboard_focus_listener.link);
373 		wl_list_init(&shseat->keyboard_focus_listener.link);
374 	}
375 }
376 
377 static struct kiosk_shell_seat *
kiosk_shell_seat_create(struct weston_seat * seat)378 kiosk_shell_seat_create(struct weston_seat *seat)
379 {
380 	struct kiosk_shell_seat *shseat;
381 
382 	shseat = zalloc(sizeof *shseat);
383 	if (!shseat) {
384 		weston_log("no memory to allocate shell seat\n");
385 		return NULL;
386 	}
387 
388 	shseat->seat = seat;
389 
390 	shseat->seat_destroy_listener.notify = kiosk_shell_seat_handle_destroy;
391 	wl_signal_add(&seat->destroy_signal, &shseat->seat_destroy_listener);
392 
393 	shseat->keyboard_focus_listener.notify = kiosk_shell_seat_handle_keyboard_focus;
394 	wl_list_init(&shseat->keyboard_focus_listener.link);
395 
396 	shseat->caps_changed_listener.notify = kiosk_shell_seat_handle_caps_changed;
397 	wl_signal_add(&seat->updated_caps_signal,
398 		      &shseat->caps_changed_listener);
399 	kiosk_shell_seat_handle_caps_changed(&shseat->caps_changed_listener, NULL);
400 
401 	return shseat;
402 }
403 
404 /*
405  * kiosk_shell_output
406  */
407 
408 static int
kiosk_shell_background_surface_get_label(struct weston_surface * surface,char * buf,size_t len)409 kiosk_shell_background_surface_get_label(struct weston_surface *surface,
410 					 char *buf, size_t len)
411 {
412 	return snprintf(buf, len, "kiosk shell background surface");
413 }
414 
415 static void
kiosk_shell_output_recreate_background(struct kiosk_shell_output * shoutput)416 kiosk_shell_output_recreate_background(struct kiosk_shell_output *shoutput)
417 {
418 	struct kiosk_shell *shell = shoutput->shell;
419 	struct weston_output *output = shoutput->output;
420 
421 	if (shoutput->background_view)
422 		weston_surface_destroy(shoutput->background_view->surface);
423 
424 	if (!output)
425 		return;
426 
427 	shoutput->background_view =
428 			create_colored_surface(shoutput->shell->compositor,
429 					       0.5, 0.5, 0.5,
430 					       output->x, output->y,
431 					       output->width,
432 			                       output->height);
433 
434 	weston_surface_set_role(shoutput->background_view->surface,
435 				"kiosk-shell-background", NULL, 0);
436 	weston_surface_set_label_func(shoutput->background_view->surface,
437 				      kiosk_shell_background_surface_get_label);
438 
439 	weston_layer_entry_insert(&shell->background_layer.view_list,
440 				  &shoutput->background_view->layer_link);
441 
442 	shoutput->background_view->is_mapped = true;
443 	shoutput->background_view->surface->is_mapped = true;
444 	shoutput->background_view->surface->output = output;
445 	weston_view_set_output(shoutput->background_view, output);
446 }
447 
448 static void
kiosk_shell_output_destroy(struct kiosk_shell_output * shoutput)449 kiosk_shell_output_destroy(struct kiosk_shell_output *shoutput)
450 {
451 	shoutput->output = NULL;
452 	shoutput->output_destroy_listener.notify = NULL;
453 
454 	if (shoutput->background_view)
455 		weston_surface_destroy(shoutput->background_view->surface);
456 
457 	wl_list_remove(&shoutput->output_destroy_listener.link);
458 	wl_list_remove(&shoutput->link);
459 
460 	free(shoutput->app_ids);
461 
462 	free(shoutput);
463 }
464 
465 static bool
kiosk_shell_output_has_app_id(struct kiosk_shell_output * shoutput,const char * app_id)466 kiosk_shell_output_has_app_id(struct kiosk_shell_output *shoutput,
467 			      const char *app_id)
468 {
469 	char *cur;
470 	size_t app_id_len;
471 
472 	if (!shoutput->app_ids)
473 		return false;
474 
475 	cur = shoutput->app_ids;
476 	app_id_len = strlen(app_id);
477 
478 	while ((cur = strstr(cur, app_id))) {
479 		/* Check whether we have found a complete match of app_id. */
480 		if ((cur[app_id_len] == ',' || cur[app_id_len] == '\0') &&
481 		    (cur == shoutput->app_ids || cur[-1] == ','))
482 			return true;
483 		cur++;
484 	}
485 
486 	return false;
487 }
488 
489 static void
kiosk_shell_output_configure(struct kiosk_shell_output * shoutput)490 kiosk_shell_output_configure(struct kiosk_shell_output *shoutput)
491 {
492 	struct weston_config *wc = wet_get_config(shoutput->shell->compositor);
493 	struct weston_config_section *section =
494 		weston_config_get_section(wc, "output", "name", shoutput->output->name);
495 
496 	assert(shoutput->app_ids == NULL);
497 
498 	if (section) {
499 		weston_config_section_get_string(section, "app-ids",
500 						 &shoutput->app_ids, NULL);
501 	}
502 }
503 
504 static void
kiosk_shell_output_notify_output_destroy(struct wl_listener * listener,void * data)505 kiosk_shell_output_notify_output_destroy(struct wl_listener *listener, void *data)
506 {
507 	struct kiosk_shell_output *shoutput =
508 		container_of(listener,
509 			     struct kiosk_shell_output, output_destroy_listener);
510 
511 	kiosk_shell_output_destroy(shoutput);
512 }
513 
514 static struct kiosk_shell_output *
kiosk_shell_output_create(struct kiosk_shell * shell,struct weston_output * output)515 kiosk_shell_output_create(struct kiosk_shell *shell, struct weston_output *output)
516 {
517 	struct kiosk_shell_output *shoutput;
518 
519 	shoutput = zalloc(sizeof *shoutput);
520 	if (shoutput == NULL)
521 		return NULL;
522 
523 	shoutput->output = output;
524 	shoutput->shell = shell;
525 
526 	shoutput->output_destroy_listener.notify =
527 		kiosk_shell_output_notify_output_destroy;
528 	wl_signal_add(&shoutput->output->destroy_signal,
529 		      &shoutput->output_destroy_listener);
530 
531 	wl_list_insert(shell->output_list.prev, &shoutput->link);
532 
533 	kiosk_shell_output_recreate_background(shoutput);
534 	kiosk_shell_output_configure(shoutput);
535 
536 	return shoutput;
537 }
538 
539 /*
540  * libweston-desktop
541  */
542 
543 static void
desktop_surface_added(struct weston_desktop_surface * desktop_surface,void * data)544 desktop_surface_added(struct weston_desktop_surface *desktop_surface,
545 		      void *data)
546 {
547 	struct kiosk_shell *shell = data;
548 	struct kiosk_shell_surface *shsurf;
549 	struct weston_seat *seat;
550 
551 	shsurf = kiosk_shell_surface_create(shell, desktop_surface);
552 	if (!shsurf)
553 		return;
554 
555 	kiosk_shell_surface_set_fullscreen(shsurf, NULL);
556 
557 	wl_list_for_each(seat, &shell->compositor->seat_list, link)
558 		weston_view_activate(shsurf->view, seat, 0);
559 }
560 
561 /* Return the view that should gain focus after the specified shsurf is
562  * destroyed. We prefer the top remaining view from the same parent surface,
563  * but if we can't find one we fall back to the top view regardless of
564  * parentage. */
565 static struct weston_view *
find_focus_successor(struct weston_layer * layer,struct kiosk_shell_surface * shsurf)566 find_focus_successor(struct weston_layer *layer,
567 		     struct kiosk_shell_surface *shsurf)
568 {
569 	struct kiosk_shell_surface *parent_root =
570 		kiosk_shell_surface_get_parent_root(shsurf);
571 	struct weston_view *top_view = NULL;
572 	struct weston_view *view;
573 
574 	wl_list_for_each(view, &layer->view_list.link, layer_link.link) {
575 		struct kiosk_shell_surface *view_shsurf;
576 		struct kiosk_shell_surface *root;
577 
578 		if (!view->is_mapped || view == shsurf->view)
579 			continue;
580 
581 		view_shsurf = get_kiosk_shell_surface(view->surface);
582 		if (!view_shsurf)
583 			continue;
584 
585 		if (!top_view)
586 			top_view = view;
587 
588 		root = kiosk_shell_surface_get_parent_root(view_shsurf);
589 		if (root == parent_root)
590 			return view;
591 	}
592 
593 	return top_view;
594 }
595 
596 static void
desktop_surface_removed(struct weston_desktop_surface * desktop_surface,void * data)597 desktop_surface_removed(struct weston_desktop_surface *desktop_surface,
598 			void *data)
599 {
600 	struct kiosk_shell *shell = data;
601 	struct kiosk_shell_surface *shsurf =
602 		weston_desktop_surface_get_user_data(desktop_surface);
603 	struct weston_surface *surface =
604 		weston_desktop_surface_get_surface(desktop_surface);
605 	struct weston_view *focus_view;
606 	struct weston_seat *seat;
607 
608 	if (!shsurf)
609 		return;
610 
611 	focus_view = find_focus_successor(&shell->normal_layer, shsurf);
612 
613 	if (focus_view) {
614 		wl_list_for_each(seat, &shell->compositor->seat_list, link) {
615 			struct weston_keyboard *keyboard = seat->keyboard_state;
616 			if (keyboard && keyboard->focus == surface)
617 				weston_view_activate(focus_view, seat, 0);
618 		}
619 	}
620 
621 	kiosk_shell_surface_destroy(shsurf);
622 }
623 
624 static void
desktop_surface_committed(struct weston_desktop_surface * desktop_surface,int32_t sx,int32_t sy,void * data)625 desktop_surface_committed(struct weston_desktop_surface *desktop_surface,
626 			  int32_t sx, int32_t sy, void *data)
627 {
628 	struct kiosk_shell_surface *shsurf =
629 		weston_desktop_surface_get_user_data(desktop_surface);
630 	struct weston_surface *surface =
631 		weston_desktop_surface_get_surface(desktop_surface);
632 	bool is_resized;
633 	bool is_fullscreen;
634 
635 	if (surface->width == 0)
636 		return;
637 
638 	/* TODO: When the top-level surface is committed with a new size after an
639 	 * output resize, sometimes the view appears scaled. What state are we not
640 	 * updating?
641 	 */
642 
643 	is_resized = surface->width != shsurf->last_width ||
644 		     surface->height != shsurf->last_height;
645 	is_fullscreen = weston_desktop_surface_get_maximized(desktop_surface) ||
646 			weston_desktop_surface_get_fullscreen(desktop_surface);
647 
648 	if (!weston_surface_is_mapped(surface) || (is_resized && is_fullscreen)) {
649 		if (is_fullscreen || !shsurf->xwayland.is_set) {
650 			center_on_output(shsurf->view, shsurf->output);
651 		} else {
652 			struct weston_geometry geometry =
653 				weston_desktop_surface_get_geometry(desktop_surface);
654 			float x = shsurf->xwayland.x - geometry.x;
655 			float y = shsurf->xwayland.y - geometry.y;
656 
657 			weston_view_set_position(shsurf->view, x, y);
658 		}
659 
660 		weston_view_update_transform(shsurf->view);
661 	}
662 
663 	if (!weston_surface_is_mapped(surface)) {
664 		weston_layer_entry_insert(&shsurf->shell->normal_layer.view_list,
665 					  &shsurf->view->layer_link);
666 		shsurf->view->is_mapped = true;
667 		surface->is_mapped = true;
668 	}
669 
670 	if (!is_fullscreen && (sx != 0 || sy != 0)) {
671 		float from_x, from_y;
672 		float to_x, to_y;
673 		float x, y;
674 
675 		weston_view_to_global_float(shsurf->view, 0, 0, &from_x, &from_y);
676 		weston_view_to_global_float(shsurf->view, sx, sy, &to_x, &to_y);
677 		x = shsurf->view->geometry.x + to_x - from_x;
678 		y = shsurf->view->geometry.y + to_y - from_y;
679 
680 		weston_view_set_position(shsurf->view, x, y);
681 		weston_view_update_transform(shsurf->view);
682 	}
683 
684 	shsurf->last_width = surface->width;
685 	shsurf->last_height = surface->height;
686 }
687 
688 static void
desktop_surface_move(struct weston_desktop_surface * desktop_surface,struct weston_seat * seat,uint32_t serial,void * shell)689 desktop_surface_move(struct weston_desktop_surface *desktop_surface,
690 		     struct weston_seat *seat, uint32_t serial, void *shell)
691 {
692 	struct weston_pointer *pointer = weston_seat_get_pointer(seat);
693 	struct weston_touch *touch = weston_seat_get_touch(seat);
694 	struct kiosk_shell_surface *shsurf =
695 		weston_desktop_surface_get_user_data(desktop_surface);
696 	struct weston_surface *surface =
697 		weston_desktop_surface_get_surface(shsurf->desktop_surface);
698 	struct weston_surface *focus;
699 
700 	if (pointer &&
701 	    pointer->focus &&
702 	    pointer->button_count > 0 &&
703 	    pointer->grab_serial == serial) {
704 		focus = weston_surface_get_main_surface(pointer->focus->surface);
705 		if ((focus == surface) &&
706 		    (kiosk_shell_grab_start_for_pointer_move(shsurf, pointer) ==
707 			KIOSK_SHELL_GRAB_RESULT_ERROR))
708 			wl_resource_post_no_memory(surface->resource);
709 	}
710 	else if (touch &&
711 		 touch->focus &&
712 		 touch->grab_serial == serial) {
713 		focus = weston_surface_get_main_surface(touch->focus->surface);
714 		if ((focus == surface) &&
715 		    (kiosk_shell_grab_start_for_touch_move(shsurf, touch) ==
716 			KIOSK_SHELL_GRAB_RESULT_ERROR))
717 			wl_resource_post_no_memory(surface->resource);
718 	}
719 }
720 
721 static void
desktop_surface_resize(struct weston_desktop_surface * desktop_surface,struct weston_seat * seat,uint32_t serial,enum weston_desktop_surface_edge edges,void * shell)722 desktop_surface_resize(struct weston_desktop_surface *desktop_surface,
723 		       struct weston_seat *seat, uint32_t serial,
724 		       enum weston_desktop_surface_edge edges, void *shell)
725 {
726 }
727 
728 static void
desktop_surface_set_parent(struct weston_desktop_surface * desktop_surface,struct weston_desktop_surface * parent,void * shell)729 desktop_surface_set_parent(struct weston_desktop_surface *desktop_surface,
730 			   struct weston_desktop_surface *parent,
731 			   void *shell)
732 {
733 	struct kiosk_shell_surface *shsurf =
734 		weston_desktop_surface_get_user_data(desktop_surface);
735 	struct kiosk_shell_surface *shsurf_parent =
736 		parent ? weston_desktop_surface_get_user_data(parent) : NULL;
737 
738 	kiosk_shell_surface_set_parent(shsurf, shsurf_parent);
739 }
740 
741 static void
desktop_surface_fullscreen_requested(struct weston_desktop_surface * desktop_surface,bool fullscreen,struct weston_output * output,void * shell)742 desktop_surface_fullscreen_requested(struct weston_desktop_surface *desktop_surface,
743 				     bool fullscreen,
744 				     struct weston_output *output, void *shell)
745 {
746 	struct kiosk_shell_surface *shsurf =
747 		weston_desktop_surface_get_user_data(desktop_surface);
748 
749 	/* We should normally be able to ignore fullscreen requests for
750 	 * top-level surfaces, since we set them as fullscreen at creation
751 	 * time. However, xwayland surfaces set their internal WM state
752 	 * regardless of what the shell wants, so they may remove fullscreen
753 	 * state before informing weston-desktop of this request. Since we
754 	 * always want top-level surfaces to be fullscreen, we need to reapply
755 	 * the fullscreen state to force the correct xwayland WM state.
756 	 *
757 	 * TODO: Explore a model where the XWayland WM doesn't set the internal
758 	 * WM surface state itself, rather letting the shell make the decision.
759 	 */
760 
761 	if (!shsurf->parent || fullscreen)
762 		kiosk_shell_surface_set_fullscreen(shsurf, output);
763 	else
764 		kiosk_shell_surface_set_normal(shsurf);
765 }
766 
767 static void
desktop_surface_maximized_requested(struct weston_desktop_surface * desktop_surface,bool maximized,void * shell)768 desktop_surface_maximized_requested(struct weston_desktop_surface *desktop_surface,
769 				    bool maximized, void *shell)
770 {
771 	struct kiosk_shell_surface *shsurf =
772 		weston_desktop_surface_get_user_data(desktop_surface);
773 
774 	/* Since xwayland surfaces may have already applied the max/min states
775 	 * internally, reapply fullscreen to force the correct xwayland WM state.
776 	 * Also see comment in desktop_surface_fullscreen_requested(). */
777 	if (!shsurf->parent)
778 		kiosk_shell_surface_set_fullscreen(shsurf, NULL);
779 	else if (maximized)
780 		kiosk_shell_surface_set_maximized(shsurf);
781 	else
782 		kiosk_shell_surface_set_normal(shsurf);
783 }
784 
785 static void
desktop_surface_minimized_requested(struct weston_desktop_surface * desktop_surface,void * shell)786 desktop_surface_minimized_requested(struct weston_desktop_surface *desktop_surface,
787 				    void *shell)
788 {
789 }
790 
791 static void
desktop_surface_ping_timeout(struct weston_desktop_client * desktop_client,void * shell_)792 desktop_surface_ping_timeout(struct weston_desktop_client *desktop_client,
793 			     void *shell_)
794 {
795 }
796 
797 static void
desktop_surface_pong(struct weston_desktop_client * desktop_client,void * shell_)798 desktop_surface_pong(struct weston_desktop_client *desktop_client,
799 		     void *shell_)
800 {
801 }
802 
803 static void
desktop_surface_set_xwayland_position(struct weston_desktop_surface * desktop_surface,int32_t x,int32_t y,void * shell)804 desktop_surface_set_xwayland_position(struct weston_desktop_surface *desktop_surface,
805 				      int32_t x, int32_t y, void *shell)
806 {
807 	struct kiosk_shell_surface *shsurf =
808 		weston_desktop_surface_get_user_data(desktop_surface);
809 
810 	shsurf->xwayland.x = x;
811 	shsurf->xwayland.y = y;
812 	shsurf->xwayland.is_set = true;
813 }
814 
815 static const struct weston_desktop_api kiosk_shell_desktop_api = {
816 	.struct_size = sizeof(struct weston_desktop_api),
817 	.surface_added = desktop_surface_added,
818 	.surface_removed = desktop_surface_removed,
819 	.committed = desktop_surface_committed,
820 	.move = desktop_surface_move,
821 	.resize = desktop_surface_resize,
822 	.set_parent = desktop_surface_set_parent,
823 	.fullscreen_requested = desktop_surface_fullscreen_requested,
824 	.maximized_requested = desktop_surface_maximized_requested,
825 	.minimized_requested = desktop_surface_minimized_requested,
826 	.ping_timeout = desktop_surface_ping_timeout,
827 	.pong = desktop_surface_pong,
828 	.set_xwayland_position = desktop_surface_set_xwayland_position,
829 };
830 
831 /*
832  * kiosk_shell
833  */
834 
835 static struct kiosk_shell_output *
kiosk_shell_find_shell_output(struct kiosk_shell * shell,struct weston_output * output)836 kiosk_shell_find_shell_output(struct kiosk_shell *shell,
837 			      struct weston_output *output)
838 {
839 	struct kiosk_shell_output *shoutput;
840 
841 	wl_list_for_each(shoutput, &shell->output_list, link) {
842 		if (shoutput->output == output)
843 			return shoutput;
844 	}
845 
846 	return NULL;
847 }
848 
849 static void
kiosk_shell_activate_view(struct kiosk_shell * shell,struct weston_view * view,struct weston_seat * seat,uint32_t flags)850 kiosk_shell_activate_view(struct kiosk_shell *shell,
851 			  struct weston_view *view,
852 			  struct weston_seat *seat,
853 			  uint32_t flags)
854 {
855 	struct weston_surface *main_surface =
856 		weston_surface_get_main_surface(view->surface);
857 	struct kiosk_shell_surface *shsurf =
858 		get_kiosk_shell_surface(main_surface);
859 
860 	if (!shsurf)
861 		return;
862 
863 	/* If the view belongs to a child window bring it to the front.
864 	 * We don't do this for the parent top-level, since that would
865 	 * obscure all children.
866 	 */
867 	if (shsurf->parent) {
868 		weston_layer_entry_remove(&view->layer_link);
869 		weston_layer_entry_insert(&shell->normal_layer.view_list,
870 					  &view->layer_link);
871 		weston_view_geometry_dirty(view);
872 		weston_surface_damage(view->surface);
873 	}
874 
875 	weston_view_activate(view, seat, flags);
876 }
877 
878 static void
kiosk_shell_click_to_activate_binding(struct weston_pointer * pointer,const struct timespec * time,uint32_t button,void * data)879 kiosk_shell_click_to_activate_binding(struct weston_pointer *pointer,
880 				      const struct timespec *time,
881 				      uint32_t button, void *data)
882 {
883 	struct kiosk_shell *shell = data;
884 
885 	if (pointer->grab != &pointer->default_grab)
886 		return;
887 	if (pointer->focus == NULL)
888 		return;
889 
890 	kiosk_shell_activate_view(shell, pointer->focus, pointer->seat,
891 				  WESTON_ACTIVATE_FLAG_CLICKED);
892 }
893 
894 static void
kiosk_shell_touch_to_activate_binding(struct weston_touch * touch,const struct timespec * time,void * data)895 kiosk_shell_touch_to_activate_binding(struct weston_touch *touch,
896 				      const struct timespec *time,
897 				      void *data)
898 {
899 	struct kiosk_shell *shell = data;
900 
901 	if (touch->grab != &touch->default_grab)
902 		return;
903 	if (touch->focus == NULL)
904 		return;
905 
906 	kiosk_shell_activate_view(shell, touch->focus, touch->seat,
907 				  WESTON_ACTIVATE_FLAG_NONE);
908 }
909 
910 static void
kiosk_shell_add_bindings(struct kiosk_shell * shell)911 kiosk_shell_add_bindings(struct kiosk_shell *shell)
912 {
913 	weston_compositor_add_button_binding(shell->compositor, BTN_LEFT, 0,
914 					     kiosk_shell_click_to_activate_binding,
915 					     shell);
916 	weston_compositor_add_button_binding(shell->compositor, BTN_RIGHT, 0,
917 					     kiosk_shell_click_to_activate_binding,
918 					     shell);
919 	weston_compositor_add_touch_binding(shell->compositor, 0,
920 					    kiosk_shell_touch_to_activate_binding,
921 					    shell);
922 }
923 
924 static void
kiosk_shell_handle_output_created(struct wl_listener * listener,void * data)925 kiosk_shell_handle_output_created(struct wl_listener *listener, void *data)
926 {
927 	struct kiosk_shell *shell =
928 		container_of(listener, struct kiosk_shell, output_created_listener);
929 	struct weston_output *output = data;
930 
931 	kiosk_shell_output_create(shell, output);
932 }
933 
934 static void
kiosk_shell_handle_output_resized(struct wl_listener * listener,void * data)935 kiosk_shell_handle_output_resized(struct wl_listener *listener, void *data)
936 {
937 	struct kiosk_shell *shell =
938 		container_of(listener, struct kiosk_shell, output_resized_listener);
939 	struct weston_output *output = data;
940 	struct kiosk_shell_output *shoutput =
941 		kiosk_shell_find_shell_output(shell, output);
942 	struct weston_view *view;
943 
944 	kiosk_shell_output_recreate_background(shoutput);
945 
946 	wl_list_for_each(view, &shell->normal_layer.view_list.link,
947 			 layer_link.link) {
948 		struct kiosk_shell_surface *shsurf;
949 		if (view->output != output)
950 			continue;
951 		shsurf = get_kiosk_shell_surface(view->surface);
952 		if (!shsurf)
953 			continue;
954 		kiosk_shell_surface_reconfigure_for_output(shsurf);
955 	}
956 }
957 
958 static void
kiosk_shell_handle_output_moved(struct wl_listener * listener,void * data)959 kiosk_shell_handle_output_moved(struct wl_listener *listener, void *data)
960 {
961 	struct kiosk_shell *shell =
962 		container_of(listener, struct kiosk_shell, output_moved_listener);
963 	struct weston_output *output = data;
964 	struct weston_view *view;
965 
966 	wl_list_for_each(view, &shell->background_layer.view_list.link,
967 			 layer_link.link) {
968 		if (view->output != output)
969 			continue;
970 		weston_view_set_position(view,
971 					 view->geometry.x + output->move_x,
972 					 view->geometry.y + output->move_y);
973 	}
974 
975 	wl_list_for_each(view, &shell->normal_layer.view_list.link,
976 			 layer_link.link) {
977 		if (view->output != output)
978 			continue;
979 		weston_view_set_position(view,
980 					 view->geometry.x + output->move_x,
981 					 view->geometry.y + output->move_y);
982 	}
983 }
984 
985 static void
kiosk_shell_handle_seat_created(struct wl_listener * listener,void * data)986 kiosk_shell_handle_seat_created(struct wl_listener *listener, void *data)
987 {
988 	struct weston_seat *seat = data;
989 	kiosk_shell_seat_create(seat);
990 }
991 
992 static void
kiosk_shell_destroy(struct wl_listener * listener,void * data)993 kiosk_shell_destroy(struct wl_listener *listener, void *data)
994 {
995 	struct kiosk_shell *shell =
996 		container_of(listener, struct kiosk_shell, destroy_listener);
997 	struct kiosk_shell_output *shoutput, *tmp;
998 
999 	wl_list_remove(&shell->destroy_listener.link);
1000 	wl_list_remove(&shell->output_created_listener.link);
1001 	wl_list_remove(&shell->output_resized_listener.link);
1002 	wl_list_remove(&shell->output_moved_listener.link);
1003 	wl_list_remove(&shell->seat_created_listener.link);
1004 
1005 	wl_list_for_each_safe(shoutput, tmp, &shell->output_list, link) {
1006 		kiosk_shell_output_destroy(shoutput);
1007 	}
1008 
1009 	weston_desktop_destroy(shell->desktop);
1010 
1011 	free(shell);
1012 }
1013 
1014 WL_EXPORT int
wet_shell_init(struct weston_compositor * ec,int * argc,char * argv[])1015 wet_shell_init(struct weston_compositor *ec,
1016 	       int *argc, char *argv[])
1017 {
1018 	struct kiosk_shell *shell;
1019 	struct weston_seat *seat;
1020 	struct weston_output *output;
1021 
1022 	shell = zalloc(sizeof *shell);
1023 	if (shell == NULL)
1024 		return -1;
1025 
1026 	shell->compositor = ec;
1027 
1028 	if (!weston_compositor_add_destroy_listener_once(ec,
1029 							 &shell->destroy_listener,
1030 							 kiosk_shell_destroy)) {
1031 		free(shell);
1032 		return 0;
1033 	}
1034 
1035 	weston_layer_init(&shell->background_layer, ec);
1036 	weston_layer_init(&shell->normal_layer, ec);
1037 
1038 	weston_layer_set_position(&shell->background_layer,
1039 				  WESTON_LAYER_POSITION_BACKGROUND);
1040 	/* We use the NORMAL layer position, so that xwayland surfaces, which
1041 	 * are placed at NORMAL+1, are visible.  */
1042 	weston_layer_set_position(&shell->normal_layer,
1043 				  WESTON_LAYER_POSITION_NORMAL);
1044 
1045 	shell->desktop = weston_desktop_create(ec, &kiosk_shell_desktop_api,
1046 					       shell);
1047 	if (!shell->desktop)
1048 		return -1;
1049 
1050 	wl_list_for_each(seat, &ec->seat_list, link)
1051 		kiosk_shell_seat_create(seat);
1052 	shell->seat_created_listener.notify = kiosk_shell_handle_seat_created;
1053 	wl_signal_add(&ec->seat_created_signal, &shell->seat_created_listener);
1054 
1055 	wl_list_init(&shell->output_list);
1056 	wl_list_for_each(output, &ec->output_list, link)
1057 		kiosk_shell_output_create(shell, output);
1058 
1059 	shell->output_created_listener.notify = kiosk_shell_handle_output_created;
1060 	wl_signal_add(&ec->output_created_signal, &shell->output_created_listener);
1061 
1062 	shell->output_resized_listener.notify = kiosk_shell_handle_output_resized;
1063 	wl_signal_add(&ec->output_resized_signal, &shell->output_resized_listener);
1064 
1065 	shell->output_moved_listener.notify = kiosk_shell_handle_output_moved;
1066 	wl_signal_add(&ec->output_moved_signal, &shell->output_moved_listener);
1067 
1068 	kiosk_shell_add_bindings(shell);
1069 
1070 	return 0;
1071 }
1072