[PATCH] Add support for surface enter/leave events
Kristian Hoegsberg
hoegsberg at gmail.com
Wed Apr 18 09:13:39 PDT 2012
On Tue, Apr 17, 2012 at 05:23:02PM -0400, cdahlin at redhat.com wrote:
> From: Casey Dahlin <cdahlin at redhat.com>
Thanks, that looks good, a lot of the logic is in place here. I was
thinking that we would use a uint32_t bit mask instead of the array
and the bubble sort. weston_output needs a new output->id fied,
surface needs an output_mask field and the compositor needs an
output_allocator, like what we do for crtcs and connectors in
compositor-drm.c. Then to send out the events, compare the
output_bitmask before and after changing surface outputs and send
leave events where the bit goes from 1 to 0 and enter when it goes
from 0 to 1.
Also, we have find_resource_for_surface to look through a list of
wl_resources to the one matching a given client (it needs to be
changed to find_resource_for_client), we should use that to find the
resource when sending out the event.
Kristian
> Signed-off-by: Casey Dahlin <cdahlin at redhat.com>
> ---
> src/compositor.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++---
> src/compositor.h | 13 +++++--
> src/shell.c | 52 +++++++++++++++------------
> 3 files changed, 135 insertions(+), 33 deletions(-)
>
> diff --git a/src/compositor.c b/src/compositor.c
> index 17daac4..0f59f46 100644
> --- a/src/compositor.c
> +++ b/src/compositor.c
> @@ -220,7 +220,7 @@ weston_surface_create(struct weston_compositor *compositor)
> surface->pitch = 1;
>
> surface->buffer = NULL;
> - surface->output = NULL;
> + surface->output_count = 0;
>
> pixman_region32_init(&surface->damage);
> pixman_region32_init(&surface->opaque);
> @@ -539,7 +539,7 @@ weston_surface_set_position(struct weston_surface *surface,
> WL_EXPORT int
> weston_surface_is_mapped(struct weston_surface *surface)
> {
> - if (surface->output)
> + if (surface->output_count)
> return 1;
> else
> return 0;
> @@ -614,7 +614,7 @@ weston_surface_unmap(struct weston_surface *surface)
> struct wl_input_device *device = surface->compositor->input_device;
>
> weston_surface_damage_below(surface);
> - surface->output = NULL;
> + surface->output_count = 0;
> wl_list_remove(&surface->link);
> wl_list_remove(&surface->layer_link);
>
> @@ -1112,6 +1112,86 @@ surface_destroy(struct wl_client *client, struct wl_resource *resource)
> wl_resource_destroy(resource);
> }
>
> +static inline void
> +weston_surface_send_enter(struct weston_surface *es,
> + struct weston_output *output)
> +{
> + struct wl_resource *r;
> +
> + wl_list_for_each(r, &output->resource_list, link) {
> + if (r->client != es->surface.resource.client)
> + continue;
> +
> + wl_surface_send_enter(&es->surface.resource, r);
> + return;
> + }
> +}
> +
> +static inline void
> +weston_surface_send_leave(struct weston_surface *es,
> + struct weston_output *output)
> +{
> + struct wl_resource *r;
> +
> + wl_list_for_each(r, &output->resource_list, link) {
> + if (r->client != es->surface.resource.client)
> + continue;
> +
> + wl_surface_send_leave(&es->surface.resource, r);
> + return;
> + }
> +}
> +
> +static void
> +sort_output_list(struct weston_output **list, size_t count)
> +{
> + size_t i, j;
> + struct weston_output *tmp;
> +
> + for (i = 1; i < count; i++) {
> + for (j = i; j && list[j] < list[j-1]; j--) {
> + tmp = list[j];
> + list[j] = list[j-1];
> + list[j-1] = tmp;
> + }
> + }
> +}
> +
> +static void
> +weston_surface_update_output(struct weston_surface *es,
> + struct weston_output **outputs, size_t count,
> + struct weston_output *primary)
> +{
> + size_t orig_loc = 0, new_loc = 0;
> +
> + sort_output_list(outputs, count);
> + sort_output_list(es->outputs, es->output_count);
> +
> + while (orig_loc < es->output_count && new_loc < count) {
> + if (orig_loc == es->output_count ||
> + es->outputs[orig_loc] > outputs[new_loc]) {
> + weston_surface_send_enter(es, outputs[new_loc++]);
> + } else if (new_loc == count ||
> + outputs[new_loc] > es->outputs[orig_loc]) {
> + weston_surface_send_leave(es, es->outputs[orig_loc++]);
> + } else {
> + orig_loc++;
> + new_loc++;
> + }
> + }
> +
> + es->output_count = count;
> +
> + for (orig_loc = 0; orig_loc < count; orig_loc++) {
> + es->outputs[orig_loc] = outputs[orig_loc];
> + if (es->outputs[orig_loc] == primary)
> + new_loc = orig_loc;
> + }
> +
> + es->outputs[new_loc] = es->outputs[0];
> + es->outputs[0] = primary;
> +}
> +
> WL_EXPORT void
> weston_surface_assign_output(struct weston_surface *es)
> {
> @@ -1121,6 +1201,9 @@ weston_surface_assign_output(struct weston_surface *es)
> uint32_t max, area;
> pixman_box32_t *e;
>
> + struct weston_output *output_list[8];
> + size_t output_count = 0;
> +
> weston_surface_update_transform(es);
>
> new_output = NULL;
> @@ -1133,6 +1216,11 @@ weston_surface_assign_output(struct weston_surface *es)
> e = pixman_region32_extents(®ion);
> area = (e->x2 - e->x1) * (e->y2 - e->y1);
>
> + if (! area)
> + continue;
> +
> + output_list[output_count++] = output;
> +
> if (area >= max) {
> new_output = output;
> max = area;
> @@ -1140,7 +1228,7 @@ weston_surface_assign_output(struct weston_surface *es)
> }
> pixman_region32_fini(®ion);
>
> - es->output = new_output;
> + weston_surface_update_output(es, output_list, output_count, new_output);
> if (!wl_list_empty(&es->frame_callback_list)) {
> wl_list_insert_list(new_output->frame_callback_list.prev,
> &es->frame_callback_list);
> @@ -1235,8 +1323,8 @@ surface_frame(struct wl_client *client,
>
> wl_client_add_resource(client, &cb->resource);
>
> - if (es->output) {
> - wl_list_insert(es->output->frame_callback_list.prev,
> + if (es->output_count) {
> + wl_list_insert(es->outputs[0]->frame_callback_list.prev,
> &cb->link);
> } else {
> wl_list_insert(es->frame_callback_list.prev, &cb->link);
> @@ -2129,6 +2217,8 @@ bind_output(struct wl_client *client,
> resource = wl_client_add_object(client,
> &wl_output_interface, NULL, id, data);
>
> + wl_list_insert(&output->resource_list, &resource->link);
> +
> wl_output_send_geometry(resource,
> output->x,
> output->y,
> @@ -2333,6 +2423,7 @@ weston_output_init(struct weston_output *output, struct weston_compositor *c,
> weston_output_damage(output);
>
> wl_list_init(&output->frame_callback_list);
> + wl_list_init(&output->resource_list);
>
> output->global =
> wl_display_add_global(c->wl_display, &wl_output_interface,
> diff --git a/src/compositor.h b/src/compositor.h
> index 93284c5..837ba18 100644
> --- a/src/compositor.h
> +++ b/src/compositor.h
> @@ -74,6 +74,7 @@ enum dpms_enum {
>
> struct weston_output {
> struct wl_list link;
> + struct wl_list resource_list;
> struct wl_global *global;
> struct weston_compositor *compositor;
> struct weston_matrix matrix;
> @@ -321,11 +322,15 @@ struct weston_surface {
> } transform;
>
> /*
> - * Which output to vsync this surface to.
> - * Used to determine, whether to send or queue frame events.
> - * Must be NULL, if 'link' is not in weston_compositor::surface_list.
> + * Outputs this surface is currently within the display region of.
> + *
> + * The first output in the list is the primary, which we will to vsync
> + * this surface to. Used to determine, whether to send or queue frame
> + * events. Count must be 0 if 'link' is not in
> + * weston_compositor::surface_list.
> */
> - struct weston_output *output;
> + struct weston_output *outputs[8]; /* FIXME: Unlimited outputs */
> + size_t output_count;
>
> struct wl_list frame_callback_list;
>
> diff --git a/src/shell.c b/src/shell.c
> index 02061c6..8a2fe38 100644
> --- a/src/shell.c
> +++ b/src/shell.c
> @@ -509,7 +509,7 @@ shell_surface_set_transient(struct wl_client *client,
> return;
>
> /* assign to parents output */
> - shsurf->output = pes->output;
> + shsurf->output = pes->output_count ? pes->outputs[0] : NULL;
> weston_surface_set_position(es, pes->geometry.x + x,
> pes->geometry.y + y);
>
> @@ -566,12 +566,12 @@ shell_surface_set_maximized(struct wl_client *client,
> shsurf->saved_position_valid = true;
>
> shell = shell_surface_get_shell(shsurf);
> - panel_height = get_output_panel_height(shell, es->output);
> + panel_height = get_output_panel_height(shell, es->outputs[0]);
> edges = WL_SHELL_SURFACE_RESIZE_TOP|WL_SHELL_SURFACE_RESIZE_LEFT;
>
> wl_shell_surface_send_configure(&shsurf->resource, edges,
> - es->output->current->width,
> - es->output->current->height - panel_height);
> + es->outputs[0]->current->width,
> + es->outputs[0]->current->height - panel_height);
>
> shsurf->type = SHELL_SURFACE_MAXIMIZED;
> }
> @@ -622,7 +622,8 @@ shell_configure_fullscreen(struct shell_surface *shsurf)
> wl_list_remove(&shsurf->fullscreen.black_surface->layer_link);
> wl_list_insert(&surface->layer_link,
> &shsurf->fullscreen.black_surface->layer_link);
> - shsurf->fullscreen.black_surface->output = output;
> + shsurf->fullscreen.black_surface->outputs[0] = output;
> + shsurf->fullscreen.black_surface->output_count = 1;
>
> switch (shsurf->fullscreen.type) {
> case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT:
> @@ -777,7 +778,8 @@ shell_map_popup(struct shell_surface *shsurf)
> struct weston_surface *es = shsurf->surface;
> struct weston_surface *parent = shsurf->parent->surface;
>
> - es->output = parent->output;
> + es->output_count = parent->output_count;
> + memcpy(es->outputs, parent->outputs, 8 * sizeof(struct weston_output *));
> shsurf->popup.grab.interface = &popup_grab_interface;
>
> weston_surface_update_transform(parent);
> @@ -998,7 +1000,8 @@ show_screensaver(struct desktop_shell *shell, struct shell_surface *surface)
>
> wl_list_remove(&surface->surface->layer_link);
> wl_list_insert(list, &surface->surface->layer_link);
> - surface->surface->output = surface->output;
> + surface->surface->outputs[0] = surface->output;
> + surface->surface->output_count = 1;
> weston_surface_damage(surface->surface);
> }
>
> @@ -1007,7 +1010,7 @@ hide_screensaver(struct desktop_shell *shell, struct shell_surface *surface)
> {
> wl_list_remove(&surface->surface->layer_link);
> wl_list_init(&surface->surface->layer_link);
> - surface->surface->output = NULL;
> + surface->surface->output_count = 0;
> }
>
> static void
> @@ -1026,7 +1029,7 @@ desktop_shell_set_background(struct wl_client *client,
>
> wl_list_for_each(priv, &shell->backgrounds, link) {
> if (priv->output == output_resource->data) {
> - priv->surface->output = NULL;
> + priv->surface->output_count = 0;
> wl_list_remove(&priv->surface->layer_link);
> wl_list_remove(&priv->link);
> break;
> @@ -1063,7 +1066,7 @@ desktop_shell_set_panel(struct wl_client *client,
>
> wl_list_for_each(priv, &shell->panels, link) {
> if (priv->output == output_resource->data) {
> - priv->surface->output = NULL;
> + priv->surface->output_count = 0;
> wl_list_remove(&priv->surface->layer_link);
> wl_list_remove(&priv->link);
> break;
> @@ -1675,9 +1678,9 @@ map(struct desktop_shell *shell, struct weston_surface *surface,
> break;
> case SHELL_SURFACE_MAXIMIZED:
> /* use surface configure to set the geometry */
> - panel_height = get_output_panel_height(shell,surface->output);
> - weston_surface_set_position(surface, surface->output->x,
> - surface->output->y + panel_height);
> + panel_height = get_output_panel_height(shell,surface->outputs[0]);
> + weston_surface_set_position(surface, surface->outputs[0]->x,
> + surface->outputs[0]->y + panel_height);
> break;
> case SHELL_SURFACE_LOCK:
> center_on_output(surface, get_default_output(compositor));
> @@ -1737,8 +1740,10 @@ map(struct desktop_shell *shell, struct weston_surface *surface,
>
> if (surface_type != SHELL_SURFACE_NONE) {
> weston_surface_assign_output(surface);
> - if (surface_type == SHELL_SURFACE_MAXIMIZED)
> - surface->output = shsurf->output;
> + if (surface_type == SHELL_SURFACE_MAXIMIZED) {
> + surface->outputs[0] = shsurf->output;
> + surface->output_count = 1;
> + }
> }
>
> switch (surface_type) {
> @@ -1788,9 +1793,9 @@ configure(struct desktop_shell *shell, struct weston_surface *surface,
> break;
> case SHELL_SURFACE_MAXIMIZED:
> /* setting x, y and using configure to change that geometry */
> - surface->geometry.x = surface->output->x;
> - surface->geometry.y = surface->output->y +
> - get_output_panel_height(shell,surface->output);
> + surface->geometry.x = surface->outputs[0]->x;
> + surface->geometry.y = surface->outputs[0]->y +
> + get_output_panel_height(shell,surface->outputs[0]);
> break;
> case SHELL_SURFACE_TOPLEVEL:
> break;
> @@ -1799,13 +1804,14 @@ configure(struct desktop_shell *shell, struct weston_surface *surface,
> }
>
> /* XXX: would a fullscreen surface need the same handling? */
> - if (surface->output) {
> + if (surface->output_count) {
> weston_surface_assign_output(surface);
>
> - if (surface_type == SHELL_SURFACE_SCREENSAVER)
> - surface->output = shsurf->output;
> - else if (surface_type == SHELL_SURFACE_MAXIMIZED)
> - surface->output = shsurf->output;
> + if (surface_type == SHELL_SURFACE_SCREENSAVER ||
> + surface_type == SHELL_SURFACE_MAXIMIZED) {
> + surface->outputs[0] = shsurf->output;
> + surface->output_count = 1;
> + }
> }
> }
>
> --
> 1.7.7.6
>
More information about the wayland-devel
mailing list