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