[PATCH v2] shell: moving drag surface refine

Kristian Høgsberg hoegsberg at gmail.com
Thu Aug 2 09:01:42 PDT 2012


On Tue, Jul 31, 2012 at 01:00:26AM -0700, juan.j.zhao at linux.intel.com wrote:
> From: Juan Zhao <juan.j.zhao at linux.intel.com>
> 
> When applications not directly based on toytoolkit, like simple-egl, efl
> applications is grabbed and moved, they may be moved to the place under
> the panel. Then they could not be grabbed again.
> Don't allow the pointer's bounding box move across the shell's active_regions.
> 
> One more open question, I also added current output's check and did not enable
>  it, and it works, should we need this?
> 
> Signed-off-by: Juan Zhao <juan.j.zhao at linux.intel.com>
> ---
>  src/compositor-drm.c |   5 ++-
>  src/compositor.h     |   2 +-
>  src/shell.c          | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++-
>  3 files changed, 106 insertions(+), 4 deletions(-)
> 
> diff --git a/src/compositor-drm.c b/src/compositor-drm.c
> index cd0395e..723ca13 100644
> --- a/src/compositor-drm.c
> +++ b/src/compositor-drm.c
> @@ -1669,7 +1669,10 @@ update_outputs(struct drm_compositor *ec, struct udev_device *drm_device)
>  		}
>  	}
>  
> -	/* FIXME: handle zero outputs, without terminating */	
> +	ec->base.shell_interface.reconf_active_regions(
> +					ec->base.shell_interface.shell);
> +

Let's use a wl_signal for this.  Outputs changing is an event
generated by the core compositor, and there may many places that want
to do something when that happens.  Put a struct wl_signal
outputs_signal in weston_compositor and emit it whenever the list of
outputs, their resolution or position changes.  Let's also add an
output_region region in weston_compositor.h that we keep up to date
with then union of all output->regions.  Rebuild it before emitting
the outputs_signal.

> +	/* FIXME: handle zero outputs, without terminating */
>  	if (ec->connector_allocator == 0)
>  		wl_display_terminate(ec->base.wl_display);
>  }
> diff --git a/src/compositor.h b/src/compositor.h
> index 22c0174..4ea47bd 100644
> --- a/src/compositor.h
> +++ b/src/compositor.h
> @@ -88,7 +88,7 @@ struct weston_shell_interface {
>  	int (*move)(struct shell_surface *shsurf, struct weston_seat *ws);
>  	int (*resize)(struct shell_surface *shsurf,
>  		      struct weston_seat *ws, uint32_t edges);
> -
> +	void (*reconf_active_regions)(void *shell);
>  };
>  
>  struct weston_border {
> diff --git a/src/shell.c b/src/shell.c
> index a9e4d4f..09ebf73 100644
> --- a/src/shell.c
> +++ b/src/shell.c
> @@ -124,6 +124,7 @@ struct desktop_shell {
>  	uint32_t binding_modifier;
>  	enum animation_type win_animation_type;
>  	struct weston_surface *debug_repaint_surface;
> +	pixman_region32_t active_regions;

Just call it active_region, there's only one.

>  };
>  
>  enum shell_surface_type {
> @@ -221,6 +222,17 @@ get_shell_surface(struct weston_surface *surface);
>  static struct desktop_shell *
>  shell_surface_get_shell(struct shell_surface *shsurf);
>  
> +static int
> +get_output_panel_height(struct desktop_shell *shell,
> +                        struct weston_output *output);
> +
> +static struct weston_output *
> +get_default_output(struct weston_compositor *compositor);
> +
> +static void
> +shell_active_regions_subtract(struct desktop_shell *shell, int32_t x,
> +			       int32_t y, int32_t width, int32_t height);
> +
>  static bool
>  shell_surface_is_top_fullscreen(struct shell_surface *shsurf)
>  {
> @@ -784,13 +796,44 @@ move_grab_motion(struct wl_pointer_grab *grab,
>  	struct wl_pointer *pointer = grab->pointer;
>  	struct shell_surface *shsurf = move->base.shsurf;
>  	struct weston_surface *es;
> +	struct desktop_shell *shell = NULL;
>  	int dx = wl_fixed_to_int(pointer->x + move->dx);
>  	int dy = wl_fixed_to_int(pointer->y + move->dy);
> +	int boxsize = 4;
> +	int bounding_x = wl_fixed_to_int(pointer->x) - boxsize;
> +	int bounding_y = wl_fixed_to_int(pointer->y) - boxsize;
> +	pixman_box32_t *e;
> +	pixman_region32_t region;
>  
>  	if (!shsurf)
>  		return;
>  
>  	es = shsurf->surface;
> +	shell = shell_surface_get_shell(shsurf);
> +
> +	bounding_x = bounding_x>0 ? bounding_x:0;
> +	bounding_y = bounding_y>0 ? bounding_y:0;
> +	pixman_region32_init_rect(&region, bounding_x, bounding_y,
> +				   boxsize<<1, boxsize<<1);
> +
> +	pixman_region32_intersect(&region, &region,
> +				  &shell->active_regions);

The idea was to use the bounding box of the surface

	pixman_region32_intersect(&region,
	                          &shsurf->surface->transform.boundingbox,
				  &shell->active_regions);

> +	/*FIXME: should be focus on the surface's output only?*/
> +	/*
> +	struct weston_output * current_output;
> +	current_output = shsurf->output ? shsurf->output
> +			                : get_default_output(es->compositor);
> +	pixman_region32_intersect(&region, &region,
> +				  &current_output->region);
> +	*/

Let's drop this.

> +	e = pixman_region32_extents(&region);
> +	if (e->x2 - e->x1 <= boxsize) {
> +		if(e->y2 - e->y1 <= boxsize)
> +			return;
> +		dx = (int)es->geometry.x;
> +	}
> +	if (e->y2 - e->y1 <= boxsize)
> +		dy = (int)es->geometry.y;

We need to loop through the rectangles in the region and make sure at
least one of them is at least boxsize wide and high.  Consider a
common configuration:

     +------------+-------------------------------+
     |            |                               |
     |  LVDS1     |      DP1                      |
     |            |                               |
     |            |                               |
     +------------+                               |
                  |                               |
                  |                               |
                  |                               |
                  |                               |
                  +-------------------------------+

If you put a surface here:

     +------------+-------------------------------+
     |            |                               |
     |  LVDS1     |      DP1                      |
     |            |                               |
     |     +------++                              |
     +-----|------+|                              |
           | SURF ||                              |
           |      ||                              |
           +------++                              |
                  |                               |
                  +-------------------------------+

There will be two rectangles in the region, one really wide and low
and one relaly tall and narrow.  While the extent of the region may be
wide and tall, this may only leave a 1-pixel top edge and a 1-pixel
right edge of the window on the screen.  So to prevent this, we need
to make sure at least on of the rectangles in the region are at least
boxsize wide and high.

>  	weston_surface_configure(es, dx, dy,
>  				 es->geometry.width, es->geometry.height);
> @@ -1909,11 +1952,27 @@ desktop_shell_set_background(struct wl_client *client,
>  }
>  
>  static void
> +shell_active_regions_subtract(struct desktop_shell *shell, int32_t x,
> +			       int32_t y, int32_t width, int32_t height)
> +{
> +	pixman_region32_t region;
> +	pixman_region32_init_rect(&region, x, y, width, height);
> +
> +	pixman_region32_subtract(&shell->active_regions,
> +				  &shell->active_regions, &region);
> +}
> +
> +static void
>  panel_configure(struct weston_surface *es, int32_t sx, int32_t sy)
>  {
>  	struct desktop_shell *shell = es->private;
>  
>  	configure_static_surface(es, &shell->panel_layer);
> +	shell_active_regions_subtract( shell,
> +				      (int32_t)es->geometry.x,
> +				      (int32_t)es->geometry.y,
> +				       es->geometry.width,
> +				       es->geometry.height);

Let's just have one function that computes the active_region from
compositor->output_region and the panels, and lets just call that from
panel_configure and from the output_signal handler.

>  }
>  
>  static void
> @@ -3216,11 +3275,48 @@ shell_destroy(struct wl_listener *listener, void *data)
>  		workspace_destroy(*ws);
>  	wl_array_release(&shell->workspaces.array);
>  
> +	pixman_region32_fini(&shell->active_regions);
> +
>  	free(shell->screensaver.path);
>  	free(shell);
>  }
>  
>  static void
> +shell_init_active_regions(struct weston_compositor *ec, struct desktop_shell *shell)
> +{
> +	struct weston_output *output;
> +	pixman_region32_init(&shell->active_regions);
> +	wl_list_for_each(output, &ec->output_list, link) {
> +		pixman_region32_union(&shell->active_regions, &shell->active_regions,
> +				&output->region);
> +	}
> +
> +	return;
> +}
> +
> +static void
> +shell_reconf_active_regions(void *dshell)
> +{
> +	struct desktop_shell *shell = (struct desktop_shell *)dshell;
> +	struct weston_surface *surface;
> +
> +	pixman_region32_fini(&shell->active_regions);
> +	shell_init_active_regions(shell->compositor, shell);
> +
> +	wl_list_for_each(surface, &shell->panel_layer.surface_list, layer_link) {
> +		if (!surface->output)
> +			continue;
> +
> +		shell_active_regions_subtract( shell,
> +				      (int32_t)surface->geometry.x,
> +				      (int32_t)surface->geometry.y,
> +				       surface->geometry.width,
> +				       surface->geometry.height);
> +	}
> +
> +}
> +
> +static void
>  shell_add_bindings(struct weston_compositor *ec, struct desktop_shell *shell)
>  {
>  	uint32_t mod;
> @@ -3266,9 +3362,9 @@ shell_add_bindings(struct weston_compositor *ec, struct desktop_shell *shell)
>  				          debug_repaint_binding, shell);
>  	weston_compositor_add_key_binding(ec, KEY_K, mod,
>  				          force_kill_binding, shell);
> -	weston_compositor_add_key_binding(ec, KEY_UP, mod,
> +	weston_compositor_add_key_binding(ec, KEY_U, mod,
>  					  workspace_up_binding, shell);
> -	weston_compositor_add_key_binding(ec, KEY_DOWN, mod,
> +	weston_compositor_add_key_binding(ec, KEY_J, mod,
>  					  workspace_down_binding, shell);

This doesn't look right :)

>  	/* Add bindings for mod+F[1-6] for workspace 1 to 6. */
> @@ -3317,6 +3413,7 @@ shell_init(struct weston_compositor *ec)
>  	ec->shell_interface.set_transient = set_transient;
>  	ec->shell_interface.move = surface_move;
>  	ec->shell_interface.resize = surface_resize;
> +	ec->shell_interface.reconf_active_regions = shell_reconf_active_regions;
>  
>  	wl_list_init(&shell->screensaver.surfaces);
>  	wl_list_init(&shell->input_panel.surfaces);
> @@ -3372,5 +3469,7 @@ shell_init(struct weston_compositor *ec)
>  
>  	shell_add_bindings(ec, shell);
>  
> +	shell_init_active_regions(ec, shell);
> +
>  	return 0;
>  }
> -- 
> 1.7.11
> 


More information about the wayland-devel mailing list