blob: 35e6d8fd92451e56a1a64e99be8dee21b96421c2 [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);
Giulio Camuffod1ceecf2014-07-29 21:57:24 +0300265 weston_layer_entry_insert(&shell->layer.view_list,
Jason Ekstrand946a9482014-04-02 19:53:47 -0500266 &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{
Derek Foreman6ae7bc92014-11-04 10:47:33 -0600287 if (output->original_mode)
288 weston_output_mode_switch_to_native(output);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500289}
290
291/*
292 * Returns the bounding box of a surface and all its sub-surfaces,
293 * in the surface coordinates system. */
294static void
295surface_subsurfaces_boundingbox(struct weston_surface *surface, int32_t *x,
296 int32_t *y, int32_t *w, int32_t *h) {
297 pixman_region32_t region;
298 pixman_box32_t *box;
299 struct weston_subsurface *subsurface;
300
301 pixman_region32_init_rect(&region, 0, 0,
302 surface->width,
303 surface->height);
304
305 wl_list_for_each(subsurface, &surface->subsurface_list, parent_link) {
306 pixman_region32_union_rect(&region, &region,
307 subsurface->position.x,
308 subsurface->position.y,
309 subsurface->surface->width,
310 subsurface->surface->height);
311 }
312
313 box = pixman_region32_extents(&region);
314 if (x)
315 *x = box->x1;
316 if (y)
317 *y = box->y1;
318 if (w)
319 *w = box->x2 - box->x1;
320 if (h)
321 *h = box->y2 - box->y1;
322
323 pixman_region32_fini(&region);
324}
325
326static void
327fs_output_center_view(struct fs_output *fsout)
328{
329 int32_t surf_x, surf_y, surf_width, surf_height;
330 float x, y;
331 struct weston_output *output = fsout->output;
332
333 surface_subsurfaces_boundingbox(fsout->view->surface, &surf_x, &surf_y,
334 &surf_width, &surf_height);
335
336 x = output->x + (output->width - surf_width) / 2 - surf_x / 2;
337 y = output->y + (output->height - surf_height) / 2 - surf_y / 2;
338
339 weston_view_set_position(fsout->view, x, y);
340}
341
342static void
343fs_output_scale_view(struct fs_output *fsout, float width, float height)
344{
345 float x, y;
346 int32_t surf_x, surf_y, surf_width, surf_height;
347 struct weston_matrix *matrix;
348 struct weston_view *view = fsout->view;
349 struct weston_output *output = fsout->output;
350
351 surface_subsurfaces_boundingbox(view->surface, &surf_x, &surf_y,
352 &surf_width, &surf_height);
353
354 if (output->width == surf_width && output->height == surf_height) {
355 weston_view_set_position(view,
356 fsout->output->x - surf_x,
357 fsout->output->y - surf_y);
358 } else {
359 matrix = &fsout->transform.matrix;
360 weston_matrix_init(matrix);
361
362 weston_matrix_scale(matrix, width / surf_width,
363 height / surf_height, 1);
364 wl_list_remove(&fsout->transform.link);
365 wl_list_insert(&fsout->view->geometry.transformation_list,
366 &fsout->transform.link);
367
368 x = output->x + (output->width - width) / 2 - surf_x;
369 y = output->y + (output->height - height) / 2 - surf_y;
370
371 weston_view_set_position(view, x, y);
372 }
373}
374
375static void
376fs_output_configure(struct fs_output *fsout, struct weston_surface *surface);
377
378static void
379fs_output_configure_simple(struct fs_output *fsout,
380 struct weston_surface *configured_surface)
381{
382 struct weston_output *output = fsout->output;
383 float output_aspect, surface_aspect;
384 int32_t surf_x, surf_y, surf_width, surf_height;
385
386 if (fsout->pending.surface == configured_surface)
387 fs_output_apply_pending(fsout);
388
389 assert(fsout->view);
390
391 restore_output_mode(fsout->output);
392
393 wl_list_remove(&fsout->transform.link);
394 wl_list_init(&fsout->transform.link);
395
396 surface_subsurfaces_boundingbox(fsout->view->surface,
397 &surf_x, &surf_y,
398 &surf_width, &surf_height);
399
400 output_aspect = (float) output->width / (float) output->height;
401 surface_aspect = (float) surf_width / (float) surf_height;
402
403 switch (fsout->method) {
404 case _WL_FULLSCREEN_SHELL_PRESENT_METHOD_DEFAULT:
405 case _WL_FULLSCREEN_SHELL_PRESENT_METHOD_CENTER:
406 fs_output_center_view(fsout);
407 break;
408
409 case _WL_FULLSCREEN_SHELL_PRESENT_METHOD_ZOOM:
410 if (output_aspect < surface_aspect)
411 fs_output_scale_view(fsout,
412 output->width,
413 output->width / surface_aspect);
414 else
415 fs_output_scale_view(fsout,
416 output->height * surface_aspect,
417 output->height);
418 break;
419
420 case _WL_FULLSCREEN_SHELL_PRESENT_METHOD_ZOOM_CROP:
421 if (output_aspect < surface_aspect)
422 fs_output_scale_view(fsout,
423 output->height * surface_aspect,
424 output->height);
425 else
426 fs_output_scale_view(fsout,
427 output->width,
428 output->width / surface_aspect);
429 break;
430
431 case _WL_FULLSCREEN_SHELL_PRESENT_METHOD_STRETCH:
432 fs_output_scale_view(fsout, output->width, output->height);
433 break;
434 default:
435 break;
436 }
437
438 weston_view_set_position(fsout->black_view,
439 fsout->output->x - surf_x,
440 fsout->output->y - surf_y);
441 weston_surface_set_size(fsout->black_view->surface,
442 fsout->output->width,
443 fsout->output->height);
444}
445
446static void
447fs_output_configure_for_mode(struct fs_output *fsout,
448 struct weston_surface *configured_surface)
449{
450 int32_t surf_x, surf_y, surf_width, surf_height;
451 struct weston_mode mode;
452 int ret;
453
454 if (fsout->pending.surface != configured_surface) {
455 /* Nothing to really reconfigure. We'll just recenter the
456 * view in case they played with subsurfaces */
457 fs_output_center_view(fsout);
458 return;
459 }
460
461 /* We have a pending surface */
462 surface_subsurfaces_boundingbox(fsout->pending.surface,
463 &surf_x, &surf_y,
464 &surf_width, &surf_height);
465
466 mode.flags = 0;
467 mode.width = surf_width * fsout->output->native_scale;
468 mode.height = surf_height * fsout->output->native_scale;
469 mode.refresh = fsout->pending.framerate;
470
Derek Foreman6ae7bc92014-11-04 10:47:33 -0600471 ret = weston_output_mode_switch_to_temporary(fsout->output, &mode,
472 fsout->output->native_scale);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500473
474 if (ret != 0) {
475 /* The mode switch failed. Clear the pending and
476 * reconfigure as per normal */
477 if (fsout->pending.mode_feedback) {
478 _wl_fullscreen_shell_mode_feedback_send_mode_failed(
479 fsout->pending.mode_feedback);
480 wl_resource_destroy(fsout->pending.mode_feedback);
481 fsout->pending.mode_feedback = NULL;
482 }
483
484 fs_output_clear_pending(fsout);
485 return;
486 }
487
488 if (fsout->pending.mode_feedback) {
489 _wl_fullscreen_shell_mode_feedback_send_mode_successful(
490 fsout->pending.mode_feedback);
491 wl_resource_destroy(fsout->pending.mode_feedback);
492 fsout->pending.mode_feedback = NULL;
493 }
494
495 fs_output_apply_pending(fsout);
496
497 weston_view_set_position(fsout->view,
498 fsout->output->x - surf_x,
499 fsout->output->y - surf_y);
500}
501
502static void
503fs_output_configure(struct fs_output *fsout,
504 struct weston_surface *surface)
505{
506 if (fsout->pending.surface == surface) {
507 if (fsout->pending.presented_for_mode)
508 fs_output_configure_for_mode(fsout, surface);
509 else
510 fs_output_configure_simple(fsout, surface);
511 } else {
512 if (fsout->presented_for_mode)
513 fs_output_configure_for_mode(fsout, surface);
514 else
515 fs_output_configure_simple(fsout, surface);
516 }
517
518 weston_output_schedule_repaint(fsout->output);
519}
520
521static void
522configure_presented_surface(struct weston_surface *surface, int32_t sx,
523 int32_t sy)
524{
525 struct fullscreen_shell *shell = surface->configure_private;
526 struct fs_output *fsout;
527
528 if (surface->configure != configure_presented_surface)
529 return;
530
531 wl_list_for_each(fsout, &shell->output_list, link)
532 if (fsout->surface == surface ||
533 fsout->pending.surface == surface)
534 fs_output_configure(fsout, surface);
535}
536
537static void
538fs_output_apply_pending(struct fs_output *fsout)
539{
540 assert(fsout->pending.surface);
541
542 if (fsout->surface && fsout->surface != fsout->pending.surface) {
543 wl_list_remove(&fsout->surface_destroyed.link);
544
545 weston_view_destroy(fsout->view);
546 fsout->view = NULL;
547
548 if (wl_list_empty(&fsout->surface->views)) {
549 fsout->surface->configure = NULL;
550 fsout->surface->configure_private = NULL;
551 }
552
553 fsout->surface = NULL;
554 }
555
556 fsout->method = fsout->pending.method;
557 fsout->framerate = fsout->pending.framerate;
558 fsout->presented_for_mode = fsout->pending.presented_for_mode;
559
560 if (fsout->surface != fsout->pending.surface) {
561 fsout->surface = fsout->pending.surface;
562
563 fsout->view = weston_view_create(fsout->surface);
564 if (!fsout->view) {
565 weston_log("no memory\n");
566 return;
567 }
568
569 wl_signal_add(&fsout->surface->destroy_signal,
570 &fsout->surface_destroyed);
Giulio Camuffod1ceecf2014-07-29 21:57:24 +0300571 weston_layer_entry_insert(&fsout->shell->layer.view_list,
Jason Ekstrand946a9482014-04-02 19:53:47 -0500572 &fsout->view->layer_link);
573 }
574
575 fs_output_clear_pending(fsout);
576}
577
578static void
579fs_output_clear_pending(struct fs_output *fsout)
580{
581 if (!fsout->pending.surface)
582 return;
583
584 if (fsout->pending.mode_feedback) {
585 _wl_fullscreen_shell_mode_feedback_send_present_cancelled(
586 fsout->pending.mode_feedback);
587 wl_resource_destroy(fsout->pending.mode_feedback);
588 fsout->pending.mode_feedback = NULL;
589 }
590
591 wl_list_remove(&fsout->pending.surface_destroyed.link);
592 fsout->pending.surface = NULL;
593}
594
595static void
596fs_output_set_surface(struct fs_output *fsout, struct weston_surface *surface,
597 enum _wl_fullscreen_shell_present_method method,
598 int32_t framerate, int presented_for_mode)
599{
600 fs_output_clear_pending(fsout);
601
602 if (surface) {
603 if (!surface->configure) {
604 surface->configure = configure_presented_surface;
605 surface->configure_private = fsout->shell;
606 }
607
608 fsout->pending.surface = surface;
609 wl_signal_add(&fsout->pending.surface->destroy_signal,
610 &fsout->pending.surface_destroyed);
611
612 fsout->pending.method = method;
613 fsout->pending.framerate = framerate;
614 fsout->pending.presented_for_mode = presented_for_mode;
615 } else if (fsout->surface) {
616 /* we clear immediately */
617 wl_list_remove(&fsout->surface_destroyed.link);
618
619 weston_view_destroy(fsout->view);
620 fsout->view = NULL;
621
622 if (wl_list_empty(&fsout->surface->views)) {
623 fsout->surface->configure = NULL;
624 fsout->surface->configure_private = NULL;
625 }
626
627 fsout->surface = NULL;
628
629 weston_output_schedule_repaint(fsout->output);
630 }
631}
632
633static void
634fullscreen_shell_release(struct wl_client *client,
635 struct wl_resource *resource)
636{
637 wl_resource_destroy(resource);
638}
639
640static void
641fullscreen_shell_present_surface(struct wl_client *client,
642 struct wl_resource *resource,
643 struct wl_resource *surface_res,
644 uint32_t method,
645 struct wl_resource *output_res)
646{
647 struct fullscreen_shell *shell =
648 wl_resource_get_user_data(resource);
649 struct weston_output *output;
650 struct weston_surface *surface;
651 struct weston_seat *seat;
652 struct fs_output *fsout;
653
654 surface = surface_res ? wl_resource_get_user_data(surface_res) : NULL;
655
656 switch(method) {
657 case _WL_FULLSCREEN_SHELL_PRESENT_METHOD_DEFAULT:
658 case _WL_FULLSCREEN_SHELL_PRESENT_METHOD_CENTER:
659 case _WL_FULLSCREEN_SHELL_PRESENT_METHOD_ZOOM:
660 case _WL_FULLSCREEN_SHELL_PRESENT_METHOD_ZOOM_CROP:
661 case _WL_FULLSCREEN_SHELL_PRESENT_METHOD_STRETCH:
662 break;
663 default:
664 wl_resource_post_error(resource,
665 _WL_FULLSCREEN_SHELL_ERROR_INVALID_METHOD,
666 "Invalid presentation method");
667 }
668
669 if (output_res) {
670 output = wl_resource_get_user_data(output_res);
671 fsout = fs_output_for_output(output);
672 fs_output_set_surface(fsout, surface, method, 0, 0);
673 } else {
674 wl_list_for_each(fsout, &shell->output_list, link)
675 fs_output_set_surface(fsout, surface, method, 0, 0);
676 }
677
678 if (surface) {
679 wl_list_for_each(seat, &shell->compositor->seat_list, link) {
680 if (seat->keyboard && seat->keyboard->focus == NULL)
681 weston_surface_activate(surface, seat);
682 }
683 }
684}
685
686static void
687mode_feedback_destroyed(struct wl_resource *resource)
688{
689 struct fs_output *fsout = wl_resource_get_user_data(resource);
690
691 fsout->pending.mode_feedback = NULL;
692}
693
694static void
695fullscreen_shell_present_surface_for_mode(struct wl_client *client,
696 struct wl_resource *resource,
697 struct wl_resource *surface_res,
698 struct wl_resource *output_res,
699 int32_t framerate,
700 uint32_t feedback_id)
701{
702 struct fullscreen_shell *shell =
703 wl_resource_get_user_data(resource);
704 struct weston_output *output;
705 struct weston_surface *surface;
706 struct weston_seat *seat;
707 struct fs_output *fsout;
708
709 output = wl_resource_get_user_data(output_res);
710 fsout = fs_output_for_output(output);
711
712 if (surface_res == NULL) {
713 fs_output_set_surface(fsout, NULL, 0, 0, 0);
714 return;
715 }
716
717 surface = wl_resource_get_user_data(surface_res);
718 fs_output_set_surface(fsout, surface, 0, framerate, 1);
719
720 fsout->pending.mode_feedback =
721 wl_resource_create(client,
722 &_wl_fullscreen_shell_mode_feedback_interface,
723 1, feedback_id);
724 wl_resource_set_implementation(fsout->pending.mode_feedback, NULL,
725 fsout, mode_feedback_destroyed);
726
727 wl_list_for_each(seat, &shell->compositor->seat_list, link) {
728 if (seat->keyboard && seat->keyboard->focus == NULL)
729 weston_surface_activate(surface, seat);
730 }
731}
732
733struct _wl_fullscreen_shell_interface fullscreen_shell_implementation = {
734 fullscreen_shell_release,
735 fullscreen_shell_present_surface,
736 fullscreen_shell_present_surface_for_mode,
737};
738
739static void
740output_created(struct wl_listener *listener, void *data)
741{
742 struct fullscreen_shell *shell;
743
744 shell = container_of(listener, struct fullscreen_shell,
745 output_created_listener);
746
747 fs_output_create(shell, data);
748}
749
750static void
751client_destroyed(struct wl_listener *listener, void *data)
752{
753 struct fullscreen_shell *shell = container_of(listener,
754 struct fullscreen_shell,
755 client_destroyed);
756 shell->client = NULL;
757}
758
759static void
760bind_fullscreen_shell(struct wl_client *client, void *data, uint32_t version,
761 uint32_t id)
762{
763 struct fullscreen_shell *shell = data;
764 struct wl_resource *resource;
765
766 if (shell->client != NULL && shell->client != client)
767 return;
768 else if (shell->client == NULL) {
769 shell->client = client;
770 wl_client_add_destroy_listener(client, &shell->client_destroyed);
771 }
772
773 resource = wl_resource_create(client, &_wl_fullscreen_shell_interface,
774 1, id);
775 wl_resource_set_implementation(resource,
776 &fullscreen_shell_implementation,
777 shell, NULL);
778
779 if (shell->compositor->capabilities & WESTON_CAP_CURSOR_PLANE)
780 _wl_fullscreen_shell_send_capability(resource,
781 _WL_FULLSCREEN_SHELL_CAPABILITY_CURSOR_PLANE);
782
783 if (shell->compositor->capabilities & WESTON_CAP_ARBITRARY_MODES)
784 _wl_fullscreen_shell_send_capability(resource,
785 _WL_FULLSCREEN_SHELL_CAPABILITY_ARBITRARY_MODES);
786}
787
788WL_EXPORT int
789module_init(struct weston_compositor *compositor,
790 int *argc, char *argv[])
791{
792 struct fullscreen_shell *shell;
793 struct weston_seat *seat;
794 struct weston_output *output;
795
796 shell = malloc(sizeof *shell);
797 if (shell == NULL)
798 return -1;
799
800 memset(shell, 0, sizeof *shell);
801 shell->compositor = compositor;
802
803 shell->client_destroyed.notify = client_destroyed;
804
805 weston_layer_init(&shell->layer, &compositor->cursor_layer.link);
806
807 wl_list_init(&shell->output_list);
808 shell->output_created_listener.notify = output_created;
809 wl_signal_add(&compositor->output_created_signal,
810 &shell->output_created_listener);
811 wl_list_for_each(output, &compositor->output_list, link)
812 fs_output_create(shell, output);
813
814 shell->seat_created_listener.notify = seat_created;
815 wl_signal_add(&compositor->seat_created_signal,
816 &shell->seat_created_listener);
817 wl_list_for_each(seat, &compositor->seat_list, link)
818 seat_created(NULL, seat);
819
820 wl_global_create(compositor->wl_display,
821 &_wl_fullscreen_shell_interface, 1, shell,
822 bind_fullscreen_shell);
823
824 return 0;
825}