blob: b3083d889b6de1f64aa899e2cc56173df04caf87 [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>
Jussi Kukkonen649bbce2016-07-19 14:16:27 +030031#include <stdint.h>
Jason Ekstrand946a9482014-04-02 19:53:47 -050032#include <stdio.h>
33#include <string.h>
34#include <assert.h>
35
36#include "compositor.h"
Jonas Ådahl496adb32015-11-17 16:00:27 +080037#include "fullscreen-shell-unstable-v1-server-protocol.h"
Jon Cruz867d50e2015-06-15 15:37:10 -070038#include "shared/helpers.h"
Jason Ekstrand946a9482014-04-02 19:53:47 -050039
40struct fullscreen_shell {
41 struct wl_client *client;
42 struct wl_listener client_destroyed;
43 struct weston_compositor *compositor;
44
45 struct weston_layer layer;
46 struct wl_list output_list;
47 struct wl_listener output_created_listener;
48
49 struct wl_listener seat_created_listener;
Armin Krezovićccfd0292016-08-11 15:49:59 +020050
51 /* List of one surface per client, presented for the NULL output
52 *
53 * This is implemented as a list in case someone fixes the shell
54 * implementation to support more than one client.
55 */
56 struct wl_list default_surface_list; /* struct fs_client_surface::link */
Jason Ekstrand946a9482014-04-02 19:53:47 -050057};
58
59struct fs_output {
60 struct fullscreen_shell *shell;
61 struct wl_list link;
62
63 struct weston_output *output;
64 struct wl_listener output_destroyed;
65
66 struct {
67 struct weston_surface *surface;
68 struct wl_listener surface_destroyed;
69 struct wl_resource *mode_feedback;
70
71 int presented_for_mode;
Jonas Ådahl496adb32015-11-17 16:00:27 +080072 enum zwp_fullscreen_shell_v1_present_method method;
Jason Ekstrand946a9482014-04-02 19:53:47 -050073 int32_t framerate;
74 } pending;
75
76 struct weston_surface *surface;
77 struct wl_listener surface_destroyed;
78 struct weston_view *view;
79 struct weston_view *black_view;
80 struct weston_transform transform; /* matrix from x, y */
81
82 int presented_for_mode;
Jonas Ådahl496adb32015-11-17 16:00:27 +080083 enum zwp_fullscreen_shell_v1_present_method method;
Jason Ekstrand946a9482014-04-02 19:53:47 -050084 uint32_t framerate;
85};
86
87struct pointer_focus_listener {
88 struct fullscreen_shell *shell;
89 struct wl_listener pointer_focus;
90 struct wl_listener seat_caps;
91 struct wl_listener seat_destroyed;
92};
93
Armin Krezovićccfd0292016-08-11 15:49:59 +020094struct fs_client_surface {
95 struct weston_surface *surface;
96 enum zwp_fullscreen_shell_v1_present_method method;
97 struct wl_list link; /* struct fullscreen_shell::default_surface_list */
98 struct wl_listener surface_destroyed;
99};
100
101static void
102remove_default_surface(struct fs_client_surface *surf)
103{
104 wl_list_remove(&surf->surface_destroyed.link);
105 wl_list_remove(&surf->link);
106 free(surf);
107}
108
109static void
110default_surface_destroy_listener(struct wl_listener *listener, void *data)
111{
112 struct fs_client_surface *surf;
113
114 surf = container_of(listener, struct fs_client_surface, surface_destroyed);
115
116 remove_default_surface(surf);
117}
118
119static void
120replace_default_surface(struct fullscreen_shell *shell, struct weston_surface *surface,
121 enum zwp_fullscreen_shell_v1_present_method method)
122{
123 struct fs_client_surface *surf, *prev = NULL;
124
125 if (!wl_list_empty(&shell->default_surface_list))
126 prev = container_of(shell->default_surface_list.prev,
127 struct fs_client_surface, link);
128
129 surf = zalloc(sizeof *surf);
130 if (!surf)
131 return;
132
133 surf->surface = surface;
134 surf->method = method;
135
136 if (prev)
137 remove_default_surface(prev);
138
139 wl_list_insert(shell->default_surface_list.prev, &surf->link);
140
141 surf->surface_destroyed.notify = default_surface_destroy_listener;
142 wl_signal_add(&surface->destroy_signal, &surf->surface_destroyed);
143}
144
Jason Ekstrand946a9482014-04-02 19:53:47 -0500145static void
146pointer_focus_changed(struct wl_listener *listener, void *data)
147{
148 struct weston_pointer *pointer = data;
149
150 if (pointer->focus && pointer->focus->surface->resource)
Bryce Harrington260c2ff2016-06-29 19:04:06 -0700151 weston_seat_set_keyboard_focus(pointer->seat, pointer->focus->surface);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500152}
153
154static void
155seat_caps_changed(struct wl_listener *l, void *data)
156{
157 struct weston_seat *seat = data;
Derek Foreman1281a362015-07-31 16:55:32 -0500158 struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
159 struct weston_pointer *pointer = weston_seat_get_pointer(seat);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500160 struct pointer_focus_listener *listener;
161 struct fs_output *fsout;
162
163 listener = container_of(l, struct pointer_focus_listener, seat_caps);
164
165 /* no pointer */
Derek Foreman1281a362015-07-31 16:55:32 -0500166 if (pointer) {
Jason Ekstrand946a9482014-04-02 19:53:47 -0500167 if (!listener->pointer_focus.link.prev) {
Derek Foreman1281a362015-07-31 16:55:32 -0500168 wl_signal_add(&pointer->focus_signal,
Jason Ekstrand946a9482014-04-02 19:53:47 -0500169 &listener->pointer_focus);
170 }
171 } else {
172 if (listener->pointer_focus.link.prev) {
173 wl_list_remove(&listener->pointer_focus.link);
174 }
175 }
176
Derek Foreman1281a362015-07-31 16:55:32 -0500177 if (keyboard && keyboard->focus != NULL) {
Jason Ekstrand946a9482014-04-02 19:53:47 -0500178 wl_list_for_each(fsout, &listener->shell->output_list, link) {
179 if (fsout->surface) {
Bryce Harrington260c2ff2016-06-29 19:04:06 -0700180 weston_seat_set_keyboard_focus(seat, fsout->surface);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500181 return;
182 }
183 }
184 }
185}
186
187static void
188seat_destroyed(struct wl_listener *l, void *data)
189{
190 struct pointer_focus_listener *listener;
191
192 listener = container_of(l, struct pointer_focus_listener,
193 seat_destroyed);
194
195 free(listener);
196}
197
198static void
199seat_created(struct wl_listener *l, void *data)
200{
201 struct weston_seat *seat = data;
202 struct pointer_focus_listener *listener;
203
Ryo Munakata5e653ca2015-08-07 20:20:46 +0900204 listener = zalloc(sizeof *listener);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500205 if (!listener)
206 return;
Jason Ekstrand946a9482014-04-02 19:53:47 -0500207
208 listener->shell = container_of(l, struct fullscreen_shell,
209 seat_created_listener);
210 listener->pointer_focus.notify = pointer_focus_changed;
211 listener->seat_caps.notify = seat_caps_changed;
212 listener->seat_destroyed.notify = seat_destroyed;
213
214 wl_signal_add(&seat->destroy_signal, &listener->seat_destroyed);
215 wl_signal_add(&seat->updated_caps_signal, &listener->seat_caps);
216
217 seat_caps_changed(&listener->seat_caps, seat);
218}
219
220static void
Quentin Glidic2edc3d52016-08-12 10:41:33 +0200221black_surface_committed(struct weston_surface *es, int32_t sx, int32_t sy)
Jason Ekstrand946a9482014-04-02 19:53:47 -0500222{
223}
224
225static struct weston_view *
226create_black_surface(struct weston_compositor *ec, struct fs_output *fsout,
227 float x, float y, int w, int h)
228{
229 struct weston_surface *surface = NULL;
230 struct weston_view *view;
231
232 surface = weston_surface_create(ec);
233 if (surface == NULL) {
234 weston_log("no memory\n");
235 return NULL;
236 }
237 view = weston_view_create(surface);
238 if (!view) {
239 weston_surface_destroy(surface);
240 weston_log("no memory\n");
241 return NULL;
242 }
243
Quentin Glidic2edc3d52016-08-12 10:41:33 +0200244 surface->committed = black_surface_committed;
245 surface->committed_private = fsout;
Jason Ekstrand946a9482014-04-02 19:53:47 -0500246 weston_surface_set_color(surface, 0.0f, 0.0f, 0.0f, 1.0f);
247 pixman_region32_fini(&surface->opaque);
248 pixman_region32_init_rect(&surface->opaque, 0, 0, w, h);
249 pixman_region32_fini(&surface->input);
250 pixman_region32_init_rect(&surface->input, 0, 0, w, h);
251
252 weston_surface_set_size(surface, w, h);
253 weston_view_set_position(view, x, y);
254
255 return view;
256}
257
258static void
259fs_output_set_surface(struct fs_output *fsout, struct weston_surface *surface,
Jonas Ådahl496adb32015-11-17 16:00:27 +0800260 enum zwp_fullscreen_shell_v1_present_method method,
Jason Ekstrand946a9482014-04-02 19:53:47 -0500261 int32_t framerate, int presented_for_mode);
262static void
263fs_output_apply_pending(struct fs_output *fsout);
264static void
265fs_output_clear_pending(struct fs_output *fsout);
266
267static void
268fs_output_destroy(struct fs_output *fsout)
269{
270 fs_output_set_surface(fsout, NULL, 0, 0, 0);
271 fs_output_clear_pending(fsout);
272
273 wl_list_remove(&fsout->link);
274
275 if (fsout->output)
276 wl_list_remove(&fsout->output_destroyed.link);
277}
278
279static void
280output_destroyed(struct wl_listener *listener, void *data)
281{
282 struct fs_output *output = container_of(listener,
283 struct fs_output,
284 output_destroyed);
285 fs_output_destroy(output);
286}
287
288static void
289surface_destroyed(struct wl_listener *listener, void *data)
290{
291 struct fs_output *fsout = container_of(listener,
292 struct fs_output,
293 surface_destroyed);
294 fsout->surface = NULL;
295 fsout->view = NULL;
Arnaud Vrace91b6e92016-06-08 17:55:08 +0200296 wl_list_remove(&fsout->transform.link);
297 wl_list_init(&fsout->transform.link);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500298}
299
300static void
301pending_surface_destroyed(struct wl_listener *listener, void *data)
302{
303 struct fs_output *fsout = container_of(listener,
304 struct fs_output,
305 pending.surface_destroyed);
306 fsout->pending.surface = NULL;
307}
308
Armin Krezovićccfd0292016-08-11 15:49:59 +0200309static void
310configure_presented_surface(struct weston_surface *surface, int32_t sx,
311 int32_t sy);
312
Jason Ekstrand946a9482014-04-02 19:53:47 -0500313static struct fs_output *
314fs_output_create(struct fullscreen_shell *shell, struct weston_output *output)
315{
316 struct fs_output *fsout;
Armin Krezovićccfd0292016-08-11 15:49:59 +0200317 struct fs_client_surface *surf;
Jason Ekstrand946a9482014-04-02 19:53:47 -0500318
Ryo Munakata5e653ca2015-08-07 20:20:46 +0900319 fsout = zalloc(sizeof *fsout);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500320 if (!fsout)
321 return NULL;
Jason Ekstrand946a9482014-04-02 19:53:47 -0500322
323 fsout->shell = shell;
324 wl_list_insert(&shell->output_list, &fsout->link);
325
326 fsout->output = output;
327 fsout->output_destroyed.notify = output_destroyed;
328 wl_signal_add(&output->destroy_signal, &fsout->output_destroyed);
329
330 fsout->surface_destroyed.notify = surface_destroyed;
331 fsout->pending.surface_destroyed.notify = pending_surface_destroyed;
332 fsout->black_view = create_black_surface(shell->compositor, fsout,
333 output->x, output->y,
334 output->width, output->height);
Armin Krezovićb1a48e62016-06-30 06:04:30 +0200335 fsout->black_view->surface->is_mapped = true;
336 fsout->black_view->is_mapped = true;
Giulio Camuffod1ceecf2014-07-29 21:57:24 +0300337 weston_layer_entry_insert(&shell->layer.view_list,
Jason Ekstrand946a9482014-04-02 19:53:47 -0500338 &fsout->black_view->layer_link);
339 wl_list_init(&fsout->transform.link);
Armin Krezovićccfd0292016-08-11 15:49:59 +0200340
341 if (!wl_list_empty(&shell->default_surface_list)) {
342 surf = container_of(shell->default_surface_list.prev,
343 struct fs_client_surface, link);
344
345 fs_output_set_surface(fsout, surf->surface, surf->method, 0, 0);
346 configure_presented_surface(surf->surface, 0, 0);
347 }
348
Jason Ekstrand946a9482014-04-02 19:53:47 -0500349 return fsout;
350}
351
352static struct fs_output *
353fs_output_for_output(struct weston_output *output)
354{
355 struct wl_listener *listener;
356
357 if (!output)
358 return NULL;
359
360 listener = wl_signal_get(&output->destroy_signal, output_destroyed);
361
362 return container_of(listener, struct fs_output, output_destroyed);
363}
364
365static void
366restore_output_mode(struct weston_output *output)
367{
Armin Krezović70487cd2016-06-23 11:59:33 +0200368 if (output && output->original_mode)
Derek Foreman6ae7bc92014-11-04 10:47:33 -0600369 weston_output_mode_switch_to_native(output);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500370}
371
372/*
373 * Returns the bounding box of a surface and all its sub-surfaces,
Yong Bakos3b227612016-04-28 11:59:07 -0500374 * in surface-local coordinates. */
Jason Ekstrand946a9482014-04-02 19:53:47 -0500375static void
376surface_subsurfaces_boundingbox(struct weston_surface *surface, int32_t *x,
377 int32_t *y, int32_t *w, int32_t *h) {
378 pixman_region32_t region;
379 pixman_box32_t *box;
380 struct weston_subsurface *subsurface;
381
382 pixman_region32_init_rect(&region, 0, 0,
383 surface->width,
384 surface->height);
385
386 wl_list_for_each(subsurface, &surface->subsurface_list, parent_link) {
387 pixman_region32_union_rect(&region, &region,
388 subsurface->position.x,
389 subsurface->position.y,
390 subsurface->surface->width,
391 subsurface->surface->height);
392 }
393
394 box = pixman_region32_extents(&region);
395 if (x)
396 *x = box->x1;
397 if (y)
398 *y = box->y1;
399 if (w)
400 *w = box->x2 - box->x1;
401 if (h)
402 *h = box->y2 - box->y1;
403
404 pixman_region32_fini(&region);
405}
406
407static void
408fs_output_center_view(struct fs_output *fsout)
409{
410 int32_t surf_x, surf_y, surf_width, surf_height;
411 float x, y;
412 struct weston_output *output = fsout->output;
413
414 surface_subsurfaces_boundingbox(fsout->view->surface, &surf_x, &surf_y,
415 &surf_width, &surf_height);
416
417 x = output->x + (output->width - surf_width) / 2 - surf_x / 2;
418 y = output->y + (output->height - surf_height) / 2 - surf_y / 2;
419
420 weston_view_set_position(fsout->view, x, y);
421}
422
423static void
424fs_output_scale_view(struct fs_output *fsout, float width, float height)
425{
426 float x, y;
427 int32_t surf_x, surf_y, surf_width, surf_height;
428 struct weston_matrix *matrix;
429 struct weston_view *view = fsout->view;
430 struct weston_output *output = fsout->output;
431
432 surface_subsurfaces_boundingbox(view->surface, &surf_x, &surf_y,
433 &surf_width, &surf_height);
434
435 if (output->width == surf_width && output->height == surf_height) {
436 weston_view_set_position(view,
437 fsout->output->x - surf_x,
438 fsout->output->y - surf_y);
439 } else {
440 matrix = &fsout->transform.matrix;
441 weston_matrix_init(matrix);
442
443 weston_matrix_scale(matrix, width / surf_width,
444 height / surf_height, 1);
445 wl_list_remove(&fsout->transform.link);
446 wl_list_insert(&fsout->view->geometry.transformation_list,
447 &fsout->transform.link);
448
449 x = output->x + (output->width - width) / 2 - surf_x;
450 y = output->y + (output->height - height) / 2 - surf_y;
451
452 weston_view_set_position(view, x, y);
453 }
454}
455
456static void
457fs_output_configure(struct fs_output *fsout, struct weston_surface *surface);
458
459static void
460fs_output_configure_simple(struct fs_output *fsout,
461 struct weston_surface *configured_surface)
462{
463 struct weston_output *output = fsout->output;
464 float output_aspect, surface_aspect;
465 int32_t surf_x, surf_y, surf_width, surf_height;
466
467 if (fsout->pending.surface == configured_surface)
468 fs_output_apply_pending(fsout);
469
470 assert(fsout->view);
471
472 restore_output_mode(fsout->output);
473
474 wl_list_remove(&fsout->transform.link);
475 wl_list_init(&fsout->transform.link);
476
477 surface_subsurfaces_boundingbox(fsout->view->surface,
478 &surf_x, &surf_y,
479 &surf_width, &surf_height);
480
481 output_aspect = (float) output->width / (float) output->height;
482 surface_aspect = (float) surf_width / (float) surf_height;
483
484 switch (fsout->method) {
Jonas Ådahl496adb32015-11-17 16:00:27 +0800485 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_DEFAULT:
486 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_CENTER:
Jason Ekstrand946a9482014-04-02 19:53:47 -0500487 fs_output_center_view(fsout);
488 break;
489
Jonas Ådahl496adb32015-11-17 16:00:27 +0800490 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_ZOOM:
Jason Ekstrand946a9482014-04-02 19:53:47 -0500491 if (output_aspect < surface_aspect)
492 fs_output_scale_view(fsout,
493 output->width,
494 output->width / surface_aspect);
495 else
496 fs_output_scale_view(fsout,
497 output->height * surface_aspect,
498 output->height);
499 break;
500
Jonas Ådahl496adb32015-11-17 16:00:27 +0800501 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_ZOOM_CROP:
Jason Ekstrand946a9482014-04-02 19:53:47 -0500502 if (output_aspect < surface_aspect)
503 fs_output_scale_view(fsout,
504 output->height * surface_aspect,
505 output->height);
506 else
507 fs_output_scale_view(fsout,
508 output->width,
509 output->width / surface_aspect);
510 break;
511
Jonas Ådahl496adb32015-11-17 16:00:27 +0800512 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_STRETCH:
Jason Ekstrand946a9482014-04-02 19:53:47 -0500513 fs_output_scale_view(fsout, output->width, output->height);
514 break;
515 default:
516 break;
517 }
518
519 weston_view_set_position(fsout->black_view,
520 fsout->output->x - surf_x,
521 fsout->output->y - surf_y);
522 weston_surface_set_size(fsout->black_view->surface,
523 fsout->output->width,
524 fsout->output->height);
525}
526
527static void
528fs_output_configure_for_mode(struct fs_output *fsout,
529 struct weston_surface *configured_surface)
530{
531 int32_t surf_x, surf_y, surf_width, surf_height;
532 struct weston_mode mode;
533 int ret;
534
535 if (fsout->pending.surface != configured_surface) {
536 /* Nothing to really reconfigure. We'll just recenter the
537 * view in case they played with subsurfaces */
538 fs_output_center_view(fsout);
539 return;
540 }
541
542 /* We have a pending surface */
543 surface_subsurfaces_boundingbox(fsout->pending.surface,
544 &surf_x, &surf_y,
545 &surf_width, &surf_height);
546
Jason Ekstrand58106d72015-01-08 08:57:44 -0800547 /* The actual output mode is in physical units. We need to
548 * transform the surface size to physical unit size by flipping ans
549 * possibly scaling it.
550 */
551 switch (fsout->output->transform) {
552 case WL_OUTPUT_TRANSFORM_90:
553 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
554 case WL_OUTPUT_TRANSFORM_270:
555 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
556 mode.width = surf_height * fsout->output->native_scale;
557 mode.height = surf_width * fsout->output->native_scale;
558 break;
559
560 case WL_OUTPUT_TRANSFORM_NORMAL:
561 case WL_OUTPUT_TRANSFORM_FLIPPED:
562 case WL_OUTPUT_TRANSFORM_180:
563 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
564 default:
565 mode.width = surf_width * fsout->output->native_scale;
566 mode.height = surf_height * fsout->output->native_scale;
567 }
Jason Ekstrand946a9482014-04-02 19:53:47 -0500568 mode.flags = 0;
Jason Ekstrand946a9482014-04-02 19:53:47 -0500569 mode.refresh = fsout->pending.framerate;
570
Derek Foreman6ae7bc92014-11-04 10:47:33 -0600571 ret = weston_output_mode_switch_to_temporary(fsout->output, &mode,
572 fsout->output->native_scale);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500573
574 if (ret != 0) {
575 /* The mode switch failed. Clear the pending and
576 * reconfigure as per normal */
577 if (fsout->pending.mode_feedback) {
Jonas Ådahl496adb32015-11-17 16:00:27 +0800578 zwp_fullscreen_shell_mode_feedback_v1_send_mode_failed(
Jason Ekstrand946a9482014-04-02 19:53:47 -0500579 fsout->pending.mode_feedback);
580 wl_resource_destroy(fsout->pending.mode_feedback);
581 fsout->pending.mode_feedback = NULL;
582 }
583
584 fs_output_clear_pending(fsout);
585 return;
586 }
587
588 if (fsout->pending.mode_feedback) {
Jonas Ådahl496adb32015-11-17 16:00:27 +0800589 zwp_fullscreen_shell_mode_feedback_v1_send_mode_successful(
Jason Ekstrand946a9482014-04-02 19:53:47 -0500590 fsout->pending.mode_feedback);
591 wl_resource_destroy(fsout->pending.mode_feedback);
592 fsout->pending.mode_feedback = NULL;
593 }
594
595 fs_output_apply_pending(fsout);
596
597 weston_view_set_position(fsout->view,
598 fsout->output->x - surf_x,
599 fsout->output->y - surf_y);
600}
601
602static void
603fs_output_configure(struct fs_output *fsout,
604 struct weston_surface *surface)
605{
606 if (fsout->pending.surface == surface) {
607 if (fsout->pending.presented_for_mode)
608 fs_output_configure_for_mode(fsout, surface);
609 else
610 fs_output_configure_simple(fsout, surface);
611 } else {
612 if (fsout->presented_for_mode)
613 fs_output_configure_for_mode(fsout, surface);
614 else
615 fs_output_configure_simple(fsout, surface);
616 }
617
618 weston_output_schedule_repaint(fsout->output);
619}
620
621static void
622configure_presented_surface(struct weston_surface *surface, int32_t sx,
623 int32_t sy)
624{
Quentin Glidic2edc3d52016-08-12 10:41:33 +0200625 struct fullscreen_shell *shell = surface->committed_private;
Jason Ekstrand946a9482014-04-02 19:53:47 -0500626 struct fs_output *fsout;
627
Quentin Glidic2edc3d52016-08-12 10:41:33 +0200628 if (surface->committed != configure_presented_surface)
Jason Ekstrand946a9482014-04-02 19:53:47 -0500629 return;
630
631 wl_list_for_each(fsout, &shell->output_list, link)
632 if (fsout->surface == surface ||
633 fsout->pending.surface == surface)
634 fs_output_configure(fsout, surface);
635}
636
637static void
638fs_output_apply_pending(struct fs_output *fsout)
639{
640 assert(fsout->pending.surface);
641
642 if (fsout->surface && fsout->surface != fsout->pending.surface) {
643 wl_list_remove(&fsout->surface_destroyed.link);
644
645 weston_view_destroy(fsout->view);
646 fsout->view = NULL;
647
648 if (wl_list_empty(&fsout->surface->views)) {
Quentin Glidic2edc3d52016-08-12 10:41:33 +0200649 fsout->surface->committed = NULL;
650 fsout->surface->committed_private = NULL;
Jason Ekstrand946a9482014-04-02 19:53:47 -0500651 }
652
653 fsout->surface = NULL;
654 }
655
656 fsout->method = fsout->pending.method;
657 fsout->framerate = fsout->pending.framerate;
658 fsout->presented_for_mode = fsout->pending.presented_for_mode;
659
660 if (fsout->surface != fsout->pending.surface) {
661 fsout->surface = fsout->pending.surface;
662
663 fsout->view = weston_view_create(fsout->surface);
664 if (!fsout->view) {
665 weston_log("no memory\n");
666 return;
667 }
Armin Krezovićb1a48e62016-06-30 06:04:30 +0200668 fsout->view->is_mapped = true;
Jason Ekstrand946a9482014-04-02 19:53:47 -0500669
670 wl_signal_add(&fsout->surface->destroy_signal,
671 &fsout->surface_destroyed);
Giulio Camuffod1ceecf2014-07-29 21:57:24 +0300672 weston_layer_entry_insert(&fsout->shell->layer.view_list,
Jason Ekstrand946a9482014-04-02 19:53:47 -0500673 &fsout->view->layer_link);
674 }
675
676 fs_output_clear_pending(fsout);
677}
678
679static void
680fs_output_clear_pending(struct fs_output *fsout)
681{
682 if (!fsout->pending.surface)
683 return;
684
685 if (fsout->pending.mode_feedback) {
Jonas Ådahl496adb32015-11-17 16:00:27 +0800686 zwp_fullscreen_shell_mode_feedback_v1_send_present_cancelled(
Jason Ekstrand946a9482014-04-02 19:53:47 -0500687 fsout->pending.mode_feedback);
688 wl_resource_destroy(fsout->pending.mode_feedback);
689 fsout->pending.mode_feedback = NULL;
690 }
691
692 wl_list_remove(&fsout->pending.surface_destroyed.link);
693 fsout->pending.surface = NULL;
694}
695
696static void
697fs_output_set_surface(struct fs_output *fsout, struct weston_surface *surface,
Jonas Ådahl496adb32015-11-17 16:00:27 +0800698 enum zwp_fullscreen_shell_v1_present_method method,
Jason Ekstrand946a9482014-04-02 19:53:47 -0500699 int32_t framerate, int presented_for_mode)
700{
701 fs_output_clear_pending(fsout);
702
703 if (surface) {
Quentin Glidic2edc3d52016-08-12 10:41:33 +0200704 if (!surface->committed) {
705 surface->committed = configure_presented_surface;
706 surface->committed_private = fsout->shell;
Jason Ekstrand946a9482014-04-02 19:53:47 -0500707 }
708
709 fsout->pending.surface = surface;
710 wl_signal_add(&fsout->pending.surface->destroy_signal,
711 &fsout->pending.surface_destroyed);
712
713 fsout->pending.method = method;
714 fsout->pending.framerate = framerate;
715 fsout->pending.presented_for_mode = presented_for_mode;
716 } else if (fsout->surface) {
717 /* we clear immediately */
718 wl_list_remove(&fsout->surface_destroyed.link);
719
720 weston_view_destroy(fsout->view);
721 fsout->view = NULL;
722
723 if (wl_list_empty(&fsout->surface->views)) {
Quentin Glidic2edc3d52016-08-12 10:41:33 +0200724 fsout->surface->committed = NULL;
725 fsout->surface->committed_private = NULL;
Jason Ekstrand946a9482014-04-02 19:53:47 -0500726 }
727
728 fsout->surface = NULL;
729
730 weston_output_schedule_repaint(fsout->output);
731 }
732}
733
734static void
735fullscreen_shell_release(struct wl_client *client,
736 struct wl_resource *resource)
737{
738 wl_resource_destroy(resource);
739}
740
741static void
742fullscreen_shell_present_surface(struct wl_client *client,
743 struct wl_resource *resource,
744 struct wl_resource *surface_res,
745 uint32_t method,
746 struct wl_resource *output_res)
747{
748 struct fullscreen_shell *shell =
749 wl_resource_get_user_data(resource);
750 struct weston_output *output;
751 struct weston_surface *surface;
752 struct weston_seat *seat;
753 struct fs_output *fsout;
754
755 surface = surface_res ? wl_resource_get_user_data(surface_res) : NULL;
756
757 switch(method) {
Jonas Ådahl496adb32015-11-17 16:00:27 +0800758 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_DEFAULT:
759 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_CENTER:
760 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_ZOOM:
761 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_ZOOM_CROP:
762 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_STRETCH:
Jason Ekstrand946a9482014-04-02 19:53:47 -0500763 break;
764 default:
765 wl_resource_post_error(resource,
Jonas Ådahl496adb32015-11-17 16:00:27 +0800766 ZWP_FULLSCREEN_SHELL_V1_ERROR_INVALID_METHOD,
Jason Ekstrand946a9482014-04-02 19:53:47 -0500767 "Invalid presentation method");
768 }
769
770 if (output_res) {
771 output = wl_resource_get_user_data(output_res);
772 fsout = fs_output_for_output(output);
773 fs_output_set_surface(fsout, surface, method, 0, 0);
774 } else {
Armin Krezovićccfd0292016-08-11 15:49:59 +0200775 replace_default_surface(shell, surface, method);
776
Jason Ekstrand946a9482014-04-02 19:53:47 -0500777 wl_list_for_each(fsout, &shell->output_list, link)
778 fs_output_set_surface(fsout, surface, method, 0, 0);
779 }
780
781 if (surface) {
782 wl_list_for_each(seat, &shell->compositor->seat_list, link) {
Derek Foreman1281a362015-07-31 16:55:32 -0500783 struct weston_keyboard *keyboard =
784 weston_seat_get_keyboard(seat);
785
786 if (keyboard && !keyboard->focus)
Bryce Harrington260c2ff2016-06-29 19:04:06 -0700787 weston_seat_set_keyboard_focus(seat, surface);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500788 }
789 }
790}
791
792static void
793mode_feedback_destroyed(struct wl_resource *resource)
794{
795 struct fs_output *fsout = wl_resource_get_user_data(resource);
796
797 fsout->pending.mode_feedback = NULL;
798}
799
800static void
801fullscreen_shell_present_surface_for_mode(struct wl_client *client,
802 struct wl_resource *resource,
803 struct wl_resource *surface_res,
804 struct wl_resource *output_res,
805 int32_t framerate,
806 uint32_t feedback_id)
807{
808 struct fullscreen_shell *shell =
809 wl_resource_get_user_data(resource);
810 struct weston_output *output;
811 struct weston_surface *surface;
812 struct weston_seat *seat;
813 struct fs_output *fsout;
814
815 output = wl_resource_get_user_data(output_res);
816 fsout = fs_output_for_output(output);
817
818 if (surface_res == NULL) {
819 fs_output_set_surface(fsout, NULL, 0, 0, 0);
820 return;
821 }
822
823 surface = wl_resource_get_user_data(surface_res);
824 fs_output_set_surface(fsout, surface, 0, framerate, 1);
825
826 fsout->pending.mode_feedback =
827 wl_resource_create(client,
Jonas Ådahl496adb32015-11-17 16:00:27 +0800828 &zwp_fullscreen_shell_mode_feedback_v1_interface,
Jason Ekstrand946a9482014-04-02 19:53:47 -0500829 1, feedback_id);
830 wl_resource_set_implementation(fsout->pending.mode_feedback, NULL,
831 fsout, mode_feedback_destroyed);
832
833 wl_list_for_each(seat, &shell->compositor->seat_list, link) {
Derek Foreman1281a362015-07-31 16:55:32 -0500834 struct weston_keyboard *keyboard =
835 weston_seat_get_keyboard(seat);
836
837 if (keyboard && !keyboard->focus)
Bryce Harrington260c2ff2016-06-29 19:04:06 -0700838 weston_seat_set_keyboard_focus(seat, surface);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500839 }
840}
841
Jonas Ådahl496adb32015-11-17 16:00:27 +0800842struct zwp_fullscreen_shell_v1_interface fullscreen_shell_implementation = {
Jason Ekstrand946a9482014-04-02 19:53:47 -0500843 fullscreen_shell_release,
844 fullscreen_shell_present_surface,
845 fullscreen_shell_present_surface_for_mode,
846};
847
848static void
849output_created(struct wl_listener *listener, void *data)
850{
851 struct fullscreen_shell *shell;
852
853 shell = container_of(listener, struct fullscreen_shell,
854 output_created_listener);
855
856 fs_output_create(shell, data);
857}
858
859static void
860client_destroyed(struct wl_listener *listener, void *data)
861{
862 struct fullscreen_shell *shell = container_of(listener,
863 struct fullscreen_shell,
864 client_destroyed);
865 shell->client = NULL;
866}
867
868static void
869bind_fullscreen_shell(struct wl_client *client, void *data, uint32_t version,
870 uint32_t id)
871{
872 struct fullscreen_shell *shell = data;
873 struct wl_resource *resource;
874
875 if (shell->client != NULL && shell->client != client)
876 return;
877 else if (shell->client == NULL) {
878 shell->client = client;
879 wl_client_add_destroy_listener(client, &shell->client_destroyed);
880 }
881
Jonas Ådahl496adb32015-11-17 16:00:27 +0800882 resource = wl_resource_create(client,
883 &zwp_fullscreen_shell_v1_interface,
Jason Ekstrand946a9482014-04-02 19:53:47 -0500884 1, id);
885 wl_resource_set_implementation(resource,
886 &fullscreen_shell_implementation,
887 shell, NULL);
888
889 if (shell->compositor->capabilities & WESTON_CAP_CURSOR_PLANE)
Jonas Ådahl496adb32015-11-17 16:00:27 +0800890 zwp_fullscreen_shell_v1_send_capability(resource,
891 ZWP_FULLSCREEN_SHELL_V1_CAPABILITY_CURSOR_PLANE);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500892
893 if (shell->compositor->capabilities & WESTON_CAP_ARBITRARY_MODES)
Jonas Ådahl496adb32015-11-17 16:00:27 +0800894 zwp_fullscreen_shell_v1_send_capability(resource,
895 ZWP_FULLSCREEN_SHELL_V1_CAPABILITY_ARBITRARY_MODES);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500896}
897
898WL_EXPORT int
899module_init(struct weston_compositor *compositor,
900 int *argc, char *argv[])
901{
902 struct fullscreen_shell *shell;
903 struct weston_seat *seat;
904 struct weston_output *output;
905
Ryo Munakata5e653ca2015-08-07 20:20:46 +0900906 shell = zalloc(sizeof *shell);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500907 if (shell == NULL)
908 return -1;
909
Jason Ekstrand946a9482014-04-02 19:53:47 -0500910 shell->compositor = compositor;
Armin Krezovićccfd0292016-08-11 15:49:59 +0200911 wl_list_init(&shell->default_surface_list);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500912
913 shell->client_destroyed.notify = client_destroyed;
914
915 weston_layer_init(&shell->layer, &compositor->cursor_layer.link);
916
917 wl_list_init(&shell->output_list);
918 shell->output_created_listener.notify = output_created;
919 wl_signal_add(&compositor->output_created_signal,
920 &shell->output_created_listener);
921 wl_list_for_each(output, &compositor->output_list, link)
922 fs_output_create(shell, output);
923
924 shell->seat_created_listener.notify = seat_created;
925 wl_signal_add(&compositor->seat_created_signal,
926 &shell->seat_created_listener);
927 wl_list_for_each(seat, &compositor->seat_list, link)
928 seat_created(NULL, seat);
929
930 wl_global_create(compositor->wl_display,
Jonas Ådahl496adb32015-11-17 16:00:27 +0800931 &zwp_fullscreen_shell_v1_interface, 1, shell,
Jason Ekstrand946a9482014-04-02 19:53:47 -0500932 bind_fullscreen_shell);
933
934 return 0;
935}