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