From 97cdcccaf07b27a71bc8a06d4b2df32fc368b481 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sun, 1 Oct 2017 06:47:14 -0400 Subject: xdg-surface: get popup --- include/wlr/types/wlr_xdg_shell_v6.h | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'include/wlr') diff --git a/include/wlr/types/wlr_xdg_shell_v6.h b/include/wlr/types/wlr_xdg_shell_v6.h index cc52d9c7..2d38dba0 100644 --- a/include/wlr/types/wlr_xdg_shell_v6.h +++ b/include/wlr/types/wlr_xdg_shell_v6.h @@ -28,6 +28,15 @@ struct wlr_xdg_client_v6 { struct wl_event_source *ping_timer; }; +struct wlr_xdg_popup_v6 { + struct wlr_xdg_surface_v6 *base; + + struct wl_resource *resource; + bool committed; + struct wlr_xdg_surface_v6 *parent; + struct wlr_seat *seat; + struct wlr_box geometry; +}; enum wlr_xdg_surface_v6_role { WLR_XDG_SURFACE_V6_ROLE_NONE, @@ -74,7 +83,11 @@ struct wlr_xdg_surface_v6 { struct wlr_surface *surface; struct wl_list link; // wlr_xdg_client_v6::surfaces enum wlr_xdg_surface_v6_role role; - struct wlr_xdg_toplevel_v6 *toplevel_state; + + union { + struct wlr_xdg_toplevel_v6 *toplevel_state; + struct wlr_xdg_popup_v6 *popup_state; + }; bool configured; struct wl_event_source *configure_idle; -- cgit v1.2.3 From e003296c23fb0a974a13121cd940d6bf3fe63fac Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Mon, 2 Oct 2017 09:15:21 -0400 Subject: xdg-popup: render popups in the right place --- include/wlr/types/wlr_xdg_shell_v6.h | 3 +++ rootston/output.c | 23 +++++++++++++++++++++++ rootston/xdg_shell_v6.c | 11 +++++++++-- types/wlr_xdg_shell_v6.c | 4 ++++ 4 files changed, 39 insertions(+), 2 deletions(-) (limited to 'include/wlr') diff --git a/include/wlr/types/wlr_xdg_shell_v6.h b/include/wlr/types/wlr_xdg_shell_v6.h index 2d38dba0..b7acc2c4 100644 --- a/include/wlr/types/wlr_xdg_shell_v6.h +++ b/include/wlr/types/wlr_xdg_shell_v6.h @@ -89,6 +89,9 @@ struct wlr_xdg_surface_v6 { struct wlr_xdg_popup_v6 *popup_state; }; + struct wl_list popups; + struct wl_list popup_link; + bool configured; struct wl_event_source *configure_idle; struct wl_list configure_list; diff --git a/rootston/output.c b/rootston/output.c index 14d1783e..06786395 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -53,10 +53,33 @@ static void render_surface(struct wlr_surface *surface, } } +static void render_xdg_v6_popups(struct wlr_xdg_surface_v6 *surface, + struct roots_desktop *desktop, struct wlr_output *wlr_output, + struct timespec *when, double base_x, double base_y) { + struct wlr_xdg_surface_v6 *popup; + wl_list_for_each(popup, &surface->popups, popup_link) { + if (!popup->configured) { + continue; + } + + double popup_x = base_x + surface->geometry->x + + popup->popup_state->geometry.x - popup->geometry->x; + double popup_y = base_y + surface->geometry->y + + popup->popup_state->geometry.y - popup->geometry->y; + render_surface(popup->surface, desktop, wlr_output, when, popup_x, + popup_y); + render_xdg_v6_popups(popup, desktop, wlr_output, when, popup_x, popup_y); + } +} + static void render_view(struct roots_view *view, struct roots_desktop *desktop, struct wlr_output *wlr_output, struct timespec *when) { render_surface(view->wlr_surface, desktop, wlr_output, when, view->x, view->y); + if (view->type == ROOTS_XDG_SHELL_V6_VIEW) { + render_xdg_v6_popups(view->xdg_surface_v6, desktop, wlr_output, + when, view->x, view->y); + } } static void output_frame_notify(struct wl_listener *listener, void *data) { diff --git a/rootston/xdg_shell_v6.c b/rootston/xdg_shell_v6.c index ab34f52a..ff0dd090 100644 --- a/rootston/xdg_shell_v6.c +++ b/rootston/xdg_shell_v6.c @@ -73,11 +73,18 @@ static void handle_destroy(struct wl_listener *listener, void *data) { } void handle_xdg_shell_v6_surface(struct wl_listener *listener, void *data) { + struct wlr_xdg_surface_v6 *surface = data; + assert(surface->role != WLR_XDG_SURFACE_V6_ROLE_NONE); + + if (surface->role == WLR_XDG_SURFACE_V6_ROLE_POPUP) { + wlr_log(L_DEBUG, "new xdg popup"); + return; + } + struct roots_desktop *desktop = wl_container_of(listener, desktop, xdg_shell_v6_surface); - struct wlr_xdg_surface_v6 *surface = data; - wlr_log(L_DEBUG, "new xdg surface: title=%s, app_id=%s", + wlr_log(L_DEBUG, "new xdg toplevel: title=%s, app_id=%s", surface->title, surface->app_id); wlr_xdg_surface_v6_ping(surface); diff --git a/types/wlr_xdg_shell_v6.c b/types/wlr_xdg_shell_v6.c index 718e12fe..6e32ebdf 100644 --- a/types/wlr_xdg_shell_v6.c +++ b/types/wlr_xdg_shell_v6.c @@ -57,6 +57,7 @@ static void xdg_surface_destroy(struct wlr_xdg_surface_v6 *surface) { if (surface->role == WLR_XDG_SURFACE_V6_ROLE_POPUP) { wl_resource_set_user_data(surface->popup_state->resource, NULL); + wl_list_remove(&surface->popup_link); free(surface->popup_state); } @@ -317,6 +318,8 @@ static void xdg_surface_get_popup(struct wl_client *client, surface->popup_state->parent = parent; surface->popup_state->geometry = xdg_positioner_get_geometry(positioner, surface, parent); + wl_list_insert(&surface->popup_state->parent->popups, + &surface->popup_link); wl_resource_set_implementation(surface->popup_state->resource, &zxdg_popup_v6_implementation, surface, @@ -914,6 +917,7 @@ static void xdg_shell_get_xdg_surface(struct wl_client *wl_client, } wl_list_init(&surface->configure_list); + wl_list_init(&surface->popups); wl_signal_init(&surface->events.request_minimize); wl_signal_init(&surface->events.request_move); -- cgit v1.2.3 From 17b134e1783acab00e494d5343b3611ece65e582 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Thu, 5 Oct 2017 13:28:26 -0400 Subject: wlr-seat: pointer grab interface --- include/wlr/types/wlr_seat.h | 83 ++++++++++++++++++++++++++++++++++++++++++-- rootston/cursor.c | 8 ++--- types/wlr_seat.c | 80 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 165 insertions(+), 6 deletions(-) (limited to 'include/wlr') diff --git a/include/wlr/types/wlr_seat.h b/include/wlr/types/wlr_seat.h index 489bd529..ad120d6e 100644 --- a/include/wlr/types/wlr_seat.h +++ b/include/wlr/types/wlr_seat.h @@ -24,6 +24,30 @@ struct wlr_seat_handle { struct wl_list link; }; +struct wlr_seat_pointer_grab; + +struct wlr_pointer_grab_interface { + void (*enter)(struct wlr_seat_pointer_grab *grab, + struct wlr_surface *surface, double sx, double sy); + void (*motion)(struct wlr_seat_pointer_grab *grab, uint32_t time, + double sx, double sy); + uint32_t (*button)(struct wlr_seat_pointer_grab *grab, uint32_t time, + uint32_t button, uint32_t state); + void (*axis)(struct wlr_seat_pointer_grab *grab, uint32_t time, + enum wlr_axis_orientation orientation, double value); + void (*cancel)(struct wlr_seat_pointer_grab *grab); +}; + +/** + * Passed to `wlr_seat_pointer_start_grab()` to start a grab of the pointer. The + * grabber is responsible for handling pointer events for the seat. + */ +struct wlr_seat_pointer_grab { + const struct wlr_pointer_grab_interface *interface; + struct wlr_seat *seat; + void *data; +}; + struct wlr_seat_pointer_state { struct wlr_seat *wlr_seat; struct wlr_seat_handle *focused_handle; @@ -31,6 +55,9 @@ struct wlr_seat_pointer_state { struct wl_listener surface_destroy; struct wl_listener resource_destroy; + + struct wlr_seat_pointer_grab *grab; + struct wlr_seat_pointer_grab *default_grab; }; struct wlr_seat_keyboard { @@ -109,6 +136,8 @@ bool wlr_seat_pointer_surface_has_focus(struct wlr_seat *wlr_seat, * Send a pointer enter event to the given surface and consider it to be the * focused surface for the pointer. This will send a leave event to the last * surface that was entered. Coordinates for the enter event are surface-local. + * Compositor should use `wlr_seat_pointer_notify_enter()` to change pointer + * focus to respect pointer grabs. */ void wlr_seat_pointer_enter(struct wlr_seat *wlr_seat, struct wlr_surface *surface, double sx, double sy); @@ -120,21 +149,71 @@ void wlr_seat_pointer_clear_focus(struct wlr_seat *wlr_seat); /** * Send a motion event to the surface with pointer focus. Coordinates for the - * motion event are surface-local. + * motion event are surface-local. Compositors should use + * `wlr_seat_pointer_notify_motion()` to send motion events to respect pointer + * grabs. */ void wlr_seat_pointer_send_motion(struct wlr_seat *wlr_seat, uint32_t time, double sx, double sy); /** * Send a button event to the surface with pointer focus. Coordinates for the - * button event are surface-local. Returns the serial. + * button event are surface-local. Returns the serial. Compositors should use + * `wlr_seat_pointer_notify_button()` to send button events to respect pointer + * grabs. */ uint32_t wlr_seat_pointer_send_button(struct wlr_seat *wlr_seat, uint32_t time, uint32_t button, uint32_t state); +/** + * Send an axis event to the surface with pointer focus. Compositors should use + * `wlr_seat_pointer_notify_axis()` to send axis events to respect pointer + * grabs. + **/ void wlr_seat_pointer_send_axis(struct wlr_seat *wlr_seat, uint32_t time, enum wlr_axis_orientation orientation, double value); +/** + * Start a grab of the pointer of this seat. The grabber is responsible for + * handling all pointer events until the grab ends. + */ +void wlr_seat_pointer_start_grab(struct wlr_seat *wlr_seat, + struct wlr_seat_pointer_grab *grab); + +/** + * End the grab of the pointer of this seat. This reverts the grab back to the + * default grab for the pointer. + */ +void wlr_seat_pointer_end_grab(struct wlr_seat *wlr_seat); + +/** + * Notify the seat of a pointer enter event to the given surface and request it to be the + * focused surface for the pointer. Pass surface-local coordinates where the + * enter occurred. + */ +void wlr_seat_pointer_notify_enter(struct wlr_seat *wlr_seat, + struct wlr_surface *surface, double sx, double sy); + +/** + * Notify the seat of motion over the given surface. Pass surface-local + * coordinates where the pointer motion occurred. + */ +void wlr_seat_pointer_notify_motion(struct wlr_seat *wlr_seat, uint32_t time, + double sx, double sy); + +/** + * Notify the seat that a button has been pressed. Returns the serial of the + * button press or zero if no button press was sent. + */ +uint32_t wlr_seat_pointer_notify_button(struct wlr_seat *wlr_seat, + uint32_t time, uint32_t button, uint32_t state); + +/** + * Notify the seat of an axis event. + */ +void wlr_seat_pointer_notify_axis(struct wlr_seat *wlr_seat, uint32_t time, + enum wlr_axis_orientation orientation, double value); + /** * Attaches this keyboard to the seat. Key events from this keyboard will be * propegated to the focused client. diff --git a/rootston/cursor.c b/rootston/cursor.c index c24e6989..a0fd36d0 100644 --- a/rootston/cursor.c +++ b/rootston/cursor.c @@ -55,8 +55,8 @@ void cursor_update_position(struct roots_input *input, uint32_t time) { view = view_at(desktop, input->cursor->x, input->cursor->y, &surface, &sx, &sy); if (view) { - wlr_seat_pointer_enter(input->wl_seat, surface, sx, sy); - wlr_seat_pointer_send_motion(input->wl_seat, time, sx, sy); + wlr_seat_pointer_notify_enter(input->wl_seat, surface, sx, sy); + wlr_seat_pointer_notify_motion(input->wl_seat, time, sx, sy); } else { wlr_seat_pointer_clear_focus(input->wl_seat); } @@ -137,7 +137,7 @@ static void handle_cursor_axis(struct wl_listener *listener, void *data) { struct roots_input *input = wl_container_of(listener, input, cursor_axis); struct wlr_event_pointer_axis *event = data; - wlr_seat_pointer_send_axis(input->wl_seat, event->time_sec, + wlr_seat_pointer_notify_axis(input->wl_seat, event->time_sec, event->orientation, event->delta); } @@ -149,7 +149,7 @@ static void do_cursor_button_press(struct roots_input *input, double sx, sy; struct roots_view *view = view_at(desktop, input->cursor->x, input->cursor->y, &surface, &sx, &sy); - uint32_t serial = wlr_seat_pointer_send_button( + uint32_t serial = wlr_seat_pointer_notify_button( input->wl_seat, time, button, state); int i; switch (state) { diff --git a/types/wlr_seat.c b/types/wlr_seat.c index 2d0bb01c..e6decc8a 100644 --- a/types/wlr_seat.c +++ b/types/wlr_seat.c @@ -173,6 +173,38 @@ static void wl_seat_bind(struct wl_client *wl_client, void *_wlr_seat, wl_signal_emit(&wlr_seat->events.client_bound, handle); } +static void default_pointer_enter(struct wlr_seat_pointer_grab *grab, + struct wlr_surface *surface, double sx, double sy) { + wlr_seat_pointer_enter(grab->seat, surface, sx, sy); +} + +static void default_pointer_motion(struct wlr_seat_pointer_grab *grab, + uint32_t time, double sx, double sy) { + wlr_seat_pointer_send_motion(grab->seat, time, sx, sy); +} + +static uint32_t default_pointer_button(struct wlr_seat_pointer_grab *grab, + uint32_t time, uint32_t button, uint32_t state) { + return wlr_seat_pointer_send_button(grab->seat, time, button, state); +} + +static void default_pointer_axis(struct wlr_seat_pointer_grab *grab, + uint32_t time, enum wlr_axis_orientation orientation, double value) { + wlr_seat_pointer_send_axis(grab->seat, time, orientation, value); +} + +static void default_pointer_cancel(struct wlr_seat_pointer_grab *grab) { + // cannot be cancelled +} + +static const struct wlr_pointer_grab_interface default_pointer_grab_impl = { + .enter = default_pointer_enter, + .motion = default_pointer_motion, + .button = default_pointer_button, + .axis = default_pointer_axis, + .cancel = default_pointer_cancel, +}; + struct wlr_seat *wlr_seat_create(struct wl_display *display, const char *name) { struct wlr_seat *wlr_seat = calloc(1, sizeof(struct wlr_seat)); if (!wlr_seat) { @@ -183,6 +215,17 @@ struct wlr_seat *wlr_seat_create(struct wl_display *display, const char *name) { wl_list_init(&wlr_seat->pointer_state.surface_destroy.link); wl_list_init(&wlr_seat->pointer_state.resource_destroy.link); + struct wlr_seat_pointer_grab *default_grab = + calloc(1, sizeof(struct wlr_seat_pointer_grab)); + if (!default_grab) { + free(wlr_seat); + return NULL; + } + default_grab->interface = &default_pointer_grab_impl; + default_grab->seat = wlr_seat; + wlr_seat->pointer_state.default_grab = default_grab; + wlr_seat->pointer_state.grab = default_grab; + wlr_seat->keyboard_state.wlr_seat = wlr_seat; wl_list_init(&wlr_seat->keyboard_state.resource_destroy.link); wl_list_init( @@ -218,6 +261,7 @@ void wlr_seat_destroy(struct wlr_seat *wlr_seat) { } wl_global_destroy(wlr_seat->wl_global); + free(wlr_seat->pointer_state.default_grab); free(wlr_seat->data_device); free(wlr_seat->name); free(wlr_seat); @@ -386,6 +430,42 @@ void wlr_seat_pointer_send_axis(struct wlr_seat *wlr_seat, uint32_t time, pointer_send_frame(pointer); } +void wlr_seat_pointer_start_grab(struct wlr_seat *wlr_seat, + struct wlr_seat_pointer_grab *grab) { + grab->seat = wlr_seat; + wlr_seat->pointer_state.grab = grab; + // TODO: replay the last enter +} + +void wlr_seat_pointer_end_grab(struct wlr_seat *wlr_seat) { + wlr_seat->pointer_state.grab = wlr_seat->pointer_state.default_grab; + // TODO: replay the last enter +} + +void wlr_seat_pointer_notify_enter(struct wlr_seat *wlr_seat, + struct wlr_surface *surface, double sx, double sy) { + struct wlr_seat_pointer_grab *grab = wlr_seat->pointer_state.grab; + grab->interface->enter(grab, surface, sx, sy); +} + +void wlr_seat_pointer_notify_motion(struct wlr_seat *wlr_seat, uint32_t time, + double sx, double sy) { + struct wlr_seat_pointer_grab *grab = wlr_seat->pointer_state.grab; + grab->interface->motion(grab, time, sx, sy); +} + +uint32_t wlr_seat_pointer_notify_button(struct wlr_seat *wlr_seat, + uint32_t time, uint32_t button, uint32_t state) { + struct wlr_seat_pointer_grab *grab = wlr_seat->pointer_state.grab; + return grab->interface->button(grab, time, button, state); +} + +void wlr_seat_pointer_notify_axis(struct wlr_seat *wlr_seat, uint32_t time, + enum wlr_axis_orientation orientation, double value) { + struct wlr_seat_pointer_grab *grab = wlr_seat->pointer_state.grab; + grab->interface->axis(grab, time, orientation, value); +} + static void keyboard_switch_seat_keyboard(struct wlr_seat_handle *handle, struct wlr_seat_keyboard *seat_kb) { if (handle->seat_keyboard == seat_kb) { -- cgit v1.2.3 From d3ebf99b0fcadff6b70e6d7e90b956330cefe8a1 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Fri, 6 Oct 2017 06:54:43 -0400 Subject: xdg-popup: basic pointer grab --- include/wlr/types/wlr_xdg_shell_v6.h | 14 +++++ types/wlr_xdg_shell_v6.c | 110 ++++++++++++++++++++++++++++++++++- 2 files changed, 123 insertions(+), 1 deletion(-) (limited to 'include/wlr') diff --git a/include/wlr/types/wlr_xdg_shell_v6.h b/include/wlr/types/wlr_xdg_shell_v6.h index b7acc2c4..408df16a 100644 --- a/include/wlr/types/wlr_xdg_shell_v6.h +++ b/include/wlr/types/wlr_xdg_shell_v6.h @@ -2,11 +2,13 @@ #define WLR_TYPES_WLR_XDG_SHELL_V6_H #include +#include #include struct wlr_xdg_shell_v6 { struct wl_global *wl_global; struct wl_list clients; + struct wl_list popup_grabs; uint32_t ping_timeout; struct { @@ -36,6 +38,18 @@ struct wlr_xdg_popup_v6 { struct wlr_xdg_surface_v6 *parent; struct wlr_seat *seat; struct wlr_box geometry; + + struct wl_list grab_link; // wlr_xdg_popup_grab_v6::popups +}; + +// each seat gets a popup grab +struct wlr_xdg_popup_grab_v6 { + struct wl_client *client; + struct wlr_seat_pointer_grab pointer_grab; + struct wlr_seat *seat; + struct wl_list popups; + struct wl_list link; // wlr_xdg_shell_v6::popup_grabs + // TODO: seat_handle destroy will release the grab }; enum wlr_xdg_surface_v6_role { diff --git a/types/wlr_xdg_shell_v6.c b/types/wlr_xdg_shell_v6.c index 6e32ebdf..f9546fea 100644 --- a/types/wlr_xdg_shell_v6.c +++ b/types/wlr_xdg_shell_v6.c @@ -56,8 +56,10 @@ static void xdg_surface_destroy(struct wlr_xdg_surface_v6 *surface) { } if (surface->role == WLR_XDG_SURFACE_V6_ROLE_POPUP) { + // TODO: get the current grab and if it has no more popups, end the grab wl_resource_set_user_data(surface->popup_state->resource, NULL); wl_list_remove(&surface->popup_link); + wl_list_remove(&surface->popup_state->grab_link); free(surface->popup_state); } @@ -203,10 +205,114 @@ static void xdg_shell_create_positioner(struct wl_client *wl_client, positioner, xdg_positioner_destroy); } +static void xdg_pointer_grab_end(struct wlr_seat_pointer_grab *grab) { + struct wlr_xdg_popup_grab_v6 *popup_grab = grab->data; + + struct wlr_xdg_popup_v6 *popup, *tmp; + wl_list_for_each_safe(popup, tmp, &popup_grab->popups, grab_link) { + wl_list_remove(&popup->grab_link); + wl_list_init(&popup->grab_link); + zxdg_popup_v6_send_popup_done(popup->resource); + } + + wlr_seat_pointer_end_grab(grab->seat); +} + +static void xdg_pointer_grab_enter(struct wlr_seat_pointer_grab *grab, + struct wlr_surface *surface, double sx, double sy) { + struct wlr_xdg_popup_grab_v6 *popup_grab = grab->data; + if (wl_resource_get_client(surface->resource) == popup_grab->client) { + wlr_seat_pointer_enter(grab->seat, surface, sx, sy); + } else { + wlr_seat_pointer_clear_focus(grab->seat); + } +} + +static void xdg_pointer_grab_motion(struct wlr_seat_pointer_grab *grab, + uint32_t time, double sx, double sy) { + wlr_seat_pointer_send_motion(grab->seat, time, sx, sy); +} + +static uint32_t xdg_pointer_grab_button(struct wlr_seat_pointer_grab *grab, + uint32_t time, uint32_t button, uint32_t state) { + uint32_t serial = + wlr_seat_pointer_send_button(grab->seat, time, button, state); + if (serial) { + return serial; + } else { + xdg_pointer_grab_end(grab); + return 0; + } +} + +static void xdg_pointer_grab_axis(struct wlr_seat_pointer_grab *grab, + uint32_t time, enum wlr_axis_orientation orientation, double value) { + wlr_seat_pointer_send_axis(grab->seat, time, orientation, value); +} + +static void xdg_pointer_grab_cancel(struct wlr_seat_pointer_grab *grab) { + xdg_pointer_grab_end(grab); +} + +static const struct wlr_pointer_grab_interface xdg_pointer_grab_impl = { + .enter = xdg_pointer_grab_enter, + .motion = xdg_pointer_grab_motion, + .button = xdg_pointer_grab_button, + .cancel = xdg_pointer_grab_cancel, +}; + +static struct wlr_xdg_popup_grab_v6 *xdg_shell_popup_grab_from_seat( + struct wlr_xdg_shell_v6 *shell, struct wlr_seat *seat) { + struct wlr_xdg_popup_grab_v6 *xdg_grab; + wl_list_for_each(xdg_grab, &shell->popup_grabs, link) { + if (xdg_grab->seat == seat) { + return xdg_grab; + } + } + + xdg_grab = calloc(1, sizeof(struct wlr_xdg_popup_grab_v6)); + if (!xdg_grab) { + return NULL; + } + + xdg_grab->pointer_grab.data = xdg_grab; + xdg_grab->pointer_grab.interface = &xdg_pointer_grab_impl; + // TODO: keyboard grab + + wl_list_init(&xdg_grab->popups); + + wl_list_insert(&shell->popup_grabs, &xdg_grab->link); + xdg_grab->seat = seat; + + return xdg_grab; +} + static void xdg_popup_protocol_grab(struct wl_client *client, struct wl_resource *resource, struct wl_resource *seat_resource, uint32_t serial) { - wlr_log(L_DEBUG, "TODO: xdg popup grab"); + struct wlr_xdg_surface_v6 *surface = wl_resource_get_user_data(resource); + struct wlr_seat_handle *handle = wl_resource_get_user_data(seat_resource); + //bool parent_is_toplevel = + //surface->popup_state->parent->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL; + + // TODO: handle make sure the grab is valid for the protocol + + if (surface->popup_state->committed) { + wl_resource_post_error(surface->popup_state->resource, + ZXDG_POPUP_V6_ERROR_INVALID_GRAB, + "xdg_popup is already mapped"); + return; + } + + struct wlr_xdg_popup_grab_v6 *popup_grab = + xdg_shell_popup_grab_from_seat(surface->client->shell, + handle->wlr_seat); + + popup_grab->client = surface->client->client; + + wl_list_insert(&popup_grab->popups, &surface->popup_state->grab_link); + + wlr_seat_pointer_start_grab(handle->wlr_seat, &popup_grab->pointer_grab); } static const struct zxdg_popup_v6_interface zxdg_popup_v6_implementation = { @@ -318,6 +424,7 @@ static void xdg_surface_get_popup(struct wl_client *client, surface->popup_state->parent = parent; surface->popup_state->geometry = xdg_positioner_get_geometry(positioner, surface, parent); + wl_list_init(&surface->popup_state->grab_link); wl_list_insert(&surface->popup_state->parent->popups, &surface->popup_link); @@ -1037,6 +1144,7 @@ struct wlr_xdg_shell_v6 *wlr_xdg_shell_v6_create(struct wl_display *display) { xdg_shell->ping_timeout = 10000; wl_list_init(&xdg_shell->clients); + wl_list_init(&xdg_shell->popup_grabs); struct wl_global *wl_global = wl_global_create(display, &zxdg_shell_v6_interface, 1, xdg_shell, xdg_shell_bind); -- cgit v1.2.3 From 48ae4fc5882d5d1b47e951b9f4fc0c64584d856e Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Fri, 6 Oct 2017 07:32:59 -0400 Subject: rootston: handle grab end --- include/rootston/input.h | 2 ++ include/wlr/types/wlr_seat.h | 3 +++ rootston/cursor.c | 9 +++++++++ types/wlr_seat.c | 9 +++++++-- 4 files changed, 21 insertions(+), 2 deletions(-) (limited to 'include/wlr') diff --git a/include/rootston/input.h b/include/rootston/input.h index ae3e3b80..4b9bd1dd 100644 --- a/include/rootston/input.h +++ b/include/rootston/input.h @@ -105,6 +105,8 @@ struct roots_input { struct wl_listener cursor_axis; struct wl_listener cursor_tool_axis; struct wl_listener cursor_tool_tip; + + struct wl_listener pointer_grab_end; }; struct roots_input *input_create(struct roots_server *server, diff --git a/include/wlr/types/wlr_seat.h b/include/wlr/types/wlr_seat.h index ad120d6e..6b66fd69 100644 --- a/include/wlr/types/wlr_seat.h +++ b/include/wlr/types/wlr_seat.h @@ -94,6 +94,9 @@ struct wlr_seat { struct { struct wl_signal client_bound; struct wl_signal client_unbound; + + struct wl_signal pointer_grab_begin; + struct wl_signal pointer_grab_end; } events; void *data; diff --git a/rootston/cursor.c b/rootston/cursor.c index 7ea1ed4d..df5869e5 100644 --- a/rootston/cursor.c +++ b/rootston/cursor.c @@ -265,6 +265,12 @@ static void handle_tool_tip(struct wl_listener *listener, void *data) { (uint32_t)(event->time_usec / 1000), BTN_LEFT, event->state); } +static void handle_pointer_grab_end(struct wl_listener *listener, void *data) { + struct roots_input *input = + wl_container_of(listener, input, pointer_grab_end); + cursor_update_position(input, 0); +} + void cursor_initialize(struct roots_input *input) { struct wlr_cursor *cursor = input->cursor; @@ -292,6 +298,9 @@ void cursor_initialize(struct roots_input *input) { wl_list_init(&input->cursor_tool_tip.link); wl_signal_add(&cursor->events.tablet_tool_tip, &input->cursor_tool_tip); input->cursor_tool_tip.notify = handle_tool_tip; + + wl_signal_add(&input->wl_seat->events.pointer_grab_end, &input->pointer_grab_end); + input->pointer_grab_end.notify = handle_pointer_grab_end; } static void reset_device_mappings(struct roots_config *config, diff --git a/types/wlr_seat.c b/types/wlr_seat.c index efb95a78..c4fd3f65 100644 --- a/types/wlr_seat.c +++ b/types/wlr_seat.c @@ -246,6 +246,9 @@ struct wlr_seat *wlr_seat_create(struct wl_display *display, const char *name) { wl_signal_init(&wlr_seat->events.client_bound); wl_signal_init(&wlr_seat->events.client_unbound); + wl_signal_init(&wlr_seat->events.pointer_grab_begin); + wl_signal_init(&wlr_seat->events.pointer_grab_end); + return wlr_seat; } @@ -438,12 +441,14 @@ void wlr_seat_pointer_start_grab(struct wlr_seat *wlr_seat, struct wlr_seat_pointer_grab *grab) { grab->seat = wlr_seat; wlr_seat->pointer_state.grab = grab; - // TODO: replay the last enter + + wl_signal_emit(&wlr_seat->events.pointer_grab_begin, grab); } void wlr_seat_pointer_end_grab(struct wlr_seat *wlr_seat) { + struct wlr_seat_pointer_grab *grab = wlr_seat->pointer_state.grab; wlr_seat->pointer_state.grab = wlr_seat->pointer_state.default_grab; - // TODO: replay the last enter + wl_signal_emit(&wlr_seat->events.pointer_grab_end, grab); } void wlr_seat_pointer_notify_enter(struct wlr_seat *wlr_seat, -- cgit v1.2.3 From 67ea30775390cf535ae6431186b367a6a63a3621 Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Fri, 6 Oct 2017 07:52:18 -0400 Subject: xdg-shell: cleanup --- include/wlr/types/wlr_xdg_shell_v6.h | 2 -- types/wlr_xdg_shell_v6.c | 6 +++--- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'include/wlr') diff --git a/include/wlr/types/wlr_xdg_shell_v6.h b/include/wlr/types/wlr_xdg_shell_v6.h index 408df16a..c7067e80 100644 --- a/include/wlr/types/wlr_xdg_shell_v6.h +++ b/include/wlr/types/wlr_xdg_shell_v6.h @@ -49,7 +49,6 @@ struct wlr_xdg_popup_grab_v6 { struct wlr_seat *seat; struct wl_list popups; struct wl_list link; // wlr_xdg_shell_v6::popup_grabs - // TODO: seat_handle destroy will release the grab }; enum wlr_xdg_surface_v6_role { @@ -84,7 +83,6 @@ struct wlr_xdg_toplevel_v6 { struct wlr_xdg_toplevel_v6_state current; }; -// TODO split up into toplevel and popup configure struct wlr_xdg_surface_v6_configure { struct wl_list link; // wlr_xdg_surface_v6::configure_list uint32_t serial; diff --git a/types/wlr_xdg_shell_v6.c b/types/wlr_xdg_shell_v6.c index f9546fea..eb0547d3 100644 --- a/types/wlr_xdg_shell_v6.c +++ b/types/wlr_xdg_shell_v6.c @@ -170,7 +170,8 @@ static void xdg_positioner_protocol_set_offset(struct wl_client *client, positioner->offset.y = y; } -static const struct zxdg_positioner_v6_interface zxdg_positioner_v6_implementation = { +static const struct zxdg_positioner_v6_interface + zxdg_positioner_v6_implementation = { .destroy = resource_destroy, .set_size = xdg_positioner_protocol_set_size, .set_anchor_rect = xdg_positioner_protocol_set_anchor_rect, @@ -259,6 +260,7 @@ static const struct wlr_pointer_grab_interface xdg_pointer_grab_impl = { .motion = xdg_pointer_grab_motion, .button = xdg_pointer_grab_button, .cancel = xdg_pointer_grab_cancel, + .axis = xdg_pointer_grab_axis, }; static struct wlr_xdg_popup_grab_v6 *xdg_shell_popup_grab_from_seat( @@ -431,8 +433,6 @@ static void xdg_surface_get_popup(struct wl_client *client, wl_resource_set_implementation(surface->popup_state->resource, &zxdg_popup_v6_implementation, surface, xdg_popup_resource_destroy); - - // TODO: set relative to parent? } -- cgit v1.2.3 From 4680943e749bfd441d31c988faa50f2b1ae043ad Mon Sep 17 00:00:00 2001 From: Tony Crisci Date: Sat, 7 Oct 2017 11:02:11 -0400 Subject: xdg-seat: keyboard grabs --- include/wlr/types/wlr_seat.h | 69 ++++++++++++++++++++- include/wlr/types/wlr_xdg_shell_v6.h | 1 + rootston/cursor.c | 2 +- types/wlr_seat.c | 115 +++++++++++++++++++++++++++++++---- types/wlr_xdg_shell_v6.c | 42 +++++++++++-- 5 files changed, 211 insertions(+), 18 deletions(-) (limited to 'include/wlr') diff --git a/include/wlr/types/wlr_seat.h b/include/wlr/types/wlr_seat.h index 6b66fd69..d3d3e00d 100644 --- a/include/wlr/types/wlr_seat.h +++ b/include/wlr/types/wlr_seat.h @@ -38,6 +38,28 @@ struct wlr_pointer_grab_interface { void (*cancel)(struct wlr_seat_pointer_grab *grab); }; +struct wlr_seat_keyboard_grab; + +struct wlr_keyboard_grab_interface { + void (*enter)(struct wlr_seat_keyboard_grab *grab, struct wlr_surface *surface); + void (*key)(struct wlr_seat_keyboard_grab *grab, uint32_t time, + uint32_t key, uint32_t state); + void (*modifiers)(struct wlr_seat_keyboard_grab *grab, + uint32_t mods_depressed, uint32_t mods_latched, + uint32_t mods_locked, uint32_t group); + void (*cancel)(struct wlr_seat_keyboard_grab *grab); +}; + +/** + * Passed to `wlr_seat_keyboard_start_grab()` to start a grab of the keyboard. + * The grabber is responsible for handling keyboard events for the seat. + */ +struct wlr_seat_keyboard_grab { + const struct wlr_keyboard_grab_interface *interface; + struct wlr_seat *seat; + void *data; +}; + /** * Passed to `wlr_seat_pointer_start_grab()` to start a grab of the pointer. The * grabber is responsible for handling pointer events for the seat. @@ -77,6 +99,9 @@ struct wlr_seat_keyboard_state { struct wl_listener surface_destroy; struct wl_listener resource_destroy; + + struct wlr_seat_keyboard_grab *grab; + struct wlr_seat_keyboard_grab *default_grab; }; struct wlr_seat { @@ -97,12 +122,14 @@ struct wlr_seat { struct wl_signal pointer_grab_begin; struct wl_signal pointer_grab_end; + + struct wl_signal keyboard_grab_begin; + struct wl_signal keyboard_grab_end; } events; void *data; }; - /** * Allocates a new wlr_seat and adds a wl_seat global to the display. */ @@ -231,10 +258,48 @@ void wlr_seat_attach_keyboard(struct wlr_seat *seat, */ void wlr_seat_detach_keyboard(struct wlr_seat *seat, struct wlr_keyboard *kb); +/** + * Start a grab of the keyboard of this seat. The grabber is responsible for + * handling all keyboard events until the grab ends. + */ +void wlr_seat_keyboard_start_grab(struct wlr_seat *wlr_seat, + struct wlr_seat_keyboard_grab *grab); + +/** + * End the grab of the keyboard of this seat. This reverts the grab back to the + * default grab for the keyboard. + */ +void wlr_seat_keyboard_end_grab(struct wlr_seat *wlr_seat); + +/** + * Send the keyboard key to focused keyboard resources. Compositors should use + * `wlr_seat_attach_keyboard()` to automatically handle keyboard events. + */ +void wlr_seat_keyboard_send_key(struct wlr_seat *seat, uint32_t time, + uint32_t key, uint32_t state); + +/** + * Send the modifier state to focused keyboard resources. Compositors should use + * `wlr_seat_attach_keyboard()` to automatically handle keyboard events. + */ +void wlr_seat_keyboard_send_modifiers(struct wlr_seat *seat, + uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, + uint32_t group); + +/** + * Notify the seat that the keyboard focus has changed and request it to be the + * focused surface for this keyboard. Defers to any current grab of the seat's + * keyboard. + */ +void wlr_seat_keyboard_notify_enter(struct wlr_seat *wlr_seat, + struct wlr_surface *surface); + /** * Send a keyboard enter event to the given surface and consider it to be the * focused surface for the keyboard. This will send a leave event to the last - * surface that was entered. Pass an array of currently pressed keys. + * surface that was entered. Compositors should use + * `wlr_seat_keyboard_notify_enter()` to change keyboard focus to respect + * keyboard grabs. */ void wlr_seat_keyboard_enter(struct wlr_seat *wlr_seat, struct wlr_surface *surface); diff --git a/include/wlr/types/wlr_xdg_shell_v6.h b/include/wlr/types/wlr_xdg_shell_v6.h index c7067e80..0a633822 100644 --- a/include/wlr/types/wlr_xdg_shell_v6.h +++ b/include/wlr/types/wlr_xdg_shell_v6.h @@ -46,6 +46,7 @@ struct wlr_xdg_popup_v6 { struct wlr_xdg_popup_grab_v6 { struct wl_client *client; struct wlr_seat_pointer_grab pointer_grab; + struct wlr_seat_keyboard_grab keyboard_grab; struct wlr_seat *seat; struct wl_list popups; struct wl_list link; // wlr_xdg_shell_v6::popup_grabs diff --git a/rootston/cursor.c b/rootston/cursor.c index df5869e5..2918b50f 100644 --- a/rootston/cursor.c +++ b/rootston/cursor.c @@ -234,7 +234,7 @@ static void do_cursor_button_press(struct roots_input *input, % (sizeof(input->input_events) / sizeof(input->input_events[0])); set_view_focus(input, desktop, view); if (view) { - wlr_seat_keyboard_enter(input->wl_seat, surface); + wlr_seat_keyboard_notify_enter(input->wl_seat, surface); } break; } diff --git a/types/wlr_seat.c b/types/wlr_seat.c index c4fd3f65..4f8d3744 100644 --- a/types/wlr_seat.c +++ b/types/wlr_seat.c @@ -205,6 +205,34 @@ static const struct wlr_pointer_grab_interface default_pointer_grab_impl = { .cancel = default_pointer_cancel, }; +static void default_keyboard_enter(struct wlr_seat_keyboard_grab *grab, + struct wlr_surface *surface) { + wlr_seat_keyboard_enter(grab->seat, surface); +} + +static void default_keyboard_key(struct wlr_seat_keyboard_grab *grab, + uint32_t time, uint32_t key, uint32_t state) { + wlr_seat_keyboard_send_key(grab->seat, time, key, state); +} + +static void default_keyboard_modifiers(struct wlr_seat_keyboard_grab *grab, + uint32_t mods_depressed, uint32_t mods_latched, + uint32_t mods_locked, uint32_t group) { + wlr_seat_keyboard_send_modifiers(grab->seat, mods_depressed, + mods_latched, mods_locked, group); +} + +static void default_keyboard_cancel(struct wlr_seat_keyboard_grab *grab) { + // cannot be cancelled +} + +static const struct wlr_keyboard_grab_interface default_keyboard_grab_impl = { + .enter = default_keyboard_enter, + .key = default_keyboard_key, + .modifiers = default_keyboard_modifiers, + .cancel = default_keyboard_cancel, +}; + struct wlr_seat *wlr_seat_create(struct wl_display *display, const char *name) { struct wlr_seat *wlr_seat = calloc(1, sizeof(struct wlr_seat)); if (!wlr_seat) { @@ -215,16 +243,28 @@ struct wlr_seat *wlr_seat_create(struct wl_display *display, const char *name) { wl_list_init(&wlr_seat->pointer_state.surface_destroy.link); wl_list_init(&wlr_seat->pointer_state.resource_destroy.link); - struct wlr_seat_pointer_grab *default_grab = + struct wlr_seat_pointer_grab *pointer_grab = calloc(1, sizeof(struct wlr_seat_pointer_grab)); - if (!default_grab) { + if (!pointer_grab) { + free(wlr_seat); + return NULL; + } + pointer_grab->interface = &default_pointer_grab_impl; + pointer_grab->seat = wlr_seat; + wlr_seat->pointer_state.default_grab = pointer_grab; + wlr_seat->pointer_state.grab = pointer_grab; + + struct wlr_seat_keyboard_grab *keyboard_grab = + calloc(1, sizeof(struct wlr_seat_keyboard_grab)); + if (!keyboard_grab) { + free(pointer_grab); free(wlr_seat); return NULL; } - default_grab->interface = &default_pointer_grab_impl; - default_grab->seat = wlr_seat; - wlr_seat->pointer_state.default_grab = default_grab; - wlr_seat->pointer_state.grab = default_grab; + keyboard_grab->interface = &default_keyboard_grab_impl; + keyboard_grab->seat = wlr_seat; + wlr_seat->keyboard_state.default_grab = keyboard_grab; + wlr_seat->keyboard_state.grab = keyboard_grab; wlr_seat->keyboard_state.wlr_seat = wlr_seat; wl_list_init(&wlr_seat->keyboard_state.resource_destroy.link); @@ -249,6 +289,9 @@ struct wlr_seat *wlr_seat_create(struct wl_display *display, const char *name) { wl_signal_init(&wlr_seat->events.pointer_grab_begin); wl_signal_init(&wlr_seat->events.pointer_grab_end); + wl_signal_init(&wlr_seat->events.keyboard_grab_begin); + wl_signal_init(&wlr_seat->events.keyboard_grab_end); + return wlr_seat; } @@ -265,6 +308,7 @@ void wlr_seat_destroy(struct wlr_seat *wlr_seat) { wl_global_destroy(wlr_seat->wl_global); free(wlr_seat->pointer_state.default_grab); + free(wlr_seat->keyboard_state.default_grab); free(wlr_seat->data_device); free(wlr_seat->name); free(wlr_seat); @@ -495,6 +539,18 @@ static void keyboard_switch_seat_keyboard(struct wlr_seat_handle *handle, handle->seat_keyboard = seat_kb; } +void wlr_seat_keyboard_send_key(struct wlr_seat *wlr_seat, uint32_t time, + uint32_t key, uint32_t state) { + struct wlr_seat_handle *handle = wlr_seat->keyboard_state.focused_handle; + if (!handle || !handle->keyboard) { + return; + } + + uint32_t serial = wl_display_next_serial(wlr_seat->display); + wl_keyboard_send_key(handle->keyboard, serial, + time, key, state); +} + static void keyboard_key_notify(struct wl_listener *listener, void *data) { struct wlr_seat_keyboard *seat_kb = wl_container_of(listener, seat_kb, key); struct wlr_seat *seat = seat_kb->seat; @@ -508,9 +564,9 @@ static void keyboard_key_notify(struct wl_listener *listener, void *data) { struct wlr_event_keyboard_key *event = data; enum wlr_key_state key_state = event->state; - uint32_t key_serial = wl_display_next_serial(seat->display); - wl_keyboard_send_key(handle->keyboard, key_serial, - (uint32_t)event->time_usec, event->keycode, key_state); + struct wlr_seat_keyboard_grab *grab = seat->keyboard_state.grab; + grab->interface->key(grab, (uint32_t)(event->time_usec / 1000), + event->keycode, key_state); } static void keyboard_modifiers_notify(struct wl_listener *listener, @@ -527,8 +583,9 @@ static void keyboard_modifiers_notify(struct wl_listener *listener, struct wlr_keyboard *keyboard = seat_kb->keyboard; - uint32_t modifiers_serial = wl_display_next_serial(seat->display); - wl_keyboard_send_modifiers(handle->keyboard, modifiers_serial, + struct wlr_seat_keyboard_grab *grab = seat->keyboard_state.grab; + + grab->interface->modifiers(grab, keyboard->modifiers.depressed, keyboard->modifiers.latched, keyboard->modifiers.locked, keyboard->modifiers.group); } @@ -584,6 +641,21 @@ void wlr_seat_detach_keyboard(struct wlr_seat *seat, struct wlr_keyboard *kb) { } } +void wlr_seat_keyboard_start_grab(struct wlr_seat *wlr_seat, + struct wlr_seat_keyboard_grab *grab) { + grab->seat = wlr_seat; + wlr_seat->keyboard_state.grab = grab; + + wl_signal_emit(&wlr_seat->events.keyboard_grab_begin, grab); +} + +void wlr_seat_keyboard_end_grab(struct wlr_seat *wlr_seat) { + struct wlr_seat_keyboard_grab *grab = wlr_seat->keyboard_state.grab; + wlr_seat->keyboard_state.grab = wlr_seat->keyboard_state.default_grab; + + wl_signal_emit(&wlr_seat->events.keyboard_grab_end, grab); +} + static void keyboard_surface_destroy_notify(struct wl_listener *listener, void *data) { struct wlr_seat_keyboard_state *state = wl_container_of( @@ -604,6 +676,21 @@ static void keyboard_resource_destroy_notify(struct wl_listener *listener, wlr_seat_keyboard_clear_focus(state->wlr_seat); } +void wlr_seat_keyboard_send_modifiers(struct wlr_seat *seat, + uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, + uint32_t group) { + struct wlr_seat_handle *handle = seat->keyboard_state.focused_handle; + if (!handle || !handle->keyboard) { + return; + } + + uint32_t serial = wl_display_next_serial(seat->display); + + wl_keyboard_send_modifiers(handle->keyboard, serial, + mods_depressed, mods_latched, + mods_locked, group); +} + void wlr_seat_keyboard_enter(struct wlr_seat *wlr_seat, struct wlr_surface *surface) { if (wlr_seat->keyboard_state.focused_surface == surface) { @@ -660,6 +747,12 @@ void wlr_seat_keyboard_enter(struct wlr_seat *wlr_seat, wlr_seat->keyboard_state.focused_surface = surface; } +void wlr_seat_keyboard_notify_enter(struct wlr_seat *wlr_seat, struct + wlr_surface *surface) { + struct wlr_seat_keyboard_grab *grab = wlr_seat->keyboard_state.grab; + grab->interface->enter(grab, surface); +} + void wlr_seat_keyboard_clear_focus(struct wlr_seat *wlr_seat) { struct wl_array keys; wl_array_init(&keys); diff --git a/types/wlr_xdg_shell_v6.c b/types/wlr_xdg_shell_v6.c index 50e812a7..fe9a5359 100644 --- a/types/wlr_xdg_shell_v6.c +++ b/types/wlr_xdg_shell_v6.c @@ -102,6 +102,33 @@ static const struct wlr_pointer_grab_interface xdg_pointer_grab_impl = { .axis = xdg_pointer_grab_axis, }; +static void xdg_keyboard_grab_enter(struct wlr_seat_keyboard_grab *grab, struct wlr_surface *surface) { + // keyboard focus should remain on the popup +} + +static void xdg_keyboard_grab_key(struct wlr_seat_keyboard_grab *grab, uint32_t time, + uint32_t key, uint32_t state) { + wlr_seat_keyboard_send_key(grab->seat, time, key, state); +} + +static void xdg_keyboard_grab_modifiers(struct wlr_seat_keyboard_grab *grab, + uint32_t mods_depressed, uint32_t mods_latched, + uint32_t mods_locked, uint32_t group) { + wlr_seat_keyboard_send_modifiers(grab->seat, mods_depressed, mods_latched, + mods_locked, group); +} + +static void xdg_keyboard_grab_cancel(struct wlr_seat_keyboard_grab *grab) { + wlr_seat_keyboard_end_grab(grab->seat); +} + +static const struct wlr_keyboard_grab_interface xdg_keyboard_grab_impl = { + .enter = xdg_keyboard_grab_enter, + .key = xdg_keyboard_grab_key, + .modifiers = xdg_keyboard_grab_modifiers, + .cancel = xdg_keyboard_grab_cancel, +}; + static struct wlr_xdg_popup_grab_v6 *xdg_shell_popup_grab_from_seat( struct wlr_xdg_shell_v6 *shell, struct wlr_seat *seat) { struct wlr_xdg_popup_grab_v6 *xdg_grab; @@ -118,7 +145,8 @@ static struct wlr_xdg_popup_grab_v6 *xdg_shell_popup_grab_from_seat( xdg_grab->pointer_grab.data = xdg_grab; xdg_grab->pointer_grab.interface = &xdg_pointer_grab_impl; - // TODO: keyboard grab + xdg_grab->keyboard_grab.data = xdg_grab; + xdg_grab->keyboard_grab.interface = &xdg_keyboard_grab_impl; wl_list_init(&xdg_grab->popups); @@ -130,6 +158,7 @@ static struct wlr_xdg_popup_grab_v6 *xdg_shell_popup_grab_from_seat( static void xdg_surface_destroy(struct wlr_xdg_surface_v6 *surface) { + // TODO: probably need to ungrab before this event wl_signal_emit(&surface->events.destroy, surface); if (surface->configure_idle) { @@ -166,9 +195,13 @@ static void xdg_surface_destroy(struct wlr_xdg_surface_v6 *surface) { wl_list_remove(&surface->popup_state->grab_link); - if (wl_list_empty(&grab->popups) && - grab->seat->pointer_state.grab == &grab->pointer_grab) { - wlr_seat_pointer_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); + } } } @@ -355,6 +388,7 @@ static void xdg_popup_protocol_grab(struct wl_client *client, wl_list_insert(&popup_grab->popups, &surface->popup_state->grab_link); wlr_seat_pointer_start_grab(handle->wlr_seat, &popup_grab->pointer_grab); + wlr_seat_keyboard_start_grab(handle->wlr_seat, &popup_grab->keyboard_grab); } static const struct zxdg_popup_v6_interface zxdg_popup_v6_implementation = { -- cgit v1.2.3