xdg-popup: protocol errors and ungrab
This commit is contained in:
		
							parent
							
								
									67ea307753
								
							
						
					
					
						commit
						27ee171d25
					
				|  | @ -37,9 +37,100 @@ static void resource_destroy(struct wl_client *client, | |||
| 	wl_resource_destroy(resource); | ||||
| } | ||||
| 
 | ||||
| static struct wlr_xdg_surface_v6 *xdg_popup_grab_get_topmost( | ||||
| 		struct wlr_xdg_popup_grab_v6 *grab) { | ||||
| 	struct wlr_xdg_popup_v6 *popup; | ||||
| 	wl_list_for_each(popup, &grab->popups, grab_link) { | ||||
| 		return popup->base; | ||||
| 	} | ||||
| 
 | ||||
| 	return NULL; | ||||
| } | ||||
| 
 | ||||
| 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) { | ||||
| 		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, | ||||
| 	.axis = xdg_pointer_grab_axis, | ||||
| }; | ||||
| 
 | ||||
| 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_surface_destroy(struct wlr_xdg_surface_v6 *surface) { | ||||
| 	wl_signal_emit(&surface->events.destroy, surface); | ||||
| 	wl_resource_set_user_data(surface->resource, NULL); | ||||
| 
 | ||||
| 	if (surface->configure_idle) { | ||||
| 		wl_event_source_remove(surface->configure_idle); | ||||
|  | @ -56,13 +147,36 @@ 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); | ||||
| 
 | ||||
| 		if (surface->popup_state->seat) { | ||||
| 			struct wlr_xdg_popup_grab_v6 *grab = | ||||
| 				xdg_shell_popup_grab_from_seat(surface->client->shell, | ||||
| 					surface->popup_state->seat); | ||||
| 
 | ||||
| 			struct wlr_xdg_surface_v6 *topmost = | ||||
| 				xdg_popup_grab_get_topmost(grab); | ||||
| 
 | ||||
| 			if (topmost != surface) { | ||||
| 				wl_resource_post_error(surface->client->resource, | ||||
| 						ZXDG_SHELL_V6_ERROR_NOT_THE_TOPMOST_POPUP, | ||||
| 						"xdg_popup was destroyed while it was not the topmost " | ||||
| 						"popup."); | ||||
| 			} | ||||
| 
 | ||||
| 			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); | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		wl_list_remove(&surface->popup_link); | ||||
| 		wl_list_remove(&surface->popup_state->grab_link); | ||||
| 		free(surface->popup_state); | ||||
| 	} | ||||
| 
 | ||||
| 	wl_resource_set_user_data(surface->resource, NULL); | ||||
| 	wl_list_remove(&surface->link); | ||||
| 	wl_list_remove(&surface->surface_destroy_listener.link); | ||||
| 	wl_list_remove(&surface->surface_commit_listener.link); | ||||
|  | @ -206,98 +320,11 @@ 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, | ||||
| 	.axis = xdg_pointer_grab_axis, | ||||
| }; | ||||
| 
 | ||||
| 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) { | ||||
| 	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, | ||||
|  | @ -310,7 +337,20 @@ static void xdg_popup_protocol_grab(struct wl_client *client, | |||
| 		xdg_shell_popup_grab_from_seat(surface->client->shell, | ||||
| 			handle->wlr_seat); | ||||
| 
 | ||||
| 	struct wlr_xdg_surface_v6 *topmost = xdg_popup_grab_get_topmost(popup_grab); | ||||
| 	bool parent_is_toplevel = | ||||
| 		surface->popup_state->parent->role == WLR_XDG_SURFACE_V6_ROLE_TOPLEVEL; | ||||
| 
 | ||||
| 	if ((topmost == NULL && !parent_is_toplevel) || | ||||
| 			(topmost != NULL && topmost != surface->popup_state->parent)) { | ||||
| 		wl_resource_post_error(surface->client->resource, | ||||
| 			ZXDG_SHELL_V6_ERROR_NOT_THE_TOPMOST_POPUP, | ||||
| 			"xdg_popup was not created on the topmost popup"); | ||||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	popup_grab->client = surface->client->client; | ||||
| 	surface->popup_state->seat = handle->wlr_seat; | ||||
| 
 | ||||
| 	wl_list_insert(&popup_grab->popups, &surface->popup_state->grab_link); | ||||
| 
 | ||||
|  | @ -423,10 +463,10 @@ static void xdg_surface_get_popup(struct wl_client *client, | |||
| 	} | ||||
| 
 | ||||
| 	surface->role = WLR_XDG_SURFACE_V6_ROLE_POPUP; | ||||
| 	surface->popup_state->base = surface; | ||||
| 	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); | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue