[PATCH 2/3] shell: Add implementation of fullscreen.

Kristian Hoegsberg hoegsberg at gmail.com
Sun Feb 26 12:02:47 PST 2012


On Sun, Feb 26, 2012 at 03:21:37PM +0800, zhiwen.wu at linux.intel.com wrote:
> From: Alex Wu <zhiwen.wu at linux.intel.com>

Nice.  There are a few issues below and one thing I didn't figure out
right now was that when you raise a window over the fullscreen window
and then re-raise the fullscreen window, the black surface renders
partly transparent (I can see the panel through it, but it doesn't
receive input).

> For now, fullscreen surface will be atop panels and with a black surface underlying it.
> Only the WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE method implemented in this patch. For
> other methods, just center on the surface.

(Please keep commit message lines under 78 characters)

thanks,
Kristian

> ---
>  src/shell.c |  207 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
>  1 files changed, 191 insertions(+), 16 deletions(-)
> 
> diff --git a/src/shell.c b/src/shell.c
> index ee71dcc..641a53f 100644
> --- a/src/shell.c
> +++ b/src/shell.c
> @@ -108,6 +108,14 @@ struct shell_surface {
>  		int32_t initial_up;
>  	} popup;
>  
> +	struct {
> +		enum wl_shell_surface_fullscreen_method type;
> +		struct weston_transform transform; /* matrix from x, y */
> +		bool setted;/*If transform already added to the list*/

Can we call it transform_set?  Or maybe just use
wl_list_empty(&transform.link) to indicate it's not set?  That means
you have to wl_list_init() it when you take it out of the list.

> +		uint32_t framerate;
> +		struct weston_surface *black_surface;
> +	} fullscreen;
> +
>  	struct weston_output *fullscreen_output;
>  	struct weston_output *output;
>  	struct wl_list link;
> @@ -130,6 +138,14 @@ struct rotate_grab {
>  };
>  
>  static void
> +activate(struct weston_shell *base, struct weston_surface *es,
> +	 struct weston_input_device *device, uint32_t time);
> +
> +static void
> +center_on_output(struct weston_surface *surface,
> +		 struct weston_output *output);
> +
> +static void
>  shell_configuration(struct wl_shell *shell)
>  {
>  	char *config_file;
> @@ -299,7 +315,8 @@ weston_surface_resize(struct shell_surface *shsurf,
>  {
>  	struct weston_resize_grab *resize;
>  
> -	/* FIXME: Reject if fullscreen */
> +	if (shsurf->type == SHELL_SURFACE_FULLSCREEN)
> +		return 0;
>  
>  	if (edges == 0 || edges > 15 ||
>  	    (edges & 3) == 3 || (edges & 12) == 12)
> @@ -330,7 +347,8 @@ shell_surface_resize(struct wl_client *client, struct wl_resource *resource,
>  	struct weston_input_device *wd = input_resource->data;
>  	struct shell_surface *shsurf = resource->data;
>  
> -	/* FIXME: Reject if fullscreen */
> +	if (shsurf->type == SHELL_SURFACE_FULLSCREEN)
> +		return;
>  
>  	if (wd->input_device.button_count == 0 ||
>  	    wd->input_device.grab_time != time ||
> @@ -348,15 +366,32 @@ get_default_output(struct weston_compositor *compositor)
>  			    struct weston_output, link);
>  }
>  
> +static void
> +shell_unmap_fullscreen(struct shell_surface *shsurf)
> +{
> +	weston_surface_set_position(shsurf->surface,
> +			shsurf->saved_x,
> +			shsurf->saved_y);
> +	shsurf->fullscreen_output = NULL;
> +	shsurf->fullscreen.type = 0;
> +	weston_surface_unmap(shsurf->fullscreen.black_surface);
> +	wl_list_init(&shsurf->fullscreen.black_surface->link);

We can just destroy the black surface here.

> +	weston_surface_unmap(shsurf->surface);
> +	wl_list_init(&shsurf->surface->link);
> +
> +	if (shsurf->fullscreen.setted) {
> +		wl_list_remove(&shsurf->fullscreen.transform.link);
> +		wl_list_init(&shsurf->fullscreen.transform.link);
> +		shsurf->fullscreen.setted = false;
> +	}
> +}
> +
>  static int
>  reset_shell_surface_type(struct shell_surface *surface)
>  {
>  	switch (surface->type) {
>  	case SHELL_SURFACE_FULLSCREEN:
> -		weston_surface_set_position(surface->surface,
> -					    surface->saved_x,
> -					    surface->saved_y);
> -		surface->fullscreen_output = NULL;
> +		shell_unmap_fullscreen(surface);

We don't want a full unmap here.  One problem is that when you go from
fullscreen back to toplevel, the window gets remapped including
picking a new random initial position and triggering the zoom+fade in
animation.

>  		break;
>  	case SHELL_SURFACE_MAXIMIZED:
>  		surface->output = get_default_output(surface->surface->compositor);
> @@ -483,6 +518,112 @@ shell_surface_set_maximized(struct wl_client *client,
>  	shsurf->type = SHELL_SURFACE_MAXIMIZED;
>  }
>  
> +static struct weston_surface *
> +create_black_surface(struct weston_compositor *ec)
> +{
> +	struct weston_surface *surface = NULL;
> +
> +	surface = weston_surface_create(ec);
> +	if (surface == NULL) {
> +		fprintf(stderr, "no memory\n");
> +		return NULL;
> +	}
> +
> +	weston_surface_configure(surface, 0, 0, 8192, 8192);
> +	weston_surface_set_color(surface, 0.0, 0.0, 0.0, 1);
> +	return surface;
> +}
> +
> +/*
> + * Handle size dismatch and positioning according to the method.
> + */
> +static void
> +shell_configure_fullscreen(struct shell_surface *shsurf)
> +{
> +	struct weston_output *output = shsurf->fullscreen_output;
> +	struct weston_surface *surface = shsurf->surface;
> +	struct weston_matrix *matrix;
> +
> +	center_on_output(surface, output);
> +
> +	switch (shsurf->fullscreen.type) {
> +	case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT:
> +		break;
> +	case WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE:
> +		matrix = &shsurf->fullscreen.transform.matrix;
> +		weston_matrix_init(matrix);
> +		weston_matrix_scale(matrix,
> +		                    (float)output->current->width/(float)surface->geometry.width,
> +				    (float)output->current->width/(float)surface->geometry.width,
> +				    1.0);

Break this into

  scale = (float)output->current->width/(float)surface->geometry.width;
  weston_matrix_scale(matrix, scale, scale, 1);

Mostly for indentation, but we also avoid computing the same thing twice.

> +		if (!shsurf->fullscreen.setted) {
> +			wl_list_insert(surface->geometry.transformation_list.prev,
> +				       &shsurf->fullscreen.transform.link);
> +			shsurf->fullscreen.setted = true;
> +		}

You can just always remove and re-insert it here instead of the check.

> +		weston_surface_set_position(surface, output->x, output->y);
> +		break;
> +	case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER:
> +		break;
> +	case WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL:
> +		break;
> +	default:
> +		break;
> +	}
> +}
> +
> +/*
> + * Handle the stacking order of the fullscreen surface and the associated black surface.
> + */
> +static void
> +shell_stack_fullscreen(struct shell_surface *shsurf, bool mapped)
> +{
> +	struct weston_surface *surface = shsurf->surface;
> +	struct wl_shell *shell = shell_surface_get_shell(shsurf);
> +	struct wl_list *list;
> +
> +	if (mapped) {
> +		wl_list_remove(&surface->link);
> +		wl_list_remove(&shsurf->fullscreen.black_surface->link);
> +	}
> +
> +	if (shell->locked) {
> +		wl_list_insert(&shell->hidden_surface_list, &surface->link);
> +		wl_list_insert(&surface->link, &shsurf->fullscreen.black_surface->link);
> +	} else {
> +		list = weston_compositor_top(surface->compositor);
> +		wl_list_insert(list, &surface->link);
> +		wl_list_insert(&surface->link, &shsurf->fullscreen.black_surface->link);
> +
> +		/*assign output*/
> +		surface->output = shsurf->fullscreen_output;
> +		shsurf->fullscreen.black_surface->output = shsurf->fullscreen_output;
> +		if (!wl_list_empty(&surface->frame_callback_list)) {
> +			wl_list_insert_list(surface->output->frame_callback_list.prev,
> +					    &surface->frame_callback_list);
> +			wl_list_init(&surface->frame_callback_list);
> +		}
> +		weston_compositor_repick(surface->compositor);
> +		weston_surface_damage(surface);
> +		weston_surface_damage(shsurf->fullscreen.black_surface);
> +	}
> +}
> +
> +static void
> +shell_map_fullscreen(struct shell_surface *shsurf)
> +{
> +	shell_configure_fullscreen(shsurf);
> +	shell_stack_fullscreen(shsurf, false);
> +}
> +
> +static void
> +shell_raise_fullscreen(struct shell_surface *shsurf)
> +{
> +	shell_configure_fullscreen(shsurf);
> +	shell_stack_fullscreen(shsurf, true);
> +}
> +
>  static void
>  shell_surface_set_fullscreen(struct wl_client *client,
>  			     struct wl_resource *resource,
> @@ -492,21 +633,37 @@ shell_surface_set_fullscreen(struct wl_client *client,
>  {
>  	struct shell_surface *shsurf = resource->data;
>  	struct weston_surface *es = shsurf->surface;
> -	struct weston_output *output;
> +	struct wl_shell *shell;
> +
> +	if (output_resource)
> +		shsurf->output = output_resource->data;
> +	else
> +		shsurf->output = get_default_output(es->compositor);
>  
>  	if (reset_shell_surface_type(shsurf))
>  		return;
>  
> -	/* FIXME: Fullscreen on first output */
> -	/* FIXME: Handle output going away */
> -	output = get_default_output(es->compositor);
> -
>  	shsurf->saved_x = es->geometry.x;
>  	shsurf->saved_y = es->geometry.y;
> -	shsurf->output = output;
> -	shsurf->fullscreen_output = output;
> +	shsurf->fullscreen_output = shsurf->output;
> +	shsurf->fullscreen.type = method;
> +	shsurf->fullscreen.framerate = framerate;
>  	shsurf->type = SHELL_SURFACE_FULLSCREEN;
>  
> +	if (shsurf->fullscreen.black_surface == NULL)
> +		shsurf->fullscreen.black_surface = create_black_surface(es->compositor);
> +
> +	if (es->output) {

This is never true since reset_shell_surface_type() unmaps it.  But
even when that is fixed, we can't change the surface position, size or
stacking until we receive the fullscreen buffer from the client.  If
we do, we're very likely to see a frame or two with the surface
jumping or moving before we get the real fullscreen buffer.  All we
should do here is save the fullscreen parameters and send the
configure.  Once we get the new buffer in configure, we can do all the
changes (create black surface, raise, move, add transform etc).

> +		/*already mapped, just raise it on top*/
> +		shell_raise_fullscreen(shsurf);
> +		shell = shell_surface_get_shell(shsurf);
> +		if (!shell->locked)
> +			activate(es->compositor->shell, es,
> +				 (struct weston_input_device *)
> +				 es->compositor->input_device,
> +				 weston_compositor_get_time());
> +	}
> +
>  	wl_resource_post_event(resource,
>  			       WL_SHELL_SURFACE_CONFIGURE,
>  			       weston_compositor_get_time(), 0,
> @@ -649,6 +806,9 @@ destroy_shell_surface(struct wl_resource *resource)
>  	if (shsurf->surface)
>  		wl_list_remove(&shsurf->surface_destroy_listener.link);
>  
> +	if (shsurf->fullscreen.black_surface)
> +		destroy_surface(&shsurf->fullscreen.black_surface->surface.resource);
> +
>  	wl_list_remove(&shsurf->link);
>  	free(shsurf);
>  }
> @@ -712,6 +872,11 @@ shell_get_shell_surface(struct wl_client *client,
>  	shsurf->resource.data = shsurf;
>  
>  	shsurf->surface = surface;
> +	shsurf->fullscreen.type = WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT;
> +	shsurf->fullscreen.framerate = 0;
> +	shsurf->fullscreen.setted = false;
> +	shsurf->fullscreen.black_surface = NULL;
> +
>  	shsurf->surface_destroy_listener.func = shell_handle_surface_destroy;
>  	wl_list_insert(surface->surface.resource.destroy_listener_list.prev,
>  		       &shsurf->surface_destroy_listener.link);
> @@ -1254,6 +1419,9 @@ activate(struct weston_shell *base, struct weston_surface *es,
>  				       &es->link);
>  		}
>  		break;
> +	case SHELL_SURFACE_FULLSCREEN:
> +		/* should on top of panels*/
> +		break;
>  	default:
>  		if (!shell->locked) {
>  			list = weston_compositor_top(compositor);
> @@ -1418,9 +1586,11 @@ map(struct weston_shell *base, struct weston_surface *surface,
>  					    10 + random() % 400);
>  		break;
>  	case SHELL_SURFACE_SCREENSAVER:
> -	case SHELL_SURFACE_FULLSCREEN:
>  		center_on_output(surface, shsurf->fullscreen_output);
>  		break;
> +	case SHELL_SURFACE_FULLSCREEN:
> +		shell_map_fullscreen(shsurf);
> +		break;
>  	case SHELL_SURFACE_MAXIMIZED:
>  		/*use surface configure to set the geometry*/
>  		panel_height = get_output_panel_height(shell,surface->output);
> @@ -1470,6 +1640,9 @@ map(struct weston_shell *base, struct weston_surface *surface,
>  		}
>  		do_configure = 0;
>  		break;
> +	case SHELL_SURFACE_FULLSCREEN:
> +		do_configure = 0;
> +		break;
>  	case SHELL_SURFACE_NONE:
>  		do_configure = 0;
>  		break;
> @@ -1500,7 +1673,7 @@ map(struct weston_shell *base, struct weston_surface *surface,
>  		if (!shell->locked)
>  			activate(base, surface,
>  				 (struct weston_input_device *)
> -					compositor->input_device,
> +				 compositor->input_device,
>  				 weston_compositor_get_time());
>  		break;
>  	default:
> @@ -1531,9 +1704,11 @@ configure(struct weston_shell *base, struct weston_surface *surface,
>  
>  	switch (surface_type) {
>  	case SHELL_SURFACE_SCREENSAVER:
> -	case SHELL_SURFACE_FULLSCREEN:
>  		center_on_output(surface, shsurf->fullscreen_output);
>  		break;
> +	case SHELL_SURFACE_FULLSCREEN:
> +		shell_configure_fullscreen(shsurf);
> +		break;
>  	case SHELL_SURFACE_MAXIMIZED:
>  		/*setting x, y and using configure to change that geometry*/
>  		surface->geometry.x = surface->output->x;
> -- 
> 1.7.5.4
> 


More information about the wayland-devel mailing list