diff options
| -rw-r--r-- | include/rootston/cursor.h | 10 | ||||
| -rw-r--r-- | include/rootston/seat.h | 14 | ||||
| -rw-r--r-- | include/wlr/types/wlr_cursor.h | 7 | ||||
| -rw-r--r-- | include/wlr/types/wlr_data_device.h | 9 | ||||
| -rw-r--r-- | include/wlr/types/wlr_seat.h | 171 | ||||
| -rw-r--r-- | rootston/cursor.c | 219 | ||||
| -rw-r--r-- | rootston/output.c | 17 | ||||
| -rw-r--r-- | rootston/seat.c | 26 | ||||
| -rw-r--r-- | types/wlr_cursor.c | 18 | ||||
| -rw-r--r-- | types/wlr_data_device.c | 130 | ||||
| -rw-r--r-- | types/wlr_seat.c | 326 | 
11 files changed, 838 insertions, 109 deletions
| diff --git a/include/rootston/cursor.h b/include/rootston/cursor.h index f49b6439..f0c9be89 100644 --- a/include/rootston/cursor.h +++ b/include/rootston/cursor.h @@ -39,7 +39,6 @@ struct roots_cursor {  	uint32_t resize_edges;  	// Ring buffer of input events that could trigger move/resize/rotate  	int input_events_idx; -	struct wl_list touch_points;  	struct roots_input_event input_events[16];  	struct wl_listener motion; @@ -57,6 +56,9 @@ struct roots_cursor {  	struct wl_listener pointer_grab_begin;  	struct wl_listener pointer_grab_end; +	struct wl_listener touch_grab_begin; +	struct wl_listener touch_grab_end; +  	struct wl_listener request_set_cursor;  }; @@ -100,4 +102,10 @@ void roots_cursor_handle_pointer_grab_begin(struct roots_cursor *cursor,  void roots_cursor_handle_pointer_grab_end(struct roots_cursor *cursor,  		struct wlr_seat_pointer_grab *grab); +void roots_cursor_handle_touch_grab_begin(struct roots_cursor *cursor, +		struct wlr_seat_touch_grab *grab); + +void roots_cursor_handle_touch_grab_end(struct roots_cursor *cursor, +		struct wlr_seat_touch_grab *grab); +  #endif diff --git a/include/rootston/seat.h b/include/rootston/seat.h index bef515a4..aebd4399 100644 --- a/include/rootston/seat.h +++ b/include/rootston/seat.h @@ -9,6 +9,9 @@ struct roots_drag_icon {  	struct wl_list link; // roots_seat::drag_icons  	bool mapped; +	bool is_pointer; +	int32_t touch_id; +  	int32_t sx;  	int32_t sy; @@ -23,6 +26,10 @@ struct roots_seat {  	struct wl_list link;  	struct wl_list drag_icons; +	// coordinates of the first touch point if it exists +	int32_t touch_id; +	double touch_x, touch_y; +  	struct roots_view *focus;  	struct wl_list keyboards; @@ -43,13 +50,6 @@ struct roots_touch {  	struct wl_list link;  }; -struct roots_touch_point { -	struct roots_touch *device; -	int32_t slot; -	double x, y; -	struct wl_list link; -}; -  struct roots_tablet_tool {  	struct roots_seat *seat;  	struct wlr_input_device *device; diff --git a/include/wlr/types/wlr_cursor.h b/include/wlr/types/wlr_cursor.h index 0db32eb2..c73a4c8d 100644 --- a/include/wlr/types/wlr_cursor.h +++ b/include/wlr/types/wlr_cursor.h @@ -126,4 +126,11 @@ void wlr_cursor_map_to_region(struct wlr_cursor *cur, struct wlr_box *box);  void wlr_cursor_map_input_to_region(struct wlr_cursor *cur,  	struct wlr_input_device *dev, struct wlr_box *box); +/** + * Convert absolute coordinates to layout coordinates for the device. + */ +bool wlr_cursor_absolute_to_layout_coords(struct wlr_cursor *cur, +		struct wlr_input_device *device, double x_mm, double y_mm, +		double width_mm, double height_mm, double *lx, double *ly); +  #endif diff --git a/include/wlr/types/wlr_data_device.h b/include/wlr/types/wlr_data_device.h index f45c15a2..189ab59b 100644 --- a/include/wlr/types/wlr_data_device.h +++ b/include/wlr/types/wlr_data_device.h @@ -10,6 +10,9 @@ wlr_pointer_grab_interface wlr_data_device_pointer_drag_interface;  extern const struct  wlr_keyboard_grab_interface wlr_data_device_keyboard_drag_interface; +extern const struct +wlr_touch_grab_interface wlr_data_device_touch_drag_interface; +  struct wlr_data_device_manager {  	struct wl_global *global;  }; @@ -53,16 +56,22 @@ struct wlr_data_source {  struct wlr_drag {  	struct wlr_seat_pointer_grab pointer_grab;  	struct wlr_seat_keyboard_grab keyboard_grab; +	struct wlr_seat_touch_grab touch_grab; +	struct wlr_seat *seat;  	struct wlr_seat_client *seat_client;  	struct wlr_seat_client *focus_client; +	bool is_pointer_grab; +  	struct wlr_surface *icon;  	struct wlr_surface *focus;  	struct wlr_data_source *source;  	bool cancelling; +	int32_t grab_touch_id; +	struct wl_listener point_destroy;  	struct wl_listener icon_destroy;  	struct wl_listener source_destroy;  	struct wl_listener seat_client_unbound; diff --git a/include/wlr/types/wlr_seat.h b/include/wlr/types/wlr_seat.h index a5f00402..109e9be9 100644 --- a/include/wlr/types/wlr_seat.h +++ b/include/wlr/types/wlr_seat.h @@ -24,6 +24,26 @@ struct wlr_seat_client {  	struct wl_list link;  }; +struct wlr_touch_point { +	int32_t touch_id; +	struct wlr_surface *surface; +	struct wlr_seat_client *client; + +	struct wlr_surface *focus_surface; +	struct wlr_seat_client *focus_client; +	double sx, sy; + +	struct wl_listener surface_destroy; +	struct wl_listener focus_surface_destroy; +	struct wl_listener resource_destroy; + +	struct { +		struct wl_signal destroy; +	} events; + +	struct wl_list link; +}; +  struct wlr_seat_pointer_grab;  struct wlr_pointer_grab_interface { @@ -49,6 +69,32 @@ struct wlr_keyboard_grab_interface {  	void (*cancel)(struct wlr_seat_keyboard_grab *grab);  }; +struct wlr_seat_touch_grab; + +struct wlr_touch_grab_interface { +	void (*down)(struct wlr_seat_touch_grab *grab, uint32_t time, +			struct wlr_touch_point *point); +	void (*up)(struct wlr_seat_touch_grab *grab, uint32_t time, +			struct wlr_touch_point *point); +	void (*motion)(struct wlr_seat_touch_grab *grab, uint32_t time, +			struct wlr_touch_point *point); +	void (*enter)(struct wlr_seat_touch_grab *grab, uint32_t time, +			struct wlr_touch_point *point); +	// XXX this will conflict with the actual touch cancel which is different so +	// we need to rename this +	void (*cancel)(struct wlr_seat_touch_grab *grab); +}; + +/** + * Passed to `wlr_seat_touch_start_grab()` to start a grab of the touch device. + * The grabber is responsible for handling touch events for the seat. + */ +struct wlr_seat_touch_grab { +	const struct wlr_touch_grab_interface *interface; +	struct wlr_seat *seat; +	void *data; +}; +  /**   * 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. @@ -86,6 +132,7 @@ struct wlr_seat_pointer_state {  	struct wl_listener resource_destroy;  }; +// TODO: May be useful to be able to simulate keyboard input events  struct wlr_seat_keyboard_state {  	struct wlr_seat *seat;  	struct wlr_keyboard *keyboard; @@ -103,6 +150,17 @@ struct wlr_seat_keyboard_state {  	struct wlr_seat_keyboard_grab *default_grab;  }; +struct wlr_seat_touch_state { +	struct wlr_seat *seat; +	struct wl_list touch_points; // wlr_touch_point::link + +	uint32_t grab_serial; +	uint32_t grab_id; + +	struct wlr_seat_touch_grab *grab; +	struct wlr_seat_touch_grab *default_grab; +}; +  struct wlr_seat {  	struct wl_global *wl_global;  	struct wl_display *display; @@ -117,6 +175,7 @@ struct wlr_seat {  	struct wlr_seat_pointer_state pointer_state;  	struct wlr_seat_keyboard_state keyboard_state; +	struct wlr_seat_touch_state touch_state;  	struct wl_listener selection_data_source_destroy; @@ -130,6 +189,9 @@ struct wlr_seat {  		struct wl_signal keyboard_grab_begin;  		struct wl_signal keyboard_grab_end; +		struct wl_signal touch_grab_begin; +		struct wl_signal touch_grab_end; +  		struct wl_signal request_set_cursor;  		struct wl_signal selection; @@ -260,6 +322,11 @@ void wlr_seat_pointer_notify_axis(struct wlr_seat *wlr_seat, uint32_t time,  		enum wlr_axis_orientation orientation, double value);  /** + * Whether or not the pointer has a grab other than the default grab. + */ +bool wlr_seat_pointer_has_grab(struct wlr_seat *seat); + +/**   * Set this keyboard as the active keyboard for the seat.   */  void wlr_seat_set_keyboard(struct wlr_seat *seat, struct wlr_input_device *dev); @@ -326,6 +393,108 @@ void wlr_seat_keyboard_enter(struct wlr_seat *wlr_seat,   */  void wlr_seat_keyboard_clear_focus(struct wlr_seat *wlr_seat); -// TODO: May be useful to be able to simulate keyboard input events +/** + * Whether or not the keyboard has a grab other than the default grab + */ +bool wlr_seat_keyboard_has_grab(struct wlr_seat *seat); + +/** + * Start a grab of the touch device of this seat. The grabber is responsible for + * handling all touch events until the grab ends. + */ +void wlr_seat_touch_start_grab(struct wlr_seat *wlr_seat, +		struct wlr_seat_touch_grab *grab); + +/** + * End the grab of the touch device of this seat. This reverts the grab back to + * the default grab for the touch device. + */ +void wlr_seat_touch_end_grab(struct wlr_seat *wlr_seat); + +/** + * Get the active touch point with the given `touch_id`. If the touch point does + * not exist or is no longer active, returns NULL. + */ +struct wlr_touch_point *wlr_seat_touch_get_point(struct wlr_seat *seat, +		int32_t touch_id); + +/** + * Notify the seat of a touch down on the given surface. Defers to any grab of + * the touch device. + */ +void wlr_seat_touch_notify_down(struct wlr_seat *seat, +		struct wlr_surface *surface, uint32_t time, int32_t touch_id, double sx, +		double sy); + +/** + * Notify the seat that the touch point given by `touch_id` is up. Defers to any + * grab of the touch device. + */ +void wlr_seat_touch_notify_up(struct wlr_seat *seat, uint32_t time, +		int32_t touch_id); + +/** + * Notify the seat that the touch point given by `touch_id` has moved. Defers to + * any grab of the touch device. The seat should be notified of touch motion + * even if the surface is not the owner of the touch point for processing by + * grabs. + */ +void wlr_seat_touch_notify_motion(struct wlr_seat *seat, uint32_t time, +		int32_t touch_id, double sx, double sy); + +/** + * Notify the seat that the touch point given by `touch_id` has entered a new + * surface. The surface is required. To clear focus, use + * `wlr_seat_touch_point_clear_focus()`. + */ +void wlr_seat_touch_point_focus(struct wlr_seat *seat, +		struct wlr_surface *surface, uint32_t time, int32_t touch_id, double sx, +		double sy); + +/** + * Clear the focused surface for the touch point given by `touch_id`. + */ +void wlr_seat_touch_point_clear_focus(struct wlr_seat *seat, uint32_t time, +		int32_t touch_id); + +/** + * Send a touch down event to the client of the given surface. All future touch + * events for this point will go to this surface. If the touch down is valid, + * this will add a new touch point with the given `touch_id`. The touch down may + * not be valid if the surface seat client does not accept touch input. + * Coordinates are surface-local. Compositors should use + * `wlr_seat_touch_notify_down()` to respect any grabs of the touch device. + */ +void wlr_seat_touch_send_down(struct wlr_seat *seat, +		struct wlr_surface *surface, uint32_t time, int32_t touch_id, double sx, +		double sy); + +/** + * Send a touch up event for the touch point given by the `touch_id`. The event + * will go to the client for the surface given in the cooresponding touch down + * event. This will remove the touch point. Compositors should use + * `wlr_seat_touch_notify_up()` to respect any grabs of the touch device. + */ +void wlr_seat_touch_send_up(struct wlr_seat *seat, uint32_t time, +		int32_t touch_id); + +/** + * Send a touch motion event for the touch point given by the `touch_id`. The + * event will go to the client for the surface given in the corresponding touch + * down event. Compositors should use `wlr_seat_touch_notify_motion()` to + * respect any grabs of the touch device. + */ +void wlr_seat_touch_send_motion(struct wlr_seat *seat, uint32_t time, +		int32_t touch_id, double sx, double sy); + +/** + * How many touch points are currently down for the seat. + */ +int wlr_seat_touch_num_points(struct wlr_seat *seat); + +/** + * Whether or not the seat has a touch grab other than the default grab. + */ +bool wlr_seat_touch_has_grab(struct wlr_seat *seat);  #endif diff --git a/rootston/cursor.c b/rootston/cursor.c index 5949a364..35fe9c25 100644 --- a/rootston/cursor.c +++ b/rootston/cursor.c @@ -128,13 +128,14 @@ static void roots_cursor_update_position(struct roots_cursor *cursor, uint32_t t  static void roots_cursor_press_button(struct roots_cursor *cursor,  		struct wlr_input_device *device, uint32_t time, uint32_t button, -		uint32_t state) { +		uint32_t state, double lx, double ly) {  	struct roots_seat *seat = cursor->seat;  	struct roots_desktop *desktop = seat->input->server->desktop; +	bool is_touch = device->type == WLR_INPUT_DEVICE_TOUCH; +  	struct wlr_surface *surface;  	double sx, sy; -	struct roots_view *view = view_at(desktop, -		cursor->cursor->x, cursor->cursor->y, &surface, &sx, &sy); +	struct roots_view *view = view_at(desktop, lx, ly, &surface, &sx, &sy);  	if (state == WLR_BUTTON_PRESSED && view && roots_seat_has_meta_pressed(seat)) {  		roots_seat_focus_view(seat, view); @@ -165,14 +166,20 @@ static void roots_cursor_press_button(struct roots_cursor *cursor,  		return;  	} -	uint32_t serial = -		wlr_seat_pointer_notify_button(seat->seat, time, button, state); +	uint32_t serial; +	if (is_touch) { +		serial = wl_display_get_serial(desktop->server->wl_display); +	} else { +		serial = wlr_seat_pointer_notify_button(seat->seat, time, button, state); +	}  	int i;  	switch (state) {  	case WLR_BUTTON_RELEASED:  		seat->cursor->mode = ROOTS_CURSOR_PASSTHROUGH; -		roots_cursor_update_position(cursor, time); +		if (!is_touch) { +			roots_cursor_update_position(cursor, time); +		}  		break;  	case WLR_BUTTON_PRESSED:  		i = cursor->input_events_idx; @@ -203,7 +210,7 @@ void roots_cursor_handle_motion_absolute(struct roots_cursor *cursor,  void roots_cursor_handle_button(struct roots_cursor *cursor,  		struct wlr_event_pointer_button *event) {  	roots_cursor_press_button(cursor, event->device, event->time_msec, -		event->button, event->state); +		event->button, event->state, cursor->cursor->x, cursor->cursor->y);  }  void roots_cursor_handle_axis(struct roots_cursor *cursor, @@ -214,50 +221,83 @@ void roots_cursor_handle_axis(struct roots_cursor *cursor,  void roots_cursor_handle_touch_down(struct roots_cursor *cursor,  		struct wlr_event_touch_down *event) { -	struct roots_touch_point *point = -		calloc(1, sizeof(struct roots_touch_point)); -	if (!point) { -		wlr_log(L_ERROR, "could not allocate memory for touch point"); +	struct roots_desktop *desktop = cursor->seat->input->server->desktop; +	struct wlr_surface *surface = NULL; +	double lx, ly; +	bool result = +		wlr_cursor_absolute_to_layout_coords(cursor->cursor, +			event->device, event->x_mm, event->y_mm, event->width_mm, +			event->height_mm, &lx, &ly); +	if (!result) {  		return;  	} +	double sx, sy; +	view_at(desktop, lx, ly, &surface, &sx, &sy); -	point->device = event->device->data; -	point->slot = event->slot; -	point->x = event->x_mm / event->width_mm; -	point->y = event->y_mm / event->height_mm; -	wlr_cursor_warp_absolute(cursor->cursor, event->device, point->x, point->y); -	roots_cursor_update_position(cursor, event->time_msec); -	wl_list_insert(&cursor->touch_points, &point->link); -	roots_cursor_press_button(cursor,  event->device, -		event->time_msec, BTN_LEFT, 1); +	if (surface) { +		wlr_seat_touch_notify_down(cursor->seat->seat, surface, +			event->time_msec, event->slot, sx, sy); +	} + +	if (wlr_seat_touch_num_points(cursor->seat->seat) == 1) { +		cursor->seat->touch_id = event->slot; +		cursor->seat->touch_x = lx; +		cursor->seat->touch_y = ly; +		roots_cursor_press_button(cursor, event->device, event->time_msec, +			BTN_LEFT, 1, lx, ly); +	}  }  void roots_cursor_handle_touch_up(struct roots_cursor *cursor,  		struct wlr_event_touch_up *event) { -	struct roots_touch_point *point; -	wl_list_for_each(point, &cursor->touch_points, link) { -		if (point->slot == event->slot) { -			wl_list_remove(&point->link); -			free(point); -			break; -		} +	struct wlr_touch_point *point = wlr_seat_touch_get_point(cursor->seat->seat, event->slot); +	if (!point) { +		return;  	} -	roots_cursor_press_button(cursor, event->device, -		event->time_msec, BTN_LEFT, 0); + +	if (wlr_seat_touch_num_points(cursor->seat->seat) == 1) { +		roots_cursor_press_button(cursor, event->device, event->time_msec, +			BTN_LEFT, 0, cursor->seat->touch_x, cursor->seat->touch_y); +	} + +	wlr_seat_touch_notify_up(cursor->seat->seat, event->time_msec, event->slot);  }  void roots_cursor_handle_touch_motion(struct roots_cursor *cursor,  		struct wlr_event_touch_motion *event) { -	struct roots_touch_point *point; -	wl_list_for_each(point, &cursor->touch_points, link) { -		if (point->slot == event->slot) { -			point->x = event->x_mm / event->width_mm; -			point->y = event->y_mm / event->height_mm; -			wlr_cursor_warp_absolute(cursor->cursor, event->device, -					point->x, point->y); -			roots_cursor_update_position(cursor, event->time_msec); -			break; -		} +	struct roots_desktop *desktop = cursor->seat->input->server->desktop; +	struct wlr_touch_point *point = +		wlr_seat_touch_get_point(cursor->seat->seat, event->slot); +	if (!point) { +		return; +	} + +	struct wlr_surface *surface = NULL; +	double lx, ly; +	bool result = +		wlr_cursor_absolute_to_layout_coords(cursor->cursor, +			event->device, event->x_mm, event->y_mm, event->width_mm, +			event->height_mm, &lx, &ly); +	if (!result) { +		return; +	} + +	double sx, sy; +	view_at(desktop, lx, ly, &surface, &sx, &sy); + +	if (surface) { +		wlr_seat_touch_point_focus(cursor->seat->seat, surface, +			event->time_msec, event->slot, sx, sy); +		wlr_seat_touch_notify_motion(cursor->seat->seat, event->time_msec, +			event->slot, sx, sy); +	} else { +		wlr_seat_touch_point_clear_focus(cursor->seat->seat, event->time_msec, +			event->slot); +	} + +	if (event->slot == cursor->seat->touch_id) { +		cursor->seat->touch_x = lx; +		cursor->seat->touch_y = ly;  	}  } @@ -282,7 +322,8 @@ void roots_cursor_handle_tool_axis(struct roots_cursor *cursor,  void roots_cursor_handle_tool_tip(struct roots_cursor *cursor,  		struct wlr_event_tablet_tool_tip *event) {  	roots_cursor_press_button(cursor, event->device, -		event->time_msec, BTN_LEFT, event->state); +		event->time_msec, BTN_LEFT, event->state, cursor->cursor->x, +		cursor->cursor->y);  }  void roots_cursor_handle_request_set_cursor(struct roots_cursor *cursor, @@ -322,33 +363,59 @@ static void handle_drag_icon_destroy(struct wl_listener *listener, void *data) {  	free(drag_icon);  } +static struct roots_drag_icon *seat_add_drag_icon(struct roots_seat *seat, +		struct wlr_surface *icon_surface) { +	if (!icon_surface) { +		return NULL; +	} + +	struct roots_drag_icon *iter_icon; +	wl_list_for_each(iter_icon, &seat->drag_icons, link) { +		if (iter_icon->surface == icon_surface) { +			// already in the list +			return iter_icon; +		} +	} + +	struct roots_drag_icon *drag_icon = +		calloc(1, sizeof(struct roots_drag_icon)); +	drag_icon->mapped = true; +	drag_icon->surface = icon_surface; +	wl_list_insert(&seat->drag_icons, &drag_icon->link); + +	wl_signal_add(&icon_surface->events.destroy, +			&drag_icon->surface_destroy); +	drag_icon->surface_destroy.notify = handle_drag_icon_destroy; + +	wl_signal_add(&icon_surface->events.commit, +			&drag_icon->surface_commit); +	drag_icon->surface_commit.notify = handle_drag_icon_commit; + +	return drag_icon; +} + +static void seat_unmap_drag_icon(struct roots_seat *seat, +		struct wlr_surface *icon_surface) { +	if (!icon_surface) { +		return; +	} + +	struct roots_drag_icon *icon; +	wl_list_for_each(icon, &seat->drag_icons, link) { +		if (icon->surface == icon_surface) { +			icon->mapped = false; +		} +	} +} +  void roots_cursor_handle_pointer_grab_begin(struct roots_cursor *cursor,  		struct wlr_seat_pointer_grab *grab) { -	struct roots_seat *seat = cursor->seat;  	if (grab->interface == &wlr_data_device_pointer_drag_interface) {  		struct wlr_drag *drag = grab->data; -		if (drag->icon) { -			struct roots_drag_icon *iter_icon; -			wl_list_for_each(iter_icon, &seat->drag_icons, link) { -				if (iter_icon->surface == drag->icon) { -					// already in the list -					return; -				} -			} - -			struct roots_drag_icon *drag_icon = -				calloc(1, sizeof(struct roots_drag_icon)); -			drag_icon->mapped = true; -			drag_icon->surface = drag->icon; -			wl_list_insert(&seat->drag_icons, &drag_icon->link); - -			wl_signal_add(&drag->icon->events.destroy, -				&drag_icon->surface_destroy); -			drag_icon->surface_destroy.notify = handle_drag_icon_destroy; - -			wl_signal_add(&drag->icon->events.commit, -				&drag_icon->surface_commit); -			drag_icon->surface_commit.notify = handle_drag_icon_commit; +		struct roots_drag_icon *icon = +			seat_add_drag_icon(cursor->seat, drag->icon); +		if (icon) { +			icon->is_pointer = true;  		}  	}  } @@ -357,13 +424,27 @@ void roots_cursor_handle_pointer_grab_end(struct roots_cursor *cursor,  		struct wlr_seat_pointer_grab *grab) {  	if (grab->interface == &wlr_data_device_pointer_drag_interface) {  		struct wlr_drag *drag = grab->data; -		struct roots_drag_icon *icon; -		wl_list_for_each(icon, &cursor->seat->drag_icons, link) { -			if (icon->surface == drag->icon) { -				icon->mapped = false; -			} +		seat_unmap_drag_icon(cursor->seat, drag->icon); +	} +} + +void roots_cursor_handle_touch_grab_begin(struct roots_cursor *cursor, +		struct wlr_seat_touch_grab *grab) { +	if (grab->interface == &wlr_data_device_touch_drag_interface) { +		struct wlr_drag *drag = grab->data; +		struct roots_drag_icon *icon = +			seat_add_drag_icon(cursor->seat, drag->icon); +		if (icon) { +			icon->is_pointer = false; +			icon->touch_id = drag->grab_touch_id;  		}  	} +} -	roots_cursor_update_position(cursor, 0); +void roots_cursor_handle_touch_grab_end(struct roots_cursor *cursor, +		struct wlr_seat_touch_grab *grab) { +	if (grab->interface == &wlr_data_device_touch_drag_interface) { +		struct wlr_drag *drag = grab->data; +		seat_unmap_drag_icon(cursor->seat, drag->icon); +	}  } diff --git a/rootston/output.c b/rootston/output.c index 28312c2c..6c8f2519 100644 --- a/rootston/output.c +++ b/rootston/output.c @@ -200,9 +200,20 @@ static void output_frame_notify(struct wl_listener *listener, void *data) {  			}  			struct wlr_surface *icon = drag_icon->surface;  			struct wlr_cursor *cursor = seat->cursor->cursor; -			double icon_x = cursor->x + drag_icon->sx; -			double icon_y = cursor->y + drag_icon->sy; -			render_surface(icon, desktop, wlr_output, &now, icon_x, icon_y, 0); +			double icon_x = 0, icon_y = 0; +			if (drag_icon->is_pointer) { +				icon_x = cursor->x + drag_icon->sx; +				icon_y = cursor->y + drag_icon->sy; +				render_surface(icon, desktop, wlr_output, &now, icon_x, icon_y, 0); +			} else { +				struct wlr_touch_point *point = +					wlr_seat_touch_get_point(seat->seat, drag_icon->touch_id); +				if (point) { +					icon_x = seat->touch_x + drag_icon->sx; +					icon_y = seat->touch_y + drag_icon->sy; +					render_surface(icon, desktop, wlr_output, &now, icon_x, icon_y, 0); +				} +			}  		}  	} diff --git a/rootston/seat.c b/rootston/seat.c index 1fa37c44..b92643ad 100644 --- a/rootston/seat.c +++ b/rootston/seat.c @@ -111,6 +111,22 @@ static void handle_pointer_grab_end(struct wl_listener *listener,  	roots_cursor_handle_pointer_grab_end(cursor, grab);  } +static void handle_touch_grab_begin(struct wl_listener *listener, +		void *data) { +	struct roots_cursor *cursor = +		wl_container_of(listener, cursor, touch_grab_begin); +	struct wlr_seat_touch_grab *grab = data; +	roots_cursor_handle_touch_grab_begin(cursor, grab); +} + +static void handle_touch_grab_end(struct wl_listener *listener, +		void *data) { +	struct roots_cursor *cursor = +		wl_container_of(listener, cursor, touch_grab_end); +	struct wlr_seat_touch_grab *grab = data; +	roots_cursor_handle_touch_grab_end(cursor, grab); +} +  static void seat_reset_device_mappings(struct roots_seat *seat, struct wlr_input_device *device) {  	struct wlr_cursor *cursor = seat->cursor->cursor;  	struct roots_config *config = seat->input->config; @@ -188,8 +204,6 @@ static void roots_seat_init_cursor(struct roots_seat *seat) {  	// TODO: be able to configure per-seat cursor themes  	seat->cursor->xcursor_manager = desktop->xcursor_manager; -	wl_list_init(&seat->cursor->touch_points); -  	roots_seat_configure_cursor(seat);  	roots_seat_configure_xcursor(seat); @@ -233,6 +247,14 @@ static void roots_seat_init_cursor(struct roots_seat *seat) {  	wl_signal_add(&seat->seat->events.pointer_grab_end,  			&seat->cursor->pointer_grab_end);  	seat->cursor->pointer_grab_end.notify = handle_pointer_grab_end; + +	wl_signal_add(&seat->seat->events.touch_grab_begin, +			&seat->cursor->touch_grab_begin); +	seat->cursor->touch_grab_begin.notify = handle_touch_grab_begin; + +	wl_signal_add(&seat->seat->events.touch_grab_end, +			&seat->cursor->touch_grab_end); +	seat->cursor->touch_grab_end.notify = handle_touch_grab_end;  }  struct roots_seat *roots_seat_create(struct roots_input *input, char *name) { diff --git a/types/wlr_cursor.c b/types/wlr_cursor.c index e8965b68..ec66f7c7 100644 --- a/types/wlr_cursor.c +++ b/types/wlr_cursor.c @@ -637,3 +637,21 @@ void wlr_cursor_map_input_to_region(struct wlr_cursor *cur,  	c_device->mapped_box = box;  } + +bool wlr_cursor_absolute_to_layout_coords(struct wlr_cursor *cur, +		struct wlr_input_device *device, double x_mm, double y_mm, +		double width_mm, double height_mm, double *lx, double *ly) { +	if (width_mm <= 0 || height_mm <= 0) { +		return false; +	} + +	struct wlr_box *mapping = get_mapping(cur, device); +	if (!mapping) { +		mapping = wlr_output_layout_get_box(cur->state->layout, NULL); +	} + +	*lx = x_mm > 0 ? mapping->width * (x_mm / width_mm) + mapping->x : cur->x; +	*ly = y_mm > 0 ? mapping->height * (y_mm / height_mm) + mapping->y : cur->y; + +	return true; +} diff --git a/types/wlr_data_device.c b/types/wlr_data_device.c index 4d926236..999faa22 100644 --- a/types/wlr_data_device.c +++ b/types/wlr_data_device.c @@ -275,7 +275,8 @@ void wlr_seat_client_send_selection(struct wlr_seat_client *seat_client) {  		struct wlr_data_offer *offer =  			wlr_data_source_send_offer(seat_client->seat->selection_source,  				seat_client->data_device); -		wl_data_device_send_selection(seat_client->data_device, offer->resource); +		wl_data_device_send_selection(seat_client->data_device, +			offer->resource);  	} else {  		wl_data_device_send_selection(seat_client->data_device, NULL);  	} @@ -437,8 +438,12 @@ static void wlr_drag_set_focus(struct wlr_drag *drag,  static void wlr_drag_end(struct wlr_drag *drag) {  	if (!drag->cancelling) {  		drag->cancelling = true; -		wlr_seat_pointer_end_grab(drag->pointer_grab.seat); -		wlr_seat_keyboard_end_grab(drag->keyboard_grab.seat); +		if (drag->is_pointer_grab) { +			wlr_seat_pointer_end_grab(drag->seat); +		} else { +			wlr_seat_touch_end_grab(drag->seat); +		} +		wlr_seat_keyboard_end_grab(drag->seat);  		if (drag->source) {  			wl_list_remove(&drag->source_destroy.link); @@ -521,6 +526,53 @@ wlr_pointer_grab_interface wlr_data_device_pointer_drag_interface = {  	.cancel = pointer_drag_cancel,  }; +static void touch_drag_down(struct wlr_seat_touch_grab *grab, +		uint32_t time, struct wlr_touch_point *point) { +	// eat the event +} + +static void touch_drag_up(struct wlr_seat_touch_grab *grab, uint32_t time, +		struct wlr_touch_point *point) { +	struct wlr_drag *drag = grab->data; +	if (drag->grab_touch_id != point->touch_id) { +		return; +	} + +	if (drag->focus_client && drag->focus_client->data_device) { +		wl_data_device_send_drop(drag->focus_client->data_device); +	} + +	wlr_drag_end(drag); +} + +static void touch_drag_motion(struct wlr_seat_touch_grab *grab, uint32_t time, +		struct wlr_touch_point *point) { +	struct wlr_drag *drag = grab->data; +	if (drag->focus && drag->focus_client && drag->focus_client->data_device) { +		wl_data_device_send_motion(drag->focus_client->data_device, time, +			wl_fixed_from_double(point->sx), wl_fixed_from_double(point->sy)); +	} +} + +static void touch_drag_enter(struct wlr_seat_touch_grab *grab, uint32_t time, +		struct wlr_touch_point *point) { +	struct wlr_drag *drag = grab->data; +	wlr_drag_set_focus(drag, point->focus_surface, point->sx, point->sy); +} + +static void touch_drag_cancel(struct wlr_seat_touch_grab *grab) { +	struct wlr_drag *drag = grab->data; +	wlr_drag_end(drag); +} + +const struct wlr_touch_grab_interface wlr_data_device_touch_drag_interface = { +	.down = touch_drag_down, +	.up = touch_drag_up, +	.motion = touch_drag_motion, +	.enter = touch_drag_enter, +	.cancel = touch_drag_cancel, +}; +  static void keyboard_drag_enter(struct wlr_seat_keyboard_grab *grab,  		struct wlr_surface *surface) {  	// nothing has keyboard focus during drags @@ -562,13 +614,38 @@ static void drag_handle_drag_source_destroy(struct wl_listener *listener,  }  static bool seat_client_start_drag(struct wlr_seat_client *client, -		struct wlr_data_source *source, struct wlr_surface *icon) { +		struct wlr_data_source *source, struct wlr_surface *icon, +		struct wlr_surface *origin, uint32_t serial) {  	struct wlr_drag *drag = calloc(1, sizeof(struct wlr_drag));  	if (drag == NULL) {  		return false;  	} -	struct wlr_seat *seat = client->seat; +	drag->seat = client->seat; + +	drag->is_pointer_grab = client->pointer != NULL && +		client->seat->pointer_state.button_count == 1 && +		client->seat->pointer_state.grab_serial == serial && +		client->seat->pointer_state.focused_surface && +		client->seat->pointer_state.focused_surface == origin; + +	bool is_touch_grab = client->touch && +		wl_list_length(&client->seat->touch_state.touch_points) == 1 && +		client->seat->touch_state.grab_serial == serial; + +	struct wlr_touch_point *point = NULL; +	if (is_touch_grab) { +		wl_list_for_each(point, &client->seat->touch_state.touch_points, link) { +			if (point->surface && point->surface == origin) { +				is_touch_grab = true; +			} +			break; +		} +	} + +	if (!drag->is_pointer_grab && !is_touch_grab) { +		return true; +	}  	if (icon) {  		drag->icon = icon; @@ -587,13 +664,22 @@ static bool seat_client_start_drag(struct wlr_seat_client *client,  	drag->pointer_grab.data = drag;  	drag->pointer_grab.interface = &wlr_data_device_pointer_drag_interface; +	drag->touch_grab.data = drag; +	drag->touch_grab.interface = &wlr_data_device_touch_drag_interface; +	drag->grab_touch_id = drag->seat->touch_state.grab_id; +  	drag->keyboard_grab.data = drag;  	drag->keyboard_grab.interface = &wlr_data_device_keyboard_drag_interface; -	wlr_seat_pointer_clear_focus(seat); +	wlr_seat_keyboard_start_grab(drag->seat, &drag->keyboard_grab); -	wlr_seat_keyboard_start_grab(seat, &drag->keyboard_grab); -	wlr_seat_pointer_start_grab(seat, &drag->pointer_grab); +	if (drag->is_pointer_grab) { +		wlr_seat_pointer_clear_focus(drag->seat); +		wlr_seat_pointer_start_grab(drag->seat, &drag->pointer_grab); +	} else { +		wlr_seat_touch_start_grab(drag->seat, &drag->touch_grab); +		wlr_drag_set_focus(drag, point->surface, point->sx, point->sy); +	}  	return true;  } @@ -603,21 +689,12 @@ static void data_device_start_drag(struct wl_client *client,  		struct wl_resource *source_resource,  		struct wl_resource *origin_resource, struct wl_resource *icon_resource,  		uint32_t serial) { -	struct wlr_seat_client *seat_client = wl_resource_get_user_data(device_resource); -	struct wlr_seat *seat = seat_client->seat; +	struct wlr_seat_client *seat_client = +		wl_resource_get_user_data(device_resource);  	struct wlr_surface *origin = wl_resource_get_user_data(origin_resource);  	struct wlr_data_source *source = NULL;  	struct wlr_surface *icon = NULL; -	bool is_pointer_grab = seat->pointer_state.button_count == 1 && -		seat->pointer_state.grab_serial == serial && -		seat->pointer_state.focused_surface && -		seat->pointer_state.focused_surface == origin; - -	if (!is_pointer_grab) { -		return; -	} -  	if (source_resource) {  		source = wl_resource_get_user_data(source_resource);  	} @@ -634,7 +711,7 @@ static void data_device_start_drag(struct wl_client *client,  	// TODO touch grab -	if (!seat_client_start_drag(seat_client, source, icon)) { +	if (!seat_client_start_drag(seat_client, source, icon, origin, serial)) {  		wl_resource_post_no_memory(device_resource);  		return;  	} @@ -653,7 +730,8 @@ static const struct wl_data_device_interface data_device_impl = {  void data_device_manager_get_data_device(struct wl_client *client,  		struct wl_resource *manager_resource, uint32_t id,  		struct wl_resource *seat_resource) { -	struct wlr_seat_client *seat_client = wl_resource_get_user_data(seat_resource); +	struct wlr_seat_client *seat_client = +		wl_resource_get_user_data(seat_resource);  	struct wl_resource *resource =  		wl_resource_create(client, @@ -820,9 +898,9 @@ struct wlr_data_device_manager *wlr_data_device_manager_create(  }  void wlr_data_device_manager_destroy(struct wlr_data_device_manager *manager) { -  if (!manager) { -    return; -  } -  wl_global_destroy(manager->global); -  free(manager); +	if (!manager) { +		return; +	} +	wl_global_destroy(manager->global); +	free(manager);  } diff --git a/types/wlr_seat.c b/types/wlr_seat.c index dad88354..c37611b3 100644 --- a/types/wlr_seat.c +++ b/types/wlr_seat.c @@ -300,12 +300,50 @@ static const struct wlr_keyboard_grab_interface default_keyboard_grab_impl = {  	.cancel = default_keyboard_cancel,  }; +static void default_touch_down(struct wlr_seat_touch_grab *grab, uint32_t time, +		struct wlr_touch_point *point) { +	wlr_seat_touch_send_down(grab->seat, point->surface, time, point->touch_id, +		point->sx, point->sy); +} + +static void default_touch_up(struct wlr_seat_touch_grab *grab, uint32_t time, +		struct wlr_touch_point *point) { +	wlr_seat_touch_send_up(grab->seat, time, point->touch_id); +} + +static void default_touch_motion(struct wlr_seat_touch_grab *grab, +		uint32_t time, struct wlr_touch_point *point) { +	if (!point->focus_surface || point->focus_surface == point->surface) { +		wlr_seat_touch_send_motion(grab->seat, time, point->touch_id, point->sx, +			point->sy); +	} +} + +static void default_touch_enter(struct wlr_seat_touch_grab *grab, +		uint32_t time, struct wlr_touch_point *point) { +	// not handled by default +} + +static void default_touch_cancel(struct wlr_seat_touch_grab *grab) { +	// cannot be cancelled +} + +static const struct wlr_touch_grab_interface default_touch_grab_impl = { +	.down = default_touch_down, +	.up = default_touch_up, +	.motion = default_touch_motion, +	.enter = default_touch_enter, +	.cancel = default_touch_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) {  		return NULL;  	} +	// pointer state  	wlr_seat->pointer_state.seat = wlr_seat;  	wl_list_init(&wlr_seat->pointer_state.surface_destroy.link);  	wl_list_init(&wlr_seat->pointer_state.resource_destroy.link); @@ -321,6 +359,7 @@ struct wlr_seat *wlr_seat_create(struct wl_display *display, const char *name) {  	wlr_seat->pointer_state.default_grab = pointer_grab;  	wlr_seat->pointer_state.grab = pointer_grab; +	// keyboard state  	struct wlr_seat_keyboard_grab *keyboard_grab =  		calloc(1, sizeof(struct wlr_seat_keyboard_grab));  	if (!keyboard_grab) { @@ -338,6 +377,23 @@ struct wlr_seat *wlr_seat_create(struct wl_display *display, const char *name) {  	wl_list_init(  		&wlr_seat->keyboard_state.surface_destroy.link); +	// touch state +	struct wlr_seat_touch_grab *touch_grab = +		calloc(1, sizeof(struct wlr_seat_touch_grab)); +	if (!touch_grab) { +		free(pointer_grab); +		free(keyboard_grab); +		free(wlr_seat); +		return NULL; +	} +	touch_grab->interface = &default_touch_grab_impl; +	touch_grab->seat = wlr_seat; +	wlr_seat->touch_state.default_grab = touch_grab; +	wlr_seat->touch_state.grab = touch_grab; + +	wlr_seat->touch_state.seat = wlr_seat; +	wl_list_init(&wlr_seat->touch_state.touch_points); +  	struct wl_global *wl_global = wl_global_create(display,  		&wl_seat_interface, 6, wlr_seat, wl_seat_bind);  	if (!wl_global) { @@ -361,6 +417,9 @@ struct wlr_seat *wlr_seat_create(struct wl_display *display, const char *name) {  	wl_signal_init(&wlr_seat->events.keyboard_grab_begin);  	wl_signal_init(&wlr_seat->events.keyboard_grab_end); +	wl_signal_init(&wlr_seat->events.touch_grab_begin); +	wl_signal_init(&wlr_seat->events.touch_grab_end); +  	return wlr_seat;  } @@ -378,6 +437,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->touch_state.default_grab);  	free(wlr_seat->data_device);  	free(wlr_seat->name);  	free(wlr_seat); @@ -550,7 +610,9 @@ void wlr_seat_pointer_send_axis(struct wlr_seat *wlr_seat, uint32_t time,  void wlr_seat_pointer_start_grab(struct wlr_seat *wlr_seat,  		struct wlr_seat_pointer_grab *grab) { +	assert(wlr_seat);  	grab->seat = wlr_seat; +	assert(grab->seat);  	wlr_seat->pointer_state.grab = grab;  	wl_signal_emit(&wlr_seat->events.pointer_grab_begin, grab); @@ -610,6 +672,10 @@ void wlr_seat_pointer_notify_axis(struct wlr_seat *wlr_seat, uint32_t time,  	grab->interface->axis(grab, time, orientation, value);  } +bool wlr_seat_pointer_has_grab(struct wlr_seat *seat) { +	return seat->pointer_state.grab->interface != &default_pointer_grab_impl; +} +  void wlr_seat_keyboard_send_key(struct wlr_seat *wlr_seat, uint32_t time,  		uint32_t key, uint32_t state) {  	struct wlr_seat_client *client = wlr_seat->keyboard_state.focused_client; @@ -807,6 +873,10 @@ void wlr_seat_keyboard_clear_focus(struct wlr_seat *seat) {  	wlr_seat_keyboard_enter(seat, NULL);  } +bool wlr_seat_keyboard_has_grab(struct wlr_seat *seat) { +	return seat->keyboard_state.grab->interface != &default_keyboard_grab_impl; +} +  void wlr_seat_keyboard_notify_modifiers(struct wlr_seat *seat) {  	clock_gettime(CLOCK_MONOTONIC, &seat->last_event);  	struct wlr_seat_keyboard_grab *grab = seat->keyboard_state.grab; @@ -819,3 +889,259 @@ void wlr_seat_keyboard_notify_key(struct wlr_seat *seat, uint32_t time,  	struct wlr_seat_keyboard_grab *grab = seat->keyboard_state.grab;  	grab->interface->key(grab, time, key, state);  } + +void wlr_seat_touch_start_grab(struct wlr_seat *wlr_seat, +		struct wlr_seat_touch_grab *grab) { +	grab->seat = wlr_seat; +	wlr_seat->touch_state.grab = grab; + +	wl_signal_emit(&wlr_seat->events.touch_grab_begin, grab); +} + +void wlr_seat_touch_end_grab(struct wlr_seat *wlr_seat) { +	struct wlr_seat_touch_grab *grab = wlr_seat->touch_state.grab; + +	if (grab != wlr_seat->touch_state.default_grab) { +		wlr_seat->touch_state.grab = wlr_seat->touch_state.default_grab; +		wl_signal_emit(&wlr_seat->events.touch_grab_end, grab); +		if (grab->interface->cancel) { +			grab->interface->cancel(grab); +		} +	} +} + +static void touch_point_destroy(struct wlr_touch_point *point) { +	wl_signal_emit(&point->events.destroy, point); +	wl_list_remove(&point->surface_destroy.link); +	wl_list_remove(&point->resource_destroy.link); +	wl_list_remove(&point->link); +	free(point); +} +static void handle_touch_point_resource_destroy(struct wl_listener *listener, +		void *data) { +	struct wlr_touch_point *point = +		wl_container_of(listener, point, resource_destroy); +	touch_point_destroy(point); +} + +static void handle_touch_point_surface_destroy(struct wl_listener *listener, +		void *data) { +	struct wlr_touch_point *point = +		wl_container_of(listener, point, surface_destroy); +	touch_point_destroy(point); +} + +static struct wlr_touch_point *touch_point_create( +		struct wlr_seat *seat, int32_t touch_id, +		struct wlr_surface *surface, double sx, double sy) { +	struct wl_client *wl_client = wl_resource_get_client(surface->resource); +	struct wlr_seat_client *client = wlr_seat_client_for_wl_client(seat, wl_client); + +	if (!client || !client->touch) { +		// touch points are not valid without a connected client with touch +		return NULL; +	} + +	struct wlr_touch_point *point = calloc(1, sizeof(struct wlr_touch_point)); +	if (!point) { +		return NULL; +	} + +	point->touch_id = touch_id; +	point->surface = surface; +	point->client = client; + +	point->sx = sx; +	point->sy = sy; + +	wl_signal_init(&point->events.destroy); + +	wl_signal_add(&surface->events.destroy, &point->surface_destroy); +	point->surface_destroy.notify = handle_touch_point_surface_destroy; +	wl_resource_add_destroy_listener(surface->resource, +		&point->resource_destroy); +	point->resource_destroy.notify = handle_touch_point_resource_destroy; + +	wl_list_insert(&seat->touch_state.touch_points, &point->link); + +	return point; +} + +struct wlr_touch_point *wlr_seat_touch_get_point( +		struct wlr_seat *seat, int32_t touch_id) { +	struct wlr_touch_point *point = NULL; +	wl_list_for_each(point, &seat->touch_state.touch_points, link) { +		if (point->touch_id == touch_id) { +			return point; +		} +	} + +	return NULL; +} + +void wlr_seat_touch_notify_down(struct wlr_seat *seat, +		struct wlr_surface *surface, uint32_t time, int32_t touch_id, double sx, +		double sy) { +	clock_gettime(CLOCK_MONOTONIC, &seat->last_event); +	struct wlr_seat_touch_grab *grab = seat->touch_state.grab; +	struct wlr_touch_point *point = +		touch_point_create(seat, touch_id, surface, sx, sy); +	if (!point) { +		wlr_log(L_ERROR, "could not create touch point"); +		return; +	} + +	grab->interface->down(grab, time, point); + +	if (wl_list_length(&seat->touch_state.touch_points) == 1) { +		seat->touch_state.grab_serial = wl_display_get_serial(seat->display); +		seat->touch_state.grab_id = touch_id; +	} +} + +void wlr_seat_touch_notify_up(struct wlr_seat *seat, uint32_t time, +		int32_t touch_id) { +	clock_gettime(CLOCK_MONOTONIC, &seat->last_event); +	struct wlr_seat_touch_grab *grab = seat->touch_state.grab; +	struct wlr_touch_point *point = wlr_seat_touch_get_point(seat, touch_id); +	if (!point) { +		wlr_log(L_ERROR, "got touch up for unknown touch point"); +		return; +	} + +	grab->interface->up(grab, time, point); + +	touch_point_destroy(point); +} + +void wlr_seat_touch_notify_motion(struct wlr_seat *seat, uint32_t time, +		int32_t touch_id, double sx, double sy) { +	clock_gettime(CLOCK_MONOTONIC, &seat->last_event); +	struct wlr_seat_touch_grab *grab = seat->touch_state.grab; +	struct wlr_touch_point *point = wlr_seat_touch_get_point(seat, touch_id); +	if (!point) { +		wlr_log(L_ERROR, "got touch motion for unknown touch point"); +		return; +	} + +	point->sx = sx; +	point->sy = sy; + +	grab->interface->motion(grab, time, point); +} + +static void touch_point_clear_focus(struct wlr_touch_point *point) { +	if (point->focus_surface) { +		wl_list_remove(&point->focus_surface_destroy.link); +		point->focus_client = NULL; +		point->focus_surface = NULL; +	} +} + +static void handle_point_focus_destroy(struct wl_listener *listener, +		void *data) { +	struct wlr_touch_point *point = +		wl_container_of(listener, point, focus_surface_destroy); +	touch_point_clear_focus(point); +} + +static void touch_point_set_focus(struct wlr_touch_point *point, +		struct wlr_surface *surface, double sx, double sy) { +	if (point->focus_surface == surface) { +		return; +	} + +	touch_point_clear_focus(point); + +	if (surface && surface->resource) { +		struct wlr_seat_client *client = +			wlr_seat_client_for_wl_client(point->client->seat, +				wl_resource_get_client(surface->resource)); + +		if (client && client->touch) { +			wl_signal_add(&surface->events.destroy, &point->focus_surface_destroy); +			point->focus_surface_destroy.notify = handle_point_focus_destroy; +			point->focus_surface = surface; +			point->focus_client = client; +			point->sx = sx; +			point->sy = sy; +		} +	} +} + +void wlr_seat_touch_point_focus(struct wlr_seat *seat, +		struct wlr_surface *surface, uint32_t time, int32_t touch_id, double sx, +		double sy) { +	assert(surface); +	struct wlr_touch_point *point = wlr_seat_touch_get_point(seat, touch_id); +	if (!point) { +		wlr_log(L_ERROR, "got touch point focus for unknown touch point"); +		return; +	} +	struct wlr_surface *focus = point->focus_surface; +	touch_point_set_focus(point, surface, sx, sy); + +	if (focus != point->focus_surface) { +		struct wlr_seat_touch_grab *grab = seat->touch_state.grab; +		grab->interface->enter(grab, time, point); +	} +} + +void wlr_seat_touch_point_clear_focus(struct wlr_seat *seat, uint32_t time, +		int32_t touch_id) { +	struct wlr_touch_point *point = wlr_seat_touch_get_point(seat, touch_id); +	if (!point) { +		wlr_log(L_ERROR, "got touch point focus for unknown touch point"); +		return; +	} + +	touch_point_set_focus(point, NULL, 0, 0); +} + +void wlr_seat_touch_send_down(struct wlr_seat *seat, +		struct wlr_surface *surface, uint32_t time, int32_t touch_id, double sx, +		double sy) { +	struct wlr_touch_point *point = wlr_seat_touch_get_point(seat, touch_id); +	if (!point) { +		wlr_log(L_ERROR, "got touch down for unknown touch point"); +		return; +	} + +	uint32_t serial = wl_display_next_serial(seat->display); +	wl_touch_send_down(point->client->touch, serial, time, surface->resource, +		touch_id, wl_fixed_from_double(sx), wl_fixed_from_double(sy)); +	wl_touch_send_frame(point->client->touch); +} + +void wlr_seat_touch_send_up(struct wlr_seat *seat, uint32_t time, int32_t touch_id) { +	struct wlr_touch_point *point = wlr_seat_touch_get_point(seat, touch_id); +	if (!point) { +		wlr_log(L_ERROR, "got touch up for unknown touch point"); +		return; +	} + +	uint32_t serial = wl_display_next_serial(seat->display); +	wl_touch_send_up(point->client->touch, serial, time, touch_id); +	wl_touch_send_frame(point->client->touch); +} + +void wlr_seat_touch_send_motion(struct wlr_seat *seat, uint32_t time, int32_t touch_id, +		double sx, double sy) { +	struct wlr_touch_point *point = wlr_seat_touch_get_point(seat, touch_id); +	if (!point) { +		wlr_log(L_ERROR, "got touch motion for unknown touch point"); +		return; +	} + +	wl_touch_send_motion(point->client->touch, time, touch_id, +		wl_fixed_from_double(sx), wl_fixed_from_double(sy)); +	wl_touch_send_frame(point->client->touch); +} + +int wlr_seat_touch_num_points(struct wlr_seat *seat) { +	return wl_list_length(&seat->touch_state.touch_points); +} + +bool wlr_seat_touch_has_grab(struct wlr_seat *seat) { +	return seat->touch_state.grab->interface != &default_touch_grab_impl; +} | 
