xdg-shell-v6: don't destroy role resources on unmap

The motivation for this is:
- `get_popup` and `get_toplevel` allocate role-specific resources.
- On the first non-null commit, the surface gets mapped.
- On a null commit, the surface gets unmapped. It can be mapped
  again with a non-null commit.
- When the role object (xdg-toplevel or xdg-popup) is
  destroyed, the surface is unmapped and role-specific resources
  are destroyed. The client can call `get_popup` or `get_toplevel`
  again on that surface.
- When the xdg-surface object is destroyed, the surface is
  unmapped, role-specific resources are destroyed and the surface
  itself is destroyed.
This commit is contained in:
emersion 2018-03-26 18:35:36 -04:00
parent 891610081f
commit 5233801530
No known key found for this signature in database
GPG key ID: 0FDE7BE0E88F5E48
3 changed files with 53 additions and 28 deletions

View file

@ -106,6 +106,7 @@ struct wlr_xdg_surface {
uint32_t configure_next_serial; uint32_t configure_next_serial;
struct wl_list configure_list; struct wl_list configure_list;
// Only for toplevel
char *title; char *title;
char *app_id; char *app_id;

View file

@ -106,6 +106,7 @@ struct wlr_xdg_surface_v6 {
uint32_t configure_next_serial; uint32_t configure_next_serial;
struct wl_list configure_list; struct wl_list configure_list;
// Only for toplevel
char *title; char *title;
char *app_id; char *app_id;

View file

@ -198,35 +198,24 @@ static void xdg_surface_unmap(struct wlr_xdg_surface_v6 *surface) {
wlr_signal_emit_safe(&surface->events.unmap, surface); wlr_signal_emit_safe(&surface->events.unmap, surface);
} }
if (surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL) { if (surface->role == WLR_XDG_SURFACE_V6_ROLE_POPUP &&
wl_resource_set_user_data(surface->toplevel->resource, NULL); surface->popup->seat != NULL) {
free(surface->toplevel); struct wlr_xdg_popup_grab_v6 *grab =
surface->toplevel = NULL; xdg_shell_popup_grab_from_seat(surface->client->shell,
} surface->popup->seat);
if (surface->role == WLR_XDG_SURFACE_V6_ROLE_POPUP) { wl_list_remove(&surface->popup->grab_link);
wl_resource_set_user_data(surface->popup->resource, NULL);
if (surface->popup->seat) { if (wl_list_empty(&grab->popups)) {
struct wlr_xdg_popup_grab_v6 *grab = if (grab->seat->pointer_state.grab == &grab->pointer_grab) {
xdg_shell_popup_grab_from_seat(surface->client->shell, wlr_seat_pointer_end_grab(grab->seat);
surface->popup->seat); }
if (grab->seat->keyboard_state.grab == &grab->keyboard_grab) {
wl_list_remove(&surface->popup->grab_link); wlr_seat_keyboard_end_grab(grab->seat);
if (wl_list_empty(&grab->popups)) {
if (grab->seat->pointer_state.grab == &grab->pointer_grab) {
wlr_seat_pointer_end_grab(grab->seat);
}
if (grab->seat->keyboard_state.grab == &grab->keyboard_grab) {
wlr_seat_keyboard_end_grab(grab->seat);
}
} }
} }
wl_list_remove(&surface->popup->link); surface->popup->seat = NULL;
free(surface->popup);
surface->popup = NULL;
} }
struct wlr_xdg_surface_v6_configure *configure, *tmp; struct wlr_xdg_surface_v6_configure *configure, *tmp;
@ -234,13 +223,12 @@ static void xdg_surface_unmap(struct wlr_xdg_surface_v6 *surface) {
xdg_surface_configure_destroy(configure); xdg_surface_configure_destroy(configure);
} }
surface->role = WLR_XDG_SURFACE_V6_ROLE_NONE;
free(surface->title); free(surface->title);
surface->title = NULL; surface->title = NULL;
free(surface->app_id); free(surface->app_id);
surface->app_id = NULL; surface->app_id = NULL;
surface->added = surface->configured = surface->mapped = false; surface->configured = surface->mapped = false;
surface->configure_serial = 0; surface->configure_serial = 0;
if (surface->configure_idle) { if (surface->configure_idle) {
wl_event_source_remove(surface->configure_idle); wl_event_source_remove(surface->configure_idle);
@ -253,6 +241,29 @@ static void xdg_surface_unmap(struct wlr_xdg_surface_v6 *surface) {
memset(&surface->next_geometry, 0, sizeof(struct wlr_box)); memset(&surface->next_geometry, 0, sizeof(struct wlr_box));
} }
static void xdg_toplevel_destroy(struct wlr_xdg_surface_v6 *surface) {
assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL);
xdg_surface_unmap(surface);
wl_resource_set_user_data(surface->toplevel->resource, NULL);
free(surface->toplevel);
surface->toplevel = NULL;
surface->role = WLR_XDG_SURFACE_V6_ROLE_NONE;
}
static void xdg_popup_destroy(struct wlr_xdg_surface_v6 *surface) {
assert(surface->role == WLR_XDG_SURFACE_V6_ROLE_POPUP);
xdg_surface_unmap(surface);
wl_resource_set_user_data(surface->popup->resource, NULL);
wl_list_remove(&surface->popup->link);
free(surface->popup);
surface->popup = NULL;
surface->role = WLR_XDG_SURFACE_V6_ROLE_NONE;
}
static void xdg_surface_destroy(struct wlr_xdg_surface_v6 *surface) { static void xdg_surface_destroy(struct wlr_xdg_surface_v6 *surface) {
if (surface->role != WLR_XDG_SURFACE_V6_ROLE_NONE) { if (surface->role != WLR_XDG_SURFACE_V6_ROLE_NONE) {
xdg_surface_unmap(surface); xdg_surface_unmap(surface);
@ -260,6 +271,18 @@ static void xdg_surface_destroy(struct wlr_xdg_surface_v6 *surface) {
wlr_signal_emit_safe(&surface->events.destroy, surface); wlr_signal_emit_safe(&surface->events.destroy, surface);
switch (surface->role) {
case WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL:
xdg_toplevel_destroy(surface);
break;
case WLR_XDG_SURFACE_V6_ROLE_POPUP:
xdg_popup_destroy(surface);
break;
case WLR_XDG_SURFACE_V6_ROLE_NONE:
// This space is intentionally left blank
break;
}
wl_resource_set_user_data(surface->resource, NULL); wl_resource_set_user_data(surface->resource, NULL);
wl_list_remove(&surface->link); wl_list_remove(&surface->link);
wl_list_remove(&surface->surface_destroy_listener.link); wl_list_remove(&surface->surface_destroy_listener.link);
@ -545,7 +568,7 @@ static void xdg_popup_resource_destroy(struct wl_resource *resource) {
struct wlr_xdg_surface_v6 *surface = struct wlr_xdg_surface_v6 *surface =
xdg_surface_from_xdg_popup_resource(resource); xdg_surface_from_xdg_popup_resource(resource);
if (surface != NULL) { if (surface != NULL) {
xdg_surface_unmap(surface); xdg_popup_destroy(surface);
} }
} }
@ -856,7 +879,7 @@ static void xdg_toplevel_resource_destroy(struct wl_resource *resource) {
struct wlr_xdg_surface_v6 *surface = struct wlr_xdg_surface_v6 *surface =
xdg_surface_from_xdg_toplevel_resource(resource); xdg_surface_from_xdg_toplevel_resource(resource);
if (surface != NULL) { if (surface != NULL) {
xdg_surface_unmap(surface); xdg_toplevel_destroy(surface);
} }
} }