shell: Implement "driver" method of fullsceen.

Switching display mode may happen when:
1. The fullscreen surface is at top most in fullscreen layer and with
   "driver" method. Shell will switch output mode to match the surface
   size. If no matched mode found, fall back to "fill" method.
2. The top fullscreen surface is destroyed or unset. Switch back to the
   origin mode.
dev
Alex Wu 13 years ago committed by Kristian Høgsberg
parent b7b8bda600
commit bd3354b8b2
  1. 1
      src/compositor-drm.c
  2. 1
      src/compositor-openwfd.c
  3. 1
      src/compositor-wayland.c
  4. 1
      src/compositor-x11.c
  5. 1
      src/compositor.h
  6. 87
      src/shell.c

@ -1309,6 +1309,7 @@ create_output_for_connector(struct drm_compositor *ec,
output_handle_pending_scanout_buffer_destroy; output_handle_pending_scanout_buffer_destroy;
output->next_fb_id = 0; output->next_fb_id = 0;
output->base.origin = output->base.current;
output->base.repaint = drm_output_repaint; output->base.repaint = drm_output_repaint;
output->base.destroy = drm_output_destroy; output->base.destroy = drm_output_destroy;
output->base.assign_planes = drm_assign_planes; output->base.assign_planes = drm_assign_planes;

@ -401,6 +401,7 @@ create_output_for_port(struct wfd_compositor *ec,
wfdDeviceCommit(ec->dev, WFD_COMMIT_ENTIRE_DEVICE, WFD_INVALID_HANDLE); wfdDeviceCommit(ec->dev, WFD_COMMIT_ENTIRE_DEVICE, WFD_INVALID_HANDLE);
output->base.origin = output->base.current;
output->base.repaint = wfd_output_repaint; output->base.repaint = wfd_output_repaint;
output->base.prepare_scanout_surface = output->base.prepare_scanout_surface =
wfd_output_prepare_scanout_surface; wfd_output_prepare_scanout_surface;

@ -456,6 +456,7 @@ wayland_compositor_create_output(struct wayland_compositor *c,
/* FIXME: add shell_surface listener for resizing */ /* FIXME: add shell_surface listener for resizing */
wl_shell_surface_set_toplevel(output->parent.shell_surface); wl_shell_surface_set_toplevel(output->parent.shell_surface);
output->base.origin = output->base.current;
output->base.repaint = wayland_output_repaint; output->base.repaint = wayland_output_repaint;
output->base.destroy = wayland_output_destroy; output->base.destroy = wayland_output_destroy;
output->base.assign_planes = NULL; output->base.assign_planes = NULL;

@ -466,6 +466,7 @@ x11_compositor_create_output(struct x11_compositor *c, int x, int y,
output->finish_frame_timer = output->finish_frame_timer =
wl_event_loop_add_timer(loop, finish_frame_handler, output); wl_event_loop_add_timer(loop, finish_frame_handler, output);
output->base.origin = output->base.current;
output->base.repaint = x11_output_repaint; output->base.repaint = x11_output_repaint;
output->base.destroy = x11_output_destroy; output->base.destroy = x11_output_destroy;
output->base.assign_planes = NULL; output->base.assign_planes = NULL;

@ -92,6 +92,7 @@ struct weston_output {
uint32_t subpixel; uint32_t subpixel;
struct weston_mode *current; struct weston_mode *current;
struct weston_mode *origin;
struct wl_list mode_list; struct wl_list mode_list;
void (*repaint)(struct weston_output *output, void (*repaint)(struct weston_output *output,

@ -155,6 +155,29 @@ struct rotate_grab {
} center; } center;
}; };
static struct shell_surface *
get_shell_surface(struct weston_surface *surface);
static struct desktop_shell *
shell_surface_get_shell(struct shell_surface *shsurf);
static bool
shell_surface_is_top_fullscreen(struct shell_surface *shsurf)
{
struct desktop_shell *shell;
struct weston_surface *top_fs_es;
shell = shell_surface_get_shell(shsurf);
if (wl_list_empty(&shell->fullscreen_layer.surface_list))
return false;
top_fs_es = container_of(shell->fullscreen_layer.surface_list.next,
struct weston_surface,
layer_link);
return (shsurf == get_shell_surface(top_fs_es));
}
static void static void
destroy_shell_grab_shsurf(struct wl_listener *listener, void *data) destroy_shell_grab_shsurf(struct wl_listener *listener, void *data)
{ {
@ -189,9 +212,6 @@ static void
center_on_output(struct weston_surface *surface, center_on_output(struct weston_surface *surface,
struct weston_output *output); struct weston_output *output);
static struct shell_surface *
get_shell_surface(struct weston_surface *surface);
static void static void
shell_configuration(struct desktop_shell *shell) shell_configuration(struct desktop_shell *shell)
{ {
@ -434,10 +454,16 @@ static void
shell_unset_fullscreen(struct shell_surface *shsurf) shell_unset_fullscreen(struct shell_surface *shsurf)
{ {
/* undo all fullscreen things here */ /* undo all fullscreen things here */
if (shsurf->fullscreen.type == WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER &&
shell_surface_is_top_fullscreen(shsurf)) {
weston_output_switch_mode(shsurf->fullscreen_output,
shsurf->fullscreen_output->origin);
}
shsurf->fullscreen.type = WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT; shsurf->fullscreen.type = WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT;
shsurf->fullscreen.framerate = 0; shsurf->fullscreen.framerate = 0;
wl_list_remove(&shsurf->fullscreen.transform.link); wl_list_remove(&shsurf->fullscreen.transform.link);
wl_list_init(&shsurf->fullscreen.transform.link); wl_list_init(&shsurf->fullscreen.transform.link);
if (shsurf->fullscreen.black_surface)
weston_surface_destroy(shsurf->fullscreen.black_surface); weston_surface_destroy(shsurf->fullscreen.black_surface);
shsurf->fullscreen.black_surface = NULL; shsurf->fullscreen.black_surface = NULL;
shsurf->fullscreen_output = NULL; shsurf->fullscreen_output = NULL;
@ -638,6 +664,21 @@ shell_configure_fullscreen(struct shell_surface *shsurf)
weston_surface_set_position(surface, output->x, output->y); weston_surface_set_position(surface, output->x, output->y);
break; break;
case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER: case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER:
if (shell_surface_is_top_fullscreen(shsurf)) {
struct weston_mode mode = {0,
surface->geometry.width,
surface->geometry.height,
shsurf->fullscreen.framerate};
if (weston_output_switch_mode(output, &mode) == 0) {
weston_surface_configure(shsurf->fullscreen.black_surface,
output->x, output->y,
output->current->width,
output->current->height);
weston_surface_set_position(surface, output->x, output->y);
break;
}
}
break; break;
case WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL: case WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL:
break; break;
@ -650,26 +691,34 @@ shell_configure_fullscreen(struct shell_surface *shsurf)
static void static void
shell_stack_fullscreen(struct shell_surface *shsurf) shell_stack_fullscreen(struct shell_surface *shsurf)
{ {
struct weston_output *output = shsurf->fullscreen_output;
struct weston_surface *surface = shsurf->surface; struct weston_surface *surface = shsurf->surface;
struct desktop_shell *shell = shell_surface_get_shell(shsurf); struct desktop_shell *shell = shell_surface_get_shell(shsurf);
wl_list_remove(&surface->layer_link); wl_list_remove(&surface->layer_link);
wl_list_remove(&shsurf->fullscreen.black_surface->layer_link);
wl_list_insert(&shell->fullscreen_layer.surface_list, wl_list_insert(&shell->fullscreen_layer.surface_list,
&surface->layer_link); &surface->layer_link);
weston_surface_damage(surface);
if (!shsurf->fullscreen.black_surface)
shsurf->fullscreen.black_surface =
create_black_surface(surface->compositor,
surface,
output->x, output->y,
output->current->width,
output->current->height);
wl_list_remove(&shsurf->fullscreen.black_surface->layer_link);
wl_list_insert(&surface->layer_link, wl_list_insert(&surface->layer_link,
&shsurf->fullscreen.black_surface->layer_link); &shsurf->fullscreen.black_surface->layer_link);
weston_surface_damage(surface);
weston_surface_damage(shsurf->fullscreen.black_surface); weston_surface_damage(shsurf->fullscreen.black_surface);
} }
static void static void
shell_map_fullscreen(struct shell_surface *shsurf) shell_map_fullscreen(struct shell_surface *shsurf)
{ {
shell_configure_fullscreen(shsurf);
shell_stack_fullscreen(shsurf); shell_stack_fullscreen(shsurf);
shell_configure_fullscreen(shsurf);
} }
static void static void
@ -844,15 +893,21 @@ destroy_shell_surface(struct wl_resource *resource)
if (shsurf->popup.grab.input_device) if (shsurf->popup.grab.input_device)
wl_input_device_end_pointer_grab(shsurf->popup.grab.input_device); wl_input_device_end_pointer_grab(shsurf->popup.grab.input_device);
/* in case cleaning up a dead client destroys shell_surface first */ if (shsurf->fullscreen.type == WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER &&
if (shsurf->surface) { shell_surface_is_top_fullscreen(shsurf)) {
wl_list_remove(&shsurf->surface_destroy_listener.link); weston_output_switch_mode(shsurf->fullscreen_output,
shsurf->surface->configure = NULL; shsurf->fullscreen_output->origin);
} }
if (shsurf->fullscreen.black_surface) if (shsurf->fullscreen.black_surface)
weston_surface_destroy(shsurf->fullscreen.black_surface); weston_surface_destroy(shsurf->fullscreen.black_surface);
/* As destroy_resource() use wl_list_for_each_safe(),
* we can always remove the listener.
*/
wl_list_remove(&shsurf->surface_destroy_listener.link);
shsurf->surface->configure = NULL;
wl_list_remove(&shsurf->link); wl_list_remove(&shsurf->link);
free(shsurf); free(shsurf);
} }
@ -864,7 +919,6 @@ shell_handle_surface_destroy(struct wl_listener *listener, void *data)
struct shell_surface, struct shell_surface,
surface_destroy_listener); surface_destroy_listener);
shsurf->surface = NULL;
wl_resource_destroy(&shsurf->resource); wl_resource_destroy(&shsurf->resource);
} }
@ -897,7 +951,7 @@ shell_get_shell_surface(struct wl_client *client,
if (get_shell_surface(surface)) { if (get_shell_surface(surface)) {
wl_resource_post_error(surface_resource, wl_resource_post_error(surface_resource,
WL_DISPLAY_ERROR_INVALID_OBJECT, WL_DISPLAY_ERROR_INVALID_OBJECT,
"wl_shell::get_shell_surface already requested"); "desktop_shell::get_shell_surface already requested");
return; return;
} }
@ -1499,6 +1553,7 @@ activate(struct desktop_shell *shell, struct weston_surface *es,
case SHELL_SURFACE_FULLSCREEN: case SHELL_SURFACE_FULLSCREEN:
/* should on top of panels */ /* should on top of panels */
shell_stack_fullscreen(get_shell_surface(es)); shell_stack_fullscreen(get_shell_surface(es));
shell_configure_fullscreen(get_shell_surface(es));
break; break;
default: default:
/* move the fullscreen surfaces down into the toplevel layer */ /* move the fullscreen surfaces down into the toplevel layer */
@ -1764,7 +1819,6 @@ configure(struct desktop_shell *shell, struct weston_surface *surface,
GLfloat x, GLfloat y, int32_t width, int32_t height) GLfloat x, GLfloat y, int32_t width, int32_t height)
{ {
enum shell_surface_type surface_type = SHELL_SURFACE_NONE; enum shell_surface_type surface_type = SHELL_SURFACE_NONE;
enum shell_surface_type prev_surface_type = SHELL_SURFACE_NONE;
struct shell_surface *shsurf; struct shell_surface *shsurf;
shsurf = get_shell_surface(surface); shsurf = get_shell_surface(surface);
@ -1782,9 +1836,8 @@ configure(struct desktop_shell *shell, struct weston_surface *surface,
center_on_output(surface, shsurf->fullscreen_output); center_on_output(surface, shsurf->fullscreen_output);
break; break;
case SHELL_SURFACE_FULLSCREEN: case SHELL_SURFACE_FULLSCREEN:
shell_configure_fullscreen(shsurf);
if (prev_surface_type != SHELL_SURFACE_FULLSCREEN)
shell_stack_fullscreen(shsurf); shell_stack_fullscreen(shsurf);
shell_configure_fullscreen(shsurf);
break; break;
case SHELL_SURFACE_MAXIMIZED: case SHELL_SURFACE_MAXIMIZED:
/* setting x, y and using configure to change that geometry */ /* setting x, y and using configure to change that geometry */

Loading…
Cancel
Save