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