blob: a32e46a47ff1ff498575fb44bccf14d498008c68 [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"
Jonas Ådahl496adb32015-11-17 16:00:27 +080036#include "fullscreen-shell-unstable-v1-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;
Jonas Ådahl496adb32015-11-17 16:00:27 +080064 enum zwp_fullscreen_shell_v1_present_method method;
Jason Ekstrand946a9482014-04-02 19:53:47 -050065 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;
Jonas Ådahl496adb32015-11-17 16:00:27 +080075 enum zwp_fullscreen_shell_v1_present_method method;
Jason Ekstrand946a9482014-04-02 19:53:47 -050076 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
Ryo Munakata5e653ca2015-08-07 20:20:46 +0900145 listener = zalloc(sizeof *listener);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500146 if (!listener)
147 return;
Jason Ekstrand946a9482014-04-02 19:53:47 -0500148
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
161static void
162black_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
163{
164}
165
166static struct weston_view *
167create_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
199static void
200fs_output_set_surface(struct fs_output *fsout, struct weston_surface *surface,
Jonas Ådahl496adb32015-11-17 16:00:27 +0800201 enum zwp_fullscreen_shell_v1_present_method method,
Jason Ekstrand946a9482014-04-02 19:53:47 -0500202 int32_t framerate, int presented_for_mode);
203static void
204fs_output_apply_pending(struct fs_output *fsout);
205static void
206fs_output_clear_pending(struct fs_output *fsout);
207
208static void
209fs_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
220static void
221output_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
229static void
230surface_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
239static void
240pending_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
248static struct fs_output *
249fs_output_create(struct fullscreen_shell *shell, struct weston_output *output)
250{
251 struct fs_output *fsout;
252
Ryo Munakata5e653ca2015-08-07 20:20:46 +0900253 fsout = zalloc(sizeof *fsout);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500254 if (!fsout)
255 return NULL;
Jason Ekstrand946a9482014-04-02 19:53:47 -0500256
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,
Yong Bakos3b227612016-04-28 11:59:07 -0500297 * in surface-local coordinates. */
Jason Ekstrand946a9482014-04-02 19:53:47 -0500298static 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) {
Jonas Ådahl496adb32015-11-17 16:00:27 +0800408 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_DEFAULT:
409 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_CENTER:
Jason Ekstrand946a9482014-04-02 19:53:47 -0500410 fs_output_center_view(fsout);
411 break;
412
Jonas Ådahl496adb32015-11-17 16:00:27 +0800413 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_ZOOM:
Jason Ekstrand946a9482014-04-02 19:53:47 -0500414 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
Jonas Ådahl496adb32015-11-17 16:00:27 +0800424 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_ZOOM_CROP:
Jason Ekstrand946a9482014-04-02 19:53:47 -0500425 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
Jonas Ådahl496adb32015-11-17 16:00:27 +0800435 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_STRETCH:
Jason Ekstrand946a9482014-04-02 19:53:47 -0500436 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
Jason Ekstrand58106d72015-01-08 08:57:44 -0800470 /* The actual output mode is in physical units. We need to
471 * transform the surface size to physical unit size by flipping ans
472 * possibly scaling it.
473 */
474 switch (fsout->output->transform) {
475 case WL_OUTPUT_TRANSFORM_90:
476 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
477 case WL_OUTPUT_TRANSFORM_270:
478 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
479 mode.width = surf_height * fsout->output->native_scale;
480 mode.height = surf_width * fsout->output->native_scale;
481 break;
482
483 case WL_OUTPUT_TRANSFORM_NORMAL:
484 case WL_OUTPUT_TRANSFORM_FLIPPED:
485 case WL_OUTPUT_TRANSFORM_180:
486 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
487 default:
488 mode.width = surf_width * fsout->output->native_scale;
489 mode.height = surf_height * fsout->output->native_scale;
490 }
Jason Ekstrand946a9482014-04-02 19:53:47 -0500491 mode.flags = 0;
Jason Ekstrand946a9482014-04-02 19:53:47 -0500492 mode.refresh = fsout->pending.framerate;
493
Derek Foreman6ae7bc92014-11-04 10:47:33 -0600494 ret = weston_output_mode_switch_to_temporary(fsout->output, &mode,
495 fsout->output->native_scale);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500496
497 if (ret != 0) {
498 /* The mode switch failed. Clear the pending and
499 * reconfigure as per normal */
500 if (fsout->pending.mode_feedback) {
Jonas Ådahl496adb32015-11-17 16:00:27 +0800501 zwp_fullscreen_shell_mode_feedback_v1_send_mode_failed(
Jason Ekstrand946a9482014-04-02 19:53:47 -0500502 fsout->pending.mode_feedback);
503 wl_resource_destroy(fsout->pending.mode_feedback);
504 fsout->pending.mode_feedback = NULL;
505 }
506
507 fs_output_clear_pending(fsout);
508 return;
509 }
510
511 if (fsout->pending.mode_feedback) {
Jonas Ådahl496adb32015-11-17 16:00:27 +0800512 zwp_fullscreen_shell_mode_feedback_v1_send_mode_successful(
Jason Ekstrand946a9482014-04-02 19:53:47 -0500513 fsout->pending.mode_feedback);
514 wl_resource_destroy(fsout->pending.mode_feedback);
515 fsout->pending.mode_feedback = NULL;
516 }
517
518 fs_output_apply_pending(fsout);
519
520 weston_view_set_position(fsout->view,
521 fsout->output->x - surf_x,
522 fsout->output->y - surf_y);
523}
524
525static void
526fs_output_configure(struct fs_output *fsout,
527 struct weston_surface *surface)
528{
529 if (fsout->pending.surface == surface) {
530 if (fsout->pending.presented_for_mode)
531 fs_output_configure_for_mode(fsout, surface);
532 else
533 fs_output_configure_simple(fsout, surface);
534 } else {
535 if (fsout->presented_for_mode)
536 fs_output_configure_for_mode(fsout, surface);
537 else
538 fs_output_configure_simple(fsout, surface);
539 }
540
541 weston_output_schedule_repaint(fsout->output);
542}
543
544static void
545configure_presented_surface(struct weston_surface *surface, int32_t sx,
546 int32_t sy)
547{
548 struct fullscreen_shell *shell = surface->configure_private;
549 struct fs_output *fsout;
550
551 if (surface->configure != configure_presented_surface)
552 return;
553
554 wl_list_for_each(fsout, &shell->output_list, link)
555 if (fsout->surface == surface ||
556 fsout->pending.surface == surface)
557 fs_output_configure(fsout, surface);
558}
559
560static void
561fs_output_apply_pending(struct fs_output *fsout)
562{
563 assert(fsout->pending.surface);
564
565 if (fsout->surface && fsout->surface != fsout->pending.surface) {
566 wl_list_remove(&fsout->surface_destroyed.link);
567
568 weston_view_destroy(fsout->view);
569 fsout->view = NULL;
570
571 if (wl_list_empty(&fsout->surface->views)) {
572 fsout->surface->configure = NULL;
573 fsout->surface->configure_private = NULL;
574 }
575
576 fsout->surface = NULL;
577 }
578
579 fsout->method = fsout->pending.method;
580 fsout->framerate = fsout->pending.framerate;
581 fsout->presented_for_mode = fsout->pending.presented_for_mode;
582
583 if (fsout->surface != fsout->pending.surface) {
584 fsout->surface = fsout->pending.surface;
585
586 fsout->view = weston_view_create(fsout->surface);
587 if (!fsout->view) {
588 weston_log("no memory\n");
589 return;
590 }
591
592 wl_signal_add(&fsout->surface->destroy_signal,
593 &fsout->surface_destroyed);
Giulio Camuffod1ceecf2014-07-29 21:57:24 +0300594 weston_layer_entry_insert(&fsout->shell->layer.view_list,
Jason Ekstrand946a9482014-04-02 19:53:47 -0500595 &fsout->view->layer_link);
596 }
597
598 fs_output_clear_pending(fsout);
599}
600
601static void
602fs_output_clear_pending(struct fs_output *fsout)
603{
604 if (!fsout->pending.surface)
605 return;
606
607 if (fsout->pending.mode_feedback) {
Jonas Ådahl496adb32015-11-17 16:00:27 +0800608 zwp_fullscreen_shell_mode_feedback_v1_send_present_cancelled(
Jason Ekstrand946a9482014-04-02 19:53:47 -0500609 fsout->pending.mode_feedback);
610 wl_resource_destroy(fsout->pending.mode_feedback);
611 fsout->pending.mode_feedback = NULL;
612 }
613
614 wl_list_remove(&fsout->pending.surface_destroyed.link);
615 fsout->pending.surface = NULL;
616}
617
618static void
619fs_output_set_surface(struct fs_output *fsout, struct weston_surface *surface,
Jonas Ådahl496adb32015-11-17 16:00:27 +0800620 enum zwp_fullscreen_shell_v1_present_method method,
Jason Ekstrand946a9482014-04-02 19:53:47 -0500621 int32_t framerate, int presented_for_mode)
622{
623 fs_output_clear_pending(fsout);
624
625 if (surface) {
626 if (!surface->configure) {
627 surface->configure = configure_presented_surface;
628 surface->configure_private = fsout->shell;
629 }
630
631 fsout->pending.surface = surface;
632 wl_signal_add(&fsout->pending.surface->destroy_signal,
633 &fsout->pending.surface_destroyed);
634
635 fsout->pending.method = method;
636 fsout->pending.framerate = framerate;
637 fsout->pending.presented_for_mode = presented_for_mode;
638 } else if (fsout->surface) {
639 /* we clear immediately */
640 wl_list_remove(&fsout->surface_destroyed.link);
641
642 weston_view_destroy(fsout->view);
643 fsout->view = NULL;
644
645 if (wl_list_empty(&fsout->surface->views)) {
646 fsout->surface->configure = NULL;
647 fsout->surface->configure_private = NULL;
648 }
649
650 fsout->surface = NULL;
651
652 weston_output_schedule_repaint(fsout->output);
653 }
654}
655
656static void
657fullscreen_shell_release(struct wl_client *client,
658 struct wl_resource *resource)
659{
660 wl_resource_destroy(resource);
661}
662
663static void
664fullscreen_shell_present_surface(struct wl_client *client,
665 struct wl_resource *resource,
666 struct wl_resource *surface_res,
667 uint32_t method,
668 struct wl_resource *output_res)
669{
670 struct fullscreen_shell *shell =
671 wl_resource_get_user_data(resource);
672 struct weston_output *output;
673 struct weston_surface *surface;
674 struct weston_seat *seat;
675 struct fs_output *fsout;
676
677 surface = surface_res ? wl_resource_get_user_data(surface_res) : NULL;
678
679 switch(method) {
Jonas Ådahl496adb32015-11-17 16:00:27 +0800680 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_DEFAULT:
681 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_CENTER:
682 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_ZOOM:
683 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_ZOOM_CROP:
684 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_STRETCH:
Jason Ekstrand946a9482014-04-02 19:53:47 -0500685 break;
686 default:
687 wl_resource_post_error(resource,
Jonas Ådahl496adb32015-11-17 16:00:27 +0800688 ZWP_FULLSCREEN_SHELL_V1_ERROR_INVALID_METHOD,
Jason Ekstrand946a9482014-04-02 19:53:47 -0500689 "Invalid presentation method");
690 }
691
692 if (output_res) {
693 output = wl_resource_get_user_data(output_res);
694 fsout = fs_output_for_output(output);
695 fs_output_set_surface(fsout, surface, method, 0, 0);
696 } else {
697 wl_list_for_each(fsout, &shell->output_list, link)
698 fs_output_set_surface(fsout, surface, method, 0, 0);
699 }
700
701 if (surface) {
702 wl_list_for_each(seat, &shell->compositor->seat_list, link) {
Derek Foreman1281a362015-07-31 16:55:32 -0500703 struct weston_keyboard *keyboard =
704 weston_seat_get_keyboard(seat);
705
706 if (keyboard && !keyboard->focus)
Jason Ekstrand946a9482014-04-02 19:53:47 -0500707 weston_surface_activate(surface, seat);
708 }
709 }
710}
711
712static void
713mode_feedback_destroyed(struct wl_resource *resource)
714{
715 struct fs_output *fsout = wl_resource_get_user_data(resource);
716
717 fsout->pending.mode_feedback = NULL;
718}
719
720static void
721fullscreen_shell_present_surface_for_mode(struct wl_client *client,
722 struct wl_resource *resource,
723 struct wl_resource *surface_res,
724 struct wl_resource *output_res,
725 int32_t framerate,
726 uint32_t feedback_id)
727{
728 struct fullscreen_shell *shell =
729 wl_resource_get_user_data(resource);
730 struct weston_output *output;
731 struct weston_surface *surface;
732 struct weston_seat *seat;
733 struct fs_output *fsout;
734
735 output = wl_resource_get_user_data(output_res);
736 fsout = fs_output_for_output(output);
737
738 if (surface_res == NULL) {
739 fs_output_set_surface(fsout, NULL, 0, 0, 0);
740 return;
741 }
742
743 surface = wl_resource_get_user_data(surface_res);
744 fs_output_set_surface(fsout, surface, 0, framerate, 1);
745
746 fsout->pending.mode_feedback =
747 wl_resource_create(client,
Jonas Ådahl496adb32015-11-17 16:00:27 +0800748 &zwp_fullscreen_shell_mode_feedback_v1_interface,
Jason Ekstrand946a9482014-04-02 19:53:47 -0500749 1, feedback_id);
750 wl_resource_set_implementation(fsout->pending.mode_feedback, NULL,
751 fsout, mode_feedback_destroyed);
752
753 wl_list_for_each(seat, &shell->compositor->seat_list, link) {
Derek Foreman1281a362015-07-31 16:55:32 -0500754 struct weston_keyboard *keyboard =
755 weston_seat_get_keyboard(seat);
756
757 if (keyboard && !keyboard->focus)
Jason Ekstrand946a9482014-04-02 19:53:47 -0500758 weston_surface_activate(surface, seat);
759 }
760}
761
Jonas Ådahl496adb32015-11-17 16:00:27 +0800762struct zwp_fullscreen_shell_v1_interface fullscreen_shell_implementation = {
Jason Ekstrand946a9482014-04-02 19:53:47 -0500763 fullscreen_shell_release,
764 fullscreen_shell_present_surface,
765 fullscreen_shell_present_surface_for_mode,
766};
767
768static void
769output_created(struct wl_listener *listener, void *data)
770{
771 struct fullscreen_shell *shell;
772
773 shell = container_of(listener, struct fullscreen_shell,
774 output_created_listener);
775
776 fs_output_create(shell, data);
777}
778
779static void
780client_destroyed(struct wl_listener *listener, void *data)
781{
782 struct fullscreen_shell *shell = container_of(listener,
783 struct fullscreen_shell,
784 client_destroyed);
785 shell->client = NULL;
786}
787
788static void
789bind_fullscreen_shell(struct wl_client *client, void *data, uint32_t version,
790 uint32_t id)
791{
792 struct fullscreen_shell *shell = data;
793 struct wl_resource *resource;
794
795 if (shell->client != NULL && shell->client != client)
796 return;
797 else if (shell->client == NULL) {
798 shell->client = client;
799 wl_client_add_destroy_listener(client, &shell->client_destroyed);
800 }
801
Jonas Ådahl496adb32015-11-17 16:00:27 +0800802 resource = wl_resource_create(client,
803 &zwp_fullscreen_shell_v1_interface,
Jason Ekstrand946a9482014-04-02 19:53:47 -0500804 1, id);
805 wl_resource_set_implementation(resource,
806 &fullscreen_shell_implementation,
807 shell, NULL);
808
809 if (shell->compositor->capabilities & WESTON_CAP_CURSOR_PLANE)
Jonas Ådahl496adb32015-11-17 16:00:27 +0800810 zwp_fullscreen_shell_v1_send_capability(resource,
811 ZWP_FULLSCREEN_SHELL_V1_CAPABILITY_CURSOR_PLANE);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500812
813 if (shell->compositor->capabilities & WESTON_CAP_ARBITRARY_MODES)
Jonas Ådahl496adb32015-11-17 16:00:27 +0800814 zwp_fullscreen_shell_v1_send_capability(resource,
815 ZWP_FULLSCREEN_SHELL_V1_CAPABILITY_ARBITRARY_MODES);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500816}
817
818WL_EXPORT int
819module_init(struct weston_compositor *compositor,
820 int *argc, char *argv[])
821{
822 struct fullscreen_shell *shell;
823 struct weston_seat *seat;
824 struct weston_output *output;
825
Ryo Munakata5e653ca2015-08-07 20:20:46 +0900826 shell = zalloc(sizeof *shell);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500827 if (shell == NULL)
828 return -1;
829
Jason Ekstrand946a9482014-04-02 19:53:47 -0500830 shell->compositor = compositor;
831
832 shell->client_destroyed.notify = client_destroyed;
833
834 weston_layer_init(&shell->layer, &compositor->cursor_layer.link);
835
836 wl_list_init(&shell->output_list);
837 shell->output_created_listener.notify = output_created;
838 wl_signal_add(&compositor->output_created_signal,
839 &shell->output_created_listener);
840 wl_list_for_each(output, &compositor->output_list, link)
841 fs_output_create(shell, output);
842
843 shell->seat_created_listener.notify = seat_created;
844 wl_signal_add(&compositor->seat_created_signal,
845 &shell->seat_created_listener);
846 wl_list_for_each(seat, &compositor->seat_list, link)
847 seat_created(NULL, seat);
848
849 wl_global_create(compositor->wl_display,
Jonas Ådahl496adb32015-11-17 16:00:27 +0800850 &zwp_fullscreen_shell_v1_interface, 1, shell,
Jason Ekstrand946a9482014-04-02 19:53:47 -0500851 bind_fullscreen_shell);
852
853 return 0;
854}