mirror of
				https://gitlab.freedesktop.org/wlroots/wlroots.git
				synced 2025-11-03 09:01:40 -05:00 
			
		
		
		
	xwayland: send DND_ENTER
This commit is contained in:
		
							parent
							
								
									b6c1760de5
								
							
						
					
					
						commit
						0d7a81ccdf
					
				
					 7 changed files with 192 additions and 82 deletions
				
			
		| 
						 | 
					@ -104,6 +104,11 @@ struct wlr_drag {
 | 
				
			||||||
	struct wl_listener source_destroy;
 | 
						struct wl_listener source_destroy;
 | 
				
			||||||
	struct wl_listener seat_client_destroy;
 | 
						struct wl_listener seat_client_destroy;
 | 
				
			||||||
	struct wl_listener icon_destroy;
 | 
						struct wl_listener icon_destroy;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
							struct wl_signal focus;
 | 
				
			||||||
 | 
							struct wl_signal destroy;
 | 
				
			||||||
 | 
						} events;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -187,6 +187,9 @@ struct wlr_seat {
 | 
				
			||||||
	struct wlr_primary_selection_source *primary_selection_source;
 | 
						struct wlr_primary_selection_source *primary_selection_source;
 | 
				
			||||||
	uint32_t primary_selection_serial;
 | 
						uint32_t primary_selection_serial;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wlr_drag *drag;
 | 
				
			||||||
 | 
						uint32_t drag_serial;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_seat_pointer_state pointer_state;
 | 
						struct wlr_seat_pointer_state pointer_state;
 | 
				
			||||||
	struct wlr_seat_keyboard_state keyboard_state;
 | 
						struct wlr_seat_keyboard_state keyboard_state;
 | 
				
			||||||
	struct wlr_seat_touch_state touch_state;
 | 
						struct wlr_seat_touch_state touch_state;
 | 
				
			||||||
| 
						 | 
					@ -210,6 +213,7 @@ struct wlr_seat {
 | 
				
			||||||
		struct wl_signal selection;
 | 
							struct wl_signal selection;
 | 
				
			||||||
		struct wl_signal primary_selection;
 | 
							struct wl_signal primary_selection;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							struct wl_signal start_drag;
 | 
				
			||||||
		struct wl_signal new_drag_icon;
 | 
							struct wl_signal new_drag_icon;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		struct wl_signal destroy;
 | 
							struct wl_signal destroy;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -115,8 +115,7 @@ struct wlr_xwm {
 | 
				
			||||||
	xcb_window_t selection_window;
 | 
						xcb_window_t selection_window;
 | 
				
			||||||
	struct wlr_xwm_selection clipboard_selection;
 | 
						struct wlr_xwm_selection clipboard_selection;
 | 
				
			||||||
	struct wlr_xwm_selection primary_selection;
 | 
						struct wlr_xwm_selection primary_selection;
 | 
				
			||||||
 | 
						struct wlr_xwm_selection dnd_selection;
 | 
				
			||||||
	xcb_window_t dnd_window;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	struct wlr_xwayland_surface *focus_surface;
 | 
						struct wlr_xwayland_surface *focus_surface;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -132,6 +131,9 @@ struct wlr_xwm {
 | 
				
			||||||
	struct wl_listener compositor_destroy;
 | 
						struct wl_listener compositor_destroy;
 | 
				
			||||||
	struct wl_listener seat_selection;
 | 
						struct wl_listener seat_selection;
 | 
				
			||||||
	struct wl_listener seat_primary_selection;
 | 
						struct wl_listener seat_primary_selection;
 | 
				
			||||||
 | 
						struct wl_listener seat_start_drag;
 | 
				
			||||||
 | 
						struct wl_listener seat_drag_focus;
 | 
				
			||||||
 | 
						struct wl_listener seat_drag_destroy;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct wlr_xwm *xwm_create(struct wlr_xwayland *wlr_xwayland);
 | 
					struct wlr_xwm *xwm_create(struct wlr_xwayland *wlr_xwayland);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -131,7 +131,8 @@ static void roots_cursor_update_position(struct roots_cursor *cursor,
 | 
				
			||||||
				cursor->pointer_view = seat_view;
 | 
									cursor->pointer_view = seat_view;
 | 
				
			||||||
				seat_view_deco_motion(seat_view, sx, sy);
 | 
									seat_view_deco_motion(seat_view, sx, sy);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} if (view && surface) {
 | 
							}
 | 
				
			||||||
 | 
							if (view && surface) {
 | 
				
			||||||
			// motion over a view surface
 | 
								// motion over a view surface
 | 
				
			||||||
			wlr_seat_pointer_notify_enter(seat->seat, surface, sx, sy);
 | 
								wlr_seat_pointer_notify_enter(seat->seat, surface, sx, sy);
 | 
				
			||||||
			wlr_seat_pointer_notify_motion(seat->seat, time, sx, sy);
 | 
								wlr_seat_pointer_notify_motion(seat->seat, time, sx, sy);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -427,7 +427,7 @@ static void wlr_drag_set_focus(struct wlr_drag *drag,
 | 
				
			||||||
		wlr_seat_client_for_wl_client(drag->seat_client->seat,
 | 
							wlr_seat_client_for_wl_client(drag->seat_client->seat,
 | 
				
			||||||
			wl_resource_get_client(surface->resource));
 | 
								wl_resource_get_client(surface->resource));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!focus_client || wl_list_empty(&focus_client->data_devices)) {
 | 
						if (!focus_client) {
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -436,10 +436,7 @@ static void wlr_drag_set_focus(struct wlr_drag *drag,
 | 
				
			||||||
		drag->source->accepted = false;
 | 
							drag->source->accepted = false;
 | 
				
			||||||
		struct wlr_data_offer *offer = wlr_data_source_send_offer(drag->source,
 | 
							struct wlr_data_offer *offer = wlr_data_source_send_offer(drag->source,
 | 
				
			||||||
			focus_client);
 | 
								focus_client);
 | 
				
			||||||
		if (offer == NULL) {
 | 
							if (offer != NULL) {
 | 
				
			||||||
			return;
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
			data_offer_update_action(offer);
 | 
								data_offer_update_action(offer);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (wl_resource_get_version(offer->resource) >=
 | 
								if (wl_resource_get_version(offer->resource) >=
 | 
				
			||||||
| 
						 | 
					@ -450,20 +447,25 @@ static void wlr_drag_set_focus(struct wlr_drag *drag,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			offer_resource = offer->resource;
 | 
								offer_resource = offer->resource;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (!wl_list_empty(&focus_client->data_devices)) {
 | 
				
			||||||
		uint32_t serial =
 | 
							uint32_t serial =
 | 
				
			||||||
			wl_display_next_serial(drag->seat_client->seat->display);
 | 
								wl_display_next_serial(drag->seat_client->seat->display);
 | 
				
			||||||
		struct wl_resource *resource;
 | 
							struct wl_resource *resource;
 | 
				
			||||||
		wl_resource_for_each(resource, &focus_client->data_devices) {
 | 
							wl_resource_for_each(resource, &focus_client->data_devices) {
 | 
				
			||||||
			wl_data_device_send_enter(resource, serial, surface->resource,
 | 
								wl_data_device_send_enter(resource, serial, surface->resource,
 | 
				
			||||||
			wl_fixed_from_double(sx), wl_fixed_from_double(sy), offer_resource);
 | 
									wl_fixed_from_double(sx), wl_fixed_from_double(sy),
 | 
				
			||||||
 | 
									offer_resource);
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	drag->focus = surface;
 | 
						drag->focus = surface;
 | 
				
			||||||
	drag->focus_client = focus_client;
 | 
						drag->focus_client = focus_client;
 | 
				
			||||||
	drag->seat_client_destroy.notify = handle_drag_seat_client_destroy;
 | 
						drag->seat_client_destroy.notify = handle_drag_seat_client_destroy;
 | 
				
			||||||
	wl_signal_add(&focus_client->events.destroy,
 | 
						wl_signal_add(&focus_client->events.destroy, &drag->seat_client_destroy);
 | 
				
			||||||
		&drag->seat_client_destroy);
 | 
					
 | 
				
			||||||
 | 
						wlr_signal_emit_safe(&drag->events.focus, drag);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void wlr_drag_end(struct wlr_drag *drag) {
 | 
					static void wlr_drag_end(struct wlr_drag *drag) {
 | 
				
			||||||
| 
						 | 
					@ -488,10 +490,14 @@ static void wlr_drag_end(struct wlr_drag *drag) {
 | 
				
			||||||
			wlr_signal_emit_safe(&drag->icon->events.map, drag->icon);
 | 
								wlr_signal_emit_safe(&drag->icon->events.map, drag->icon);
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							wlr_signal_emit_safe(&drag->events.destroy, drag);
 | 
				
			||||||
		free(drag);
 | 
							free(drag);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const struct
 | 
				
			||||||
 | 
					wlr_pointer_grab_interface wlr_data_device_pointer_drag_interface;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void pointer_drag_enter(struct wlr_seat_pointer_grab *grab,
 | 
					static void pointer_drag_enter(struct wlr_seat_pointer_grab *grab,
 | 
				
			||||||
		struct wlr_surface *surface, double sx, double sy) {
 | 
							struct wlr_surface *surface, double sx, double sy) {
 | 
				
			||||||
	struct wlr_drag *drag = grab->data;
 | 
						struct wlr_drag *drag = grab->data;
 | 
				
			||||||
| 
						 | 
					@ -732,22 +738,26 @@ static bool seat_client_start_drag(struct wlr_seat_client *client,
 | 
				
			||||||
		return false;
 | 
							return false;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	drag->seat = client->seat;
 | 
						wl_signal_init(&drag->events.focus);
 | 
				
			||||||
 | 
						wl_signal_init(&drag->events.destroy);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct wlr_seat *seat = client->seat;
 | 
				
			||||||
 | 
						drag->seat = seat;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	drag->is_pointer_grab = !wl_list_empty(&client->pointers) &&
 | 
						drag->is_pointer_grab = !wl_list_empty(&client->pointers) &&
 | 
				
			||||||
		client->seat->pointer_state.button_count == 1 &&
 | 
							seat->pointer_state.button_count == 1 &&
 | 
				
			||||||
		client->seat->pointer_state.grab_serial == serial &&
 | 
							seat->pointer_state.grab_serial == serial &&
 | 
				
			||||||
		client->seat->pointer_state.focused_surface &&
 | 
							seat->pointer_state.focused_surface &&
 | 
				
			||||||
		client->seat->pointer_state.focused_surface == origin;
 | 
							seat->pointer_state.focused_surface == origin;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	bool is_touch_grab = !wl_list_empty(&client->touches) &&
 | 
						bool is_touch_grab = !wl_list_empty(&client->touches) &&
 | 
				
			||||||
		wlr_seat_touch_num_points(client->seat) == 1 &&
 | 
							wlr_seat_touch_num_points(seat) == 1 &&
 | 
				
			||||||
		client->seat->touch_state.grab_serial == serial;
 | 
							seat->touch_state.grab_serial == serial;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// set in the iteration
 | 
						// set in the iteration
 | 
				
			||||||
	struct wlr_touch_point *point = NULL;
 | 
						struct wlr_touch_point *point = NULL;
 | 
				
			||||||
	if (is_touch_grab) {
 | 
						if (is_touch_grab) {
 | 
				
			||||||
		wl_list_for_each(point, &client->seat->touch_state.touch_points, link) {
 | 
							wl_list_for_each(point, &seat->touch_state.touch_points, link) {
 | 
				
			||||||
			is_touch_grab = point->surface && point->surface == origin;
 | 
								is_touch_grab = point->surface && point->surface == origin;
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
| 
						 | 
					@ -785,22 +795,26 @@ static bool seat_client_start_drag(struct wlr_seat_client *client,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	drag->touch_grab.data = drag;
 | 
						drag->touch_grab.data = drag;
 | 
				
			||||||
	drag->touch_grab.interface = &wlr_data_device_touch_drag_interface;
 | 
						drag->touch_grab.interface = &wlr_data_device_touch_drag_interface;
 | 
				
			||||||
	drag->grab_touch_id = drag->seat->touch_state.grab_id;
 | 
						drag->grab_touch_id = seat->touch_state.grab_id;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	drag->keyboard_grab.data = drag;
 | 
						drag->keyboard_grab.data = drag;
 | 
				
			||||||
	drag->keyboard_grab.interface = &wlr_data_device_keyboard_drag_interface;
 | 
						drag->keyboard_grab.interface = &wlr_data_device_keyboard_drag_interface;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wlr_seat_keyboard_start_grab(drag->seat, &drag->keyboard_grab);
 | 
						wlr_seat_keyboard_start_grab(seat, &drag->keyboard_grab);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (drag->is_pointer_grab) {
 | 
						if (drag->is_pointer_grab) {
 | 
				
			||||||
		wlr_seat_pointer_clear_focus(drag->seat);
 | 
							wlr_seat_pointer_clear_focus(seat);
 | 
				
			||||||
		wlr_seat_pointer_start_grab(drag->seat, &drag->pointer_grab);
 | 
							wlr_seat_pointer_start_grab(seat, &drag->pointer_grab);
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		assert(point);
 | 
							assert(point);
 | 
				
			||||||
		wlr_seat_touch_start_grab(drag->seat, &drag->touch_grab);
 | 
							wlr_seat_touch_start_grab(seat, &drag->touch_grab);
 | 
				
			||||||
		wlr_drag_set_focus(drag, point->surface, point->sx, point->sy);
 | 
							wlr_drag_set_focus(drag, point->surface, point->sx, point->sy);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						seat->drag = drag; // TODO: unset this thing somewhere
 | 
				
			||||||
 | 
						seat->drag_serial = serial;
 | 
				
			||||||
 | 
						wlr_signal_emit_safe(&seat->events.start_drag, drag);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return true;
 | 
						return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -465,6 +465,7 @@ struct wlr_seat *wlr_seat_create(struct wl_display *display, const char *name) {
 | 
				
			||||||
	wl_list_init(&wlr_seat->clients);
 | 
						wl_list_init(&wlr_seat->clients);
 | 
				
			||||||
	wl_list_init(&wlr_seat->drag_icons);
 | 
						wl_list_init(&wlr_seat->drag_icons);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wl_signal_init(&wlr_seat->events.start_drag);
 | 
				
			||||||
	wl_signal_init(&wlr_seat->events.new_drag_icon);
 | 
						wl_signal_init(&wlr_seat->events.new_drag_icon);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	wl_signal_init(&wlr_seat->events.request_set_cursor);
 | 
						wl_signal_init(&wlr_seat->events.request_set_cursor);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,7 +12,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static const size_t incr_chunk_size = 64 * 1024;
 | 
					static const size_t incr_chunk_size = 64 * 1024;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static xcb_atom_t data_device_manager_dnd_action_to_atom(
 | 
					/*static xcb_atom_t data_device_manager_dnd_action_to_atom(
 | 
				
			||||||
		struct wlr_xwm *xwm, enum wl_data_device_manager_dnd_action action) {
 | 
							struct wlr_xwm *xwm, enum wl_data_device_manager_dnd_action action) {
 | 
				
			||||||
	if (action & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY) {
 | 
						if (action & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY) {
 | 
				
			||||||
		return xwm->atoms[DND_ACTION_COPY];
 | 
							return xwm->atoms[DND_ACTION_COPY];
 | 
				
			||||||
| 
						 | 
					@ -36,7 +36,7 @@ static enum wl_data_device_manager_dnd_action
 | 
				
			||||||
		return WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK;
 | 
							return WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	return WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
 | 
						return WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
 | 
				
			||||||
}
 | 
					}*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void xwm_selection_send_notify(struct wlr_xwm_selection *selection,
 | 
					static void xwm_selection_send_notify(struct wlr_xwm_selection *selection,
 | 
				
			||||||
		xcb_atom_t property) {
 | 
							xcb_atom_t property) {
 | 
				
			||||||
| 
						 | 
					@ -241,6 +241,81 @@ static void xwm_selection_send_timestamp(struct wlr_xwm_selection *selection) {
 | 
				
			||||||
	xwm_selection_send_notify(selection, selection->request.property);
 | 
						xwm_selection_send_notify(selection, selection->request.property);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static xcb_atom_t xwm_get_mime_type_atom(struct wlr_xwm *xwm, char *mime_type) {
 | 
				
			||||||
 | 
						if (strcmp(mime_type, "text/plain;charset=utf-8") == 0) {
 | 
				
			||||||
 | 
							return xwm->atoms[UTF8_STRING];
 | 
				
			||||||
 | 
						} else if (strcmp(mime_type, "text/plain") == 0) {
 | 
				
			||||||
 | 
							return xwm->atoms[TEXT];
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						xcb_intern_atom_cookie_t cookie =
 | 
				
			||||||
 | 
							xcb_intern_atom(xwm->xcb_conn, 0, strlen(mime_type), mime_type);
 | 
				
			||||||
 | 
						xcb_intern_atom_reply_t *reply =
 | 
				
			||||||
 | 
							xcb_intern_atom_reply(xwm->xcb_conn, cookie, NULL);
 | 
				
			||||||
 | 
						if (reply == NULL) {
 | 
				
			||||||
 | 
							return XCB_ATOM_NONE;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						xcb_atom_t atom = reply->atom;
 | 
				
			||||||
 | 
						free(reply);
 | 
				
			||||||
 | 
						return atom;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void xwm_dnd_send_enter(struct wlr_xwm *xwm, struct wlr_drag *drag,
 | 
				
			||||||
 | 
							struct wlr_xwayland_surface *dest) {
 | 
				
			||||||
 | 
						struct wl_array *mime_types = &drag->source->mime_types;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						xcb_client_message_data_t data = { 0 };
 | 
				
			||||||
 | 
						data.data32[0] = xwm->dnd_selection.window;
 | 
				
			||||||
 | 
						data.data32[1] = XDND_VERSION << 24;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						size_t n = mime_types->size / sizeof(char *);
 | 
				
			||||||
 | 
						if (n <= 3) {
 | 
				
			||||||
 | 
							size_t i = 0;
 | 
				
			||||||
 | 
							char **mime_type_ptr;
 | 
				
			||||||
 | 
							wl_array_for_each(mime_type_ptr, mime_types) {
 | 
				
			||||||
 | 
								char *mime_type = *mime_type_ptr;
 | 
				
			||||||
 | 
								data.data32[2+i] = xwm_get_mime_type_atom(xwm, mime_type);
 | 
				
			||||||
 | 
								++i;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							// Let the client know that targets are not contained in the message
 | 
				
			||||||
 | 
							// data and must be retrieved with the DND_TYPE_LIST property
 | 
				
			||||||
 | 
							data.data32[1] |= 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							xcb_atom_t targets[n];
 | 
				
			||||||
 | 
							size_t i = 0;
 | 
				
			||||||
 | 
							char **mime_type_ptr;
 | 
				
			||||||
 | 
							wl_array_for_each(mime_type_ptr, mime_types) {
 | 
				
			||||||
 | 
								char *mime_type = *mime_type_ptr;
 | 
				
			||||||
 | 
								targets[i] = xwm_get_mime_type_atom(xwm, mime_type);
 | 
				
			||||||
 | 
								++i;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							xcb_change_property(xwm->xcb_conn,
 | 
				
			||||||
 | 
								XCB_PROP_MODE_REPLACE,
 | 
				
			||||||
 | 
								xwm->dnd_selection.window,
 | 
				
			||||||
 | 
								xwm->atoms[DND_TYPE_LIST],
 | 
				
			||||||
 | 
								XCB_ATOM_ATOM,
 | 
				
			||||||
 | 
								32, // format
 | 
				
			||||||
 | 
								n, targets);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						xcb_client_message_event_t event = {
 | 
				
			||||||
 | 
							.response_type = XCB_CLIENT_MESSAGE,
 | 
				
			||||||
 | 
							.format = 32,
 | 
				
			||||||
 | 
							.sequence = 0,
 | 
				
			||||||
 | 
							.window = dest->window_id,
 | 
				
			||||||
 | 
							.type = xwm->atoms[DND_ENTER],
 | 
				
			||||||
 | 
							.data = data,
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						xcb_send_event(xwm->xcb_conn,
 | 
				
			||||||
 | 
							0, // propagate
 | 
				
			||||||
 | 
							dest->window_id,
 | 
				
			||||||
 | 
							XCB_EVENT_MASK_NO_EVENT,
 | 
				
			||||||
 | 
							(const char *)&event);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct wl_array *xwm_selection_source_get_mime_types(
 | 
					static struct wl_array *xwm_selection_source_get_mime_types(
 | 
				
			||||||
		struct wlr_xwm_selection *selection) {
 | 
							struct wlr_xwm_selection *selection) {
 | 
				
			||||||
	if (selection == &selection->xwm->clipboard_selection) {
 | 
						if (selection == &selection->xwm->clipboard_selection) {
 | 
				
			||||||
| 
						 | 
					@ -271,35 +346,15 @@ static void xwm_selection_send_targets(struct wlr_xwm_selection *selection) {
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	size_t n = 2 + mime_types->size / sizeof(char *);
 | 
						size_t n = 2 + mime_types->size / sizeof(char *);
 | 
				
			||||||
	xcb_atom_t *targets = malloc(n * sizeof(xcb_atom_t));
 | 
						xcb_atom_t targets[n];
 | 
				
			||||||
	if (targets == NULL) {
 | 
					 | 
				
			||||||
		return;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	targets[0] = xwm->atoms[TIMESTAMP];
 | 
						targets[0] = xwm->atoms[TIMESTAMP];
 | 
				
			||||||
	targets[1] = xwm->atoms[TARGETS];
 | 
						targets[1] = xwm->atoms[TARGETS];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	size_t i = 2;
 | 
						size_t i = 0;
 | 
				
			||||||
	char **mime_type_ptr;
 | 
						char **mime_type_ptr;
 | 
				
			||||||
	wl_array_for_each(mime_type_ptr, mime_types) {
 | 
						wl_array_for_each(mime_type_ptr, mime_types) {
 | 
				
			||||||
		char *mime_type = *mime_type_ptr;
 | 
							char *mime_type = *mime_type_ptr;
 | 
				
			||||||
		xcb_atom_t atom;
 | 
							targets[2+i] = xwm_get_mime_type_atom(xwm, mime_type);
 | 
				
			||||||
		if (strcmp(mime_type, "text/plain;charset=utf-8") == 0) {
 | 
					 | 
				
			||||||
			atom = xwm->atoms[UTF8_STRING];
 | 
					 | 
				
			||||||
		} else if (strcmp(mime_type, "text/plain") == 0) {
 | 
					 | 
				
			||||||
			atom = xwm->atoms[TEXT];
 | 
					 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			xcb_intern_atom_cookie_t cookie =
 | 
					 | 
				
			||||||
				xcb_intern_atom(xwm->xcb_conn, 0, strlen(mime_type), mime_type);
 | 
					 | 
				
			||||||
			xcb_intern_atom_reply_t *reply =
 | 
					 | 
				
			||||||
				xcb_intern_atom_reply(xwm->xcb_conn, cookie, NULL);
 | 
					 | 
				
			||||||
			if (reply == NULL) {
 | 
					 | 
				
			||||||
				--n;
 | 
					 | 
				
			||||||
				continue;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
			atom = reply->atom;
 | 
					 | 
				
			||||||
			free(reply);
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
		targets[i] = atom;
 | 
					 | 
				
			||||||
		++i;
 | 
							++i;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -312,8 +367,6 @@ static void xwm_selection_send_targets(struct wlr_xwm_selection *selection) {
 | 
				
			||||||
		n, targets);
 | 
							n, targets);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	xwm_selection_send_notify(selection, selection->request.property);
 | 
						xwm_selection_send_notify(selection, selection->request.property);
 | 
				
			||||||
 | 
					 | 
				
			||||||
	free(targets);
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct wlr_xwm_selection *xwm_get_selection(struct wlr_xwm *xwm,
 | 
					static struct wlr_xwm_selection *xwm_get_selection(struct wlr_xwm *xwm,
 | 
				
			||||||
| 
						 | 
					@ -322,6 +375,8 @@ static struct wlr_xwm_selection *xwm_get_selection(struct wlr_xwm *xwm,
 | 
				
			||||||
		return &xwm->clipboard_selection;
 | 
							return &xwm->clipboard_selection;
 | 
				
			||||||
	} else if (selection_atom == xwm->atoms[PRIMARY]) {
 | 
						} else if (selection_atom == xwm->atoms[PRIMARY]) {
 | 
				
			||||||
		return &xwm->primary_selection;
 | 
							return &xwm->primary_selection;
 | 
				
			||||||
 | 
						} else if (selection_atom == xwm->atoms[DND_SELECTION]) {
 | 
				
			||||||
 | 
							return &xwm->dnd_selection;
 | 
				
			||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		return NULL;
 | 
							return NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					@ -856,28 +911,18 @@ void xwm_selection_init(struct wlr_xwm *xwm) {
 | 
				
			||||||
	selection_init(xwm, &xwm->primary_selection, xwm->atoms[PRIMARY]);
 | 
						selection_init(xwm, &xwm->primary_selection, xwm->atoms[PRIMARY]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Drag'n'drop
 | 
						// Drag'n'drop
 | 
				
			||||||
	uint32_t dnd_values[] = { XCB_EVENT_MASK_PROPERTY_CHANGE };
 | 
					 | 
				
			||||||
	xwm->dnd_window = xcb_generate_id(xwm->xcb_conn);
 | 
					 | 
				
			||||||
	xcb_create_window(xwm->xcb_conn,
 | 
					 | 
				
			||||||
		XCB_COPY_FROM_PARENT,
 | 
					 | 
				
			||||||
		xwm->dnd_window,
 | 
					 | 
				
			||||||
		xwm->screen->root,
 | 
					 | 
				
			||||||
		0, 0,
 | 
					 | 
				
			||||||
		10, 10,
 | 
					 | 
				
			||||||
		0,
 | 
					 | 
				
			||||||
		XCB_WINDOW_CLASS_INPUT_OUTPUT,
 | 
					 | 
				
			||||||
		xwm->screen->root_visual,
 | 
					 | 
				
			||||||
		XCB_CW_EVENT_MASK, dnd_values);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	uint32_t version = XDND_VERSION;
 | 
						uint32_t version = XDND_VERSION;
 | 
				
			||||||
	xcb_change_property(xwm->xcb_conn,
 | 
						xcb_change_property(xwm->xcb_conn,
 | 
				
			||||||
		XCB_PROP_MODE_REPLACE,
 | 
							XCB_PROP_MODE_REPLACE,
 | 
				
			||||||
		xwm->dnd_window,
 | 
							xwm->selection_window,
 | 
				
			||||||
		xwm->atoms[DND_AWARE],
 | 
							xwm->atoms[DND_AWARE],
 | 
				
			||||||
		XCB_ATOM_ATOM,
 | 
							XCB_ATOM_ATOM,
 | 
				
			||||||
		32,
 | 
							32,
 | 
				
			||||||
		1,
 | 
							1,
 | 
				
			||||||
		&version);
 | 
							&version);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						selection_init(xwm, &xwm->dnd_selection, xwm->atoms[DND_SELECTION]);
 | 
				
			||||||
 | 
						wlr_log(L_DEBUG, "DND_SELECTION=%d", xwm->atoms[DND_SELECTION]);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void xwm_selection_finish(struct wlr_xwm *xwm) {
 | 
					void xwm_selection_finish(struct wlr_xwm *xwm) {
 | 
				
			||||||
| 
						 | 
					@ -887,9 +932,6 @@ void xwm_selection_finish(struct wlr_xwm *xwm) {
 | 
				
			||||||
	if (xwm->selection_window) {
 | 
						if (xwm->selection_window) {
 | 
				
			||||||
		xcb_destroy_window(xwm->xcb_conn, xwm->selection_window);
 | 
							xcb_destroy_window(xwm->xcb_conn, xwm->selection_window);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if (xwm->dnd_window) {
 | 
					 | 
				
			||||||
		xcb_destroy_window(xwm->xcb_conn, xwm->dnd_window);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if (xwm->seat) {
 | 
						if (xwm->seat) {
 | 
				
			||||||
		if (xwm->seat->selection_data_source &&
 | 
							if (xwm->seat->selection_data_source &&
 | 
				
			||||||
				xwm->seat->selection_data_source->cancel == data_source_cancel) {
 | 
									xwm->seat->selection_data_source->cancel == data_source_cancel) {
 | 
				
			||||||
| 
						 | 
					@ -903,7 +945,6 @@ void xwm_selection_finish(struct wlr_xwm *xwm) {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		wlr_xwayland_set_seat(xwm->xwayland, NULL);
 | 
							wlr_xwayland_set_seat(xwm->xwayland, NULL);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void xwm_selection_set_owner(struct wlr_xwm_selection *selection,
 | 
					static void xwm_selection_set_owner(struct wlr_xwm_selection *selection,
 | 
				
			||||||
| 
						 | 
					@ -951,10 +992,50 @@ static void seat_handle_primary_selection(struct wl_listener *listener,
 | 
				
			||||||
	xwm_selection_set_owner(&xwm->primary_selection, source != NULL);
 | 
						xwm_selection_set_owner(&xwm->primary_selection, source != NULL);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void seat_handle_drag_focus(struct wl_listener *listener, void *data) {
 | 
				
			||||||
 | 
						struct wlr_drag *drag = data;
 | 
				
			||||||
 | 
						struct wlr_xwm *xwm = wl_container_of(listener, xwm, seat_drag_focus);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// TODO: check for subsurfaces?
 | 
				
			||||||
 | 
						bool found = false;
 | 
				
			||||||
 | 
						struct wlr_xwayland_surface *surface;
 | 
				
			||||||
 | 
						wl_list_for_each(surface, &xwm->surfaces, link) {
 | 
				
			||||||
 | 
							if (surface->surface == drag->focus) {
 | 
				
			||||||
 | 
								found = true;
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if (!found) {
 | 
				
			||||||
 | 
							return;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						xwm_dnd_send_enter(xwm, drag, surface);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void seat_handle_drag_destroy(struct wl_listener *listener, void *data) {
 | 
				
			||||||
 | 
						struct wlr_xwm *xwm = wl_container_of(listener, xwm, seat_drag_destroy);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wl_list_remove(&xwm->seat_drag_focus.link);
 | 
				
			||||||
 | 
						wl_list_remove(&xwm->seat_drag_destroy.link);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void seat_handle_start_drag(struct wl_listener *listener, void *data) {
 | 
				
			||||||
 | 
						struct wlr_drag *drag = data;
 | 
				
			||||||
 | 
						struct wlr_xwm *xwm = wl_container_of(listener, xwm, seat_start_drag);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						xwm_selection_set_owner(&xwm->dnd_selection, drag != NULL);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						wl_signal_add(&drag->events.focus, &xwm->seat_drag_focus);
 | 
				
			||||||
 | 
						xwm->seat_drag_focus.notify = seat_handle_drag_focus;
 | 
				
			||||||
 | 
						wl_signal_add(&drag->events.destroy, &xwm->seat_drag_destroy);
 | 
				
			||||||
 | 
						xwm->seat_drag_destroy.notify = seat_handle_drag_destroy;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void xwm_set_seat(struct wlr_xwm *xwm, struct wlr_seat *seat) {
 | 
					void xwm_set_seat(struct wlr_xwm *xwm, struct wlr_seat *seat) {
 | 
				
			||||||
	if (xwm->seat != NULL) {
 | 
						if (xwm->seat != NULL) {
 | 
				
			||||||
		wl_list_remove(&xwm->seat_selection.link);
 | 
							wl_list_remove(&xwm->seat_selection.link);
 | 
				
			||||||
		wl_list_remove(&xwm->seat_primary_selection.link);
 | 
							wl_list_remove(&xwm->seat_primary_selection.link);
 | 
				
			||||||
 | 
							wl_list_remove(&xwm->seat_start_drag.link);
 | 
				
			||||||
		xwm->seat = NULL;
 | 
							xwm->seat = NULL;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -968,6 +1049,8 @@ void xwm_set_seat(struct wlr_xwm *xwm, struct wlr_seat *seat) {
 | 
				
			||||||
	xwm->seat_selection.notify = seat_handle_selection;
 | 
						xwm->seat_selection.notify = seat_handle_selection;
 | 
				
			||||||
	wl_signal_add(&seat->events.primary_selection, &xwm->seat_primary_selection);
 | 
						wl_signal_add(&seat->events.primary_selection, &xwm->seat_primary_selection);
 | 
				
			||||||
	xwm->seat_primary_selection.notify = seat_handle_primary_selection;
 | 
						xwm->seat_primary_selection.notify = seat_handle_primary_selection;
 | 
				
			||||||
 | 
						wl_signal_add(&seat->events.start_drag, &xwm->seat_start_drag);
 | 
				
			||||||
 | 
						xwm->seat_start_drag.notify = seat_handle_start_drag;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	seat_handle_selection(&xwm->seat_selection, seat);
 | 
						seat_handle_selection(&xwm->seat_selection, seat);
 | 
				
			||||||
	seat_handle_primary_selection(&xwm->seat_primary_selection, seat);
 | 
						seat_handle_primary_selection(&xwm->seat_primary_selection, seat);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue