[PATCH v2] shell: grab the parent popup when a sub popup window is deleted or hidden
Giulio Camuffo
giuliocamuffo at gmail.com
Tue Feb 19 13:03:36 PST 2013
If the client opens a popup menu and submenu, when it closes or hides the
submenu the pointer grab should return to the parent menu.
Furthermore, when clicking outside the client area the popup_done event
is sent to the active popup surface and recursively to its parent.
---
src/shell.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 50 insertions(+), 5 deletions(-)
diff --git a/src/shell.c b/src/shell.c
index 345ca8e..099ff1e 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -182,6 +182,7 @@ struct shell_surface {
int32_t initial_up;
struct wl_seat *seat;
uint32_t serial;
+ struct shell_surface *prev;
} popup;
struct {
@@ -1885,11 +1886,20 @@ popup_grab_end(struct wl_pointer *pointer)
struct wl_pointer_grab *grab = pointer->grab;
struct shell_surface *shsurf =
container_of(grab, struct shell_surface, popup.grab);
+ struct shell_surface *tmp;
if (pointer->grab->interface == &popup_grab_interface) {
- wl_shell_surface_send_popup_done(&shsurf->resource);
wl_pointer_end_grab(grab->pointer);
- shsurf->popup.grab.pointer = NULL;
+ /* Send the popup_done event to all the popups open, and not just
+ * the one that currently has the grab. */
+ while (shsurf && shsurf->popup.grab.pointer) {
+ wl_shell_surface_send_popup_done(&shsurf->resource);
+ shsurf->popup.grab.pointer = NULL;
+
+ tmp = shsurf;
+ shsurf = shsurf->popup.prev;
+ tmp->popup.prev = NULL;
+ }
}
}
@@ -1899,6 +1909,7 @@ shell_map_popup(struct shell_surface *shsurf)
struct wl_seat *seat = shsurf->popup.seat;
struct weston_surface *es = shsurf->surface;
struct weston_surface *parent = shsurf->parent;
+ struct shell_surface *popup_parent;
/* Remove the old transform. We don't want to add it twice
* otherwise Weston will go into an infinite loop when going
@@ -1932,9 +1943,25 @@ shell_map_popup(struct shell_surface *shsurf)
weston_surface_set_position(es, shsurf->popup.x, shsurf->popup.y);
weston_surface_update_transform(es);
+ if (seat->pointer->grab->interface == &popup_grab_interface)
+ popup_parent = container_of(seat->pointer->grab,
+ struct shell_surface, popup.grab);
+ else
+ popup_parent = NULL;
+
/* We don't require the grab to still be active, but if another
* grab has started in the meantime, we end the popup now. */
- if (seat->pointer->grab_serial == shsurf->popup.serial) {
+
+ /* Need to make sure here that a sub-popup doesn't trigger the
+ * send_popup_done case. And we need to set the popup.prev
+ * pointer. We can look at seat->pointer->grab.interface to
+ * see if it's &popup_grab_interface and if it is use
+ * container_of on seat->pointer->grab to get back to the
+ * shsurf. */
+
+ if (seat->pointer->grab_serial == shsurf->popup.serial ||
+ (popup_parent && popup_parent->resource.client == shsurf->resource.client)) {
+ shsurf->popup.prev = popup_parent;
wl_pointer_start_grab(seat->pointer, &shsurf->popup.grab);
} else {
wl_shell_surface_send_popup_done(&shsurf->resource);
@@ -1973,10 +2000,22 @@ static const struct wl_shell_surface_interface shell_surface_implementation = {
};
static void
+grab_parent_popup(struct shell_surface *shsurf)
+{
+ wl_pointer_end_grab(shsurf->popup.grab.pointer);
+ struct shell_surface *parent = shsurf->popup.prev;
+ if (shsurf->popup.prev != NULL) {
+ wl_pointer_start_grab(parent->popup.seat->pointer, &parent->popup.grab);
+ }
+}
+
+static void
destroy_shell_surface(struct shell_surface *shsurf)
{
- if (shsurf->popup.grab.pointer)
- wl_pointer_end_grab(shsurf->popup.grab.pointer);
+ /* If this surface has a parent popup, grab it. */
+ if (shsurf->popup.grab.pointer) {
+ grab_parent_popup(shsurf);
+ }
if (shsurf->fullscreen.type == WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER &&
shell_surface_is_top_fullscreen(shsurf)) {
@@ -3098,6 +3137,12 @@ shell_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
struct shell_surface *shsurf = get_shell_surface(es);
struct desktop_shell *shell = shsurf->shell;
+ /* If this surface has just been unmapped and we have a parent popup,
+ * grab it. */
+ if (es->pending.remove_contents && shsurf->popup.grab.pointer) {
+ grab_parent_popup(shsurf);
+ }
+
if (!es->buffer_ref.buffer)
return;
--
1.8.1.3
More information about the wayland-devel
mailing list