subsurface: add map/unmap events
Fixes https://github.com/swaywm/wlroots/issues/1414
This commit is contained in:
parent
3c9f791d0e
commit
943e918a96
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue