blob: cae6ed5f903e64e9cb803b477b6ee64f3c796a21 [file] [log] [blame]
Jason Ekstrand946a9482014-04-02 19:53:47 -05001/*
2 * Copyright © 2013 Jason Ekstrand
3 *
Bryce Harringtonaf637c22015-06-11 12:55:55 -07004 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files (the
6 * "Software"), to deal in the Software without restriction, including
7 * without limitation the rights to use, copy, modify, merge, publish,
8 * distribute, sublicense, and/or sell copies of the Software, and to
9 * permit persons to whom the Software is furnished to do so, subject to
10 * the following conditions:
Jason Ekstrand946a9482014-04-02 19:53:47 -050011 *
Bryce Harringtonaf637c22015-06-11 12:55:55 -070012 * The above copyright notice and this permission notice (including the
13 * next paragraph) shall be included in all copies or substantial
14 * portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
20 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
21 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
Jason Ekstrand946a9482014-04-02 19:53:47 -050024 */
25
26#include "config.h"
27
28#include <sys/wait.h>
29#include <unistd.h>
30#include <stdlib.h>
31#include <stdio.h>
32#include <string.h>
33#include <assert.h>
34
35#include "compositor.h"
36#include "fullscreen-shell-server-protocol.h"
Jon Cruz867d50e2015-06-15 15:37:10 -070037#include "shared/helpers.h"
Jason Ekstrand946a9482014-04-02 19:53:47 -050038
39struct fullscreen_shell {
40 struct wl_client *client;
41 struct wl_listener client_destroyed;
42 struct weston_compositor *compositor;
43
44 struct weston_layer layer;
45 struct wl_list output_list;
46 struct wl_listener output_created_listener;
47
48 struct wl_listener seat_created_listener;
49};
50
51struct fs_output {
52 struct fullscreen_shell *shell;
53 struct wl_list link;
54
55 struct weston_output *output;
56 struct wl_listener output_destroyed;
57
58 struct {
59 struct weston_surface *surface;
60 struct wl_listener surface_destroyed;
61 struct wl_resource *mode_feedback;
62
63 int presented_for_mode;
64 enum _wl_fullscreen_shell_present_method method;
65 int32_t framerate;
66 } pending;
67
68 struct weston_surface *surface;
69 struct wl_listener surface_destroyed;
70 struct weston_view *view;
71 struct weston_view *black_view;
72 struct weston_transform transform; /* matrix from x, y */
73
74 int presented_for_mode;
75 enum _wl_fullscreen_shell_present_method method;
76 uint32_t framerate;
77};
78
79struct pointer_focus_listener {
80 struct fullscreen_shell *shell;
81 struct wl_listener pointer_focus;
82 struct wl_listener seat_caps;
83 struct wl_listener seat_destroyed;
84};
85
86static void
87pointer_focus_changed(struct wl_listener *listener, void *data)
88{
89 struct weston_pointer *pointer = data;
90
91 if (pointer->focus && pointer->focus->surface->resource)
92 weston_surface_activate(pointer->focus->surface, pointer->seat);
93}
94
95static void
96seat_caps_changed(struct wl_listener *l, void *data)
97{
98 struct weston_seat *seat = data;
99 struct pointer_focus_listener *listener;
100 struct fs_output *fsout;
101
102 listener = container_of(l, struct pointer_focus_listener, seat_caps);
103
104 /* no pointer */
Derek Foremanb41b59e2015-07-15 13:00:47 -0500105 if (seat->pointer_device_count) {
Jason Ekstrand946a9482014-04-02 19:53:47 -0500106 if (!listener->pointer_focus.link.prev) {
107 wl_signal_add(&seat->pointer->focus_signal,
108 &listener->pointer_focus);
109 }
110 } else {
111 if (listener->pointer_focus.link.prev) {
112 wl_list_remove(&listener->pointer_focus.link);
113 }
114 }
115
Derek Foremanb41b59e2015-07-15 13:00:47 -0500116 if (seat->keyboard_device_count && seat->keyboard->focus != NULL) {
Jason Ekstrand946a9482014-04-02 19:53:47 -0500117 wl_list_for_each(fsout, &listener->shell->output_list, link) {
118 if (fsout->surface) {
119 weston_surface_activate(fsout->surface, seat);
120 return;
121 }
122 }
123 }
124}
125
126static void
127seat_destroyed(struct wl_listener *l, void *data)
128{
129 struct pointer_focus_listener *listener;
130
131 listener = container_of(l, struct pointer_focus_listener,
132 seat_destroyed);
133
134 free(listener);
135}
136
137static void
138seat_created(struct wl_listener *l, void *data)
139{
140 struct weston_seat *seat = data;
141 struct pointer_focus_listener *listener;
142
143 listener = malloc(sizeof *listener);
144 if (!listener)
145 return;
146 memset(listener, 0, sizeof *listener);
147
148 listener->shell = container_of(l, struct fullscreen_shell,
149 seat_created_listener);
150 listener->pointer_focus.notify = pointer_focus_changed;
151 listener->seat_caps.notify = seat_caps_changed;
152 listener->seat_destroyed.notify = seat_destroyed;
153
154 wl_signal_add(&seat->destroy_signal, &listener->seat_destroyed);
155 wl_signal_add(&seat->updated_caps_signal, &listener->seat_caps);
156
157 seat_caps_changed(&listener->seat_caps, seat);
158}
159
160static void
161black_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
162{
163}
164
165static struct weston_view *
166create_black_surface(struct weston_compositor *ec, struct fs_output *fsout,
167 float x, float y, int w, int h)
168{
169 struct weston_surface *surface = NULL;
170 struct weston_view *view;
171
172 surface = weston_surface_create(ec);
173 if (surface == NULL) {
174 weston_log("no memory\n");
175 return NULL;
176 }
177 view = weston_view_create(surface);
178 if (!view) {
179 weston_surface_destroy(surface);
180 weston_log("no memory\n");
181 return NULL;
182 }
183
184 surface->configure = black_surface_configure;
185 surface->configure_private = fsout;
186 weston_surface_set_color(surface, 0.0f, 0.0f, 0.0f, 1.0f);
187 pixman_region32_fini(&surface->opaque);
188 pixman_region32_init_rect(&surface->opaque, 0, 0, w, h);
189 pixman_region32_fini(&surface->input);
190 pixman_region32_init_rect(&surface->input, 0, 0, w, h);
191
192 weston_surface_set_size(surface, w, h);
193 weston_view_set_position(view, x, y);
194
195 return view;
196}
197
198static void
199fs_output_set_surface(struct fs_output *fsout, struct weston_surface *surface,
200 enum _wl_fullscreen_shell_present_method method,
201 int32_t framerate, int presented_for_mode);
202static void
203fs_output_apply_pending(struct fs_output *fsout);
204static void
205fs_output_clear_pending(struct fs_output *fsout);
206
207static void
208fs_output_destroy(struct fs_output *fsout)
209{
210 fs_output_set_surface(fsout, NULL, 0, 0, 0);
211 fs_output_clear_pending(fsout);
212
213 wl_list_remove(&fsout->link);
214
215 if (fsout->output)
216 wl_list_remove(&fsout->output_destroyed.link);
217}
218
219static void
220output_destroyed(struct wl_listener *listener, void *data)
221{
222 struct fs_output *output = container_of(listener,
223 struct fs_output,
224 output_destroyed);
225 fs_output_destroy(output);
226}
227
228static void
229surface_destroyed(struct wl_listener *listener, void *data)
230{
231 struct fs_output *fsout = container_of(listener,
232 struct fs_output,
233 surface_destroyed);
234 fsout->surface = NULL;
235 fsout->view = NULL;
236}
237
238static void
239pending_surface_destroyed(struct wl_listener *listener, void *data)
240{
241 struct fs_output *fsout = container_of(listener,
242 struct fs_output,
243 pending.surface_destroyed);
244 fsout->pending.surface = NULL;
245}
246
247static struct fs_output *
248fs_output_create(struct fullscreen_shell *shell, struct weston_output *output)
249{
250 struct fs_output *fsout;
251
252 fsout = malloc(sizeof *fsout);
253 if (!fsout)
254 return NULL;
255 memset(fsout, 0, sizeof *fsout);
256
257 fsout->shell = shell;
258 wl_list_insert(&shell->output_list, &fsout->link);
259
260 fsout->output = output;
261 fsout->output_destroyed.notify = output_destroyed;
262 wl_signal_add(&output->destroy_signal, &fsout->output_destroyed);
263
264 fsout->surface_destroyed.notify = surface_destroyed;
265 fsout->pending.surface_destroyed.notify = pending_surface_destroyed;
266 fsout->black_view = create_black_surface(shell->compositor, fsout,
267 output->x, output->y,
268 output->width, output->height);
Giulio Camuffod1ceecf2014-07-29 21:57:24 +0300269 weston_layer_entry_insert(&shell->layer.view_list,
Jason Ekstrand946a9482014-04-02 19:53:47 -0500270 &fsout->black_view->layer_link);
271 wl_list_init(&fsout->transform.link);
272 return fsout;
273}
274
275static struct fs_output *
276fs_output_for_output(struct weston_output *output)
277{
278 struct wl_listener *listener;
279
280 if (!output)
281 return NULL;
282
283 listener = wl_signal_get(&output->destroy_signal, output_destroyed);
284
285 return container_of(listener, struct fs_output, output_destroyed);
286}
287
288static void
289restore_output_mode(struct weston_output *output)
290{
Derek Foreman6ae7bc92014-11-04 10:47:33 -0600291 if (output->original_mode)
292 weston_output_mode_switch_to_native(output);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500293}
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
Derek Foreman6ae7bc92014-11-04 10:47:33 -0600475 ret = weston_output_mode_switch_to_temporary(fsout->output, &mode,
476 fsout->output->native_scale);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500477
478 if (ret != 0) {
479 /* The mode switch failed. Clear the pending and
480 * reconfigure as per normal */
481 if (fsout->pending.mode_feedback) {
482 _wl_fullscreen_shell_mode_feedback_send_mode_failed(
483 fsout->pending.mode_feedback);
484 wl_resource_destroy(fsout->pending.mode_feedback);
485 fsout->pending.mode_feedback = NULL;
486 }
487
488 fs_output_clear_pending(fsout);
489 return;
490 }
491
492 if (fsout->pending.mode_feedback) {
493 _wl_fullscreen_shell_mode_feedback_send_mode_successful(
494 fsout->pending.mode_feedback);
495 wl_resource_destroy(fsout->pending.mode_feedback);
496 fsout->pending.mode_feedback = NULL;
497 }
498
499 fs_output_apply_pending(fsout);
500
501 weston_view_set_position(fsout->view,
502 fsout->output->x - surf_x,
503 fsout->output->y - surf_y);
504}
505
506static void
507fs_output_configure(struct fs_output *fsout,
508 struct weston_surface *surface)
509{
510 if (fsout->pending.surface == surface) {
511 if (fsout->pending.presented_for_mode)
512 fs_output_configure_for_mode(fsout, surface);
513 else
514 fs_output_configure_simple(fsout, surface);
515 } else {
516 if (fsout->presented_for_mode)
517 fs_output_configure_for_mode(fsout, surface);
518 else
519 fs_output_configure_simple(fsout, surface);
520 }
521
522 weston_output_schedule_repaint(fsout->output);
523}
524
525static void
526configure_presented_surface(struct weston_surface *surface, int32_t sx,
527 int32_t sy)
528{
529 struct fullscreen_shell *shell = surface->configure_private;
530 struct fs_output *fsout;
531
532 if (surface->configure != configure_presented_surface)
533 return;
534
535 wl_list_for_each(fsout, &shell->output_list, link)
536 if (fsout->surface == surface ||
537 fsout->pending.surface == surface)
538 fs_output_configure(fsout, surface);
539}
540
541static void
542fs_output_apply_pending(struct fs_output *fsout)
543{
544 assert(fsout->pending.surface);
545
546 if (fsout->surface && fsout->surface != fsout->pending.surface) {
547 wl_list_remove(&fsout->surface_destroyed.link);
548
549 weston_view_destroy(fsout->view);
550 fsout->view = NULL;
551
552 if (wl_list_empty(&fsout->surface->views)) {
553 fsout->surface->configure = NULL;
554 fsout->surface->configure_private = NULL;
555 }
556
557 fsout->surface = NULL;
558 }
559
560 fsout->method = fsout->pending.method;
561 fsout->framerate = fsout->pending.framerate;
562 fsout->presented_for_mode = fsout->pending.presented_for_mode;
563
564 if (fsout->surface != fsout->pending.surface) {
565 fsout->surface = fsout->pending.surface;
566
567 fsout->view = weston_view_create(fsout->surface);
568 if (!fsout->view) {
569 weston_log("no memory\n");
570 return;
571 }
572
573 wl_signal_add(&fsout->surface->destroy_signal,
574 &fsout->surface_destroyed);
Giulio Camuffod1ceecf2014-07-29 21:57:24 +0300575 weston_layer_entry_insert(&fsout->shell->layer.view_list,
Jason Ekstrand946a9482014-04-02 19:53:47 -0500576 &fsout->view->layer_link);
577 }
578
579 fs_output_clear_pending(fsout);
580}
581
582static void
583fs_output_clear_pending(struct fs_output *fsout)
584{
585 if (!fsout->pending.surface)
586 return;
587
588 if (fsout->pending.mode_feedback) {
589 _wl_fullscreen_shell_mode_feedback_send_present_cancelled(
590 fsout->pending.mode_feedback);
591 wl_resource_destroy(fsout->pending.mode_feedback);
592 fsout->pending.mode_feedback = NULL;
593 }
594
595 wl_list_remove(&fsout->pending.surface_destroyed.link);
596 fsout->pending.surface = NULL;
597}
598
599static void
600fs_output_set_surface(struct fs_output *fsout, struct weston_surface *surface,
601 enum _wl_fullscreen_shell_present_method method,
602 int32_t framerate, int presented_for_mode)
603{
604 fs_output_clear_pending(fsout);
605
606 if (surface) {
607 if (!surface->configure) {
608 surface->configure = configure_presented_surface;
609 surface->configure_private = fsout->shell;
610 }
611
612 fsout->pending.surface = surface;
613 wl_signal_add(&fsout->pending.surface->destroy_signal,
614 &fsout->pending.surface_destroyed);
615
616 fsout->pending.method = method;
617 fsout->pending.framerate = framerate;
618 fsout->pending.presented_for_mode = presented_for_mode;
619 } else if (fsout->surface) {
620 /* we clear immediately */
621 wl_list_remove(&fsout->surface_destroyed.link);
622
623 weston_view_destroy(fsout->view);
624 fsout->view = NULL;
625
626 if (wl_list_empty(&fsout->surface->views)) {
627 fsout->surface->configure = NULL;
628 fsout->surface->configure_private = NULL;
629 }
630
631 fsout->surface = NULL;
632
633 weston_output_schedule_repaint(fsout->output);
634 }
635}
636
637static void
638fullscreen_shell_release(struct wl_client *client,
639 struct wl_resource *resource)
640{
641 wl_resource_destroy(resource);
642}
643
644static void
645fullscreen_shell_present_surface(struct wl_client *client,
646 struct wl_resource *resource,
647 struct wl_resource *surface_res,
648 uint32_t method,
649 struct wl_resource *output_res)
650{
651 struct fullscreen_shell *shell =
652 wl_resource_get_user_data(resource);
653 struct weston_output *output;
654 struct weston_surface *surface;
655 struct weston_seat *seat;
656 struct fs_output *fsout;
657
658 surface = surface_res ? wl_resource_get_user_data(surface_res) : NULL;
659
660 switch(method) {
661 case _WL_FULLSCREEN_SHELL_PRESENT_METHOD_DEFAULT:
662 case _WL_FULLSCREEN_SHELL_PRESENT_METHOD_CENTER:
663 case _WL_FULLSCREEN_SHELL_PRESENT_METHOD_ZOOM:
664 case _WL_FULLSCREEN_SHELL_PRESENT_METHOD_ZOOM_CROP:
665 case _WL_FULLSCREEN_SHELL_PRESENT_METHOD_STRETCH:
666 break;
667 default:
668 wl_resource_post_error(resource,
669 _WL_FULLSCREEN_SHELL_ERROR_INVALID_METHOD,
670 "Invalid presentation method");
671 }
672
673 if (output_res) {
674 output = wl_resource_get_user_data(output_res);
675 fsout = fs_output_for_output(output);
676 fs_output_set_surface(fsout, surface, method, 0, 0);
677 } else {
678 wl_list_for_each(fsout, &shell->output_list, link)
679 fs_output_set_surface(fsout, surface, method, 0, 0);
680 }
681
682 if (surface) {
683 wl_list_for_each(seat, &shell->compositor->seat_list, link) {
684 if (seat->keyboard && seat->keyboard->focus == NULL)
685 weston_surface_activate(surface, seat);
686 }
687 }
688}
689
690static void
691mode_feedback_destroyed(struct wl_resource *resource)
692{
693 struct fs_output *fsout = wl_resource_get_user_data(resource);
694
695 fsout->pending.mode_feedback = NULL;
696}
697
698static void
699fullscreen_shell_present_surface_for_mode(struct wl_client *client,
700 struct wl_resource *resource,
701 struct wl_resource *surface_res,
702 struct wl_resource *output_res,
703 int32_t framerate,
704 uint32_t feedback_id)
705{
706 struct fullscreen_shell *shell =
707 wl_resource_get_user_data(resource);
708 struct weston_output *output;
709 struct weston_surface *surface;
710 struct weston_seat *seat;
711 struct fs_output *fsout;
712
713 output = wl_resource_get_user_data(output_res);
714 fsout = fs_output_for_output(output);
715
716 if (surface_res == NULL) {
717 fs_output_set_surface(fsout, NULL, 0, 0, 0);
718 return;
719 }
720
721 surface = wl_resource_get_user_data(surface_res);
722 fs_output_set_surface(fsout, surface, 0, framerate, 1);
723
724 fsout->pending.mode_feedback =
725 wl_resource_create(client,
726 &_wl_fullscreen_shell_mode_feedback_interface,
727 1, feedback_id);
728 wl_resource_set_implementation(fsout->pending.mode_feedback, NULL,
729 fsout, mode_feedback_destroyed);
730
731 wl_list_for_each(seat, &shell->compositor->seat_list, link) {
732 if (seat->keyboard && seat->keyboard->focus == NULL)
733 weston_surface_activate(surface, seat);
734 }
735}
736
737struct _wl_fullscreen_shell_interface fullscreen_shell_implementation = {
738 fullscreen_shell_release,
739 fullscreen_shell_present_surface,
740 fullscreen_shell_present_surface_for_mode,
741};
742
743static void
744output_created(struct wl_listener *listener, void *data)
745{
746 struct fullscreen_shell *shell;
747
748 shell = container_of(listener, struct fullscreen_shell,
749 output_created_listener);
750
751 fs_output_create(shell, data);
752}
753
754static void
755client_destroyed(struct wl_listener *listener, void *data)
756{
757 struct fullscreen_shell *shell = container_of(listener,
758 struct fullscreen_shell,
759 client_destroyed);
760 shell->client = NULL;
761}
762
763static void
764bind_fullscreen_shell(struct wl_client *client, void *data, uint32_t version,
765 uint32_t id)
766{
767 struct fullscreen_shell *shell = data;
768 struct wl_resource *resource;
769
770 if (shell->client != NULL && shell->client != client)
771 return;
772 else if (shell->client == NULL) {
773 shell->client = client;
774 wl_client_add_destroy_listener(client, &shell->client_destroyed);
775 }
776
777 resource = wl_resource_create(client, &_wl_fullscreen_shell_interface,
778 1, id);
779 wl_resource_set_implementation(resource,
780 &fullscreen_shell_implementation,
781 shell, NULL);
782
783 if (shell->compositor->capabilities & WESTON_CAP_CURSOR_PLANE)
784 _wl_fullscreen_shell_send_capability(resource,
785 _WL_FULLSCREEN_SHELL_CAPABILITY_CURSOR_PLANE);
786
787 if (shell->compositor->capabilities & WESTON_CAP_ARBITRARY_MODES)
788 _wl_fullscreen_shell_send_capability(resource,
789 _WL_FULLSCREEN_SHELL_CAPABILITY_ARBITRARY_MODES);
790}
791
792WL_EXPORT int
793module_init(struct weston_compositor *compositor,
794 int *argc, char *argv[])
795{
796 struct fullscreen_shell *shell;
797 struct weston_seat *seat;
798 struct weston_output *output;
799
800 shell = malloc(sizeof *shell);
801 if (shell == NULL)
802 return -1;
803
804 memset(shell, 0, sizeof *shell);
805 shell->compositor = compositor;
806
807 shell->client_destroyed.notify = client_destroyed;
808
809 weston_layer_init(&shell->layer, &compositor->cursor_layer.link);
810
811 wl_list_init(&shell->output_list);
812 shell->output_created_listener.notify = output_created;
813 wl_signal_add(&compositor->output_created_signal,
814 &shell->output_created_listener);
815 wl_list_for_each(output, &compositor->output_list, link)
816 fs_output_create(shell, output);
817
818 shell->seat_created_listener.notify = seat_created;
819 wl_signal_add(&compositor->seat_created_signal,
820 &shell->seat_created_listener);
821 wl_list_for_each(seat, &compositor->seat_list, link)
822 seat_created(NULL, seat);
823
824 wl_global_create(compositor->wl_display,
825 &_wl_fullscreen_shell_interface, 1, shell,
826 bind_fullscreen_shell);
827
828 return 0;
829}