diff --git a/src/wayland/meta-wayland-pointer.c b/src/wayland/meta-wayland-pointer.c index 5905cb95c..1531a4a00 100644 --- a/src/wayland/meta-wayland-pointer.c +++ b/src/wayland/meta-wayland-pointer.c @@ -741,3 +741,15 @@ meta_wayland_pointer_can_popup (MetaWaylandPointer *pointer, uint32_t serial) { return pointer->grab_serial == serial; } + +MetaWaylandSurface * +meta_wayland_pointer_get_top_popup (MetaWaylandPointer *pointer) +{ + MetaWaylandPopupGrab *grab; + + if (!meta_wayland_pointer_grab_is_popup_grab (pointer->grab)) + return NULL; + + grab = (MetaWaylandPopupGrab*)pointer->grab; + return meta_wayland_popup_grab_get_top_popup(grab); +} diff --git a/src/wayland/meta-wayland-pointer.h b/src/wayland/meta-wayland-pointer.h index 60125ace7..70b7b427a 100644 --- a/src/wayland/meta-wayland-pointer.h +++ b/src/wayland/meta-wayland-pointer.h @@ -125,4 +125,6 @@ gboolean meta_wayland_pointer_can_grab_surface (MetaWaylandPointer *pointer, gboolean meta_wayland_pointer_can_popup (MetaWaylandPointer *pointer, uint32_t serial); +MetaWaylandSurface *meta_wayland_pointer_get_top_popup (MetaWaylandPointer *pointer); + #endif /* META_WAYLAND_POINTER_H */ diff --git a/src/wayland/meta-wayland-popup.c b/src/wayland/meta-wayland-popup.c index cc8b4bd8d..f3d47aef7 100644 --- a/src/wayland/meta-wayland-popup.c +++ b/src/wayland/meta-wayland-popup.c @@ -172,6 +172,17 @@ meta_wayland_popup_grab_end (MetaWaylandPopupGrab *grab) meta_wayland_pointer_end_grab (grab->generic.pointer); } +MetaWaylandSurface * +meta_wayland_popup_grab_get_top_popup (MetaWaylandPopupGrab *grab) +{ + MetaWaylandPopup *popup; + + g_assert (!wl_list_empty (&grab->all_popups)); + popup = wl_container_of (grab->all_popups.next, popup, link); + + return popup->surface; +} + gboolean meta_wayland_pointer_grab_is_popup_grab (MetaWaylandPointerGrab *grab) { @@ -199,6 +210,12 @@ meta_wayland_popup_dismiss (MetaWaylandPopup *popup) meta_wayland_pointer_end_popup_grab (popup_grab->generic.pointer); } +MetaWaylandSurface * +meta_wayland_popup_get_top_popup (MetaWaylandPopup *popup) +{ + return meta_wayland_popup_grab_get_top_popup (popup->grab); +} + struct wl_signal * meta_wayland_popup_get_destroy_signal (MetaWaylandPopup *popup) { diff --git a/src/wayland/meta-wayland-popup.h b/src/wayland/meta-wayland-popup.h index 70822250d..0bee220d4 100644 --- a/src/wayland/meta-wayland-popup.h +++ b/src/wayland/meta-wayland-popup.h @@ -37,6 +37,8 @@ void meta_wayland_popup_grab_begin (MetaWaylandPopupGrab *grab, void meta_wayland_popup_grab_end (MetaWaylandPopupGrab *grab); +MetaWaylandSurface *meta_wayland_popup_grab_get_top_popup (MetaWaylandPopupGrab *grab); + gboolean meta_wayland_pointer_grab_is_popup_grab (MetaWaylandPointerGrab *grab); MetaWaylandPopup *meta_wayland_popup_create (MetaWaylandSurface *surface, @@ -46,6 +48,8 @@ void meta_wayland_popup_destroy (MetaWaylandPopup *popup); void meta_wayland_popup_dismiss (MetaWaylandPopup *popup); +MetaWaylandSurface *meta_wayland_popup_get_top_popup (MetaWaylandPopup *popup); + struct wl_signal *meta_wayland_popup_get_destroy_signal (MetaWaylandPopup *popup); #endif /* META_WAYLAND_POPUP_H */ diff --git a/src/wayland/meta-wayland-surface.c b/src/wayland/meta-wayland-surface.c index 67513014e..b1364e8c6 100644 --- a/src/wayland/meta-wayland-surface.c +++ b/src/wayland/meta-wayland-surface.c @@ -1041,9 +1041,19 @@ static const struct xdg_popup_interface meta_wayland_xdg_popup_interface = { static void handle_popup_destroyed (struct wl_listener *listener, void *data) { + MetaWaylandPopup *popup = data; + MetaWaylandSurface *top_popup; MetaWaylandSurface *surface = wl_container_of (listener, surface, popup.destroy_listener); + top_popup = meta_wayland_popup_get_top_popup (popup); + if (surface != top_popup) + { + wl_resource_post_error (surface->xdg_popup, + XDG_POPUP_ERROR_NOT_THE_TOPMOST_POPUP, + "destroyed popup not top most popup"); + } + surface->popup.popup = NULL; destroy_window (surface); @@ -1063,6 +1073,7 @@ xdg_shell_get_xdg_popup (struct wl_client *client, struct wl_resource *popup_resource; MetaWaylandSurface *surface = wl_resource_get_user_data (surface_resource); MetaWaylandSurface *parent_surf = wl_resource_get_user_data (parent_resource); + MetaWaylandSurface *top_popup; MetaWaylandSeat *seat = wl_resource_get_user_data (seat_resource); MetaWindow *window; MetaDisplay *display = meta_get_display (); @@ -1093,6 +1104,16 @@ xdg_shell_get_xdg_popup (struct wl_client *client, return; } + top_popup = meta_wayland_pointer_get_top_popup (&seat->pointer); + if ((top_popup == NULL && parent_surf->xdg_surface == NULL) || + (top_popup != NULL && parent_surf != top_popup)) + { + wl_resource_post_error (resource, + XDG_POPUP_ERROR_NOT_THE_TOPMOST_POPUP, + "parent not top most surface"); + return; + } + popup_resource = wl_resource_create (client, &xdg_popup_interface, wl_resource_get_version (resource), id); wl_resource_set_implementation (popup_resource,