subsurface: add map/unmap events

Fixes https://github.com/swaywm/wlroots/issues/1414
This commit is contained in:
emersion 2019-02-16 17:32:01 +01:00
parent 3c9f791d0e
commit 943e918a96
No known key found for this signature in database
GPG key ID: 0FDE7BE0E88F5E48
4 changed files with 108 additions and 2 deletions

View file

@ -181,6 +181,8 @@ struct roots_subsurface {
struct roots_view_child view_child; struct roots_view_child view_child;
struct wlr_subsurface *wlr_subsurface; struct wlr_subsurface *wlr_subsurface;
struct wl_listener destroy; struct wl_listener destroy;
struct wl_listener map;
struct wl_listener unmap;
}; };
struct roots_wl_shell_popup { struct roots_wl_shell_popup {

View file

@ -130,6 +130,7 @@ struct wlr_subsurface {
bool synchronized; bool synchronized;
bool reordered; bool reordered;
bool mapped;
struct wl_list parent_link; struct wl_list parent_link;
struct wl_list parent_pending_link; struct wl_list parent_pending_link;
@ -139,6 +140,8 @@ struct wlr_subsurface {
struct { struct {
struct wl_signal destroy; struct wl_signal destroy;
struct wl_signal map;
struct wl_signal unmap;
} events; } events;
void *data; void *data;

View file

@ -420,6 +420,8 @@ static void subsurface_destroy(struct roots_view_child *child) {
return; return;
} }
wl_list_remove(&subsurface->destroy.link); wl_list_remove(&subsurface->destroy.link);
wl_list_remove(&subsurface->map.link);
wl_list_remove(&subsurface->unmap.link);
view_child_finish(&subsurface->view_child); view_child_finish(&subsurface->view_child);
free(subsurface); free(subsurface);
} }
@ -428,7 +430,25 @@ static void subsurface_handle_destroy(struct wl_listener *listener,
void *data) { void *data) {
struct roots_subsurface *subsurface = struct roots_subsurface *subsurface =
wl_container_of(listener, subsurface, destroy); 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, 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); view_child_init(&subsurface->view_child, view, wlr_subsurface->surface);
subsurface->destroy.notify = subsurface_handle_destroy; subsurface->destroy.notify = subsurface_handle_destroy;
wl_signal_add(&wlr_subsurface->events.destroy, &subsurface->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; return subsurface;
} }

View file

@ -534,11 +534,15 @@ static void surface_state_finish(struct wlr_surface_state *state) {
pixman_region32_fini(&state->input); pixman_region32_fini(&state->input);
} }
static void subsurface_unmap(struct wlr_subsurface *subsurface);
static void subsurface_destroy(struct wlr_subsurface *subsurface) { static void subsurface_destroy(struct wlr_subsurface *subsurface) {
if (subsurface == NULL) { if (subsurface == NULL) {
return; return;
} }
subsurface_unmap(subsurface);
wlr_signal_emit_safe(&subsurface->events.destroy, subsurface); wlr_signal_emit_safe(&subsurface->events.destroy, subsurface);
wl_list_remove(&subsurface->surface_destroy.link); 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, .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) { static void subsurface_role_commit(struct wlr_surface *surface) {
struct wlr_subsurface *subsurface = struct wlr_subsurface *subsurface =
wlr_subsurface_from_wlr_surface(surface); 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->buffer_damage, 0, 0,
surface->current.buffer_width, surface->current.buffer_height); 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 = { const struct wlr_surface_role subsurface_role = {
.name = "wl_subsurface", .name = "wl_subsurface",
.commit = subsurface_role_commit, .commit = subsurface_role_commit,
.precommit = subsurface_role_precommit,
}; };
static void subsurface_handle_parent_destroy(struct wl_listener *listener, static void subsurface_handle_parent_destroy(struct wl_listener *listener,
void *data) { void *data) {
struct wlr_subsurface *subsurface = struct wlr_subsurface *subsurface =
wl_container_of(listener, subsurface, parent_destroy); wl_container_of(listener, subsurface, parent_destroy);
subsurface_unmap(subsurface);
wl_list_remove(&subsurface->parent_link); wl_list_remove(&subsurface->parent_link);
wl_list_remove(&subsurface->parent_pending_link); wl_list_remove(&subsurface->parent_pending_link);
wl_list_remove(&subsurface->parent_destroy.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); subsurface_resource_destroy);
wl_signal_init(&subsurface->events.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); wl_signal_add(&surface->events.destroy, &subsurface->surface_destroy);
subsurface->surface_destroy.notify = subsurface_handle_surface_destroy; subsurface->surface_destroy.notify = subsurface_handle_surface_destroy;