[PATCH] Add support for surface enter/leave events
cdahlin at redhat.com
cdahlin at redhat.com
Tue Apr 17 14:23:02 PDT 2012
From: Casey Dahlin <cdahlin at redhat.com>
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