blob: 6f4565a75204d6a81ff24e1fa1ae4c570a5aa795 [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"
Quentin Glidic3d7ca3b2016-12-02 14:20:35 +010037#include "compositor/weston.h"
Jonas Ådahl496adb32015-11-17 16:00:27 +080038#include "fullscreen-shell-unstable-v1-server-protocol.h"
Jon Cruz867d50e2015-06-15 15:37:10 -070039#include "shared/helpers.h"
Jason Ekstrand946a9482014-04-02 19:53:47 -050040
41struct fullscreen_shell {
42 struct wl_client *client;
43 struct wl_listener client_destroyed;
44 struct weston_compositor *compositor;
45
46 struct weston_layer layer;
47 struct wl_list output_list;
48 struct wl_listener output_created_listener;
49
50 struct wl_listener seat_created_listener;
Armin Krezovićccfd0292016-08-11 15:49:59 +020051
52 /* List of one surface per client, presented for the NULL output
53 *
54 * This is implemented as a list in case someone fixes the shell
55 * implementation to support more than one client.
56 */
57 struct wl_list default_surface_list; /* struct fs_client_surface::link */
Jason Ekstrand946a9482014-04-02 19:53:47 -050058};
59
60struct fs_output {
61 struct fullscreen_shell *shell;
62 struct wl_list link;
63
64 struct weston_output *output;
65 struct wl_listener output_destroyed;
66
67 struct {
68 struct weston_surface *surface;
69 struct wl_listener surface_destroyed;
70 struct wl_resource *mode_feedback;
71
72 int presented_for_mode;
Jonas Ådahl496adb32015-11-17 16:00:27 +080073 enum zwp_fullscreen_shell_v1_present_method method;
Jason Ekstrand946a9482014-04-02 19:53:47 -050074 int32_t framerate;
75 } pending;
76
77 struct weston_surface *surface;
78 struct wl_listener surface_destroyed;
79 struct weston_view *view;
80 struct weston_view *black_view;
81 struct weston_transform transform; /* matrix from x, y */
82
83 int presented_for_mode;
Jonas Ådahl496adb32015-11-17 16:00:27 +080084 enum zwp_fullscreen_shell_v1_present_method method;
Jason Ekstrand946a9482014-04-02 19:53:47 -050085 uint32_t framerate;
86};
87
88struct pointer_focus_listener {
89 struct fullscreen_shell *shell;
90 struct wl_listener pointer_focus;
91 struct wl_listener seat_caps;
92 struct wl_listener seat_destroyed;
93};
94
Armin Krezovićccfd0292016-08-11 15:49:59 +020095struct fs_client_surface {
96 struct weston_surface *surface;
97 enum zwp_fullscreen_shell_v1_present_method method;
98 struct wl_list link; /* struct fullscreen_shell::default_surface_list */
99 struct wl_listener surface_destroyed;
100};
101
102static void
103remove_default_surface(struct fs_client_surface *surf)
104{
105 wl_list_remove(&surf->surface_destroyed.link);
106 wl_list_remove(&surf->link);
107 free(surf);
108}
109
110static void
111default_surface_destroy_listener(struct wl_listener *listener, void *data)
112{
113 struct fs_client_surface *surf;
114
115 surf = container_of(listener, struct fs_client_surface, surface_destroyed);
116
117 remove_default_surface(surf);
118}
119
120static void
121replace_default_surface(struct fullscreen_shell *shell, struct weston_surface *surface,
122 enum zwp_fullscreen_shell_v1_present_method method)
123{
124 struct fs_client_surface *surf, *prev = NULL;
125
126 if (!wl_list_empty(&shell->default_surface_list))
127 prev = container_of(shell->default_surface_list.prev,
128 struct fs_client_surface, link);
129
130 surf = zalloc(sizeof *surf);
131 if (!surf)
132 return;
133
134 surf->surface = surface;
135 surf->method = method;
136
137 if (prev)
138 remove_default_surface(prev);
139
140 wl_list_insert(shell->default_surface_list.prev, &surf->link);
141
142 surf->surface_destroyed.notify = default_surface_destroy_listener;
143 wl_signal_add(&surface->destroy_signal, &surf->surface_destroyed);
144}
145
Jason Ekstrand946a9482014-04-02 19:53:47 -0500146static void
147pointer_focus_changed(struct wl_listener *listener, void *data)
148{
149 struct weston_pointer *pointer = data;
150
151 if (pointer->focus && pointer->focus->surface->resource)
Bryce Harrington260c2ff2016-06-29 19:04:06 -0700152 weston_seat_set_keyboard_focus(pointer->seat, pointer->focus->surface);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500153}
154
155static void
156seat_caps_changed(struct wl_listener *l, void *data)
157{
158 struct weston_seat *seat = data;
Derek Foreman1281a362015-07-31 16:55:32 -0500159 struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
160 struct weston_pointer *pointer = weston_seat_get_pointer(seat);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500161 struct pointer_focus_listener *listener;
162 struct fs_output *fsout;
163
164 listener = container_of(l, struct pointer_focus_listener, seat_caps);
165
166 /* no pointer */
Derek Foreman1281a362015-07-31 16:55:32 -0500167 if (pointer) {
Jason Ekstrand946a9482014-04-02 19:53:47 -0500168 if (!listener->pointer_focus.link.prev) {
Derek Foreman1281a362015-07-31 16:55:32 -0500169 wl_signal_add(&pointer->focus_signal,
Jason Ekstrand946a9482014-04-02 19:53:47 -0500170 &listener->pointer_focus);
171 }
172 } else {
173 if (listener->pointer_focus.link.prev) {
174 wl_list_remove(&listener->pointer_focus.link);
175 }
176 }
177
Derek Foreman1281a362015-07-31 16:55:32 -0500178 if (keyboard && keyboard->focus != NULL) {
Jason Ekstrand946a9482014-04-02 19:53:47 -0500179 wl_list_for_each(fsout, &listener->shell->output_list, link) {
180 if (fsout->surface) {
Bryce Harrington260c2ff2016-06-29 19:04:06 -0700181 weston_seat_set_keyboard_focus(seat, fsout->surface);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500182 return;
183 }
184 }
185 }
186}
187
188static void
189seat_destroyed(struct wl_listener *l, void *data)
190{
191 struct pointer_focus_listener *listener;
192
193 listener = container_of(l, struct pointer_focus_listener,
194 seat_destroyed);
195
196 free(listener);
197}
198
199static void
200seat_created(struct wl_listener *l, void *data)
201{
202 struct weston_seat *seat = data;
203 struct pointer_focus_listener *listener;
204
Ryo Munakata5e653ca2015-08-07 20:20:46 +0900205 listener = zalloc(sizeof *listener);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500206 if (!listener)
207 return;
Jason Ekstrand946a9482014-04-02 19:53:47 -0500208
209 listener->shell = container_of(l, struct fullscreen_shell,
210 seat_created_listener);
211 listener->pointer_focus.notify = pointer_focus_changed;
212 listener->seat_caps.notify = seat_caps_changed;
213 listener->seat_destroyed.notify = seat_destroyed;
214
215 wl_signal_add(&seat->destroy_signal, &listener->seat_destroyed);
216 wl_signal_add(&seat->updated_caps_signal, &listener->seat_caps);
217
218 seat_caps_changed(&listener->seat_caps, seat);
219}
220
221static void
Quentin Glidic2edc3d52016-08-12 10:41:33 +0200222black_surface_committed(struct weston_surface *es, int32_t sx, int32_t sy)
Jason Ekstrand946a9482014-04-02 19:53:47 -0500223{
224}
225
226static struct weston_view *
227create_black_surface(struct weston_compositor *ec, struct fs_output *fsout,
228 float x, float y, int w, int h)
229{
230 struct weston_surface *surface = NULL;
231 struct weston_view *view;
232
233 surface = weston_surface_create(ec);
234 if (surface == NULL) {
235 weston_log("no memory\n");
236 return NULL;
237 }
238 view = weston_view_create(surface);
239 if (!view) {
240 weston_surface_destroy(surface);
241 weston_log("no memory\n");
242 return NULL;
243 }
244
Quentin Glidic2edc3d52016-08-12 10:41:33 +0200245 surface->committed = black_surface_committed;
246 surface->committed_private = fsout;
Jason Ekstrand946a9482014-04-02 19:53:47 -0500247 weston_surface_set_color(surface, 0.0f, 0.0f, 0.0f, 1.0f);
248 pixman_region32_fini(&surface->opaque);
249 pixman_region32_init_rect(&surface->opaque, 0, 0, w, h);
250 pixman_region32_fini(&surface->input);
251 pixman_region32_init_rect(&surface->input, 0, 0, w, h);
252
253 weston_surface_set_size(surface, w, h);
254 weston_view_set_position(view, x, y);
255
256 return view;
257}
258
259static void
260fs_output_set_surface(struct fs_output *fsout, struct weston_surface *surface,
Jonas Ådahl496adb32015-11-17 16:00:27 +0800261 enum zwp_fullscreen_shell_v1_present_method method,
Jason Ekstrand946a9482014-04-02 19:53:47 -0500262 int32_t framerate, int presented_for_mode);
263static void
264fs_output_apply_pending(struct fs_output *fsout);
265static void
266fs_output_clear_pending(struct fs_output *fsout);
267
268static void
269fs_output_destroy(struct fs_output *fsout)
270{
271 fs_output_set_surface(fsout, NULL, 0, 0, 0);
272 fs_output_clear_pending(fsout);
273
274 wl_list_remove(&fsout->link);
275
276 if (fsout->output)
277 wl_list_remove(&fsout->output_destroyed.link);
278}
279
280static void
281output_destroyed(struct wl_listener *listener, void *data)
282{
283 struct fs_output *output = container_of(listener,
284 struct fs_output,
285 output_destroyed);
286 fs_output_destroy(output);
287}
288
289static void
290surface_destroyed(struct wl_listener *listener, void *data)
291{
292 struct fs_output *fsout = container_of(listener,
293 struct fs_output,
294 surface_destroyed);
295 fsout->surface = NULL;
296 fsout->view = NULL;
Arnaud Vrace91b6e92016-06-08 17:55:08 +0200297 wl_list_remove(&fsout->transform.link);
298 wl_list_init(&fsout->transform.link);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500299}
300
301static void
302pending_surface_destroyed(struct wl_listener *listener, void *data)
303{
304 struct fs_output *fsout = container_of(listener,
305 struct fs_output,
306 pending.surface_destroyed);
307 fsout->pending.surface = NULL;
308}
309
Armin Krezovićccfd0292016-08-11 15:49:59 +0200310static void
311configure_presented_surface(struct weston_surface *surface, int32_t sx,
312 int32_t sy);
313
Jason Ekstrand946a9482014-04-02 19:53:47 -0500314static struct fs_output *
315fs_output_create(struct fullscreen_shell *shell, struct weston_output *output)
316{
317 struct fs_output *fsout;
Armin Krezovićccfd0292016-08-11 15:49:59 +0200318 struct fs_client_surface *surf;
Jason Ekstrand946a9482014-04-02 19:53:47 -0500319
Ryo Munakata5e653ca2015-08-07 20:20:46 +0900320 fsout = zalloc(sizeof *fsout);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500321 if (!fsout)
322 return NULL;
Jason Ekstrand946a9482014-04-02 19:53:47 -0500323
324 fsout->shell = shell;
325 wl_list_insert(&shell->output_list, &fsout->link);
326
327 fsout->output = output;
328 fsout->output_destroyed.notify = output_destroyed;
329 wl_signal_add(&output->destroy_signal, &fsout->output_destroyed);
330
331 fsout->surface_destroyed.notify = surface_destroyed;
332 fsout->pending.surface_destroyed.notify = pending_surface_destroyed;
333 fsout->black_view = create_black_surface(shell->compositor, fsout,
334 output->x, output->y,
335 output->width, output->height);
Armin Krezovićb1a48e62016-06-30 06:04:30 +0200336 fsout->black_view->surface->is_mapped = true;
337 fsout->black_view->is_mapped = true;
Giulio Camuffod1ceecf2014-07-29 21:57:24 +0300338 weston_layer_entry_insert(&shell->layer.view_list,
Jason Ekstrand946a9482014-04-02 19:53:47 -0500339 &fsout->black_view->layer_link);
340 wl_list_init(&fsout->transform.link);
Armin Krezovićccfd0292016-08-11 15:49:59 +0200341
342 if (!wl_list_empty(&shell->default_surface_list)) {
343 surf = container_of(shell->default_surface_list.prev,
344 struct fs_client_surface, link);
345
346 fs_output_set_surface(fsout, surf->surface, surf->method, 0, 0);
347 configure_presented_surface(surf->surface, 0, 0);
348 }
349
Jason Ekstrand946a9482014-04-02 19:53:47 -0500350 return fsout;
351}
352
353static struct fs_output *
354fs_output_for_output(struct weston_output *output)
355{
356 struct wl_listener *listener;
357
358 if (!output)
359 return NULL;
360
361 listener = wl_signal_get(&output->destroy_signal, output_destroyed);
362
363 return container_of(listener, struct fs_output, output_destroyed);
364}
365
366static void
367restore_output_mode(struct weston_output *output)
368{
Armin Krezović70487cd2016-06-23 11:59:33 +0200369 if (output && output->original_mode)
Derek Foreman6ae7bc92014-11-04 10:47:33 -0600370 weston_output_mode_switch_to_native(output);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500371}
372
373/*
374 * Returns the bounding box of a surface and all its sub-surfaces,
Yong Bakos3b227612016-04-28 11:59:07 -0500375 * in surface-local coordinates. */
Jason Ekstrand946a9482014-04-02 19:53:47 -0500376static void
377surface_subsurfaces_boundingbox(struct weston_surface *surface, int32_t *x,
378 int32_t *y, int32_t *w, int32_t *h) {
379 pixman_region32_t region;
380 pixman_box32_t *box;
381 struct weston_subsurface *subsurface;
382
383 pixman_region32_init_rect(&region, 0, 0,
384 surface->width,
385 surface->height);
386
387 wl_list_for_each(subsurface, &surface->subsurface_list, parent_link) {
388 pixman_region32_union_rect(&region, &region,
389 subsurface->position.x,
390 subsurface->position.y,
391 subsurface->surface->width,
392 subsurface->surface->height);
393 }
394
395 box = pixman_region32_extents(&region);
396 if (x)
397 *x = box->x1;
398 if (y)
399 *y = box->y1;
400 if (w)
401 *w = box->x2 - box->x1;
402 if (h)
403 *h = box->y2 - box->y1;
404
405 pixman_region32_fini(&region);
406}
407
408static void
409fs_output_center_view(struct fs_output *fsout)
410{
411 int32_t surf_x, surf_y, surf_width, surf_height;
412 float x, y;
413 struct weston_output *output = fsout->output;
414
415 surface_subsurfaces_boundingbox(fsout->view->surface, &surf_x, &surf_y,
416 &surf_width, &surf_height);
417
418 x = output->x + (output->width - surf_width) / 2 - surf_x / 2;
419 y = output->y + (output->height - surf_height) / 2 - surf_y / 2;
420
421 weston_view_set_position(fsout->view, x, y);
422}
423
424static void
425fs_output_scale_view(struct fs_output *fsout, float width, float height)
426{
427 float x, y;
428 int32_t surf_x, surf_y, surf_width, surf_height;
429 struct weston_matrix *matrix;
430 struct weston_view *view = fsout->view;
431 struct weston_output *output = fsout->output;
432
433 surface_subsurfaces_boundingbox(view->surface, &surf_x, &surf_y,
434 &surf_width, &surf_height);
435
436 if (output->width == surf_width && output->height == surf_height) {
437 weston_view_set_position(view,
438 fsout->output->x - surf_x,
439 fsout->output->y - surf_y);
440 } else {
441 matrix = &fsout->transform.matrix;
442 weston_matrix_init(matrix);
443
444 weston_matrix_scale(matrix, width / surf_width,
445 height / surf_height, 1);
446 wl_list_remove(&fsout->transform.link);
447 wl_list_insert(&fsout->view->geometry.transformation_list,
448 &fsout->transform.link);
449
450 x = output->x + (output->width - width) / 2 - surf_x;
451 y = output->y + (output->height - height) / 2 - surf_y;
452
453 weston_view_set_position(view, x, y);
454 }
455}
456
457static void
458fs_output_configure(struct fs_output *fsout, struct weston_surface *surface);
459
460static void
461fs_output_configure_simple(struct fs_output *fsout,
462 struct weston_surface *configured_surface)
463{
464 struct weston_output *output = fsout->output;
465 float output_aspect, surface_aspect;
466 int32_t surf_x, surf_y, surf_width, surf_height;
467
468 if (fsout->pending.surface == configured_surface)
469 fs_output_apply_pending(fsout);
470
471 assert(fsout->view);
472
473 restore_output_mode(fsout->output);
474
475 wl_list_remove(&fsout->transform.link);
476 wl_list_init(&fsout->transform.link);
477
478 surface_subsurfaces_boundingbox(fsout->view->surface,
479 &surf_x, &surf_y,
480 &surf_width, &surf_height);
481
482 output_aspect = (float) output->width / (float) output->height;
483 surface_aspect = (float) surf_width / (float) surf_height;
484
485 switch (fsout->method) {
Jonas Ådahl496adb32015-11-17 16:00:27 +0800486 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_DEFAULT:
487 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_CENTER:
Jason Ekstrand946a9482014-04-02 19:53:47 -0500488 fs_output_center_view(fsout);
489 break;
490
Jonas Ådahl496adb32015-11-17 16:00:27 +0800491 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_ZOOM:
Jason Ekstrand946a9482014-04-02 19:53:47 -0500492 if (output_aspect < surface_aspect)
493 fs_output_scale_view(fsout,
494 output->width,
495 output->width / surface_aspect);
496 else
497 fs_output_scale_view(fsout,
498 output->height * surface_aspect,
499 output->height);
500 break;
501
Jonas Ådahl496adb32015-11-17 16:00:27 +0800502 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_ZOOM_CROP:
Jason Ekstrand946a9482014-04-02 19:53:47 -0500503 if (output_aspect < surface_aspect)
504 fs_output_scale_view(fsout,
505 output->height * surface_aspect,
506 output->height);
507 else
508 fs_output_scale_view(fsout,
509 output->width,
510 output->width / surface_aspect);
511 break;
512
Jonas Ådahl496adb32015-11-17 16:00:27 +0800513 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_STRETCH:
Jason Ekstrand946a9482014-04-02 19:53:47 -0500514 fs_output_scale_view(fsout, output->width, output->height);
515 break;
516 default:
517 break;
518 }
519
520 weston_view_set_position(fsout->black_view,
521 fsout->output->x - surf_x,
522 fsout->output->y - surf_y);
523 weston_surface_set_size(fsout->black_view->surface,
524 fsout->output->width,
525 fsout->output->height);
526}
527
528static void
529fs_output_configure_for_mode(struct fs_output *fsout,
530 struct weston_surface *configured_surface)
531{
532 int32_t surf_x, surf_y, surf_width, surf_height;
533 struct weston_mode mode;
534 int ret;
535
536 if (fsout->pending.surface != configured_surface) {
537 /* Nothing to really reconfigure. We'll just recenter the
538 * view in case they played with subsurfaces */
539 fs_output_center_view(fsout);
540 return;
541 }
542
543 /* We have a pending surface */
544 surface_subsurfaces_boundingbox(fsout->pending.surface,
545 &surf_x, &surf_y,
546 &surf_width, &surf_height);
547
Jason Ekstrand58106d72015-01-08 08:57:44 -0800548 /* The actual output mode is in physical units. We need to
549 * transform the surface size to physical unit size by flipping ans
550 * possibly scaling it.
551 */
552 switch (fsout->output->transform) {
553 case WL_OUTPUT_TRANSFORM_90:
554 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
555 case WL_OUTPUT_TRANSFORM_270:
556 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
557 mode.width = surf_height * fsout->output->native_scale;
558 mode.height = surf_width * fsout->output->native_scale;
559 break;
560
561 case WL_OUTPUT_TRANSFORM_NORMAL:
562 case WL_OUTPUT_TRANSFORM_FLIPPED:
563 case WL_OUTPUT_TRANSFORM_180:
564 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
565 default:
566 mode.width = surf_width * fsout->output->native_scale;
567 mode.height = surf_height * fsout->output->native_scale;
568 }
Jason Ekstrand946a9482014-04-02 19:53:47 -0500569 mode.flags = 0;
Jason Ekstrand946a9482014-04-02 19:53:47 -0500570 mode.refresh = fsout->pending.framerate;
571
Derek Foreman6ae7bc92014-11-04 10:47:33 -0600572 ret = weston_output_mode_switch_to_temporary(fsout->output, &mode,
573 fsout->output->native_scale);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500574
575 if (ret != 0) {
576 /* The mode switch failed. Clear the pending and
577 * reconfigure as per normal */
578 if (fsout->pending.mode_feedback) {
Jonas Ådahl496adb32015-11-17 16:00:27 +0800579 zwp_fullscreen_shell_mode_feedback_v1_send_mode_failed(
Jason Ekstrand946a9482014-04-02 19:53:47 -0500580 fsout->pending.mode_feedback);
581 wl_resource_destroy(fsout->pending.mode_feedback);
582 fsout->pending.mode_feedback = NULL;
583 }
584
585 fs_output_clear_pending(fsout);
586 return;
587 }
588
589 if (fsout->pending.mode_feedback) {
Jonas Ådahl496adb32015-11-17 16:00:27 +0800590 zwp_fullscreen_shell_mode_feedback_v1_send_mode_successful(
Jason Ekstrand946a9482014-04-02 19:53:47 -0500591 fsout->pending.mode_feedback);
592 wl_resource_destroy(fsout->pending.mode_feedback);
593 fsout->pending.mode_feedback = NULL;
594 }
595
596 fs_output_apply_pending(fsout);
597
598 weston_view_set_position(fsout->view,
599 fsout->output->x - surf_x,
600 fsout->output->y - surf_y);
601}
602
603static void
604fs_output_configure(struct fs_output *fsout,
605 struct weston_surface *surface)
606{
607 if (fsout->pending.surface == surface) {
608 if (fsout->pending.presented_for_mode)
609 fs_output_configure_for_mode(fsout, surface);
610 else
611 fs_output_configure_simple(fsout, surface);
612 } else {
613 if (fsout->presented_for_mode)
614 fs_output_configure_for_mode(fsout, surface);
615 else
616 fs_output_configure_simple(fsout, surface);
617 }
618
619 weston_output_schedule_repaint(fsout->output);
620}
621
622static void
623configure_presented_surface(struct weston_surface *surface, int32_t sx,
624 int32_t sy)
625{
Quentin Glidic2edc3d52016-08-12 10:41:33 +0200626 struct fullscreen_shell *shell = surface->committed_private;
Jason Ekstrand946a9482014-04-02 19:53:47 -0500627 struct fs_output *fsout;
628
Quentin Glidic2edc3d52016-08-12 10:41:33 +0200629 if (surface->committed != configure_presented_surface)
Jason Ekstrand946a9482014-04-02 19:53:47 -0500630 return;
631
632 wl_list_for_each(fsout, &shell->output_list, link)
633 if (fsout->surface == surface ||
634 fsout->pending.surface == surface)
635 fs_output_configure(fsout, surface);
636}
637
638static void
639fs_output_apply_pending(struct fs_output *fsout)
640{
641 assert(fsout->pending.surface);
642
643 if (fsout->surface && fsout->surface != fsout->pending.surface) {
644 wl_list_remove(&fsout->surface_destroyed.link);
645
646 weston_view_destroy(fsout->view);
647 fsout->view = NULL;
648
649 if (wl_list_empty(&fsout->surface->views)) {
Quentin Glidic2edc3d52016-08-12 10:41:33 +0200650 fsout->surface->committed = NULL;
651 fsout->surface->committed_private = NULL;
Jason Ekstrand946a9482014-04-02 19:53:47 -0500652 }
653
654 fsout->surface = NULL;
655 }
656
657 fsout->method = fsout->pending.method;
658 fsout->framerate = fsout->pending.framerate;
659 fsout->presented_for_mode = fsout->pending.presented_for_mode;
660
661 if (fsout->surface != fsout->pending.surface) {
662 fsout->surface = fsout->pending.surface;
663
664 fsout->view = weston_view_create(fsout->surface);
665 if (!fsout->view) {
666 weston_log("no memory\n");
667 return;
668 }
Armin Krezovićb1a48e62016-06-30 06:04:30 +0200669 fsout->view->is_mapped = true;
Jason Ekstrand946a9482014-04-02 19:53:47 -0500670
671 wl_signal_add(&fsout->surface->destroy_signal,
672 &fsout->surface_destroyed);
Giulio Camuffod1ceecf2014-07-29 21:57:24 +0300673 weston_layer_entry_insert(&fsout->shell->layer.view_list,
Jason Ekstrand946a9482014-04-02 19:53:47 -0500674 &fsout->view->layer_link);
675 }
676
677 fs_output_clear_pending(fsout);
678}
679
680static void
681fs_output_clear_pending(struct fs_output *fsout)
682{
683 if (!fsout->pending.surface)
684 return;
685
686 if (fsout->pending.mode_feedback) {
Jonas Ådahl496adb32015-11-17 16:00:27 +0800687 zwp_fullscreen_shell_mode_feedback_v1_send_present_cancelled(
Jason Ekstrand946a9482014-04-02 19:53:47 -0500688 fsout->pending.mode_feedback);
689 wl_resource_destroy(fsout->pending.mode_feedback);
690 fsout->pending.mode_feedback = NULL;
691 }
692
693 wl_list_remove(&fsout->pending.surface_destroyed.link);
694 fsout->pending.surface = NULL;
695}
696
697static void
698fs_output_set_surface(struct fs_output *fsout, struct weston_surface *surface,
Jonas Ådahl496adb32015-11-17 16:00:27 +0800699 enum zwp_fullscreen_shell_v1_present_method method,
Jason Ekstrand946a9482014-04-02 19:53:47 -0500700 int32_t framerate, int presented_for_mode)
701{
702 fs_output_clear_pending(fsout);
703
704 if (surface) {
Quentin Glidic2edc3d52016-08-12 10:41:33 +0200705 if (!surface->committed) {
706 surface->committed = configure_presented_surface;
707 surface->committed_private = fsout->shell;
Jason Ekstrand946a9482014-04-02 19:53:47 -0500708 }
709
710 fsout->pending.surface = surface;
711 wl_signal_add(&fsout->pending.surface->destroy_signal,
712 &fsout->pending.surface_destroyed);
713
714 fsout->pending.method = method;
715 fsout->pending.framerate = framerate;
716 fsout->pending.presented_for_mode = presented_for_mode;
717 } else if (fsout->surface) {
718 /* we clear immediately */
719 wl_list_remove(&fsout->surface_destroyed.link);
720
721 weston_view_destroy(fsout->view);
722 fsout->view = NULL;
723
724 if (wl_list_empty(&fsout->surface->views)) {
Quentin Glidic2edc3d52016-08-12 10:41:33 +0200725 fsout->surface->committed = NULL;
726 fsout->surface->committed_private = NULL;
Jason Ekstrand946a9482014-04-02 19:53:47 -0500727 }
728
729 fsout->surface = NULL;
730
731 weston_output_schedule_repaint(fsout->output);
732 }
733}
734
735static void
736fullscreen_shell_release(struct wl_client *client,
737 struct wl_resource *resource)
738{
739 wl_resource_destroy(resource);
740}
741
742static void
743fullscreen_shell_present_surface(struct wl_client *client,
744 struct wl_resource *resource,
745 struct wl_resource *surface_res,
746 uint32_t method,
747 struct wl_resource *output_res)
748{
749 struct fullscreen_shell *shell =
750 wl_resource_get_user_data(resource);
751 struct weston_output *output;
752 struct weston_surface *surface;
753 struct weston_seat *seat;
754 struct fs_output *fsout;
755
756 surface = surface_res ? wl_resource_get_user_data(surface_res) : NULL;
757
758 switch(method) {
Jonas Ådahl496adb32015-11-17 16:00:27 +0800759 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_DEFAULT:
760 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_CENTER:
761 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_ZOOM:
762 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_ZOOM_CROP:
763 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_STRETCH:
Jason Ekstrand946a9482014-04-02 19:53:47 -0500764 break;
765 default:
766 wl_resource_post_error(resource,
Jonas Ådahl496adb32015-11-17 16:00:27 +0800767 ZWP_FULLSCREEN_SHELL_V1_ERROR_INVALID_METHOD,
Jason Ekstrand946a9482014-04-02 19:53:47 -0500768 "Invalid presentation method");
769 }
770
771 if (output_res) {
Pekka Paalanen9ffb2502017-03-27 15:14:32 +0300772 output = weston_output_from_resource(output_res);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500773 fsout = fs_output_for_output(output);
774 fs_output_set_surface(fsout, surface, method, 0, 0);
775 } else {
Armin Krezovićccfd0292016-08-11 15:49:59 +0200776 replace_default_surface(shell, surface, method);
777
Jason Ekstrand946a9482014-04-02 19:53:47 -0500778 wl_list_for_each(fsout, &shell->output_list, link)
779 fs_output_set_surface(fsout, surface, method, 0, 0);
780 }
781
782 if (surface) {
783 wl_list_for_each(seat, &shell->compositor->seat_list, link) {
Derek Foreman1281a362015-07-31 16:55:32 -0500784 struct weston_keyboard *keyboard =
785 weston_seat_get_keyboard(seat);
786
787 if (keyboard && !keyboard->focus)
Bryce Harrington260c2ff2016-06-29 19:04:06 -0700788 weston_seat_set_keyboard_focus(seat, surface);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500789 }
790 }
791}
792
793static void
794mode_feedback_destroyed(struct wl_resource *resource)
795{
796 struct fs_output *fsout = wl_resource_get_user_data(resource);
797
798 fsout->pending.mode_feedback = NULL;
799}
800
801static void
802fullscreen_shell_present_surface_for_mode(struct wl_client *client,
803 struct wl_resource *resource,
804 struct wl_resource *surface_res,
805 struct wl_resource *output_res,
806 int32_t framerate,
807 uint32_t feedback_id)
808{
809 struct fullscreen_shell *shell =
810 wl_resource_get_user_data(resource);
811 struct weston_output *output;
812 struct weston_surface *surface;
813 struct weston_seat *seat;
814 struct fs_output *fsout;
815
Pekka Paalanen9ffb2502017-03-27 15:14:32 +0300816 output = weston_output_from_resource(output_res);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500817 fsout = fs_output_for_output(output);
818
819 if (surface_res == NULL) {
820 fs_output_set_surface(fsout, NULL, 0, 0, 0);
821 return;
822 }
823
824 surface = wl_resource_get_user_data(surface_res);
825 fs_output_set_surface(fsout, surface, 0, framerate, 1);
826
827 fsout->pending.mode_feedback =
828 wl_resource_create(client,
Jonas Ådahl496adb32015-11-17 16:00:27 +0800829 &zwp_fullscreen_shell_mode_feedback_v1_interface,
Jason Ekstrand946a9482014-04-02 19:53:47 -0500830 1, feedback_id);
831 wl_resource_set_implementation(fsout->pending.mode_feedback, NULL,
832 fsout, mode_feedback_destroyed);
833
834 wl_list_for_each(seat, &shell->compositor->seat_list, link) {
Derek Foreman1281a362015-07-31 16:55:32 -0500835 struct weston_keyboard *keyboard =
836 weston_seat_get_keyboard(seat);
837
838 if (keyboard && !keyboard->focus)
Bryce Harrington260c2ff2016-06-29 19:04:06 -0700839 weston_seat_set_keyboard_focus(seat, surface);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500840 }
841}
842
Jonas Ådahl496adb32015-11-17 16:00:27 +0800843struct zwp_fullscreen_shell_v1_interface fullscreen_shell_implementation = {
Jason Ekstrand946a9482014-04-02 19:53:47 -0500844 fullscreen_shell_release,
845 fullscreen_shell_present_surface,
846 fullscreen_shell_present_surface_for_mode,
847};
848
849static void
850output_created(struct wl_listener *listener, void *data)
851{
852 struct fullscreen_shell *shell;
853
854 shell = container_of(listener, struct fullscreen_shell,
855 output_created_listener);
856
857 fs_output_create(shell, data);
858}
859
860static void
861client_destroyed(struct wl_listener *listener, void *data)
862{
863 struct fullscreen_shell *shell = container_of(listener,
864 struct fullscreen_shell,
865 client_destroyed);
866 shell->client = NULL;
867}
868
869static void
870bind_fullscreen_shell(struct wl_client *client, void *data, uint32_t version,
871 uint32_t id)
872{
873 struct fullscreen_shell *shell = data;
874 struct wl_resource *resource;
875
876 if (shell->client != NULL && shell->client != client)
877 return;
878 else if (shell->client == NULL) {
879 shell->client = client;
880 wl_client_add_destroy_listener(client, &shell->client_destroyed);
881 }
882
Jonas Ådahl496adb32015-11-17 16:00:27 +0800883 resource = wl_resource_create(client,
884 &zwp_fullscreen_shell_v1_interface,
Jason Ekstrand946a9482014-04-02 19:53:47 -0500885 1, id);
886 wl_resource_set_implementation(resource,
887 &fullscreen_shell_implementation,
888 shell, NULL);
889
890 if (shell->compositor->capabilities & WESTON_CAP_CURSOR_PLANE)
Jonas Ådahl496adb32015-11-17 16:00:27 +0800891 zwp_fullscreen_shell_v1_send_capability(resource,
892 ZWP_FULLSCREEN_SHELL_V1_CAPABILITY_CURSOR_PLANE);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500893
894 if (shell->compositor->capabilities & WESTON_CAP_ARBITRARY_MODES)
Jonas Ådahl496adb32015-11-17 16:00:27 +0800895 zwp_fullscreen_shell_v1_send_capability(resource,
896 ZWP_FULLSCREEN_SHELL_V1_CAPABILITY_ARBITRARY_MODES);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500897}
898
899WL_EXPORT int
Quentin Glidicda01c1d2016-12-02 14:17:08 +0100900wet_shell_init(struct weston_compositor *compositor,
901 int *argc, char *argv[])
Jason Ekstrand946a9482014-04-02 19:53:47 -0500902{
903 struct fullscreen_shell *shell;
904 struct weston_seat *seat;
905 struct weston_output *output;
906
Ryo Munakata5e653ca2015-08-07 20:20:46 +0900907 shell = zalloc(sizeof *shell);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500908 if (shell == NULL)
909 return -1;
910
Jason Ekstrand946a9482014-04-02 19:53:47 -0500911 shell->compositor = compositor;
Armin Krezovićccfd0292016-08-11 15:49:59 +0200912 wl_list_init(&shell->default_surface_list);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500913
914 shell->client_destroyed.notify = client_destroyed;
915
Quentin Glidic82681572016-12-17 13:40:51 +0100916 weston_layer_init(&shell->layer, compositor);
917 weston_layer_set_position(&shell->layer,
918 WESTON_LAYER_POSITION_FULLSCREEN);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500919
920 wl_list_init(&shell->output_list);
921 shell->output_created_listener.notify = output_created;
922 wl_signal_add(&compositor->output_created_signal,
923 &shell->output_created_listener);
924 wl_list_for_each(output, &compositor->output_list, link)
925 fs_output_create(shell, output);
926
927 shell->seat_created_listener.notify = seat_created;
928 wl_signal_add(&compositor->seat_created_signal,
929 &shell->seat_created_listener);
930 wl_list_for_each(seat, &compositor->seat_list, link)
931 seat_created(NULL, seat);
932
933 wl_global_create(compositor->wl_display,
Jonas Ådahl496adb32015-11-17 16:00:27 +0800934 &zwp_fullscreen_shell_v1_interface, 1, shell,
Jason Ekstrand946a9482014-04-02 19:53:47 -0500935 bind_fullscreen_shell);
936
937 return 0;
938}