blob: 1eea38af8db8c13d7100612bfbdf9ff00df83376 [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;
50};
51
52struct fs_output {
53 struct fullscreen_shell *shell;
54 struct wl_list link;
55
56 struct weston_output *output;
57 struct wl_listener output_destroyed;
58
59 struct {
60 struct weston_surface *surface;
61 struct wl_listener surface_destroyed;
62 struct wl_resource *mode_feedback;
63
64 int presented_for_mode;
Jonas Ådahl496adb32015-11-17 16:00:27 +080065 enum zwp_fullscreen_shell_v1_present_method method;
Jason Ekstrand946a9482014-04-02 19:53:47 -050066 int32_t framerate;
67 } pending;
68
69 struct weston_surface *surface;
70 struct wl_listener surface_destroyed;
71 struct weston_view *view;
72 struct weston_view *black_view;
73 struct weston_transform transform; /* matrix from x, y */
74
75 int presented_for_mode;
Jonas Ådahl496adb32015-11-17 16:00:27 +080076 enum zwp_fullscreen_shell_v1_present_method method;
Jason Ekstrand946a9482014-04-02 19:53:47 -050077 uint32_t framerate;
78};
79
80struct pointer_focus_listener {
81 struct fullscreen_shell *shell;
82 struct wl_listener pointer_focus;
83 struct wl_listener seat_caps;
84 struct wl_listener seat_destroyed;
85};
86
87static void
88pointer_focus_changed(struct wl_listener *listener, void *data)
89{
90 struct weston_pointer *pointer = data;
91
92 if (pointer->focus && pointer->focus->surface->resource)
Bryce Harrington260c2ff2016-06-29 19:04:06 -070093 weston_seat_set_keyboard_focus(pointer->seat, pointer->focus->surface);
Jason Ekstrand946a9482014-04-02 19:53:47 -050094}
95
96static void
97seat_caps_changed(struct wl_listener *l, void *data)
98{
99 struct weston_seat *seat = data;
Derek Foreman1281a362015-07-31 16:55:32 -0500100 struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
101 struct weston_pointer *pointer = weston_seat_get_pointer(seat);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500102 struct pointer_focus_listener *listener;
103 struct fs_output *fsout;
104
105 listener = container_of(l, struct pointer_focus_listener, seat_caps);
106
107 /* no pointer */
Derek Foreman1281a362015-07-31 16:55:32 -0500108 if (pointer) {
Jason Ekstrand946a9482014-04-02 19:53:47 -0500109 if (!listener->pointer_focus.link.prev) {
Derek Foreman1281a362015-07-31 16:55:32 -0500110 wl_signal_add(&pointer->focus_signal,
Jason Ekstrand946a9482014-04-02 19:53:47 -0500111 &listener->pointer_focus);
112 }
113 } else {
114 if (listener->pointer_focus.link.prev) {
115 wl_list_remove(&listener->pointer_focus.link);
116 }
117 }
118
Derek Foreman1281a362015-07-31 16:55:32 -0500119 if (keyboard && keyboard->focus != NULL) {
Jason Ekstrand946a9482014-04-02 19:53:47 -0500120 wl_list_for_each(fsout, &listener->shell->output_list, link) {
121 if (fsout->surface) {
Bryce Harrington260c2ff2016-06-29 19:04:06 -0700122 weston_seat_set_keyboard_focus(seat, fsout->surface);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500123 return;
124 }
125 }
126 }
127}
128
129static void
130seat_destroyed(struct wl_listener *l, void *data)
131{
132 struct pointer_focus_listener *listener;
133
134 listener = container_of(l, struct pointer_focus_listener,
135 seat_destroyed);
136
137 free(listener);
138}
139
140static void
141seat_created(struct wl_listener *l, void *data)
142{
143 struct weston_seat *seat = data;
144 struct pointer_focus_listener *listener;
145
Ryo Munakata5e653ca2015-08-07 20:20:46 +0900146 listener = zalloc(sizeof *listener);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500147 if (!listener)
148 return;
Jason Ekstrand946a9482014-04-02 19:53:47 -0500149
150 listener->shell = container_of(l, struct fullscreen_shell,
151 seat_created_listener);
152 listener->pointer_focus.notify = pointer_focus_changed;
153 listener->seat_caps.notify = seat_caps_changed;
154 listener->seat_destroyed.notify = seat_destroyed;
155
156 wl_signal_add(&seat->destroy_signal, &listener->seat_destroyed);
157 wl_signal_add(&seat->updated_caps_signal, &listener->seat_caps);
158
159 seat_caps_changed(&listener->seat_caps, seat);
160}
161
162static void
163black_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
164{
165}
166
167static struct weston_view *
168create_black_surface(struct weston_compositor *ec, struct fs_output *fsout,
169 float x, float y, int w, int h)
170{
171 struct weston_surface *surface = NULL;
172 struct weston_view *view;
173
174 surface = weston_surface_create(ec);
175 if (surface == NULL) {
176 weston_log("no memory\n");
177 return NULL;
178 }
179 view = weston_view_create(surface);
180 if (!view) {
181 weston_surface_destroy(surface);
182 weston_log("no memory\n");
183 return NULL;
184 }
185
186 surface->configure = black_surface_configure;
187 surface->configure_private = fsout;
188 weston_surface_set_color(surface, 0.0f, 0.0f, 0.0f, 1.0f);
189 pixman_region32_fini(&surface->opaque);
190 pixman_region32_init_rect(&surface->opaque, 0, 0, w, h);
191 pixman_region32_fini(&surface->input);
192 pixman_region32_init_rect(&surface->input, 0, 0, w, h);
193
194 weston_surface_set_size(surface, w, h);
195 weston_view_set_position(view, x, y);
196
197 return view;
198}
199
200static void
201fs_output_set_surface(struct fs_output *fsout, struct weston_surface *surface,
Jonas Ådahl496adb32015-11-17 16:00:27 +0800202 enum zwp_fullscreen_shell_v1_present_method method,
Jason Ekstrand946a9482014-04-02 19:53:47 -0500203 int32_t framerate, int presented_for_mode);
204static void
205fs_output_apply_pending(struct fs_output *fsout);
206static void
207fs_output_clear_pending(struct fs_output *fsout);
208
209static void
210fs_output_destroy(struct fs_output *fsout)
211{
212 fs_output_set_surface(fsout, NULL, 0, 0, 0);
213 fs_output_clear_pending(fsout);
214
215 wl_list_remove(&fsout->link);
216
217 if (fsout->output)
218 wl_list_remove(&fsout->output_destroyed.link);
219}
220
221static void
222output_destroyed(struct wl_listener *listener, void *data)
223{
224 struct fs_output *output = container_of(listener,
225 struct fs_output,
226 output_destroyed);
227 fs_output_destroy(output);
228}
229
230static void
231surface_destroyed(struct wl_listener *listener, void *data)
232{
233 struct fs_output *fsout = container_of(listener,
234 struct fs_output,
235 surface_destroyed);
236 fsout->surface = NULL;
237 fsout->view = NULL;
238}
239
240static void
241pending_surface_destroyed(struct wl_listener *listener, void *data)
242{
243 struct fs_output *fsout = container_of(listener,
244 struct fs_output,
245 pending.surface_destroyed);
246 fsout->pending.surface = NULL;
247}
248
249static struct fs_output *
250fs_output_create(struct fullscreen_shell *shell, struct weston_output *output)
251{
252 struct fs_output *fsout;
253
Ryo Munakata5e653ca2015-08-07 20:20:46 +0900254 fsout = zalloc(sizeof *fsout);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500255 if (!fsout)
256 return NULL;
Jason Ekstrand946a9482014-04-02 19:53:47 -0500257
258 fsout->shell = shell;
259 wl_list_insert(&shell->output_list, &fsout->link);
260
261 fsout->output = output;
262 fsout->output_destroyed.notify = output_destroyed;
263 wl_signal_add(&output->destroy_signal, &fsout->output_destroyed);
264
265 fsout->surface_destroyed.notify = surface_destroyed;
266 fsout->pending.surface_destroyed.notify = pending_surface_destroyed;
267 fsout->black_view = create_black_surface(shell->compositor, fsout,
268 output->x, output->y,
269 output->width, output->height);
Armin Krezovićb1a48e62016-06-30 06:04:30 +0200270 fsout->black_view->surface->is_mapped = true;
271 fsout->black_view->is_mapped = true;
Giulio Camuffod1ceecf2014-07-29 21:57:24 +0300272 weston_layer_entry_insert(&shell->layer.view_list,
Jason Ekstrand946a9482014-04-02 19:53:47 -0500273 &fsout->black_view->layer_link);
274 wl_list_init(&fsout->transform.link);
275 return fsout;
276}
277
278static struct fs_output *
279fs_output_for_output(struct weston_output *output)
280{
281 struct wl_listener *listener;
282
283 if (!output)
284 return NULL;
285
286 listener = wl_signal_get(&output->destroy_signal, output_destroyed);
287
288 return container_of(listener, struct fs_output, output_destroyed);
289}
290
291static void
292restore_output_mode(struct weston_output *output)
293{
Armin Krezović70487cd2016-06-23 11:59:33 +0200294 if (output && output->original_mode)
Derek Foreman6ae7bc92014-11-04 10:47:33 -0600295 weston_output_mode_switch_to_native(output);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500296}
297
298/*
299 * Returns the bounding box of a surface and all its sub-surfaces,
Yong Bakos3b227612016-04-28 11:59:07 -0500300 * in surface-local coordinates. */
Jason Ekstrand946a9482014-04-02 19:53:47 -0500301static void
302surface_subsurfaces_boundingbox(struct weston_surface *surface, int32_t *x,
303 int32_t *y, int32_t *w, int32_t *h) {
304 pixman_region32_t region;
305 pixman_box32_t *box;
306 struct weston_subsurface *subsurface;
307
308 pixman_region32_init_rect(&region, 0, 0,
309 surface->width,
310 surface->height);
311
312 wl_list_for_each(subsurface, &surface->subsurface_list, parent_link) {
313 pixman_region32_union_rect(&region, &region,
314 subsurface->position.x,
315 subsurface->position.y,
316 subsurface->surface->width,
317 subsurface->surface->height);
318 }
319
320 box = pixman_region32_extents(&region);
321 if (x)
322 *x = box->x1;
323 if (y)
324 *y = box->y1;
325 if (w)
326 *w = box->x2 - box->x1;
327 if (h)
328 *h = box->y2 - box->y1;
329
330 pixman_region32_fini(&region);
331}
332
333static void
334fs_output_center_view(struct fs_output *fsout)
335{
336 int32_t surf_x, surf_y, surf_width, surf_height;
337 float x, y;
338 struct weston_output *output = fsout->output;
339
340 surface_subsurfaces_boundingbox(fsout->view->surface, &surf_x, &surf_y,
341 &surf_width, &surf_height);
342
343 x = output->x + (output->width - surf_width) / 2 - surf_x / 2;
344 y = output->y + (output->height - surf_height) / 2 - surf_y / 2;
345
346 weston_view_set_position(fsout->view, x, y);
347}
348
349static void
350fs_output_scale_view(struct fs_output *fsout, float width, float height)
351{
352 float x, y;
353 int32_t surf_x, surf_y, surf_width, surf_height;
354 struct weston_matrix *matrix;
355 struct weston_view *view = fsout->view;
356 struct weston_output *output = fsout->output;
357
358 surface_subsurfaces_boundingbox(view->surface, &surf_x, &surf_y,
359 &surf_width, &surf_height);
360
361 if (output->width == surf_width && output->height == surf_height) {
362 weston_view_set_position(view,
363 fsout->output->x - surf_x,
364 fsout->output->y - surf_y);
365 } else {
366 matrix = &fsout->transform.matrix;
367 weston_matrix_init(matrix);
368
369 weston_matrix_scale(matrix, width / surf_width,
370 height / surf_height, 1);
371 wl_list_remove(&fsout->transform.link);
372 wl_list_insert(&fsout->view->geometry.transformation_list,
373 &fsout->transform.link);
374
375 x = output->x + (output->width - width) / 2 - surf_x;
376 y = output->y + (output->height - height) / 2 - surf_y;
377
378 weston_view_set_position(view, x, y);
379 }
380}
381
382static void
383fs_output_configure(struct fs_output *fsout, struct weston_surface *surface);
384
385static void
386fs_output_configure_simple(struct fs_output *fsout,
387 struct weston_surface *configured_surface)
388{
389 struct weston_output *output = fsout->output;
390 float output_aspect, surface_aspect;
391 int32_t surf_x, surf_y, surf_width, surf_height;
392
393 if (fsout->pending.surface == configured_surface)
394 fs_output_apply_pending(fsout);
395
396 assert(fsout->view);
397
398 restore_output_mode(fsout->output);
399
400 wl_list_remove(&fsout->transform.link);
401 wl_list_init(&fsout->transform.link);
402
403 surface_subsurfaces_boundingbox(fsout->view->surface,
404 &surf_x, &surf_y,
405 &surf_width, &surf_height);
406
407 output_aspect = (float) output->width / (float) output->height;
408 surface_aspect = (float) surf_width / (float) surf_height;
409
410 switch (fsout->method) {
Jonas Ådahl496adb32015-11-17 16:00:27 +0800411 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_DEFAULT:
412 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_CENTER:
Jason Ekstrand946a9482014-04-02 19:53:47 -0500413 fs_output_center_view(fsout);
414 break;
415
Jonas Ådahl496adb32015-11-17 16:00:27 +0800416 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_ZOOM:
Jason Ekstrand946a9482014-04-02 19:53:47 -0500417 if (output_aspect < surface_aspect)
418 fs_output_scale_view(fsout,
419 output->width,
420 output->width / surface_aspect);
421 else
422 fs_output_scale_view(fsout,
423 output->height * surface_aspect,
424 output->height);
425 break;
426
Jonas Ådahl496adb32015-11-17 16:00:27 +0800427 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_ZOOM_CROP:
Jason Ekstrand946a9482014-04-02 19:53:47 -0500428 if (output_aspect < surface_aspect)
429 fs_output_scale_view(fsout,
430 output->height * surface_aspect,
431 output->height);
432 else
433 fs_output_scale_view(fsout,
434 output->width,
435 output->width / surface_aspect);
436 break;
437
Jonas Ådahl496adb32015-11-17 16:00:27 +0800438 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_STRETCH:
Jason Ekstrand946a9482014-04-02 19:53:47 -0500439 fs_output_scale_view(fsout, output->width, output->height);
440 break;
441 default:
442 break;
443 }
444
445 weston_view_set_position(fsout->black_view,
446 fsout->output->x - surf_x,
447 fsout->output->y - surf_y);
448 weston_surface_set_size(fsout->black_view->surface,
449 fsout->output->width,
450 fsout->output->height);
451}
452
453static void
454fs_output_configure_for_mode(struct fs_output *fsout,
455 struct weston_surface *configured_surface)
456{
457 int32_t surf_x, surf_y, surf_width, surf_height;
458 struct weston_mode mode;
459 int ret;
460
461 if (fsout->pending.surface != configured_surface) {
462 /* Nothing to really reconfigure. We'll just recenter the
463 * view in case they played with subsurfaces */
464 fs_output_center_view(fsout);
465 return;
466 }
467
468 /* We have a pending surface */
469 surface_subsurfaces_boundingbox(fsout->pending.surface,
470 &surf_x, &surf_y,
471 &surf_width, &surf_height);
472
Jason Ekstrand58106d72015-01-08 08:57:44 -0800473 /* The actual output mode is in physical units. We need to
474 * transform the surface size to physical unit size by flipping ans
475 * possibly scaling it.
476 */
477 switch (fsout->output->transform) {
478 case WL_OUTPUT_TRANSFORM_90:
479 case WL_OUTPUT_TRANSFORM_FLIPPED_90:
480 case WL_OUTPUT_TRANSFORM_270:
481 case WL_OUTPUT_TRANSFORM_FLIPPED_270:
482 mode.width = surf_height * fsout->output->native_scale;
483 mode.height = surf_width * fsout->output->native_scale;
484 break;
485
486 case WL_OUTPUT_TRANSFORM_NORMAL:
487 case WL_OUTPUT_TRANSFORM_FLIPPED:
488 case WL_OUTPUT_TRANSFORM_180:
489 case WL_OUTPUT_TRANSFORM_FLIPPED_180:
490 default:
491 mode.width = surf_width * fsout->output->native_scale;
492 mode.height = surf_height * fsout->output->native_scale;
493 }
Jason Ekstrand946a9482014-04-02 19:53:47 -0500494 mode.flags = 0;
Jason Ekstrand946a9482014-04-02 19:53:47 -0500495 mode.refresh = fsout->pending.framerate;
496
Derek Foreman6ae7bc92014-11-04 10:47:33 -0600497 ret = weston_output_mode_switch_to_temporary(fsout->output, &mode,
498 fsout->output->native_scale);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500499
500 if (ret != 0) {
501 /* The mode switch failed. Clear the pending and
502 * reconfigure as per normal */
503 if (fsout->pending.mode_feedback) {
Jonas Ådahl496adb32015-11-17 16:00:27 +0800504 zwp_fullscreen_shell_mode_feedback_v1_send_mode_failed(
Jason Ekstrand946a9482014-04-02 19:53:47 -0500505 fsout->pending.mode_feedback);
506 wl_resource_destroy(fsout->pending.mode_feedback);
507 fsout->pending.mode_feedback = NULL;
508 }
509
510 fs_output_clear_pending(fsout);
511 return;
512 }
513
514 if (fsout->pending.mode_feedback) {
Jonas Ådahl496adb32015-11-17 16:00:27 +0800515 zwp_fullscreen_shell_mode_feedback_v1_send_mode_successful(
Jason Ekstrand946a9482014-04-02 19:53:47 -0500516 fsout->pending.mode_feedback);
517 wl_resource_destroy(fsout->pending.mode_feedback);
518 fsout->pending.mode_feedback = NULL;
519 }
520
521 fs_output_apply_pending(fsout);
522
523 weston_view_set_position(fsout->view,
524 fsout->output->x - surf_x,
525 fsout->output->y - surf_y);
526}
527
528static void
529fs_output_configure(struct fs_output *fsout,
530 struct weston_surface *surface)
531{
532 if (fsout->pending.surface == surface) {
533 if (fsout->pending.presented_for_mode)
534 fs_output_configure_for_mode(fsout, surface);
535 else
536 fs_output_configure_simple(fsout, surface);
537 } else {
538 if (fsout->presented_for_mode)
539 fs_output_configure_for_mode(fsout, surface);
540 else
541 fs_output_configure_simple(fsout, surface);
542 }
543
544 weston_output_schedule_repaint(fsout->output);
545}
546
547static void
548configure_presented_surface(struct weston_surface *surface, int32_t sx,
549 int32_t sy)
550{
551 struct fullscreen_shell *shell = surface->configure_private;
552 struct fs_output *fsout;
553
554 if (surface->configure != configure_presented_surface)
555 return;
556
557 wl_list_for_each(fsout, &shell->output_list, link)
558 if (fsout->surface == surface ||
559 fsout->pending.surface == surface)
560 fs_output_configure(fsout, surface);
561}
562
563static void
564fs_output_apply_pending(struct fs_output *fsout)
565{
566 assert(fsout->pending.surface);
567
568 if (fsout->surface && fsout->surface != fsout->pending.surface) {
569 wl_list_remove(&fsout->surface_destroyed.link);
570
571 weston_view_destroy(fsout->view);
572 fsout->view = NULL;
573
574 if (wl_list_empty(&fsout->surface->views)) {
575 fsout->surface->configure = NULL;
576 fsout->surface->configure_private = NULL;
577 }
578
579 fsout->surface = NULL;
580 }
581
582 fsout->method = fsout->pending.method;
583 fsout->framerate = fsout->pending.framerate;
584 fsout->presented_for_mode = fsout->pending.presented_for_mode;
585
586 if (fsout->surface != fsout->pending.surface) {
587 fsout->surface = fsout->pending.surface;
588
589 fsout->view = weston_view_create(fsout->surface);
590 if (!fsout->view) {
591 weston_log("no memory\n");
592 return;
593 }
Armin Krezovićb1a48e62016-06-30 06:04:30 +0200594 fsout->view->is_mapped = true;
Jason Ekstrand946a9482014-04-02 19:53:47 -0500595
596 wl_signal_add(&fsout->surface->destroy_signal,
597 &fsout->surface_destroyed);
Giulio Camuffod1ceecf2014-07-29 21:57:24 +0300598 weston_layer_entry_insert(&fsout->shell->layer.view_list,
Jason Ekstrand946a9482014-04-02 19:53:47 -0500599 &fsout->view->layer_link);
600 }
601
602 fs_output_clear_pending(fsout);
603}
604
605static void
606fs_output_clear_pending(struct fs_output *fsout)
607{
608 if (!fsout->pending.surface)
609 return;
610
611 if (fsout->pending.mode_feedback) {
Jonas Ådahl496adb32015-11-17 16:00:27 +0800612 zwp_fullscreen_shell_mode_feedback_v1_send_present_cancelled(
Jason Ekstrand946a9482014-04-02 19:53:47 -0500613 fsout->pending.mode_feedback);
614 wl_resource_destroy(fsout->pending.mode_feedback);
615 fsout->pending.mode_feedback = NULL;
616 }
617
618 wl_list_remove(&fsout->pending.surface_destroyed.link);
619 fsout->pending.surface = NULL;
620}
621
622static void
623fs_output_set_surface(struct fs_output *fsout, struct weston_surface *surface,
Jonas Ådahl496adb32015-11-17 16:00:27 +0800624 enum zwp_fullscreen_shell_v1_present_method method,
Jason Ekstrand946a9482014-04-02 19:53:47 -0500625 int32_t framerate, int presented_for_mode)
626{
627 fs_output_clear_pending(fsout);
628
629 if (surface) {
630 if (!surface->configure) {
631 surface->configure = configure_presented_surface;
632 surface->configure_private = fsout->shell;
633 }
634
635 fsout->pending.surface = surface;
636 wl_signal_add(&fsout->pending.surface->destroy_signal,
637 &fsout->pending.surface_destroyed);
638
639 fsout->pending.method = method;
640 fsout->pending.framerate = framerate;
641 fsout->pending.presented_for_mode = presented_for_mode;
642 } else if (fsout->surface) {
643 /* we clear immediately */
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)) {
650 fsout->surface->configure = NULL;
651 fsout->surface->configure_private = NULL;
652 }
653
654 fsout->surface = NULL;
655
656 weston_output_schedule_repaint(fsout->output);
657 }
658}
659
660static void
661fullscreen_shell_release(struct wl_client *client,
662 struct wl_resource *resource)
663{
664 wl_resource_destroy(resource);
665}
666
667static void
668fullscreen_shell_present_surface(struct wl_client *client,
669 struct wl_resource *resource,
670 struct wl_resource *surface_res,
671 uint32_t method,
672 struct wl_resource *output_res)
673{
674 struct fullscreen_shell *shell =
675 wl_resource_get_user_data(resource);
676 struct weston_output *output;
677 struct weston_surface *surface;
678 struct weston_seat *seat;
679 struct fs_output *fsout;
680
681 surface = surface_res ? wl_resource_get_user_data(surface_res) : NULL;
682
683 switch(method) {
Jonas Ådahl496adb32015-11-17 16:00:27 +0800684 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_DEFAULT:
685 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_CENTER:
686 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_ZOOM:
687 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_ZOOM_CROP:
688 case ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_STRETCH:
Jason Ekstrand946a9482014-04-02 19:53:47 -0500689 break;
690 default:
691 wl_resource_post_error(resource,
Jonas Ådahl496adb32015-11-17 16:00:27 +0800692 ZWP_FULLSCREEN_SHELL_V1_ERROR_INVALID_METHOD,
Jason Ekstrand946a9482014-04-02 19:53:47 -0500693 "Invalid presentation method");
694 }
695
696 if (output_res) {
697 output = wl_resource_get_user_data(output_res);
698 fsout = fs_output_for_output(output);
699 fs_output_set_surface(fsout, surface, method, 0, 0);
700 } else {
701 wl_list_for_each(fsout, &shell->output_list, link)
702 fs_output_set_surface(fsout, surface, method, 0, 0);
703 }
704
705 if (surface) {
706 wl_list_for_each(seat, &shell->compositor->seat_list, link) {
Derek Foreman1281a362015-07-31 16:55:32 -0500707 struct weston_keyboard *keyboard =
708 weston_seat_get_keyboard(seat);
709
710 if (keyboard && !keyboard->focus)
Bryce Harrington260c2ff2016-06-29 19:04:06 -0700711 weston_seat_set_keyboard_focus(seat, surface);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500712 }
713 }
714}
715
716static void
717mode_feedback_destroyed(struct wl_resource *resource)
718{
719 struct fs_output *fsout = wl_resource_get_user_data(resource);
720
721 fsout->pending.mode_feedback = NULL;
722}
723
724static void
725fullscreen_shell_present_surface_for_mode(struct wl_client *client,
726 struct wl_resource *resource,
727 struct wl_resource *surface_res,
728 struct wl_resource *output_res,
729 int32_t framerate,
730 uint32_t feedback_id)
731{
732 struct fullscreen_shell *shell =
733 wl_resource_get_user_data(resource);
734 struct weston_output *output;
735 struct weston_surface *surface;
736 struct weston_seat *seat;
737 struct fs_output *fsout;
738
739 output = wl_resource_get_user_data(output_res);
740 fsout = fs_output_for_output(output);
741
742 if (surface_res == NULL) {
743 fs_output_set_surface(fsout, NULL, 0, 0, 0);
744 return;
745 }
746
747 surface = wl_resource_get_user_data(surface_res);
748 fs_output_set_surface(fsout, surface, 0, framerate, 1);
749
750 fsout->pending.mode_feedback =
751 wl_resource_create(client,
Jonas Ådahl496adb32015-11-17 16:00:27 +0800752 &zwp_fullscreen_shell_mode_feedback_v1_interface,
Jason Ekstrand946a9482014-04-02 19:53:47 -0500753 1, feedback_id);
754 wl_resource_set_implementation(fsout->pending.mode_feedback, NULL,
755 fsout, mode_feedback_destroyed);
756
757 wl_list_for_each(seat, &shell->compositor->seat_list, link) {
Derek Foreman1281a362015-07-31 16:55:32 -0500758 struct weston_keyboard *keyboard =
759 weston_seat_get_keyboard(seat);
760
761 if (keyboard && !keyboard->focus)
Bryce Harrington260c2ff2016-06-29 19:04:06 -0700762 weston_seat_set_keyboard_focus(seat, surface);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500763 }
764}
765
Jonas Ådahl496adb32015-11-17 16:00:27 +0800766struct zwp_fullscreen_shell_v1_interface fullscreen_shell_implementation = {
Jason Ekstrand946a9482014-04-02 19:53:47 -0500767 fullscreen_shell_release,
768 fullscreen_shell_present_surface,
769 fullscreen_shell_present_surface_for_mode,
770};
771
772static void
773output_created(struct wl_listener *listener, void *data)
774{
775 struct fullscreen_shell *shell;
776
777 shell = container_of(listener, struct fullscreen_shell,
778 output_created_listener);
779
780 fs_output_create(shell, data);
781}
782
783static void
784client_destroyed(struct wl_listener *listener, void *data)
785{
786 struct fullscreen_shell *shell = container_of(listener,
787 struct fullscreen_shell,
788 client_destroyed);
789 shell->client = NULL;
790}
791
792static void
793bind_fullscreen_shell(struct wl_client *client, void *data, uint32_t version,
794 uint32_t id)
795{
796 struct fullscreen_shell *shell = data;
797 struct wl_resource *resource;
798
799 if (shell->client != NULL && shell->client != client)
800 return;
801 else if (shell->client == NULL) {
802 shell->client = client;
803 wl_client_add_destroy_listener(client, &shell->client_destroyed);
804 }
805
Jonas Ådahl496adb32015-11-17 16:00:27 +0800806 resource = wl_resource_create(client,
807 &zwp_fullscreen_shell_v1_interface,
Jason Ekstrand946a9482014-04-02 19:53:47 -0500808 1, id);
809 wl_resource_set_implementation(resource,
810 &fullscreen_shell_implementation,
811 shell, NULL);
812
813 if (shell->compositor->capabilities & WESTON_CAP_CURSOR_PLANE)
Jonas Ådahl496adb32015-11-17 16:00:27 +0800814 zwp_fullscreen_shell_v1_send_capability(resource,
815 ZWP_FULLSCREEN_SHELL_V1_CAPABILITY_CURSOR_PLANE);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500816
817 if (shell->compositor->capabilities & WESTON_CAP_ARBITRARY_MODES)
Jonas Ådahl496adb32015-11-17 16:00:27 +0800818 zwp_fullscreen_shell_v1_send_capability(resource,
819 ZWP_FULLSCREEN_SHELL_V1_CAPABILITY_ARBITRARY_MODES);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500820}
821
822WL_EXPORT int
823module_init(struct weston_compositor *compositor,
824 int *argc, char *argv[])
825{
826 struct fullscreen_shell *shell;
827 struct weston_seat *seat;
828 struct weston_output *output;
829
Ryo Munakata5e653ca2015-08-07 20:20:46 +0900830 shell = zalloc(sizeof *shell);
Jason Ekstrand946a9482014-04-02 19:53:47 -0500831 if (shell == NULL)
832 return -1;
833
Jason Ekstrand946a9482014-04-02 19:53:47 -0500834 shell->compositor = compositor;
835
836 shell->client_destroyed.notify = client_destroyed;
837
838 weston_layer_init(&shell->layer, &compositor->cursor_layer.link);
839
840 wl_list_init(&shell->output_list);
841 shell->output_created_listener.notify = output_created;
842 wl_signal_add(&compositor->output_created_signal,
843 &shell->output_created_listener);
844 wl_list_for_each(output, &compositor->output_list, link)
845 fs_output_create(shell, output);
846
847 shell->seat_created_listener.notify = seat_created;
848 wl_signal_add(&compositor->seat_created_signal,
849 &shell->seat_created_listener);
850 wl_list_for_each(seat, &compositor->seat_list, link)
851 seat_created(NULL, seat);
852
853 wl_global_create(compositor->wl_display,
Jonas Ådahl496adb32015-11-17 16:00:27 +0800854 &zwp_fullscreen_shell_v1_interface, 1, shell,
Jason Ekstrand946a9482014-04-02 19:53:47 -0500855 bind_fullscreen_shell);
856
857 return 0;
858}