aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/wlr/types/wlr_surface.h4
-rw-r--r--types/wlr_surface.c96
2 files changed, 96 insertions, 4 deletions
diff --git a/include/wlr/types/wlr_surface.h b/include/wlr/types/wlr_surface.h
index c9abf042..b6d5f79f 100644
--- a/include/wlr/types/wlr_surface.h
+++ b/include/wlr/types/wlr_surface.h
@@ -48,8 +48,10 @@ struct wlr_subsurface {
bool has_cache;
bool synchronized;
+ bool reordered;
struct wl_list parent_link;
+ struct wl_list parent_pending_link;
};
struct wlr_surface {
@@ -76,6 +78,8 @@ struct wlr_surface {
struct wlr_subsurface *subsurface;
struct wl_list subsurface_list; // wlr_subsurface::parent_link
+ // wlr_subsurface::parent_pending_link
+ struct wl_list subsurface_pending_list;
void *data;
};
diff --git a/types/wlr_surface.c b/types/wlr_surface.c
index fa4b4d5a..6f6df226 100644
--- a/types/wlr_surface.c
+++ b/types/wlr_surface.c
@@ -290,12 +290,44 @@ static void wlr_surface_move_state(struct wlr_surface *surface, struct wlr_surfa
next->invalid = 0;
}
+static void wlr_surface_damage_subsurfaces(struct wlr_subsurface *subsurface) {
+ // XXX: This is probably the wrong way to do it, because this damage should
+ // come from the client, but weston doesn't do it correctly either and it
+ // seems to work ok. See the comment on weston_surface_damage for more info
+ // about a better approach.
+ struct wlr_surface *surface = subsurface->surface;
+ pixman_region32_union_rect(&surface->current->surface_damage,
+ &surface->current->surface_damage,
+ 0, 0, surface->current->width,
+ surface->current->height);
+
+ subsurface->reordered = false;
+
+ struct wlr_subsurface *child;
+ wl_list_for_each(child, &subsurface->surface->subsurface_list, parent_link) {
+ wlr_surface_damage_subsurfaces(child);
+ }
+}
+
static void wlr_surface_commit_pending(struct wlr_surface *surface) {
int32_t oldw = surface->current->buffer_width;
int32_t oldh = surface->current->buffer_height;
wlr_surface_move_state(surface, surface->pending, surface->current);
+ // commit subsurface order
+ struct wlr_subsurface *subsurface;
+ wl_list_for_each_reverse(subsurface, &surface->subsurface_pending_list,
+ parent_pending_link) {
+ wl_list_remove(&subsurface->parent_link);
+ wl_list_insert(&surface->subsurface_list, &subsurface->parent_link);
+
+ if (subsurface->reordered) {
+ // TODO: damage all the subsurfaces
+ wlr_surface_damage_subsurfaces(subsurface);
+ }
+ }
+
surface->reupload_buffer = oldw != surface->current->buffer_width ||
oldh != surface->current->buffer_height;
@@ -546,6 +578,7 @@ struct wlr_surface *wlr_surface_create(struct wl_resource *res,
wl_signal_init(&surface->signals.commit);
wl_signal_init(&surface->signals.destroy);
wl_list_init(&surface->subsurface_list);
+ wl_list_init(&surface->subsurface_pending_list);
wl_resource_set_implementation(res, &surface_interface,
surface, destroy_surface);
return surface;
@@ -612,14 +645,69 @@ static void subsurface_set_position(struct wl_client *client,
surface->pending->subsurface_position.y = y;
}
+static struct wlr_subsurface *subsurface_find_sibling(
+ struct wlr_subsurface *subsurface, struct wlr_surface *surface) {
+ struct wlr_surface *parent = subsurface->parent;
+
+ struct wlr_subsurface *sibling;
+ wl_list_for_each(sibling, &parent->subsurface_list, parent_link) {
+ if (sibling->surface == surface && sibling != subsurface)
+ return sibling;
+ }
+
+ return NULL;
+}
+
static void subsurface_place_above(struct wl_client *client,
- struct wl_resource *resource, struct wl_resource *sibling) {
- wlr_log(L_DEBUG, "TODO: subsurface place above");
+ struct wl_resource *resource, struct wl_resource *sibling_resource) {
+ struct wlr_subsurface *subsurface = wl_resource_get_user_data(resource);
+
+ if (!subsurface) {
+ return;
+ }
+
+ struct wlr_surface *sibling_surface =
+ wl_resource_get_user_data(sibling_resource);
+ struct wlr_subsurface *sibling =
+ subsurface_find_sibling(subsurface, sibling_surface);
+
+ if (!sibling) {
+ wl_resource_post_error(subsurface->resource,
+ WL_SUBSURFACE_ERROR_BAD_SURFACE,
+ "%s: wl_surface@%d is not a parent or sibling",
+ "place_above", wl_resource_get_id(sibling_surface->resource));
+ return;
+ }
+
+ wl_list_remove(&subsurface->parent_pending_link);
+ wl_list_insert(sibling->parent_pending_link.prev,
+ &subsurface->parent_pending_link);
+
+ subsurface->reordered = true;
}
static void subsurface_place_below(struct wl_client *client,
- struct wl_resource *resource, struct wl_resource *sibling) {
- wlr_log(L_DEBUG, "TODO: subsurface place below");
+ struct wl_resource *resource, struct wl_resource *sibling_resource) {
+ struct wlr_subsurface *subsurface = wl_resource_get_user_data(resource);
+
+ struct wlr_surface *sibling_surface =
+ wl_resource_get_user_data(sibling_resource);
+ struct wlr_subsurface *sibling =
+ subsurface_find_sibling(subsurface, sibling_surface);
+
+ if (!sibling) {
+ wl_resource_post_error(subsurface->resource,
+ WL_SUBSURFACE_ERROR_BAD_SURFACE,
+ "%s: wl_surface@%d is not a parent or sibling",
+ "place_below", wl_resource_get_id(sibling_surface->resource));
+ return;
+ }
+
+ wl_list_remove(&subsurface->parent_pending_link);
+ wl_list_insert(&sibling->parent_pending_link,
+ &subsurface->parent_pending_link);
+
+ subsurface->reordered = true;
}
static void subsurface_set_sync(struct wl_client *client,