data_device_send_selection(data_device, resource);
}
+bool
+data_device_send_drag_enter(struct ds_data_device *data_device,
+ struct ds_data_source *drag_source,
+ struct wl_resource *surface_resource,
+ double sx, double sy)
+{
+ struct ds_data_offer *offer;
+ struct wl_resource *device_resource;
+ uint32_t serial;
+
+ wl_resource_for_each(device_resource, &data_device->resources) {
+ offer = create_data_offer(device_resource, drag_source,
+ DS_DATA_OFFER_DRAG);
+ if (!offer) {
+ wl_resource_post_no_memory(device_resource);
+ return false;
+ }
+
+ data_offer_update_action(offer);
+
+ if (wl_resource_get_version(offer->resource) >=
+ WL_DATA_OFFER_SOURCE_ACTIONS_SINCE_VERSION) {
+ wl_data_offer_send_source_actions(offer->resource,
+ drag_source->actions);
+ }
+
+ serial = wl_display_next_serial(data_device->manager->display);
+ wl_data_device_send_enter(device_resource, serial, surface_resource,
+ wl_fixed_from_double(sx), wl_fixed_from_double(sy),
+ offer->resource);
+ }
+
+ return true;
+}
+
+void
+data_device_send_drag_leave(struct ds_data_device *data_device)
+{
+ struct wl_resource *device_resource;
+
+ wl_resource_for_each(device_resource, &data_device->resources)
+ wl_data_device_send_leave(device_resource);
+}
+
+void
+data_device_destroy_drag_offers(struct ds_data_device *data_device,
+ struct ds_data_source *drag_source)
+{
+ struct ds_data_offer *offer, *tmp;
+
+ wl_list_for_each_safe(offer, tmp, &data_device->drag_offers, link) {
+ if (offer->source != drag_source) {
+ ds_err("Something wrong, offer->source != drag_source");
+ continue;
+ }
+
+ offer->source = NULL;
+ data_offer_destroy(offer);
+ }
+}
+
static struct ds_data_device *
data_device_get_or_create(struct ds_data_device_manager *manager,
struct ds_seat_client *seat_client)
static void drag_handle_icon_destroy(struct wl_listener *listener, void *data);
static void drag_handle_source_destroy(struct wl_listener *listener,
void *data);
-static void drag_handle_seat_client_destroy(struct wl_listener *listener,
- void *data);
static void drag_start(struct ds_drag *drag, uint32_t serial);
static void drag_set_focus(struct ds_drag *drag, struct ds_surface *surface,
double sx, double sy);
static void drag_drop(struct ds_drag *drag, uint32_t time);
static void drag_icon_destroy(struct ds_drag_icon *icon);
+static void drag_enter(struct ds_drag *drag, struct ds_surface *surface,
+ double sx, double sy);
+static void drag_leave(struct ds_drag *drag);
+static void drag_set_focus_client(struct ds_drag *drag,
+ struct ds_seat_client *seat_client);
+static void drag_unset_focus_client(struct ds_drag *drag);
+static void drag_handle_seat_client_destroy(struct wl_listener *listener,
+ void *data);
WL_EXPORT void
ds_drag_destroy(struct ds_drag *drag)
}
}
- grab_button_count = ds_seat_pointer_get_grab_button(drag->seat);
+ grab_button_count = ds_seat_pointer_get_grab_button_count(drag->seat);
if (grab_button_count == 0 &&
state == WL_POINTER_BUTTON_STATE_RELEASED) {
drag_destroy(drag);
drag_set_focus(struct ds_drag *drag, struct ds_surface *surface,
double sx, double sy)
{
- struct ds_seat_client *focused_client;
- struct ds_data_device *data_device;
- struct wl_resource *device_resource, *surface_resource;
- struct ds_data_offer *offer, *tmp;
- uint32_t serial;
-
if (drag->focused_surface == surface)
return;
- if (drag->focused_client) {
- wl_list_remove(&drag->seat_client_destroy.link);
-
- wl_list_for_each(data_device,
- &drag->data_device->manager->data_devices, link) {
- if (data_device->seat !=
- ds_seat_client_get_seat(drag->focused_client))
- continue;
-
- wl_list_for_each_safe(offer, tmp,
- &data_device->drag_offers, link) {
- if (!drag->dropped &&
- offer->source == drag->source &&
- (wl_resource_get_client(offer->resource) ==
- ds_seat_client_get_wl_client(drag->focused_client))) {
- offer->source = NULL;
- data_offer_destroy(offer);
- }
- }
- }
-
- data_device = data_device_for_seat_client(drag->data_device->manager,
- drag->focused_client);
- if (data_device) {
- wl_resource_for_each(device_resource, &data_device->resources)
- wl_data_device_send_leave(device_resource);
- }
-
- drag->focused_client = NULL;
- drag->focused_surface = NULL;
- }
-
- if (!surface)
- goto out;
-
- surface_resource = ds_surface_get_wl_resource(surface);
-
- focused_client = ds_seat_client_for_wl_client(drag->seat,
- wl_resource_get_client(surface_resource));
- if (!focused_client)
- goto out;
-
- if (!drag->source) {
- if (wl_resource_get_client(surface_resource) !=
- ds_seat_client_get_wl_client(drag->seat_client))
- goto out;
- }
- else {
- drag->source->accepted = false;
-
- data_device = data_device_for_seat_client(drag->data_device->manager,
- focused_client);
- if (data_device) {
- wl_resource_for_each(device_resource, &data_device->resources) {
- offer = create_data_offer(device_resource, drag->source,
- DS_DATA_OFFER_DRAG);
- if (!offer) {
- wl_resource_post_no_memory(device_resource);
- return;
- }
-
- data_offer_update_action(offer);
-
- if (wl_resource_get_version(offer->resource) >=
- WL_DATA_OFFER_SOURCE_ACTIONS_SINCE_VERSION) {
- wl_data_offer_send_source_actions(offer->resource,
- drag->source->actions);
- }
-
- serial = wl_display_next_serial(
- drag->data_device->manager->display);
- wl_data_device_send_enter(device_resource, serial,
- surface_resource,
- wl_fixed_from_double(sx), wl_fixed_from_double(sy),
- offer->resource);
- }
- }
- }
+ if (drag->focused_client)
+ drag_leave(drag);
- drag->focused_surface = surface;
- drag->focused_client = focused_client;
- drag->seat_client_destroy.notify = drag_handle_seat_client_destroy;
- ds_seat_client_add_destroy_listener(focused_client,
- &drag->seat_client_destroy);
+ if (surface)
+ drag_enter(drag, surface, sx, sy);
-out:
wl_signal_emit(&drag->events.focus, drag);
}
}
static void
+drag_enter(struct ds_drag *drag, struct ds_surface *surface,
+ double sx, double sy)
+{
+ struct ds_data_device *data_device;
+ struct ds_seat_client *focused_client;
+ struct wl_resource *surface_resource;
+
+ surface_resource = ds_surface_get_wl_resource(surface);
+ focused_client = ds_seat_client_for_wl_client(drag->seat,
+ wl_resource_get_client(surface_resource));
+ if (!focused_client)
+ return;
+
+ if (!drag->source &&
+ (wl_resource_get_client(surface_resource) !=
+ ds_seat_client_get_wl_client(drag->seat_client)))
+ return;
+
+ drag->source->accepted = false;
+
+ data_device = data_device_for_seat_client(drag->data_device->manager,
+ focused_client);
+ if (!data_device)
+ return;
+
+ if (data_device_send_drag_enter(data_device, drag->source,
+ surface_resource, sx, sy)) {
+ drag->focused_surface = surface;
+ drag_set_focus_client(drag, focused_client);
+ }
+}
+
+static void
+drag_leave(struct ds_drag *drag)
+{
+ struct ds_data_device *data_device;
+
+ data_device = data_device_for_seat_client(drag->data_device->manager,
+ drag->focused_client);
+ if (data_device) {
+ if (!drag->dropped && drag->source)
+ data_device_destroy_drag_offers(data_device, drag->source);
+
+ data_device_send_drag_leave(data_device);
+ }
+
+ drag_unset_focus_client(drag);
+}
+
+static void
+drag_set_focus_client(struct ds_drag *drag, struct ds_seat_client *seat_client)
+{
+ drag->focused_client = seat_client;
+
+ drag->seat_client_destroy.notify = drag_handle_seat_client_destroy;
+ ds_seat_client_add_destroy_listener(seat_client,
+ &drag->seat_client_destroy);
+}
+
+static void
+drag_unset_focus_client(struct ds_drag *drag)
+{
+ wl_list_remove(&drag->seat_client_destroy.link);
+
+ drag->focused_client = NULL;
+ drag->focused_surface = NULL;
+}
+
+static void
drag_handle_seat_client_destroy(struct wl_listener *listener, void *data)
{
struct ds_drag *drag;
drag = wl_container_of(listener, drag, seat_client_destroy);
-
- drag->focused_client = NULL;
- wl_list_remove(&drag->seat_client_destroy.link);
+ drag_unset_focus_client(drag);
}