downstream: Added string conversion utility functions
[profile/ivi/weston-ivi-shell.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 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
47 struct 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
75 struct 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
82 static void
83 pointer_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
91 static void
92 seat_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
122 static void
123 seat_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
133 static void
134 seat_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
156 static void
157 black_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
158 {
159 }
160
161 static struct weston_view *
162 create_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
194 static void
195 fs_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);
198 static void
199 fs_output_apply_pending(struct fs_output *fsout);
200 static void
201 fs_output_clear_pending(struct fs_output *fsout);
202
203 static void
204 fs_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
215 static void
216 output_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
224 static void
225 surface_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
234 static void
235 pending_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
243 static struct fs_output *
244 fs_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         weston_layer_entry_insert(&shell->layer.view_list,
266                        &fsout->black_view->layer_link);
267         wl_list_init(&fsout->transform.link);
268         return fsout;
269 }
270
271 static struct fs_output *
272 fs_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
284 static void
285 restore_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. */
298 static void
299 surface_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
330 static void
331 fs_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
346 static void
347 fs_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
379 static void
380 fs_output_configure(struct fs_output *fsout, struct weston_surface *surface);
381
382 static void
383 fs_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
450 static void
451 fs_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
507 static void
508 fs_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
526 static void
527 configure_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
542 static void
543 fs_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                 weston_layer_entry_insert(&fsout->shell->layer.view_list,
577                                &fsout->view->layer_link);
578         }
579
580         fs_output_clear_pending(fsout);
581 }
582
583 static void
584 fs_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
600 static void
601 fs_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
638 static void
639 fullscreen_shell_release(struct wl_client *client,
640                          struct wl_resource *resource)
641 {
642         wl_resource_destroy(resource);
643 }
644
645 static void
646 fullscreen_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
691 static void
692 mode_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
699 static void
700 fullscreen_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
738 struct _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
744 static void
745 output_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
755 static void
756 client_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
764 static void
765 bind_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
793 WL_EXPORT int
794 module_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 }