diff --git a/desktop-shell/shell.c b/desktop-shell/shell.c index 26f13cc7..bf52b93c 100644 --- a/desktop-shell/shell.c +++ b/desktop-shell/shell.c @@ -223,9 +223,11 @@ struct shell_seat { struct { struct weston_pointer_grab grab; + struct weston_touch_grab touch_grab; struct wl_list surfaces_list; struct wl_client *client; int32_t initial_up; + enum { POINTER, TOUCH } type; } popup_grab; }; @@ -322,6 +324,8 @@ get_default_view(struct weston_surface *surface) static void popup_grab_end(struct weston_pointer *pointer); +static void +touch_popup_grab_end(struct weston_touch *touch); static void shell_grab_start(struct shell_grab *grab, @@ -333,6 +337,8 @@ shell_grab_start(struct shell_grab *grab, struct desktop_shell *shell = shsurf->shell; popup_grab_end(pointer); + if (pointer->seat->touch) + touch_popup_grab_end(pointer->seat->touch); grab->grab.interface = interface; grab->shsurf = shsurf; @@ -497,6 +503,7 @@ shell_touch_grab_start(struct shell_touch_grab *grab, { struct desktop_shell *shell = shsurf->shell; + touch_popup_grab_end(touch); if (touch->seat->pointer) popup_grab_end(touch->seat->pointer); @@ -3116,6 +3123,81 @@ static const struct weston_pointer_grab_interface popup_grab_interface = { popup_grab_cancel, }; +static void +touch_popup_grab_down(struct weston_touch_grab *grab, uint32_t time, + int touch_id, wl_fixed_t sx, wl_fixed_t sy) +{ + struct wl_resource *resource; + struct shell_seat *shseat = + container_of(grab, struct shell_seat, popup_grab.touch_grab); + struct wl_display *display = shseat->seat->compositor->wl_display; + uint32_t serial; + struct wl_list *resource_list; + + resource_list = &grab->touch->focus_resource_list; + if (!wl_list_empty(resource_list)) { + serial = wl_display_get_serial(display); + wl_resource_for_each(resource, resource_list) { + wl_touch_send_down(resource, serial, time, + grab->touch->focus->surface->resource, + touch_id, sx, sy); + } + } +} + +static void +touch_popup_grab_up(struct weston_touch_grab *grab, uint32_t time, int touch_id) +{ + struct wl_resource *resource; + struct shell_seat *shseat = + container_of(grab, struct shell_seat, popup_grab.touch_grab); + struct wl_display *display = shseat->seat->compositor->wl_display; + uint32_t serial; + struct wl_list *resource_list; + + resource_list = &grab->touch->focus_resource_list; + if (!wl_list_empty(resource_list)) { + serial = wl_display_get_serial(display); + wl_resource_for_each(resource, resource_list) { + wl_touch_send_up(resource, serial, time, touch_id); + } + } +} + +static void +touch_popup_grab_motion(struct weston_touch_grab *grab, uint32_t time, + int touch_id, wl_fixed_t sx, wl_fixed_t sy) +{ + struct wl_resource *resource; + struct wl_list *resource_list; + + resource_list = &grab->touch->focus_resource_list; + if (!wl_list_empty(resource_list)) { + wl_resource_for_each(resource, resource_list) { + wl_touch_send_motion(resource, time, touch_id, sx, sy); + } + } +} + +static void +touch_popup_grab_frame(struct weston_touch_grab *grab) +{ +} + +static void +touch_popup_grab_cancel(struct weston_touch_grab *grab) +{ + touch_popup_grab_end(grab->touch); +} + +static const struct weston_touch_grab_interface touch_popup_grab_interface = { + touch_popup_grab_down, + touch_popup_grab_up, + touch_popup_grab_motion, + touch_popup_grab_frame, + touch_popup_grab_cancel, +}; + static void shell_surface_send_popup_done(struct shell_surface *shsurf) { @@ -3155,21 +3237,59 @@ popup_grab_end(struct weston_pointer *pointer) } static void -add_popup_grab(struct shell_surface *shsurf, struct shell_seat *shseat) +touch_popup_grab_end(struct weston_touch *touch) +{ + struct weston_touch_grab *grab = touch->grab; + struct shell_seat *shseat = + container_of(grab, struct shell_seat, popup_grab.touch_grab); + struct shell_surface *shsurf; + struct shell_surface *prev = NULL; + + if (touch->grab->interface == &touch_popup_grab_interface) { + weston_touch_end_grab(grab->touch); + shseat->popup_grab.client = NULL; + shseat->popup_grab.touch_grab.interface = NULL; + assert(!wl_list_empty(&shseat->popup_grab.surfaces_list)); + /* Send the popup_done event to all the popups open */ + wl_list_for_each(shsurf, &shseat->popup_grab.surfaces_list, popup.grab_link) { + shell_surface_send_popup_done(shsurf); + shsurf->popup.shseat = NULL; + if (prev) { + wl_list_init(&prev->popup.grab_link); + } + prev = shsurf; + } + wl_list_init(&prev->popup.grab_link); + wl_list_init(&shseat->popup_grab.surfaces_list); + } +} + +static void +add_popup_grab(struct shell_surface *shsurf, struct shell_seat *shseat, int32_t type) { struct weston_seat *seat = shseat->seat; if (wl_list_empty(&shseat->popup_grab.surfaces_list)) { + shseat->popup_grab.type = type; shseat->popup_grab.client = wl_resource_get_client(shsurf->resource); - shseat->popup_grab.grab.interface = &popup_grab_interface; - /* We must make sure here that this popup was opened after - * a mouse press, and not just by moving around with other - * popups already open. */ - if (shseat->seat->pointer->button_count > 0) - shseat->popup_grab.initial_up = 0; + + if (type == POINTER) { + shseat->popup_grab.grab.interface = &popup_grab_interface; + /* We must make sure here that this popup was opened after + * a mouse press, and not just by moving around with other + * popups already open. */ + if (shseat->seat->pointer->button_count > 0) + shseat->popup_grab.initial_up = 0; + } else if (type == TOUCH) { + shseat->popup_grab.touch_grab.interface = &touch_popup_grab_interface; + } wl_list_insert(&shseat->popup_grab.surfaces_list, &shsurf->popup.grab_link); - weston_pointer_start_grab(seat->pointer, &shseat->popup_grab.grab); + + if (type == POINTER) + weston_pointer_start_grab(seat->pointer, &shseat->popup_grab.grab); + else if (type == TOUCH) + weston_touch_start_grab(seat->touch, &shseat->popup_grab.touch_grab); } else { wl_list_insert(&shseat->popup_grab.surfaces_list, &shsurf->popup.grab_link); } @@ -3183,8 +3303,13 @@ remove_popup_grab(struct shell_surface *shsurf) wl_list_remove(&shsurf->popup.grab_link); wl_list_init(&shsurf->popup.grab_link); if (wl_list_empty(&shseat->popup_grab.surfaces_list)) { - weston_pointer_end_grab(shseat->popup_grab.grab.pointer); - shseat->popup_grab.grab.interface = NULL; + if (shseat->popup_grab.type == POINTER) { + weston_pointer_end_grab(shseat->popup_grab.grab.pointer); + shseat->popup_grab.grab.interface = NULL; + } else if (shseat->popup_grab.type == TOUCH) { + weston_touch_end_grab(shseat->popup_grab.touch_grab.touch); + shseat->popup_grab.touch_grab.interface = NULL; + } } } @@ -3203,7 +3328,10 @@ shell_map_popup(struct shell_surface *shsurf) if (shseat->seat->pointer && shseat->seat->pointer->grab_serial == shsurf->popup.serial) { - add_popup_grab(shsurf, shseat); + add_popup_grab(shsurf, shseat, POINTER); + } else if (shseat->seat->touch && + shseat->seat->touch->grab_serial == shsurf->popup.serial) { + add_popup_grab(shsurf, shseat, TOUCH); } else { shell_surface_send_popup_done(shsurf); shseat->popup_grab.client = NULL; @@ -5014,9 +5142,12 @@ idle_handler(struct wl_listener *listener, void *data) container_of(listener, struct desktop_shell, idle_listener); struct weston_seat *seat; - wl_list_for_each(seat, &shell->compositor->seat_list, link) + wl_list_for_each(seat, &shell->compositor->seat_list, link) { if (seat->pointer) popup_grab_end(seat->pointer); + if (seat->touch) + touch_popup_grab_end(seat->touch); + } shell_fade(shell, FADE_OUT); /* lock() is called from shell_fade_done() */