blob: 2ec2d0217e81a36e23d0a8134fae04cd89199f34 [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)
Bryce Harrington260c2ff2016-06-29 19:04:06 -070092 weston_seat_set_keyboard_focus(pointer->seat, pointer->focus->surface);
Jason Ekstrand946a9482014-04-02 19:53:47 -050093}
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) {
Bryce Harrington260c2ff2016-06-29 19:04:06 -0700121 weston_seat_set_keyboard_focus(seat, fsout->surface);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500122 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);
Armin Krezovićb1a48e62016-06-30 06:04:30 +0200269 fsout->black_view->surface->is_mapped = true;
270 fsout->black_view->is_mapped = true;
Giulio Camuffod1ceecf2014-07-29 21:57:24 +0300271 weston_layer_entry_insert(&shell->layer.view_list,
Jason Ekstrand946a9482014-04-02 19:53:47 -0500272 &fsout->black_view->layer_link);
273 wl_list_init(&fsout->transform.link);
274 return fsout;
275}
276
277static struct fs_output *
278fs_output_for_output(struct weston_output *output)
279{
280 struct wl_listener *listener;
281
282 if (!output)
283 return NULL;
284
285 listener = wl_signal_get(&output->destroy_signal, output_destroyed);
286
287 return container_of(listener, struct fs_output, output_destroyed);
288}
289
290static void
291restore_output_mode(struct weston_output *output)
292{
Armin Krezović70487cd2016-06-23 11:59:33 +0200293 if (output && output->original_mode)
Derek Foreman6ae7bc92014-11-04 10:47:33 -0600294 weston_output_mode_switch_to_native(output);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500295}
296
297/*
298 * Returns the bounding box of a surface and all its sub-surfaces,
Yong Bakos3b227612016-04-28 11:59:07 -0500299 * in surface-local coordinates. */
Jason Ekstrand946a9482014-04-02 19:53:47 -0500300static void
301surface_subsurfaces_boundingbox(struct weston_surface *surface, int32_t *x,
302 int32_t *y, int32_t *w, int32_t *h) {
303 pixman_region32_t region;
304 pixman_box32_t *box;
305 struct weston_subsurface *subsurface;
306
307 pixman_region32_init_rect(&region, 0, 0,
308 surface->width,
309 surface->height);
310
311 wl_list_for_each(subsurface, &surface->subsurface_list, parent_link) {
312 pixman_region32_union_rect(&region, &region,
313 subsurface->position.x,
314 subsurface->position.y,
315 subsurface->surface->width,
316 subsurface->surface->height);
317 }
318
319 box = pixman_region32_extents(&region);
320 if (x)
321 *x = box->x1;
322 if (y)
323 *y = box->y1;
324 if (w)
325 *w = box->x2 - box->x1;
326 if (h)
327 *h = box->y2 - box->y1;
328
329 pixman_region32_fini(&region);
330}
331
332static void
333fs_output_center_view(struct fs_output *fsout)
334{
335 int32_t surf_x, surf_y, surf_width, surf_height;
336 float x, y;
337 struct weston_output *output = fsout->output;
338
339 surface_subsurfaces_boundingbox(fsout->view->surface, &surf_x, &surf_y,
340 &surf_width, &surf_height);
341
342 x = output->x + (output->width - surf_width) / 2 - surf_x / 2;
343 y = output->y + (output->height - surf_height) / 2 - surf_y / 2;
344
345 weston_view_set_position(fsout->view, x, y);
346}
347
348static void
349fs_output_scale_view(struct fs_output *fsout, float width, float height)
350{
351 float x, y;
352 int32_t surf_x, surf_y, surf_width, surf_height;
353 struct weston_matrix *matrix;
354 struct weston_view *view = fsout->view;
355 struct weston_output *output = fsout->output;
356
357 surface_subsurfaces_boundingbox(view->surface, &surf_x, &surf_y,
358 &surf_width, &surf_height);
359
360 if (output->width == surf_width && output->height == surf_height) {
361 weston_view_set_position(view,
362 fsout->output->x - surf_x,
363 fsout->output->y - surf_y);
364 } else {
365 matrix = &fsout->transform.matrix;
366 weston_matrix_init(matrix);
367
368 weston_matrix_scale(matrix, width / surf_width,
369 height / surf_height, 1);
370 wl_list_remove(&fsout->transform.link);
371 wl_list_insert(&fsout->view->geometry.transformation_list,
372 &fsout->transform.link);
373
374 x = output->x + (output->width - width) / 2 - surf_x;
375 y = output->y + (output->height - height) / 2 - surf_y;
376
377 weston_view_set_position(view, x, y);
378 }
379}
380
381static void
382fs_output_configure(struct fs_output *fsout, struct weston_surface *surface);
383
384static void
385fs_output_configure_simple(struct fs_output *fsout,
386 struct weston_surface *configured_surface)
387{
388 struct weston_output *output = fsout->output;
389 float output_aspect, surface_aspect;
390 int32_t surf_x, surf_y, surf_width, surf_height;
391
392 if (fsout->pending.surface == configured_surface)
393 fs_output_apply_pending(fsout);
394
395 assert(fsout->view);
396
397 restore_output_mode(fsout->output);
398
399 wl_list_remove(&fsout->transform.link);
400 wl_list_init(&fsout->transform.link);
401
402 surface_subsurfaces_boundingbox(fsout->view->surface,
403 &surf_x, &surf_y,
404 &surf_width, &surf_height);
405
406 output_aspect = (float) output->width / (float) output->height;
407 surface_aspect = (float) surf_width / (float) surf_height;
408
409 switch (fsout->method) {
Jonas Ådahl496adb32015-11-17 16:00:27 +0800410 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_DEFAULT:
411 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_CENTER:
Jason Ekstrand946a9482014-04-02 19:53:47 -0500412 fs_output_center_view(fsout);
413 break;
414
Jonas Ådahl496adb32015-11-17 16:00:27 +0800415 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_ZOOM:
Jason Ekstrand946a9482014-04-02 19:53:47 -0500416 if (output_aspect < surface_aspect)
417 fs_output_scale_view(fsout,
418 output->width,
419 output->width / surface_aspect);
420 else
421 fs_output_scale_view(fsout,
422 output->height * surface_aspect,
423 output->height);
424 break;
425
Jonas Ådahl496adb32015-11-17 16:00:27 +0800426 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_ZOOM_CROP:
Jason Ekstrand946a9482014-04-02 19:53:47 -0500427 if (output_aspect < surface_aspect)
428 fs_output_scale_view(fsout,
429 output->height * surface_aspect,
430 output->height);
431 else
432 fs_output_scale_view(fsout,
433 output->width,
434 output->width / surface_aspect);
435 break;
436
Jonas Ådahl496adb32015-11-17 16:00:27 +0800437 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_STRETCH:
Jason Ekstrand946a9482014-04-02 19:53:47 -0500438 fs_output_scale_view(fsout, output->width, output->height);
439 break;
440 default:
441 break;
442 }
443
444 weston_view_set_position(fsout->black_view,
445 fsout->output->x - surf_x,
446 fsout->output->y - surf_y);
447 weston_surface_set_size(fsout->black_view->surface,
448 fsout->output->width,
449 fsout->output->height);
450}
451
452static void
453fs_output_configure_for_mode(struct fs_output *fsout,
454 struct weston_surface *configured_surface)
455{
456 int32_t surf_x, surf_y, surf_width, surf_height;
457 struct weston_mode mode;
458 int ret;
459
460 if (fsout->pending.surface != configured_surface) {
461 /* Nothing to really reconfigure. We'll just recenter the
462 * view in case they played with subsurfaces */
463 fs_output_center_view(fsout);
464 return;
465 }
466
467 /* We have a pending surface */
468 surface_subsurfaces_boundingbox(fsout->pending.surface,
469 &surf_x, &surf_y,
470 &surf_width, &surf_height);
471
Jason Ekstrand58106d72015-01-08 08:57:44 -0800472 /* The actual output mode is in physical units. We need to
473 * transform the surface size to physical unit size by flipping ans
474 * possibly scaling it.
475 */
476 switch (fsout->output->transform) {
477 case WL_OUTPUT_TRANSFORM_90:
478 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
479 case WL_OUTPUT_TRANSFORM_270:
480 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
481 mode.width = surf_height * fsout->output->native_scale;
482 mode.height = surf_width * fsout->output->native_scale;
483 break;
484
485 case WL_OUTPUT_TRANSFORM_NORMAL:
486 case WL_OUTPUT_TRANSFORM_FLIPPED:
487 case WL_OUTPUT_TRANSFORM_180:
488 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
489 default:
490 mode.width = surf_width * fsout->output->native_scale;
491 mode.height = surf_height * fsout->output->native_scale;
492 }
Jason Ekstrand946a9482014-04-02 19:53:47 -0500493 mode.flags = 0;
Jason Ekstrand946a9482014-04-02 19:53:47 -0500494 mode.refresh = fsout->pending.framerate;
495
Derek Foreman6ae7bc92014-11-04 10:47:33 -0600496 ret = weston_output_mode_switch_to_temporary(fsout->output, &mode,
497 fsout->output->native_scale);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500498
499 if (ret != 0) {
500 /* The mode switch failed. Clear the pending and
501 * reconfigure as per normal */
502 if (fsout->pending.mode_feedback) {
Jonas Ådahl496adb32015-11-17 16:00:27 +0800503 zwp_fullscreen_shell_mode_feedback_v1_send_mode_failed(
Jason Ekstrand946a9482014-04-02 19:53:47 -0500504 fsout->pending.mode_feedback);
505 wl_resource_destroy(fsout->pending.mode_feedback);
506 fsout->pending.mode_feedback = NULL;
507 }
508
509 fs_output_clear_pending(fsout);
510 return;
511 }
512
513 if (fsout->pending.mode_feedback) {
Jonas Ådahl496adb32015-11-17 16:00:27 +0800514 zwp_fullscreen_shell_mode_feedback_v1_send_mode_successful(
Jason Ekstrand946a9482014-04-02 19:53:47 -0500515 fsout->pending.mode_feedback);
516 wl_resource_destroy(fsout->pending.mode_feedback);
517 fsout->pending.mode_feedback = NULL;
518 }
519
520 fs_output_apply_pending(fsout);
521
522 weston_view_set_position(fsout->view,
523 fsout->output->x - surf_x,
524 fsout->output->y - surf_y);
525}
526
527static void
528fs_output_configure(struct fs_output *fsout,
529 struct weston_surface *surface)
530{
531 if (fsout->pending.surface == surface) {
532 if (fsout->pending.presented_for_mode)
533 fs_output_configure_for_mode(fsout, surface);
534 else
535 fs_output_configure_simple(fsout, surface);
536 } else {
537 if (fsout->presented_for_mode)
538 fs_output_configure_for_mode(fsout, surface);
539 else
540 fs_output_configure_simple(fsout, surface);
541 }
542
543 weston_output_schedule_repaint(fsout->output);
544}
545
546static void
547configure_presented_surface(struct weston_surface *surface, int32_t sx,
548 int32_t sy)
549{
550 struct fullscreen_shell *shell = surface->configure_private;
551 struct fs_output *fsout;
552
553 if (surface->configure != configure_presented_surface)
554 return;
555
556 wl_list_for_each(fsout, &shell->output_list, link)
557 if (fsout->surface == surface ||
558 fsout->pending.surface == surface)
559 fs_output_configure(fsout, surface);
560}
561
562static void
563fs_output_apply_pending(struct fs_output *fsout)
564{
565 assert(fsout->pending.surface);
566
567 if (fsout->surface && fsout->surface != fsout->pending.surface) {
568 wl_list_remove(&fsout->surface_destroyed.link);
569
570 weston_view_destroy(fsout->view);
571 fsout->view = NULL;
572
573 if (wl_list_empty(&fsout->surface->views)) {
574 fsout->surface->configure = NULL;
575 fsout->surface->configure_private = NULL;
576 }
577
578 fsout->surface = NULL;
579 }
580
581 fsout->method = fsout->pending.method;
582 fsout->framerate = fsout->pending.framerate;
583 fsout->presented_for_mode = fsout->pending.presented_for_mode;
584
585 if (fsout->surface != fsout->pending.surface) {
586 fsout->surface = fsout->pending.surface;
587
588 fsout->view = weston_view_create(fsout->surface);
589 if (!fsout->view) {
590 weston_log("no memory\n");
591 return;
592 }
Armin Krezovićb1a48e62016-06-30 06:04:30 +0200593 fsout->view->is_mapped = true;
Jason Ekstrand946a9482014-04-02 19:53:47 -0500594
595 wl_signal_add(&fsout->surface->destroy_signal,
596 &fsout->surface_destroyed);
Giulio Camuffod1ceecf2014-07-29 21:57:24 +0300597 weston_layer_entry_insert(&fsout->shell->layer.view_list,
Jason Ekstrand946a9482014-04-02 19:53:47 -0500598 &fsout->view->layer_link);
599 }
600
601 fs_output_clear_pending(fsout);
602}
603
604static void
605fs_output_clear_pending(struct fs_output *fsout)
606{
607 if (!fsout->pending.surface)
608 return;
609
610 if (fsout->pending.mode_feedback) {
Jonas Ådahl496adb32015-11-17 16:00:27 +0800611 zwp_fullscreen_shell_mode_feedback_v1_send_present_cancelled(
Jason Ekstrand946a9482014-04-02 19:53:47 -0500612 fsout->pending.mode_feedback);
613 wl_resource_destroy(fsout->pending.mode_feedback);
614 fsout->pending.mode_feedback = NULL;
615 }
616
617 wl_list_remove(&fsout->pending.surface_destroyed.link);
618 fsout->pending.surface = NULL;
619}
620
621static void
622fs_output_set_surface(struct fs_output *fsout, struct weston_surface *surface,
Jonas Ådahl496adb32015-11-17 16:00:27 +0800623 enum zwp_fullscreen_shell_v1_present_method method,
Jason Ekstrand946a9482014-04-02 19:53:47 -0500624 int32_t framerate, int presented_for_mode)
625{
626 fs_output_clear_pending(fsout);
627
628 if (surface) {
629 if (!surface->configure) {
630 surface->configure = configure_presented_surface;
631 surface->configure_private = fsout->shell;
632 }
633
634 fsout->pending.surface = surface;
635 wl_signal_add(&fsout->pending.surface->destroy_signal,
636 &fsout->pending.surface_destroyed);
637
638 fsout->pending.method = method;
639 fsout->pending.framerate = framerate;
640 fsout->pending.presented_for_mode = presented_for_mode;
641 } else if (fsout->surface) {
642 /* we clear immediately */
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)) {
649 fsout->surface->configure = NULL;
650 fsout->surface->configure_private = NULL;
651 }
652
653 fsout->surface = NULL;
654
655 weston_output_schedule_repaint(fsout->output);
656 }
657}
658
659static void
660fullscreen_shell_release(struct wl_client *client,
661 struct wl_resource *resource)
662{
663 wl_resource_destroy(resource);
664}
665
666static void
667fullscreen_shell_present_surface(struct wl_client *client,
668 struct wl_resource *resource,
669 struct wl_resource *surface_res,
670 uint32_t method,
671 struct wl_resource *output_res)
672{
673 struct fullscreen_shell *shell =
674 wl_resource_get_user_data(resource);
675 struct weston_output *output;
676 struct weston_surface *surface;
677 struct weston_seat *seat;
678 struct fs_output *fsout;
679
680 surface = surface_res ? wl_resource_get_user_data(surface_res) : NULL;
681
682 switch(method) {
Jonas Ådahl496adb32015-11-17 16:00:27 +0800683 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_DEFAULT:
684 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_CENTER:
685 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_ZOOM:
686 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_ZOOM_CROP:
687 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_STRETCH:
Jason Ekstrand946a9482014-04-02 19:53:47 -0500688 break;
689 default:
690 wl_resource_post_error(resource,
Jonas Ådahl496adb32015-11-17 16:00:27 +0800691 ZWP_FULLSCREEN_SHELL_V1_ERROR_INVALID_METHOD,
Jason Ekstrand946a9482014-04-02 19:53:47 -0500692 "Invalid presentation method");
693 }
694
695 if (output_res) {
696 output = wl_resource_get_user_data(output_res);
697 fsout = fs_output_for_output(output);
698 fs_output_set_surface(fsout, surface, method, 0, 0);
699 } else {
700 wl_list_for_each(fsout, &shell->output_list, link)
701 fs_output_set_surface(fsout, surface, method, 0, 0);
702 }
703
704 if (surface) {
705 wl_list_for_each(seat, &shell->compositor->seat_list, link) {
Derek Foreman1281a362015-07-31 16:55:32 -0500706 struct weston_keyboard *keyboard =
707 weston_seat_get_keyboard(seat);
708
709 if (keyboard && !keyboard->focus)
Bryce Harrington260c2ff2016-06-29 19:04:06 -0700710 weston_seat_set_keyboard_focus(seat, surface);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500711 }
712 }
713}
714
715static void
716mode_feedback_destroyed(struct wl_resource *resource)
717{
718 struct fs_output *fsout = wl_resource_get_user_data(resource);
719
720 fsout->pending.mode_feedback = NULL;
721}
722
723static void
724fullscreen_shell_present_surface_for_mode(struct wl_client *client,
725 struct wl_resource *resource,
726 struct wl_resource *surface_res,
727 struct wl_resource *output_res,
728 int32_t framerate,
729 uint32_t feedback_id)
730{
731 struct fullscreen_shell *shell =
732 wl_resource_get_user_data(resource);
733 struct weston_output *output;
734 struct weston_surface *surface;
735 struct weston_seat *seat;
736 struct fs_output *fsout;
737
738 output = wl_resource_get_user_data(output_res);
739 fsout = fs_output_for_output(output);
740
741 if (surface_res == NULL) {
742 fs_output_set_surface(fsout, NULL, 0, 0, 0);
743 return;
744 }
745
746 surface = wl_resource_get_user_data(surface_res);
747 fs_output_set_surface(fsout, surface, 0, framerate, 1);
748
749 fsout->pending.mode_feedback =
750 wl_resource_create(client,
Jonas Ådahl496adb32015-11-17 16:00:27 +0800751 &zwp_fullscreen_shell_mode_feedback_v1_interface,
Jason Ekstrand946a9482014-04-02 19:53:47 -0500752 1, feedback_id);
753 wl_resource_set_implementation(fsout->pending.mode_feedback, NULL,
754 fsout, mode_feedback_destroyed);
755
756 wl_list_for_each(seat, &shell->compositor->seat_list, link) {
Derek Foreman1281a362015-07-31 16:55:32 -0500757 struct weston_keyboard *keyboard =
758 weston_seat_get_keyboard(seat);
759
760 if (keyboard && !keyboard->focus)
Bryce Harrington260c2ff2016-06-29 19:04:06 -0700761 weston_seat_set_keyboard_focus(seat, surface);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500762 }
763}
764
Jonas Ådahl496adb32015-11-17 16:00:27 +0800765struct zwp_fullscreen_shell_v1_interface fullscreen_shell_implementation = {
Jason Ekstrand946a9482014-04-02 19:53:47 -0500766 fullscreen_shell_release,
767 fullscreen_shell_present_surface,
768 fullscreen_shell_present_surface_for_mode,
769};
770
771static void
772output_created(struct wl_listener *listener, void *data)
773{
774 struct fullscreen_shell *shell;
775
776 shell = container_of(listener, struct fullscreen_shell,
777 output_created_listener);
778
779 fs_output_create(shell, data);
780}
781
782static void
783client_destroyed(struct wl_listener *listener, void *data)
784{
785 struct fullscreen_shell *shell = container_of(listener,
786 struct fullscreen_shell,
787 client_destroyed);
788 shell->client = NULL;
789}
790
791static void
792bind_fullscreen_shell(struct wl_client *client, void *data, uint32_t version,
793 uint32_t id)
794{
795 struct fullscreen_shell *shell = data;
796 struct wl_resource *resource;
797
798 if (shell->client != NULL && shell->client != client)
799 return;
800 else if (shell->client == NULL) {
801 shell->client = client;
802 wl_client_add_destroy_listener(client, &shell->client_destroyed);
803 }
804
Jonas Ådahl496adb32015-11-17 16:00:27 +0800805 resource = wl_resource_create(client,
806 &zwp_fullscreen_shell_v1_interface,
Jason Ekstrand946a9482014-04-02 19:53:47 -0500807 1, id);
808 wl_resource_set_implementation(resource,
809 &fullscreen_shell_implementation,
810 shell, NULL);
811
812 if (shell->compositor->capabilities & WESTON_CAP_CURSOR_PLANE)
Jonas Ådahl496adb32015-11-17 16:00:27 +0800813 zwp_fullscreen_shell_v1_send_capability(resource,
814 ZWP_FULLSCREEN_SHELL_V1_CAPABILITY_CURSOR_PLANE);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500815
816 if (shell->compositor->capabilities & WESTON_CAP_ARBITRARY_MODES)
Jonas Ådahl496adb32015-11-17 16:00:27 +0800817 zwp_fullscreen_shell_v1_send_capability(resource,
818 ZWP_FULLSCREEN_SHELL_V1_CAPABILITY_ARBITRARY_MODES);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500819}
820
821WL_EXPORT int
822module_init(struct weston_compositor *compositor,
823 int *argc, char *argv[])
824{
825 struct fullscreen_shell *shell;
826 struct weston_seat *seat;
827 struct weston_output *output;
828
Ryo Munakata5e653ca2015-08-07 20:20:46 +0900829 shell = zalloc(sizeof *shell);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500830 if (shell == NULL)
831 return -1;
832
Jason Ekstrand946a9482014-04-02 19:53:47 -0500833 shell->compositor = compositor;
834
835 shell->client_destroyed.notify = client_destroyed;
836
837 weston_layer_init(&shell->layer, &compositor->cursor_layer.link);
838
839 wl_list_init(&shell->output_list);
840 shell->output_created_listener.notify = output_created;
841 wl_signal_add(&compositor->output_created_signal,
842 &shell->output_created_listener);
843 wl_list_for_each(output, &compositor->output_list, link)
844 fs_output_create(shell, output);
845
846 shell->seat_created_listener.notify = seat_created;
847 wl_signal_add(&compositor->seat_created_signal,
848 &shell->seat_created_listener);
849 wl_list_for_each(seat, &compositor->seat_list, link)
850 seat_created(NULL, seat);
851
852 wl_global_create(compositor->wl_display,
Jonas Ådahl496adb32015-11-17 16:00:27 +0800853 &zwp_fullscreen_shell_v1_interface, 1, shell,
Jason Ekstrand946a9482014-04-02 19:53:47 -0500854 bind_fullscreen_shell);
855
856 return 0;
857}