blob: 9b81212d04c6e8730246c5151fedc1891ea41da5 [file] [log] [blame]
Jason Ekstrand946a9482014-04-02 19:53:47 -05001/*
2 * Copyright © 2013 Jason Ekstrand
3 *
Bryce Harringtonaf637c22015-06-11 12:55:55 -07004 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
Jason Ekstrand946a9482014-04-02 19:53:47 -050011 *
Bryce Harringtonaf637c22015-06-11 12:55:55 -070012 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial
14 * portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
Jason Ekstrand946a9482014-04-02 19:53:47 -050024 */
25
26#include "config.h"
27
28#include <sys/wait.h>
29#include <unistd.h>
30#include <stdlib.h>
31#include <stdio.h>
32#include <string.h>
33#include <assert.h>
34
35#include "compositor.h"
36#include "fullscreen-shell-server-protocol.h"
37
38struct fullscreen_shell {
39 struct wl_client *client;
40 struct wl_listener client_destroyed;
41 struct weston_compositor *compositor;
42
43 struct weston_layer layer;
44 struct wl_list output_list;
45 struct wl_listener output_created_listener;
46
47 struct wl_listener seat_created_listener;
48};
49
50struct fs_output {
51 struct fullscreen_shell *shell;
52 struct wl_list link;
53
54 struct weston_output *output;
55 struct wl_listener output_destroyed;
56
57 struct {
58 struct weston_surface *surface;
59 struct wl_listener surface_destroyed;
60 struct wl_resource *mode_feedback;
61
62 int presented_for_mode;
63 enum _wl_fullscreen_shell_present_method method;
64 int32_t framerate;
65 } pending;
66
67 struct weston_surface *surface;
68 struct wl_listener surface_destroyed;
69 struct weston_view *view;
70 struct weston_view *black_view;
71 struct weston_transform transform; /* matrix from x, y */
72
73 int presented_for_mode;
74 enum _wl_fullscreen_shell_present_method method;
75 uint32_t framerate;
76};
77
78struct pointer_focus_listener {
79 struct fullscreen_shell *shell;
80 struct wl_listener pointer_focus;
81 struct wl_listener seat_caps;
82 struct wl_listener seat_destroyed;
83};
84
85static void
86pointer_focus_changed(struct wl_listener *listener, void *data)
87{
88 struct weston_pointer *pointer = data;
89
90 if (pointer->focus && pointer->focus->surface->resource)
91 weston_surface_activate(pointer->focus->surface, pointer->seat);
92}
93
94static void
95seat_caps_changed(struct wl_listener *l, void *data)
96{
97 struct weston_seat *seat = data;
98 struct pointer_focus_listener *listener;
99 struct fs_output *fsout;
100
101 listener = container_of(l, struct pointer_focus_listener, seat_caps);
102
103 /* no pointer */
104 if (seat->pointer) {
105 if (!listener->pointer_focus.link.prev) {
106 wl_signal_add(&seat->pointer->focus_signal,
107 &listener->pointer_focus);
108 }
109 } else {
110 if (listener->pointer_focus.link.prev) {
111 wl_list_remove(&listener->pointer_focus.link);
112 }
113 }
114
115 if (seat->keyboard && seat->keyboard->focus != NULL) {
116 wl_list_for_each(fsout, &listener->shell->output_list, link) {
117 if (fsout->surface) {
118 weston_surface_activate(fsout->surface, seat);
119 return;
120 }
121 }
122 }
123}
124
125static void
126seat_destroyed(struct wl_listener *l, void *data)
127{
128 struct pointer_focus_listener *listener;
129
130 listener = container_of(l, struct pointer_focus_listener,
131 seat_destroyed);
132
133 free(listener);
134}
135
136static void
137seat_created(struct wl_listener *l, void *data)
138{
139 struct weston_seat *seat = data;
140 struct pointer_focus_listener *listener;
141
142 listener = malloc(sizeof *listener);
143 if (!listener)
144 return;
145 memset(listener, 0, sizeof *listener);
146
147 listener->shell = container_of(l, struct fullscreen_shell,
148 seat_created_listener);
149 listener->pointer_focus.notify = pointer_focus_changed;
150 listener->seat_caps.notify = seat_caps_changed;
151 listener->seat_destroyed.notify = seat_destroyed;
152
153 wl_signal_add(&seat->destroy_signal, &listener->seat_destroyed);
154 wl_signal_add(&seat->updated_caps_signal, &listener->seat_caps);
155
156 seat_caps_changed(&listener->seat_caps, seat);
157}
158
159static void
160black_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
161{
162}
163
164static struct weston_view *
165create_black_surface(struct weston_compositor *ec, struct fs_output *fsout,
166 float x, float y, int w, int h)
167{
168 struct weston_surface *surface = NULL;
169 struct weston_view *view;
170
171 surface = weston_surface_create(ec);
172 if (surface == NULL) {
173 weston_log("no memory\n");
174 return NULL;
175 }
176 view = weston_view_create(surface);
177 if (!view) {
178 weston_surface_destroy(surface);
179 weston_log("no memory\n");
180 return NULL;
181 }
182
183 surface->configure = black_surface_configure;
184 surface->configure_private = fsout;
185 weston_surface_set_color(surface, 0.0f, 0.0f, 0.0f, 1.0f);
186 pixman_region32_fini(&surface->opaque);
187 pixman_region32_init_rect(&surface->opaque, 0, 0, w, h);
188 pixman_region32_fini(&surface->input);
189 pixman_region32_init_rect(&surface->input, 0, 0, w, h);
190
191 weston_surface_set_size(surface, w, h);
192 weston_view_set_position(view, x, y);
193
194 return view;
195}
196
197static void
198fs_output_set_surface(struct fs_output *fsout, struct weston_surface *surface,
199 enum _wl_fullscreen_shell_present_method method,
200 int32_t framerate, int presented_for_mode);
201static void
202fs_output_apply_pending(struct fs_output *fsout);
203static void
204fs_output_clear_pending(struct fs_output *fsout);
205
206static void
207fs_output_destroy(struct fs_output *fsout)
208{
209 fs_output_set_surface(fsout, NULL, 0, 0, 0);
210 fs_output_clear_pending(fsout);
211
212 wl_list_remove(&fsout->link);
213
214 if (fsout->output)
215 wl_list_remove(&fsout->output_destroyed.link);
216}
217
218static void
219output_destroyed(struct wl_listener *listener, void *data)
220{
221 struct fs_output *output = container_of(listener,
222 struct fs_output,
223 output_destroyed);
224 fs_output_destroy(output);
225}
226
227static void
228surface_destroyed(struct wl_listener *listener, void *data)
229{
230 struct fs_output *fsout = container_of(listener,
231 struct fs_output,
232 surface_destroyed);
233 fsout->surface = NULL;
234 fsout->view = NULL;
235}
236
237static void
238pending_surface_destroyed(struct wl_listener *listener, void *data)
239{
240 struct fs_output *fsout = container_of(listener,
241 struct fs_output,
242 pending.surface_destroyed);
243 fsout->pending.surface = NULL;
244}
245
246static struct fs_output *
247fs_output_create(struct fullscreen_shell *shell, struct weston_output *output)
248{
249 struct fs_output *fsout;
250
251 fsout = malloc(sizeof *fsout);
252 if (!fsout)
253 return NULL;
254 memset(fsout, 0, sizeof *fsout);
255
256 fsout->shell = shell;
257 wl_list_insert(&shell->output_list, &fsout->link);
258
259 fsout->output = output;
260 fsout->output_destroyed.notify = output_destroyed;
261 wl_signal_add(&output->destroy_signal, &fsout->output_destroyed);
262
263 fsout->surface_destroyed.notify = surface_destroyed;
264 fsout->pending.surface_destroyed.notify = pending_surface_destroyed;
265 fsout->black_view = create_black_surface(shell->compositor, fsout,
266 output->x, output->y,
267 output->width, output->height);
Giulio Camuffod1ceecf2014-07-29 21:57:24 +0300268 weston_layer_entry_insert(&shell->layer.view_list,
Jason Ekstrand946a9482014-04-02 19:53:47 -0500269 &fsout->black_view->layer_link);
270 wl_list_init(&fsout->transform.link);
271 return fsout;
272}
273
274static struct fs_output *
275fs_output_for_output(struct weston_output *output)
276{
277 struct wl_listener *listener;
278
279 if (!output)
280 return NULL;
281
282 listener = wl_signal_get(&output->destroy_signal, output_destroyed);
283
284 return container_of(listener, struct fs_output, output_destroyed);
285}
286
287static void
288restore_output_mode(struct weston_output *output)
289{
Derek Foreman6ae7bc92014-11-04 10:47:33 -0600290 if (output->original_mode)
291 weston_output_mode_switch_to_native(output);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500292}
293
294/*
295 * Returns the bounding box of a surface and all its sub-surfaces,
296 * in the surface coordinates system. */
297static void
298surface_subsurfaces_boundingbox(struct weston_surface *surface, int32_t *x,
299 int32_t *y, int32_t *w, int32_t *h) {
300 pixman_region32_t region;
301 pixman_box32_t *box;
302 struct weston_subsurface *subsurface;
303
304 pixman_region32_init_rect(&region, 0, 0,
305 surface->width,
306 surface->height);
307
308 wl_list_for_each(subsurface, &surface->subsurface_list, parent_link) {
309 pixman_region32_union_rect(&region, &region,
310 subsurface->position.x,
311 subsurface->position.y,
312 subsurface->surface->width,
313 subsurface->surface->height);
314 }
315
316 box = pixman_region32_extents(&region);
317 if (x)
318 *x = box->x1;
319 if (y)
320 *y = box->y1;
321 if (w)
322 *w = box->x2 - box->x1;
323 if (h)
324 *h = box->y2 - box->y1;
325
326 pixman_region32_fini(&region);
327}
328
329static void
330fs_output_center_view(struct fs_output *fsout)
331{
332 int32_t surf_x, surf_y, surf_width, surf_height;
333 float x, y;
334 struct weston_output *output = fsout->output;
335
336 surface_subsurfaces_boundingbox(fsout->view->surface, &surf_x, &surf_y,
337 &surf_width, &surf_height);
338
339 x = output->x + (output->width - surf_width) / 2 - surf_x / 2;
340 y = output->y + (output->height - surf_height) / 2 - surf_y / 2;
341
342 weston_view_set_position(fsout->view, x, y);
343}
344
345static void
346fs_output_scale_view(struct fs_output *fsout, float width, float height)
347{
348 float x, y;
349 int32_t surf_x, surf_y, surf_width, surf_height;
350 struct weston_matrix *matrix;
351 struct weston_view *view = fsout->view;
352 struct weston_output *output = fsout->output;
353
354 surface_subsurfaces_boundingbox(view->surface, &surf_x, &surf_y,
355 &surf_width, &surf_height);
356
357 if (output->width == surf_width && output->height == surf_height) {
358 weston_view_set_position(view,
359 fsout->output->x - surf_x,
360 fsout->output->y - surf_y);
361 } else {
362 matrix = &fsout->transform.matrix;
363 weston_matrix_init(matrix);
364
365 weston_matrix_scale(matrix, width / surf_width,
366 height / surf_height, 1);
367 wl_list_remove(&fsout->transform.link);
368 wl_list_insert(&fsout->view->geometry.transformation_list,
369 &fsout->transform.link);
370
371 x = output->x + (output->width - width) / 2 - surf_x;
372 y = output->y + (output->height - height) / 2 - surf_y;
373
374 weston_view_set_position(view, x, y);
375 }
376}
377
378static void
379fs_output_configure(struct fs_output *fsout, struct weston_surface *surface);
380
381static void
382fs_output_configure_simple(struct fs_output *fsout,
383 struct weston_surface *configured_surface)
384{
385 struct weston_output *output = fsout->output;
386 float output_aspect, surface_aspect;
387 int32_t surf_x, surf_y, surf_width, surf_height;
388
389 if (fsout->pending.surface == configured_surface)
390 fs_output_apply_pending(fsout);
391
392 assert(fsout->view);
393
394 restore_output_mode(fsout->output);
395
396 wl_list_remove(&fsout->transform.link);
397 wl_list_init(&fsout->transform.link);
398
399 surface_subsurfaces_boundingbox(fsout->view->surface,
400 &surf_x, &surf_y,
401 &surf_width, &surf_height);
402
403 output_aspect = (float) output->width / (float) output->height;
404 surface_aspect = (float) surf_width / (float) surf_height;
405
406 switch (fsout->method) {
407 case _WL_FULLSCREEN_SHELL_PRESENT_METHOD_DEFAULT:
408 case _WL_FULLSCREEN_SHELL_PRESENT_METHOD_CENTER:
409 fs_output_center_view(fsout);
410 break;
411
412 case _WL_FULLSCREEN_SHELL_PRESENT_METHOD_ZOOM:
413 if (output_aspect < surface_aspect)
414 fs_output_scale_view(fsout,
415 output->width,
416 output->width / surface_aspect);
417 else
418 fs_output_scale_view(fsout,
419 output->height * surface_aspect,
420 output->height);
421 break;
422
423 case _WL_FULLSCREEN_SHELL_PRESENT_METHOD_ZOOM_CROP:
424 if (output_aspect < surface_aspect)
425 fs_output_scale_view(fsout,
426 output->height * surface_aspect,
427 output->height);
428 else
429 fs_output_scale_view(fsout,
430 output->width,
431 output->width / surface_aspect);
432 break;
433
434 case _WL_FULLSCREEN_SHELL_PRESENT_METHOD_STRETCH:
435 fs_output_scale_view(fsout, output->width, output->height);
436 break;
437 default:
438 break;
439 }
440
441 weston_view_set_position(fsout->black_view,
442 fsout->output->x - surf_x,
443 fsout->output->y - surf_y);
444 weston_surface_set_size(fsout->black_view->surface,
445 fsout->output->width,
446 fsout->output->height);
447}
448
449static void
450fs_output_configure_for_mode(struct fs_output *fsout,
451 struct weston_surface *configured_surface)
452{
453 int32_t surf_x, surf_y, surf_width, surf_height;
454 struct weston_mode mode;
455 int ret;
456
457 if (fsout->pending.surface != configured_surface) {
458 /* Nothing to really reconfigure. We'll just recenter the
459 * view in case they played with subsurfaces */
460 fs_output_center_view(fsout);
461 return;
462 }
463
464 /* We have a pending surface */
465 surface_subsurfaces_boundingbox(fsout->pending.surface,
466 &surf_x, &surf_y,
467 &surf_width, &surf_height);
468
469 mode.flags = 0;
470 mode.width = surf_width * fsout->output->native_scale;
471 mode.height = surf_height * fsout->output->native_scale;
472 mode.refresh = fsout->pending.framerate;
473
Derek Foreman6ae7bc92014-11-04 10:47:33 -0600474 ret = weston_output_mode_switch_to_temporary(fsout->output, &mode,
475 fsout->output->native_scale);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500476
477 if (ret != 0) {
478 /* The mode switch failed. Clear the pending and
479 * reconfigure as per normal */
480 if (fsout->pending.mode_feedback) {
481 _wl_fullscreen_shell_mode_feedback_send_mode_failed(
482 fsout->pending.mode_feedback);
483 wl_resource_destroy(fsout->pending.mode_feedback);
484 fsout->pending.mode_feedback = NULL;
485 }
486
487 fs_output_clear_pending(fsout);
488 return;
489 }
490
491 if (fsout->pending.mode_feedback) {
492 _wl_fullscreen_shell_mode_feedback_send_mode_successful(
493 fsout->pending.mode_feedback);
494 wl_resource_destroy(fsout->pending.mode_feedback);
495 fsout->pending.mode_feedback = NULL;
496 }
497
498 fs_output_apply_pending(fsout);
499
500 weston_view_set_position(fsout->view,
501 fsout->output->x - surf_x,
502 fsout->output->y - surf_y);
503}
504
505static void
506fs_output_configure(struct fs_output *fsout,
507 struct weston_surface *surface)
508{
509 if (fsout->pending.surface == surface) {
510 if (fsout->pending.presented_for_mode)
511 fs_output_configure_for_mode(fsout, surface);
512 else
513 fs_output_configure_simple(fsout, surface);
514 } else {
515 if (fsout->presented_for_mode)
516 fs_output_configure_for_mode(fsout, surface);
517 else
518 fs_output_configure_simple(fsout, surface);
519 }
520
521 weston_output_schedule_repaint(fsout->output);
522}
523
524static void
525configure_presented_surface(struct weston_surface *surface, int32_t sx,
526 int32_t sy)
527{
528 struct fullscreen_shell *shell = surface->configure_private;
529 struct fs_output *fsout;
530
531 if (surface->configure != configure_presented_surface)
532 return;
533
534 wl_list_for_each(fsout, &shell->output_list, link)
535 if (fsout->surface == surface ||
536 fsout->pending.surface == surface)
537 fs_output_configure(fsout, surface);
538}
539
540static void
541fs_output_apply_pending(struct fs_output *fsout)
542{
543 assert(fsout->pending.surface);
544
545 if (fsout->surface && fsout->surface != fsout->pending.surface) {
546 wl_list_remove(&fsout->surface_destroyed.link);
547
548 weston_view_destroy(fsout->view);
549 fsout->view = NULL;
550
551 if (wl_list_empty(&fsout->surface->views)) {
552 fsout->surface->configure = NULL;
553 fsout->surface->configure_private = NULL;
554 }
555
556 fsout->surface = NULL;
557 }
558
559 fsout->method = fsout->pending.method;
560 fsout->framerate = fsout->pending.framerate;
561 fsout->presented_for_mode = fsout->pending.presented_for_mode;
562
563 if (fsout->surface != fsout->pending.surface) {
564 fsout->surface = fsout->pending.surface;
565
566 fsout->view = weston_view_create(fsout->surface);
567 if (!fsout->view) {
568 weston_log("no memory\n");
569 return;
570 }
571
572 wl_signal_add(&fsout->surface->destroy_signal,
573 &fsout->surface_destroyed);
Giulio Camuffod1ceecf2014-07-29 21:57:24 +0300574 weston_layer_entry_insert(&fsout->shell->layer.view_list,
Jason Ekstrand946a9482014-04-02 19:53:47 -0500575 &fsout->view->layer_link);
576 }
577
578 fs_output_clear_pending(fsout);
579}
580
581static void
582fs_output_clear_pending(struct fs_output *fsout)
583{
584 if (!fsout->pending.surface)
585 return;
586
587 if (fsout->pending.mode_feedback) {
588 _wl_fullscreen_shell_mode_feedback_send_present_cancelled(
589 fsout->pending.mode_feedback);
590 wl_resource_destroy(fsout->pending.mode_feedback);
591 fsout->pending.mode_feedback = NULL;
592 }
593
594 wl_list_remove(&fsout->pending.surface_destroyed.link);
595 fsout->pending.surface = NULL;
596}
597
598static void
599fs_output_set_surface(struct fs_output *fsout, struct weston_surface *surface,
600 enum _wl_fullscreen_shell_present_method method,
601 int32_t framerate, int presented_for_mode)
602{
603 fs_output_clear_pending(fsout);
604
605 if (surface) {
606 if (!surface->configure) {
607 surface->configure = configure_presented_surface;
608 surface->configure_private = fsout->shell;
609 }
610
611 fsout->pending.surface = surface;
612 wl_signal_add(&fsout->pending.surface->destroy_signal,
613 &fsout->pending.surface_destroyed);
614
615 fsout->pending.method = method;
616 fsout->pending.framerate = framerate;
617 fsout->pending.presented_for_mode = presented_for_mode;
618 } else if (fsout->surface) {
619 /* we clear immediately */
620 wl_list_remove(&fsout->surface_destroyed.link);
621
622 weston_view_destroy(fsout->view);
623 fsout->view = NULL;
624
625 if (wl_list_empty(&fsout->surface->views)) {
626 fsout->surface->configure = NULL;
627 fsout->surface->configure_private = NULL;
628 }
629
630 fsout->surface = NULL;
631
632 weston_output_schedule_repaint(fsout->output);
633 }
634}
635
636static void
637fullscreen_shell_release(struct wl_client *client,
638 struct wl_resource *resource)
639{
640 wl_resource_destroy(resource);
641}
642
643static void
644fullscreen_shell_present_surface(struct wl_client *client,
645 struct wl_resource *resource,
646 struct wl_resource *surface_res,
647 uint32_t method,
648 struct wl_resource *output_res)
649{
650 struct fullscreen_shell *shell =
651 wl_resource_get_user_data(resource);
652 struct weston_output *output;
653 struct weston_surface *surface;
654 struct weston_seat *seat;
655 struct fs_output *fsout;
656
657 surface = surface_res ? wl_resource_get_user_data(surface_res) : NULL;
658
659 switch(method) {
660 case _WL_FULLSCREEN_SHELL_PRESENT_METHOD_DEFAULT:
661 case _WL_FULLSCREEN_SHELL_PRESENT_METHOD_CENTER:
662 case _WL_FULLSCREEN_SHELL_PRESENT_METHOD_ZOOM:
663 case _WL_FULLSCREEN_SHELL_PRESENT_METHOD_ZOOM_CROP:
664 case _WL_FULLSCREEN_SHELL_PRESENT_METHOD_STRETCH:
665 break;
666 default:
667 wl_resource_post_error(resource,
668 _WL_FULLSCREEN_SHELL_ERROR_INVALID_METHOD,
669 "Invalid presentation method");
670 }
671
672 if (output_res) {
673 output = wl_resource_get_user_data(output_res);
674 fsout = fs_output_for_output(output);
675 fs_output_set_surface(fsout, surface, method, 0, 0);
676 } else {
677 wl_list_for_each(fsout, &shell->output_list, link)
678 fs_output_set_surface(fsout, surface, method, 0, 0);
679 }
680
681 if (surface) {
682 wl_list_for_each(seat, &shell->compositor->seat_list, link) {
683 if (seat->keyboard && seat->keyboard->focus == NULL)
684 weston_surface_activate(surface, seat);
685 }
686 }
687}
688
689static void
690mode_feedback_destroyed(struct wl_resource *resource)
691{
692 struct fs_output *fsout = wl_resource_get_user_data(resource);
693
694 fsout->pending.mode_feedback = NULL;
695}
696
697static void
698fullscreen_shell_present_surface_for_mode(struct wl_client *client,
699 struct wl_resource *resource,
700 struct wl_resource *surface_res,
701 struct wl_resource *output_res,
702 int32_t framerate,
703 uint32_t feedback_id)
704{
705 struct fullscreen_shell *shell =
706 wl_resource_get_user_data(resource);
707 struct weston_output *output;
708 struct weston_surface *surface;
709 struct weston_seat *seat;
710 struct fs_output *fsout;
711
712 output = wl_resource_get_user_data(output_res);
713 fsout = fs_output_for_output(output);
714
715 if (surface_res == NULL) {
716 fs_output_set_surface(fsout, NULL, 0, 0, 0);
717 return;
718 }
719
720 surface = wl_resource_get_user_data(surface_res);
721 fs_output_set_surface(fsout, surface, 0, framerate, 1);
722
723 fsout->pending.mode_feedback =
724 wl_resource_create(client,
725 &_wl_fullscreen_shell_mode_feedback_interface,
726 1, feedback_id);
727 wl_resource_set_implementation(fsout->pending.mode_feedback, NULL,
728 fsout, mode_feedback_destroyed);
729
730 wl_list_for_each(seat, &shell->compositor->seat_list, link) {
731 if (seat->keyboard && seat->keyboard->focus == NULL)
732 weston_surface_activate(surface, seat);
733 }
734}
735
736struct _wl_fullscreen_shell_interface fullscreen_shell_implementation = {
737 fullscreen_shell_release,
738 fullscreen_shell_present_surface,
739 fullscreen_shell_present_surface_for_mode,
740};
741
742static void
743output_created(struct wl_listener *listener, void *data)
744{
745 struct fullscreen_shell *shell;
746
747 shell = container_of(listener, struct fullscreen_shell,
748 output_created_listener);
749
750 fs_output_create(shell, data);
751}
752
753static void
754client_destroyed(struct wl_listener *listener, void *data)
755{
756 struct fullscreen_shell *shell = container_of(listener,
757 struct fullscreen_shell,
758 client_destroyed);
759 shell->client = NULL;
760}
761
762static void
763bind_fullscreen_shell(struct wl_client *client, void *data, uint32_t version,
764 uint32_t id)
765{
766 struct fullscreen_shell *shell = data;
767 struct wl_resource *resource;
768
769 if (shell->client != NULL && shell->client != client)
770 return;
771 else if (shell->client == NULL) {
772 shell->client = client;
773 wl_client_add_destroy_listener(client, &shell->client_destroyed);
774 }
775
776 resource = wl_resource_create(client, &_wl_fullscreen_shell_interface,
777 1, id);
778 wl_resource_set_implementation(resource,
779 &fullscreen_shell_implementation,
780 shell, NULL);
781
782 if (shell->compositor->capabilities & WESTON_CAP_CURSOR_PLANE)
783 _wl_fullscreen_shell_send_capability(resource,
784 _WL_FULLSCREEN_SHELL_CAPABILITY_CURSOR_PLANE);
785
786 if (shell->compositor->capabilities & WESTON_CAP_ARBITRARY_MODES)
787 _wl_fullscreen_shell_send_capability(resource,
788 _WL_FULLSCREEN_SHELL_CAPABILITY_ARBITRARY_MODES);
789}
790
791WL_EXPORT int
792module_init(struct weston_compositor *compositor,
793 int *argc, char *argv[])
794{
795 struct fullscreen_shell *shell;
796 struct weston_seat *seat;
797 struct weston_output *output;
798
799 shell = malloc(sizeof *shell);
800 if (shell == NULL)
801 return -1;
802
803 memset(shell, 0, sizeof *shell);
804 shell->compositor = compositor;
805
806 shell->client_destroyed.notify = client_destroyed;
807
808 weston_layer_init(&shell->layer, &compositor->cursor_layer.link);
809
810 wl_list_init(&shell->output_list);
811 shell->output_created_listener.notify = output_created;
812 wl_signal_add(&compositor->output_created_signal,
813 &shell->output_created_listener);
814 wl_list_for_each(output, &compositor->output_list, link)
815 fs_output_create(shell, output);
816
817 shell->seat_created_listener.notify = seat_created;
818 wl_signal_add(&compositor->seat_created_signal,
819 &shell->seat_created_listener);
820 wl_list_for_each(seat, &compositor->seat_list, link)
821 seat_created(NULL, seat);
822
823 wl_global_create(compositor->wl_display,
824 &_wl_fullscreen_shell_interface, 1, shell,
825 bind_fullscreen_shell);
826
827 return 0;
828}