mirror of
https://github.com/brl/mutter.git
synced 2024-11-22 08:00:42 -05:00
wayland: implement stacked popups
Allow multiple popups from the same clients to be stacked under the same pointer grab. This is necessary to implement submenus. https://bugzilla.gnome.org/show_bug.cgi?id=707863
This commit is contained in:
parent
776a86a65f
commit
9a13b857f4
@ -488,10 +488,18 @@ meta_wayland_pointer_destroy_focus (MetaWaylandPointer *pointer)
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
MetaWaylandPointerGrab generic;
|
MetaWaylandPointerGrab generic;
|
||||||
|
|
||||||
MetaWaylandSurface *popup;
|
struct wl_client *grab_client;
|
||||||
struct wl_listener popup_destroy_listener;
|
struct wl_list all_popups;
|
||||||
} MetaWaylandPopupGrab;
|
} MetaWaylandPopupGrab;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
MetaWaylandPopupGrab *grab;
|
||||||
|
MetaWaylandSurface *surface;
|
||||||
|
struct wl_listener surface_destroy_listener;
|
||||||
|
|
||||||
|
struct wl_list link;
|
||||||
|
} MetaWaylandPopup;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
popup_grab_focus (MetaWaylandPointerGrab *grab,
|
popup_grab_focus (MetaWaylandPointerGrab *grab,
|
||||||
MetaWaylandSurface *surface,
|
MetaWaylandSurface *surface,
|
||||||
@ -501,8 +509,7 @@ popup_grab_focus (MetaWaylandPointerGrab *grab,
|
|||||||
|
|
||||||
/* Popup grabs are in owner-events mode (ie, events for the same client
|
/* Popup grabs are in owner-events mode (ie, events for the same client
|
||||||
are reported as normal) */
|
are reported as normal) */
|
||||||
if (wl_resource_get_client (surface->resource) ==
|
if (wl_resource_get_client (surface->resource) == popup_grab->grab_client)
|
||||||
wl_resource_get_client (popup_grab->popup->resource))
|
|
||||||
default_grab_focus (grab, surface, event);
|
default_grab_focus (grab, surface, event);
|
||||||
else
|
else
|
||||||
meta_wayland_pointer_set_focus (grab->pointer, NULL);
|
meta_wayland_pointer_set_focus (grab->pointer, NULL);
|
||||||
@ -525,8 +532,7 @@ popup_grab_button (MetaWaylandPointerGrab *grab,
|
|||||||
if (pointer->focus_resource)
|
if (pointer->focus_resource)
|
||||||
{
|
{
|
||||||
/* This is ensured by popup_grab_focus */
|
/* This is ensured by popup_grab_focus */
|
||||||
g_assert (wl_resource_get_client (pointer->focus_resource) ==
|
g_assert (wl_resource_get_client (pointer->focus_resource) == popup_grab->grab_client);
|
||||||
wl_resource_get_client (popup_grab->popup->resource));
|
|
||||||
|
|
||||||
default_grab_button (grab, event);
|
default_grab_button (grab, event);
|
||||||
}
|
}
|
||||||
@ -545,15 +551,20 @@ static void
|
|||||||
meta_wayland_pointer_end_popup_grab (MetaWaylandPointer *pointer)
|
meta_wayland_pointer_end_popup_grab (MetaWaylandPointer *pointer)
|
||||||
{
|
{
|
||||||
MetaWaylandPopupGrab *popup_grab;
|
MetaWaylandPopupGrab *popup_grab;
|
||||||
|
MetaWaylandPopup *popup, *tmp;
|
||||||
|
|
||||||
popup_grab = (MetaWaylandPopupGrab*)pointer->grab;
|
popup_grab = (MetaWaylandPopupGrab*)pointer->grab;
|
||||||
|
|
||||||
g_assert (popup_grab->generic.interface == &popup_grab_interface);
|
g_assert (popup_grab->generic.interface == &popup_grab_interface);
|
||||||
|
|
||||||
if (popup_grab->popup)
|
wl_list_for_each_safe (popup, tmp, &popup_grab->all_popups, link)
|
||||||
{
|
{
|
||||||
wl_shell_surface_send_popup_done (popup_grab->popup->shell_surface->resource);
|
MetaWaylandSurfaceExtension *shell_surface = popup->surface->shell_surface;
|
||||||
wl_list_remove (&popup_grab->popup_destroy_listener.link);
|
|
||||||
|
wl_shell_surface_send_popup_done (shell_surface->resource);
|
||||||
|
wl_list_remove (&popup->surface_destroy_listener.link);
|
||||||
|
wl_list_remove (&popup->link);
|
||||||
|
g_slice_free (MetaWaylandPopup, popup);
|
||||||
}
|
}
|
||||||
|
|
||||||
meta_wayland_pointer_end_grab (pointer);
|
meta_wayland_pointer_end_grab (pointer);
|
||||||
@ -564,11 +575,15 @@ static void
|
|||||||
on_popup_surface_destroy (struct wl_listener *listener,
|
on_popup_surface_destroy (struct wl_listener *listener,
|
||||||
void *data)
|
void *data)
|
||||||
{
|
{
|
||||||
MetaWaylandPopupGrab *grab =
|
MetaWaylandPopup *popup =
|
||||||
wl_container_of (listener, grab, popup_destroy_listener);
|
wl_container_of (listener, popup, surface_destroy_listener);
|
||||||
|
MetaWaylandPopupGrab *popup_grab = popup->grab;
|
||||||
|
|
||||||
grab->popup = NULL;
|
wl_list_remove (&popup->link);
|
||||||
meta_wayland_pointer_end_popup_grab (grab->generic.pointer);
|
g_slice_free (MetaWaylandPopup, popup);
|
||||||
|
|
||||||
|
if (wl_list_empty (&popup_grab->all_popups))
|
||||||
|
meta_wayland_pointer_end_popup_grab (popup_grab->generic.pointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
@ -576,20 +591,42 @@ meta_wayland_pointer_start_popup_grab (MetaWaylandPointer *pointer,
|
|||||||
MetaWaylandSurface *surface)
|
MetaWaylandSurface *surface)
|
||||||
{
|
{
|
||||||
MetaWaylandPopupGrab *grab;
|
MetaWaylandPopupGrab *grab;
|
||||||
|
MetaWaylandPopup *popup;
|
||||||
|
|
||||||
if (pointer->grab != &pointer->default_grab &&
|
if (pointer->grab != &pointer->default_grab)
|
||||||
pointer->grab->interface != &popup_grab_interface)
|
{
|
||||||
|
if (pointer->grab->interface == &popup_grab_interface)
|
||||||
|
{
|
||||||
|
grab = (MetaWaylandPopupGrab*)pointer->grab;
|
||||||
|
|
||||||
|
if (wl_resource_get_client (surface->resource) != grab->grab_client)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pointer->grab == &pointer->default_grab)
|
||||||
|
{
|
||||||
grab = g_slice_new0 (MetaWaylandPopupGrab);
|
grab = g_slice_new0 (MetaWaylandPopupGrab);
|
||||||
grab->generic.interface = &popup_grab_interface;
|
grab->generic.interface = &popup_grab_interface;
|
||||||
grab->generic.pointer = pointer;
|
grab->generic.pointer = pointer;
|
||||||
grab->popup = surface;
|
grab->grab_client = wl_resource_get_client (surface->resource);
|
||||||
|
wl_list_init (&grab->all_popups);
|
||||||
grab->popup_destroy_listener.notify = on_popup_surface_destroy;
|
|
||||||
wl_resource_add_destroy_listener (surface->resource, &grab->popup_destroy_listener);
|
|
||||||
|
|
||||||
meta_wayland_pointer_start_grab (pointer, (MetaWaylandPointerGrab*)grab);
|
meta_wayland_pointer_start_grab (pointer, (MetaWaylandPointerGrab*)grab);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
grab = (MetaWaylandPopupGrab*)pointer->grab;
|
||||||
|
|
||||||
|
popup = g_slice_new0 (MetaWaylandPopup);
|
||||||
|
popup->grab = grab;
|
||||||
|
popup->surface = surface;
|
||||||
|
popup->surface_destroy_listener.notify = on_popup_surface_destroy;
|
||||||
|
wl_resource_add_destroy_listener (surface->resource, &popup->surface_destroy_listener);
|
||||||
|
|
||||||
|
wl_list_insert (&grab->all_popups, &popup->link);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user