2 * Copyright © 2013 Jason Ekstrand
4 * Permission to use, copy, modify, distribute, and sell this software and
5 * its documentation for any purpose is hereby granted without fee, provided
6 * that the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of the copyright holders not be used in
9 * advertising or publicity pertaining to distribution of the software
10 * without specific, written prior permission. The copyright holders make
11 * no representations about the suitability of this software for any
12 * purpose. It is provided "as is" without express or implied warranty.
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
15 * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
16 * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
17 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
18 * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
19 * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
20 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
32 #include "compositor.h"
33 #include "fullscreen-shell-server-protocol.h"
36 struct wl_client *client;
37 struct wl_listener client_destroyed;
41 struct fullscreen_shell {
42 struct wl_list client_list;
43 struct weston_compositor *compositor;
45 struct weston_layer layer;
46 struct wl_list output_list;
47 struct wl_listener output_created_listener;
49 struct wl_listener seat_created_listener;
53 struct fullscreen_shell *shell;
56 struct weston_output *output;
57 struct wl_listener output_destroyed;
60 struct weston_surface *surface;
61 struct wl_listener surface_destroyed;
62 struct wl_resource *mode_feedback;
64 int presented_for_mode;
65 enum _wl_fullscreen_shell_present_method method;
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 */
75 int presented_for_mode;
76 enum _wl_fullscreen_shell_present_method method;
80 struct 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;
88 pointer_focus_changed(struct wl_listener *listener, void *data)
90 struct weston_pointer *pointer = data;
92 if (pointer->focus && pointer->focus->surface->resource)
93 weston_surface_activate(pointer->focus->surface, pointer->seat);
97 seat_caps_changed(struct wl_listener *l, void *data)
99 struct weston_seat *seat = data;
100 struct pointer_focus_listener *listener;
101 struct fs_output *fsout;
103 listener = container_of(l, struct pointer_focus_listener, seat_caps);
107 if (!listener->pointer_focus.link.prev) {
108 wl_signal_add(&seat->pointer->focus_signal,
109 &listener->pointer_focus);
112 if (listener->pointer_focus.link.prev) {
113 wl_list_remove(&listener->pointer_focus.link);
117 if (seat->keyboard && seat->keyboard->focus != NULL) {
118 wl_list_for_each(fsout, &listener->shell->output_list, link) {
119 if (fsout->surface) {
120 weston_surface_activate(fsout->surface, seat);
128 seat_destroyed(struct wl_listener *l, void *data)
130 struct pointer_focus_listener *listener;
132 listener = container_of(l, struct pointer_focus_listener,
139 seat_created(struct wl_listener *l, void *data)
141 struct weston_seat *seat = data;
142 struct pointer_focus_listener *listener;
144 listener = malloc(sizeof *listener);
147 memset(listener, 0, sizeof *listener);
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;
155 wl_signal_add(&seat->destroy_signal, &listener->seat_destroyed);
156 wl_signal_add(&seat->updated_caps_signal, &listener->seat_caps);
158 seat_caps_changed(&listener->seat_caps, seat);
162 black_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
166 static struct weston_view *
167 create_black_surface(struct weston_compositor *ec, struct fs_output *fsout,
168 float x, float y, int w, int h)
170 struct weston_surface *surface = NULL;
171 struct weston_view *view;
173 surface = weston_surface_create(ec);
174 if (surface == NULL) {
175 weston_log("no memory\n");
178 view = weston_view_create(surface);
180 weston_surface_destroy(surface);
181 weston_log("no memory\n");
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);
193 weston_surface_set_size(surface, w, h);
194 weston_view_set_position(view, x, y);
200 fs_output_set_surface(struct fs_output *fsout, struct weston_surface *surface,
201 enum _wl_fullscreen_shell_present_method method,
202 int32_t framerate, int presented_for_mode);
204 fs_output_apply_pending(struct fs_output *fsout);
206 fs_output_clear_pending(struct fs_output *fsout);
209 fs_output_destroy(struct fs_output *fsout)
211 fs_output_set_surface(fsout, NULL, 0, 0, 0);
212 fs_output_clear_pending(fsout);
214 wl_list_remove(&fsout->link);
217 wl_list_remove(&fsout->output_destroyed.link);
221 output_destroyed(struct wl_listener *listener, void *data)
223 struct fs_output *output = container_of(listener,
226 fs_output_destroy(output);
230 surface_destroyed(struct wl_listener *listener, void *data)
232 struct fs_output *fsout = container_of(listener,
235 fsout->surface = NULL;
240 pending_surface_destroyed(struct wl_listener *listener, void *data)
242 struct fs_output *fsout = container_of(listener,
244 pending.surface_destroyed);
245 fsout->pending.surface = NULL;
248 static struct fs_output *
249 fs_output_create(struct fullscreen_shell *shell, struct weston_output *output)
251 struct fs_output *fsout;
253 fsout = malloc(sizeof *fsout);
256 memset(fsout, 0, sizeof *fsout);
258 fsout->shell = shell;
259 wl_list_insert(&shell->output_list, &fsout->link);
261 fsout->output = output;
262 fsout->output_destroyed.notify = output_destroyed;
263 wl_signal_add(&output->destroy_signal, &fsout->output_destroyed);
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);
270 weston_layer_entry_insert(&shell->layer.view_list,
271 &fsout->black_view->layer_link);
272 wl_list_init(&fsout->transform.link);
276 static struct fs_output *
277 fs_output_for_output(struct weston_output *output)
279 struct wl_listener *listener;
284 listener = wl_signal_get(&output->destroy_signal, output_destroyed);
286 return container_of(listener, struct fs_output, output_destroyed);
290 restore_output_mode(struct weston_output *output)
292 if (output->current_mode != output->original_mode ||
293 (int32_t)output->current_scale != output->original_scale)
294 weston_output_switch_mode(output,
295 output->original_mode,
296 output->original_scale,
297 WESTON_MODE_SWITCH_RESTORE_NATIVE);
301 * Returns the bounding box of a surface and all its sub-surfaces,
302 * in the surface coordinates system. */
304 surface_subsurfaces_boundingbox(struct weston_surface *surface, int32_t *x,
305 int32_t *y, int32_t *w, int32_t *h) {
306 pixman_region32_t region;
308 struct weston_subsurface *subsurface;
310 pixman_region32_init_rect(®ion, 0, 0,
314 wl_list_for_each(subsurface, &surface->subsurface_list, parent_link) {
315 pixman_region32_union_rect(®ion, ®ion,
316 subsurface->position.x,
317 subsurface->position.y,
318 subsurface->surface->width,
319 subsurface->surface->height);
322 box = pixman_region32_extents(®ion);
328 *w = box->x2 - box->x1;
330 *h = box->y2 - box->y1;
332 pixman_region32_fini(®ion);
336 fs_output_center_view(struct fs_output *fsout)
338 int32_t surf_x, surf_y, surf_width, surf_height;
340 struct weston_output *output = fsout->output;
342 surface_subsurfaces_boundingbox(fsout->view->surface, &surf_x, &surf_y,
343 &surf_width, &surf_height);
345 x = output->x + (output->width - surf_width) / 2 - surf_x / 2;
346 y = output->y + (output->height - surf_height) / 2 - surf_y / 2;
348 weston_view_set_position(fsout->view, x, y);
352 fs_output_scale_view(struct fs_output *fsout, float width, float height)
355 int32_t surf_x, surf_y, surf_width, surf_height;
356 struct weston_matrix *matrix;
357 struct weston_view *view = fsout->view;
358 struct weston_output *output = fsout->output;
360 surface_subsurfaces_boundingbox(view->surface, &surf_x, &surf_y,
361 &surf_width, &surf_height);
363 if (output->width == surf_width && output->height == surf_height) {
364 weston_view_set_position(view,
365 fsout->output->x - surf_x,
366 fsout->output->y - surf_y);
368 matrix = &fsout->transform.matrix;
369 weston_matrix_init(matrix);
371 weston_matrix_scale(matrix, width / surf_width,
372 height / surf_height, 1);
373 wl_list_remove(&fsout->transform.link);
374 wl_list_insert(&fsout->view->geometry.transformation_list,
375 &fsout->transform.link);
377 x = output->x + (output->width - width) / 2 - surf_x;
378 y = output->y + (output->height - height) / 2 - surf_y;
380 weston_view_set_position(view, x, y);
385 fs_output_configure(struct fs_output *fsout, struct weston_surface *surface);
388 fs_output_configure_simple(struct fs_output *fsout,
389 struct weston_surface *configured_surface)
391 struct weston_output *output = fsout->output;
392 float output_aspect, surface_aspect;
393 int32_t surf_x, surf_y, surf_width, surf_height;
395 if (fsout->pending.surface == configured_surface)
396 fs_output_apply_pending(fsout);
400 restore_output_mode(fsout->output);
402 wl_list_remove(&fsout->transform.link);
403 wl_list_init(&fsout->transform.link);
405 surface_subsurfaces_boundingbox(fsout->view->surface,
407 &surf_width, &surf_height);
409 output_aspect = (float) output->width / (float) output->height;
410 surface_aspect = (float) surf_width / (float) surf_height;
412 switch (fsout->method) {
413 case _WL_FULLSCREEN_SHELL_PRESENT_METHOD_DEFAULT:
414 case _WL_FULLSCREEN_SHELL_PRESENT_METHOD_CENTER:
415 fs_output_center_view(fsout);
418 case _WL_FULLSCREEN_SHELL_PRESENT_METHOD_ZOOM:
419 if (output_aspect < surface_aspect)
420 fs_output_scale_view(fsout,
422 output->width / surface_aspect);
424 fs_output_scale_view(fsout,
425 output->height * surface_aspect,
429 case _WL_FULLSCREEN_SHELL_PRESENT_METHOD_ZOOM_CROP:
430 if (output_aspect < surface_aspect)
431 fs_output_scale_view(fsout,
432 output->height * surface_aspect,
435 fs_output_scale_view(fsout,
437 output->width / surface_aspect);
440 case _WL_FULLSCREEN_SHELL_PRESENT_METHOD_STRETCH:
441 fs_output_scale_view(fsout, output->width, output->height);
447 weston_view_set_position(fsout->black_view,
448 fsout->output->x - surf_x,
449 fsout->output->y - surf_y);
450 weston_surface_set_size(fsout->black_view->surface,
451 fsout->output->width,
452 fsout->output->height);
456 fs_output_configure_for_mode(struct fs_output *fsout,
457 struct weston_surface *configured_surface)
459 int32_t surf_x, surf_y, surf_width, surf_height;
460 struct weston_mode mode;
463 if (fsout->pending.surface != configured_surface) {
464 /* Nothing to really reconfigure. We'll just recenter the
465 * view in case they played with subsurfaces */
466 fs_output_center_view(fsout);
470 /* We have a pending surface */
471 surface_subsurfaces_boundingbox(fsout->pending.surface,
473 &surf_width, &surf_height);
476 mode.width = surf_width * fsout->output->native_scale;
477 mode.height = surf_height * fsout->output->native_scale;
478 mode.refresh = fsout->pending.framerate;
480 ret = weston_output_switch_mode(fsout->output, &mode,
481 fsout->output->native_scale,
482 WESTON_MODE_SWITCH_SET_TEMPORARY);
485 /* The mode switch failed. Clear the pending and
486 * reconfigure as per normal */
487 if (fsout->pending.mode_feedback) {
488 _wl_fullscreen_shell_mode_feedback_send_mode_failed(
489 fsout->pending.mode_feedback);
490 wl_resource_destroy(fsout->pending.mode_feedback);
491 fsout->pending.mode_feedback = NULL;
494 fs_output_clear_pending(fsout);
498 if (fsout->pending.mode_feedback) {
499 _wl_fullscreen_shell_mode_feedback_send_mode_successful(
500 fsout->pending.mode_feedback);
501 wl_resource_destroy(fsout->pending.mode_feedback);
502 fsout->pending.mode_feedback = NULL;
505 fs_output_apply_pending(fsout);
507 weston_view_set_position(fsout->view,
508 fsout->output->x - surf_x,
509 fsout->output->y - surf_y);
513 fs_output_configure(struct fs_output *fsout,
514 struct weston_surface *surface)
516 if (fsout->pending.surface == surface) {
517 if (fsout->pending.presented_for_mode)
518 fs_output_configure_for_mode(fsout, surface);
520 fs_output_configure_simple(fsout, surface);
522 if (fsout->presented_for_mode)
523 fs_output_configure_for_mode(fsout, surface);
525 fs_output_configure_simple(fsout, surface);
528 weston_output_schedule_repaint(fsout->output);
532 configure_presented_surface(struct weston_surface *surface, int32_t sx,
535 struct fullscreen_shell *shell = surface->configure_private;
536 struct fs_output *fsout;
538 if (surface->configure != configure_presented_surface)
541 wl_list_for_each(fsout, &shell->output_list, link)
542 if (fsout->surface == surface ||
543 fsout->pending.surface == surface)
544 fs_output_configure(fsout, surface);
548 fs_output_apply_pending(struct fs_output *fsout)
550 assert(fsout->pending.surface);
552 if (fsout->surface && fsout->surface != fsout->pending.surface) {
553 wl_list_remove(&fsout->surface_destroyed.link);
555 weston_view_destroy(fsout->view);
558 if (wl_list_empty(&fsout->surface->views)) {
559 fsout->surface->configure = NULL;
560 fsout->surface->configure_private = NULL;
563 fsout->surface = NULL;
566 fsout->method = fsout->pending.method;
567 fsout->framerate = fsout->pending.framerate;
568 fsout->presented_for_mode = fsout->pending.presented_for_mode;
570 if (fsout->surface != fsout->pending.surface) {
571 fsout->surface = fsout->pending.surface;
573 fsout->view = weston_view_create(fsout->surface);
575 weston_log("no memory\n");
579 wl_signal_add(&fsout->surface->destroy_signal,
580 &fsout->surface_destroyed);
581 weston_layer_entry_insert(&fsout->shell->layer.view_list,
582 &fsout->view->layer_link);
585 fs_output_clear_pending(fsout);
589 fs_output_clear_pending(struct fs_output *fsout)
591 if (!fsout->pending.surface)
594 if (fsout->pending.mode_feedback) {
595 _wl_fullscreen_shell_mode_feedback_send_present_cancelled(
596 fsout->pending.mode_feedback);
597 wl_resource_destroy(fsout->pending.mode_feedback);
598 fsout->pending.mode_feedback = NULL;
601 wl_list_remove(&fsout->pending.surface_destroyed.link);
602 fsout->pending.surface = NULL;
606 fs_output_set_surface(struct fs_output *fsout, struct weston_surface *surface,
607 enum _wl_fullscreen_shell_present_method method,
608 int32_t framerate, int presented_for_mode)
610 fs_output_clear_pending(fsout);
613 if (!surface->configure) {
614 surface->configure = configure_presented_surface;
615 surface->configure_private = fsout->shell;
618 fsout->pending.surface = surface;
619 wl_signal_add(&fsout->pending.surface->destroy_signal,
620 &fsout->pending.surface_destroyed);
622 fsout->pending.method = method;
623 fsout->pending.framerate = framerate;
624 fsout->pending.presented_for_mode = presented_for_mode;
625 } else if (fsout->surface) {
626 /* we clear immediately */
627 wl_list_remove(&fsout->surface_destroyed.link);
629 weston_view_destroy(fsout->view);
632 if (wl_list_empty(&fsout->surface->views)) {
633 fsout->surface->configure = NULL;
634 fsout->surface->configure_private = NULL;
637 fsout->surface = NULL;
639 weston_output_schedule_repaint(fsout->output);
644 fullscreen_shell_release(struct wl_client *client,
645 struct wl_resource *resource)
647 wl_resource_destroy(resource);
651 fullscreen_shell_present_surface(struct wl_client *client,
652 struct wl_resource *resource,
653 struct wl_resource *surface_res,
655 struct wl_resource *output_res)
657 struct fullscreen_shell *shell =
658 wl_resource_get_user_data(resource);
659 struct weston_output *output;
660 struct weston_surface *surface;
661 struct weston_seat *seat;
662 struct fs_output *fsout;
664 surface = surface_res ? wl_resource_get_user_data(surface_res) : NULL;
667 case _WL_FULLSCREEN_SHELL_PRESENT_METHOD_DEFAULT:
668 case _WL_FULLSCREEN_SHELL_PRESENT_METHOD_CENTER:
669 case _WL_FULLSCREEN_SHELL_PRESENT_METHOD_ZOOM:
670 case _WL_FULLSCREEN_SHELL_PRESENT_METHOD_ZOOM_CROP:
671 case _WL_FULLSCREEN_SHELL_PRESENT_METHOD_STRETCH:
674 wl_resource_post_error(resource,
675 _WL_FULLSCREEN_SHELL_ERROR_INVALID_METHOD,
676 "Invalid presentation method");
680 output = wl_resource_get_user_data(output_res);
681 fsout = fs_output_for_output(output);
682 fs_output_set_surface(fsout, surface, method, 0, 0);
684 wl_list_for_each(fsout, &shell->output_list, link)
685 fs_output_set_surface(fsout, surface, method, 0, 0);
689 wl_list_for_each(seat, &shell->compositor->seat_list, link) {
690 if (seat->keyboard && seat->keyboard->focus == NULL)
691 weston_surface_activate(surface, seat);
697 mode_feedback_destroyed(struct wl_resource *resource)
699 struct fs_output *fsout = wl_resource_get_user_data(resource);
701 fsout->pending.mode_feedback = NULL;
705 fullscreen_shell_present_surface_for_mode(struct wl_client *client,
706 struct wl_resource *resource,
707 struct wl_resource *surface_res,
708 struct wl_resource *output_res,
710 uint32_t feedback_id)
712 struct fullscreen_shell *shell =
713 wl_resource_get_user_data(resource);
714 struct weston_output *output;
715 struct weston_surface *surface;
716 struct weston_seat *seat;
717 struct fs_output *fsout;
719 output = wl_resource_get_user_data(output_res);
720 fsout = fs_output_for_output(output);
722 if (surface_res == NULL) {
723 fs_output_set_surface(fsout, NULL, 0, 0, 0);
727 surface = wl_resource_get_user_data(surface_res);
728 fs_output_set_surface(fsout, surface, 0, framerate, 1);
730 fsout->pending.mode_feedback =
731 wl_resource_create(client,
732 &_wl_fullscreen_shell_mode_feedback_interface,
734 wl_resource_set_implementation(fsout->pending.mode_feedback, NULL,
735 fsout, mode_feedback_destroyed);
737 wl_list_for_each(seat, &shell->compositor->seat_list, link) {
738 if (seat->keyboard && seat->keyboard->focus == NULL)
739 weston_surface_activate(surface, seat);
743 struct _wl_fullscreen_shell_interface fullscreen_shell_implementation = {
744 fullscreen_shell_release,
745 fullscreen_shell_present_surface,
746 fullscreen_shell_present_surface_for_mode,
750 output_created(struct wl_listener *listener, void *data)
752 struct fullscreen_shell *shell;
754 shell = container_of(listener, struct fullscreen_shell,
755 output_created_listener);
757 fs_output_create(shell, data);
761 client_destroyed(struct wl_listener *listener, void *data)
763 struct fs_client *client = container_of(listener,
764 struct fs_client, client_destroyed);
765 if (client) wl_list_remove(&client->link);
769 bind_fullscreen_shell(struct wl_client *client, void *data, uint32_t version,
772 struct fullscreen_shell *shell = data;
773 struct wl_resource *resource;
774 struct fs_client *new_client;
776 new_client = malloc(sizeof *new_client);
778 memset(new_client, 0, sizeof *new_client);
779 new_client->client = client;
780 new_client->client_destroyed.notify = client_destroyed;
781 wl_list_insert(&shell->client_list, &new_client->link);
782 wl_client_add_destroy_listener(client, &new_client->client_destroyed);
785 resource = wl_resource_create(client, &_wl_fullscreen_shell_interface,
787 wl_resource_set_implementation(resource,
788 &fullscreen_shell_implementation,
791 if (shell->compositor->capabilities & WESTON_CAP_CURSOR_PLANE)
792 _wl_fullscreen_shell_send_capability(resource,
793 _WL_FULLSCREEN_SHELL_CAPABILITY_CURSOR_PLANE);
795 if (shell->compositor->capabilities & WESTON_CAP_ARBITRARY_MODES)
796 _wl_fullscreen_shell_send_capability(resource,
797 _WL_FULLSCREEN_SHELL_CAPABILITY_ARBITRARY_MODES);
801 module_init(struct weston_compositor *compositor,
802 int *argc, char *argv[])
804 struct fullscreen_shell *shell;
805 struct weston_seat *seat;
806 struct weston_output *output;
808 shell = malloc(sizeof *shell);
812 memset(shell, 0, sizeof *shell);
813 shell->compositor = compositor;
815 wl_list_init(&shell->client_list);
817 weston_layer_init(&shell->layer, &compositor->cursor_layer.link);
819 wl_list_init(&shell->output_list);
820 shell->output_created_listener.notify = output_created;
821 wl_signal_add(&compositor->output_created_signal,
822 &shell->output_created_listener);
823 wl_list_for_each(output, &compositor->output_list, link)
824 fs_output_create(shell, output);
826 shell->seat_created_listener.notify = seat_created;
827 wl_signal_add(&compositor->seat_created_signal,
828 &shell->seat_created_listener);
829 wl_list_for_each(seat, &compositor->seat_list, link)
830 seat_created(&shell->seat_created_listener, seat);
832 wl_global_create(compositor->wl_display,
833 &_wl_fullscreen_shell_interface, 1, shell,
834 bind_fullscreen_shell);