aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/rootston/view.h2
-rw-r--r--include/wlr/types/wlr_surface.h3
-rw-r--r--rootston/desktop.c27
-rw-r--r--types/wlr_surface.c78
4 files changed, 108 insertions, 2 deletions
diff --git a/include/rootston/view.h b/include/rootston/view.h
index b1feb5ce..0174e4f3 100644
--- a/include/rootston/view.h
+++ b/include/rootston/view.h
@@ -181,6 +181,8 @@ struct roots_subsurface {
struct roots_view_child view_child;
struct wlr_subsurface *wlr_subsurface;
struct wl_listener destroy;
+ struct wl_listener map;
+ struct wl_listener unmap;
};
struct roots_wl_shell_popup {
diff --git a/include/wlr/types/wlr_surface.h b/include/wlr/types/wlr_surface.h
index b8f8c02a..0c389987 100644
--- a/include/wlr/types/wlr_surface.h
+++ b/include/wlr/types/wlr_surface.h
@@ -130,6 +130,7 @@ struct wlr_subsurface {
bool synchronized;
bool reordered;
+ bool mapped;
struct wl_list parent_link;
struct wl_list parent_pending_link;
@@ -139,6 +140,8 @@ struct wlr_subsurface {
struct {
struct wl_signal destroy;
+ struct wl_signal map;
+ struct wl_signal unmap;
} events;
void *data;
diff --git a/rootston/desktop.c b/rootston/desktop.c
index fcb530cf..a38f4045 100644
--- a/rootston/desktop.c
+++ b/rootston/desktop.c
@@ -420,6 +420,8 @@ static void subsurface_destroy(struct roots_view_child *child) {
return;
}
wl_list_remove(&subsurface->destroy.link);
+ wl_list_remove(&subsurface->map.link);
+ wl_list_remove(&subsurface->unmap.link);
view_child_finish(&subsurface->view_child);
free(subsurface);
}
@@ -428,7 +430,25 @@ static void subsurface_handle_destroy(struct wl_listener *listener,
void *data) {
struct roots_subsurface *subsurface =
wl_container_of(listener, subsurface, destroy);
- subsurface_destroy((struct roots_view_child *)subsurface);
+ subsurface_destroy(&subsurface->view_child);
+}
+
+static void subsurface_handle_map(struct wl_listener *listener,
+ void *data) {
+ struct roots_subsurface *subsurface =
+ wl_container_of(listener, subsurface, map);
+ struct roots_view *view = subsurface->view_child.view;
+ view_damage_whole(view);
+ input_update_cursor_focus(view->desktop->server->input);
+}
+
+static void subsurface_handle_unmap(struct wl_listener *listener,
+ void *data) {
+ struct roots_subsurface *subsurface =
+ wl_container_of(listener, subsurface, unmap);
+ struct roots_view *view = subsurface->view_child.view;
+ view_damage_whole(view);
+ input_update_cursor_focus(view->desktop->server->input);
}
struct roots_subsurface *subsurface_create(struct roots_view *view,
@@ -443,7 +463,10 @@ struct roots_subsurface *subsurface_create(struct roots_view *view,
view_child_init(&subsurface->view_child, view, wlr_subsurface->surface);
subsurface->destroy.notify = subsurface_handle_destroy;
wl_signal_add(&wlr_subsurface->events.destroy, &subsurface->destroy);
- input_update_cursor_focus(view->desktop->server->input);
+ subsurface->map.notify = subsurface_handle_map;
+ wl_signal_add(&wlr_subsurface->events.map, &subsurface->map);
+ subsurface->unmap.notify = subsurface_handle_unmap;
+ wl_signal_add(&wlr_subsurface->events.unmap, &subsurface->unmap);
return subsurface;
}
diff --git a/types/wlr_surface.c b/types/wlr_surface.c
index de63bdae..febfcd43 100644
--- a/types/wlr_surface.c
+++ b/types/wlr_surface.c
@@ -534,11 +534,15 @@ static void surface_state_finish(struct wlr_surface_state *state) {
pixman_region32_fini(&state->input);
}
+static void subsurface_unmap(struct wlr_subsurface *subsurface);
+
static void subsurface_destroy(struct wlr_subsurface *subsurface) {
if (subsurface == NULL) {
return;
}
+ subsurface_unmap(subsurface);
+
wlr_signal_emit_safe(&subsurface->events.destroy, subsurface);
wl_list_remove(&subsurface->surface_destroy.link);
@@ -799,6 +803,60 @@ static const struct wl_subsurface_interface subsurface_implementation = {
.set_desync = subsurface_handle_set_desync,
};
+/**
+ * Checks if this subsurface needs to be marked as mapped. This can happen if:
+ * - The subsurface has a buffer
+ * - Its parent is mapped
+ */
+static void subsurface_consider_map(struct wlr_subsurface *subsurface,
+ bool check_parent) {
+ if (subsurface->mapped || !wlr_surface_has_buffer(subsurface->surface)) {
+ return;
+ }
+
+ if (check_parent) {
+ if (subsurface->parent == NULL) {
+ return;
+ }
+ if (wlr_surface_is_subsurface(subsurface->parent)) {
+ struct wlr_subsurface *parent =
+ wlr_subsurface_from_wlr_surface(subsurface->parent);
+ if (parent == NULL || !parent->mapped) {
+ return;
+ }
+ }
+ }
+
+ // Now we can map the subsurface
+ if (subsurface->mapped) {
+ return;
+ }
+
+ wlr_signal_emit_safe(&subsurface->events.map, subsurface);
+ subsurface->mapped = true;
+
+ // Try mapping all children too
+ struct wlr_subsurface *child;
+ wl_list_for_each(child, &subsurface->surface->subsurfaces, parent_link) {
+ subsurface_consider_map(child, false);
+ }
+}
+
+static void subsurface_unmap(struct wlr_subsurface *subsurface) {
+ if (!subsurface->mapped) {
+ return;
+ }
+
+ wlr_signal_emit_safe(&subsurface->events.unmap, subsurface);
+ subsurface->mapped = false;
+
+ // Unmap all children
+ struct wlr_subsurface *child;
+ wl_list_for_each(child, &subsurface->surface->subsurfaces, parent_link) {
+ subsurface_unmap(child);
+ }
+}
+
static void subsurface_role_commit(struct wlr_surface *surface) {
struct wlr_subsurface *subsurface =
wlr_subsurface_from_wlr_surface(surface);
@@ -829,17 +887,35 @@ static void subsurface_role_commit(struct wlr_surface *surface) {
&surface->buffer_damage, 0, 0,
surface->current.buffer_width, surface->current.buffer_height);
}
+
+ subsurface_consider_map(subsurface, true);
+}
+
+static void subsurface_role_precommit(struct wlr_surface *surface) {
+ struct wlr_subsurface *subsurface =
+ wlr_subsurface_from_wlr_surface(surface);
+ if (subsurface == NULL) {
+ return;
+ }
+
+ if (surface->pending.committed & WLR_SURFACE_STATE_BUFFER &&
+ surface->pending.buffer_resource == NULL) {
+ // This is a NULL commit
+ subsurface_unmap(subsurface);
+ }
}
const struct wlr_surface_role subsurface_role = {
.name = "wl_subsurface",
.commit = subsurface_role_commit,
+ .precommit = subsurface_role_precommit,
};
static void subsurface_handle_parent_destroy(struct wl_listener *listener,
void *data) {
struct wlr_subsurface *subsurface =
wl_container_of(listener, subsurface, parent_destroy);
+ subsurface_unmap(subsurface);
wl_list_remove(&subsurface->parent_link);
wl_list_remove(&subsurface->parent_pending_link);
wl_list_remove(&subsurface->parent_destroy.link);
@@ -882,6 +958,8 @@ struct wlr_subsurface *wlr_subsurface_create(struct wlr_surface *surface,
subsurface_resource_destroy);
wl_signal_init(&subsurface->events.destroy);
+ wl_signal_init(&subsurface->events.map);
+ wl_signal_init(&subsurface->events.unmap);
wl_signal_add(&surface->events.destroy, &subsurface->surface_destroy);
subsurface->surface_destroy.notify = subsurface_handle_surface_destroy;