Compare commits
5 Commits
wip/carlos
...
wip/dnd-ac
Author | SHA1 | Date | |
---|---|---|---|
319d0bb679 | |||
ce78db31b7 | |||
15513adcc3 | |||
832c710c81 | |||
682c13723b |
@ -42,12 +42,18 @@ struct _MetaWaylandDataOffer
|
||||
struct wl_resource *resource;
|
||||
MetaWaylandDataSource *source;
|
||||
struct wl_listener source_destroy_listener;
|
||||
uint32_t dnd_actions;
|
||||
uint32_t preferred_dnd_action;
|
||||
};
|
||||
|
||||
typedef struct _MetaWaylandDataSourcePrivate
|
||||
{
|
||||
MetaWaylandDataOffer *offer;
|
||||
struct wl_array mime_types;
|
||||
gboolean has_target;
|
||||
uint32_t dnd_actions;
|
||||
uint32_t user_dnd_action;
|
||||
uint32_t current_dnd_action;
|
||||
} MetaWaylandDataSourcePrivate;
|
||||
|
||||
typedef struct _MetaWaylandDataSourceWayland
|
||||
@ -74,6 +80,50 @@ unbind_resource (struct wl_resource *resource)
|
||||
wl_list_remove (wl_resource_get_link (resource));
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
data_offer_choose_action (MetaWaylandDataOffer *offer)
|
||||
{
|
||||
MetaWaylandDataSource *source = offer->source;
|
||||
uint32_t actions, user_action, available_actions;
|
||||
|
||||
actions = meta_wayland_data_source_get_actions (source);
|
||||
user_action = meta_wayland_data_source_get_user_action (source);
|
||||
|
||||
available_actions = actions & offer->dnd_actions;
|
||||
|
||||
if (!available_actions)
|
||||
return 0;
|
||||
|
||||
/* If the user is forcing an action, go for it */
|
||||
if ((user_action & available_actions) != 0)
|
||||
return user_action;
|
||||
|
||||
/* If the dest side has a preferred DnD action, use it */
|
||||
if ((offer->preferred_dnd_action & available_actions) != 0)
|
||||
return offer->preferred_dnd_action;
|
||||
|
||||
/* Use the first found action, in bit order */
|
||||
return 1 << (ffs (available_actions) - 1);
|
||||
}
|
||||
|
||||
static void
|
||||
data_offer_update_action (MetaWaylandDataOffer *offer)
|
||||
{
|
||||
uint32_t current_action, action;
|
||||
|
||||
if (!offer->source)
|
||||
return;
|
||||
|
||||
current_action = meta_wayland_data_source_get_current_action (offer->source);
|
||||
action = data_offer_choose_action (offer);
|
||||
|
||||
if (current_action == action)
|
||||
return;
|
||||
|
||||
meta_wayland_data_source_set_current_action (offer->source, action);
|
||||
wl_data_offer_send_action (offer->resource, action);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_wayland_data_source_target (MetaWaylandDataSource *source,
|
||||
const char *mime_type)
|
||||
@ -123,6 +173,106 @@ meta_wayland_data_source_cancel (MetaWaylandDataSource *source)
|
||||
META_WAYLAND_DATA_SOURCE_GET_CLASS (source)->cancel (source);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
meta_wayland_data_source_get_actions (MetaWaylandDataSource *source)
|
||||
{
|
||||
MetaWaylandDataSourcePrivate *priv =
|
||||
meta_wayland_data_source_get_instance_private (source);
|
||||
|
||||
return priv->dnd_actions;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
meta_wayland_data_source_get_user_action (MetaWaylandDataSource *source)
|
||||
{
|
||||
MetaWaylandDataSourcePrivate *priv =
|
||||
meta_wayland_data_source_get_instance_private (source);
|
||||
|
||||
return priv->user_dnd_action;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
meta_wayland_data_source_get_current_action (MetaWaylandDataSource *source)
|
||||
{
|
||||
MetaWaylandDataSourcePrivate *priv =
|
||||
meta_wayland_data_source_get_instance_private (source);
|
||||
|
||||
return priv->current_dnd_action;
|
||||
}
|
||||
|
||||
static void
|
||||
meta_wayland_data_source_set_current_offer (MetaWaylandDataSource *source,
|
||||
MetaWaylandDataOffer *offer)
|
||||
{
|
||||
MetaWaylandDataSourcePrivate *priv =
|
||||
meta_wayland_data_source_get_instance_private (source);
|
||||
|
||||
priv->offer = offer;
|
||||
}
|
||||
|
||||
static MetaWaylandDataOffer *
|
||||
meta_wayland_data_source_get_current_offer (MetaWaylandDataSource *source)
|
||||
{
|
||||
MetaWaylandDataSourcePrivate *priv =
|
||||
meta_wayland_data_source_get_instance_private (source);
|
||||
|
||||
return priv->offer;
|
||||
}
|
||||
|
||||
void
|
||||
meta_wayland_data_source_set_current_action (MetaWaylandDataSource *source,
|
||||
uint32_t action)
|
||||
{
|
||||
MetaWaylandDataSourcePrivate *priv =
|
||||
meta_wayland_data_source_get_instance_private (source);
|
||||
|
||||
if (priv->current_dnd_action == action)
|
||||
return;
|
||||
|
||||
priv->current_dnd_action = action;
|
||||
META_WAYLAND_DATA_SOURCE_GET_CLASS (source)->action (source, action);
|
||||
}
|
||||
|
||||
void
|
||||
meta_wayland_data_source_set_actions (MetaWaylandDataSource *source,
|
||||
uint32_t dnd_actions)
|
||||
{
|
||||
MetaWaylandDataSourcePrivate *priv =
|
||||
meta_wayland_data_source_get_instance_private (source);
|
||||
MetaWaylandDataOffer *offer;
|
||||
|
||||
if (priv->dnd_actions == dnd_actions)
|
||||
return;
|
||||
|
||||
priv->dnd_actions = dnd_actions;
|
||||
offer = meta_wayland_data_source_get_current_offer (source);
|
||||
|
||||
if (offer)
|
||||
{
|
||||
wl_data_offer_send_source_actions (offer->resource,
|
||||
priv->dnd_actions);
|
||||
data_offer_update_action (offer);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_wayland_data_source_set_user_action (MetaWaylandDataSource *source,
|
||||
uint32_t action)
|
||||
{
|
||||
MetaWaylandDataSourcePrivate *priv =
|
||||
meta_wayland_data_source_get_instance_private (source);
|
||||
MetaWaylandDataOffer *offer;
|
||||
|
||||
if (priv->user_dnd_action == action)
|
||||
return;
|
||||
|
||||
priv->user_dnd_action = action;
|
||||
offer = meta_wayland_data_source_get_current_offer (source);
|
||||
|
||||
if (offer)
|
||||
data_offer_update_action (offer);
|
||||
}
|
||||
|
||||
static void
|
||||
data_offer_accept (struct wl_client *client,
|
||||
struct wl_resource *resource,
|
||||
@ -161,21 +311,59 @@ data_offer_destroy (struct wl_client *client, struct wl_resource *resource)
|
||||
wl_resource_destroy (resource);
|
||||
}
|
||||
|
||||
static void
|
||||
data_offer_set_actions (struct wl_client *client,
|
||||
struct wl_resource *resource,
|
||||
uint32_t dnd_actions,
|
||||
uint32_t preferred_action)
|
||||
{
|
||||
MetaWaylandDataOffer *offer = wl_resource_get_user_data (resource);
|
||||
|
||||
if (offer->dnd_actions == dnd_actions &&
|
||||
offer->preferred_dnd_action == preferred_action)
|
||||
return;
|
||||
|
||||
offer->dnd_actions = dnd_actions;
|
||||
offer->preferred_dnd_action = preferred_action;
|
||||
|
||||
data_offer_update_action (offer);
|
||||
}
|
||||
|
||||
static const struct wl_data_offer_interface data_offer_interface = {
|
||||
data_offer_accept,
|
||||
data_offer_receive,
|
||||
data_offer_destroy,
|
||||
data_offer_set_actions
|
||||
};
|
||||
|
||||
static void
|
||||
meta_wayland_data_source_notify_drop_performed (MetaWaylandDataSource *source)
|
||||
{
|
||||
META_WAYLAND_DATA_SOURCE_GET_CLASS (source)->drop_performed (source);
|
||||
}
|
||||
|
||||
void
|
||||
meta_wayland_data_source_notify_finish (MetaWaylandDataSource *source)
|
||||
{
|
||||
META_WAYLAND_DATA_SOURCE_GET_CLASS (source)->drag_finished (source);
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_data_offer (struct wl_resource *resource)
|
||||
{
|
||||
MetaWaylandDataOffer *offer = wl_resource_get_user_data (resource);
|
||||
|
||||
if (offer->source)
|
||||
g_object_remove_weak_pointer (G_OBJECT (offer->source),
|
||||
(gpointer *)&offer->source);
|
||||
{
|
||||
if (offer == meta_wayland_data_source_get_current_offer (offer->source))
|
||||
meta_wayland_data_source_notify_finish (offer->source);
|
||||
|
||||
g_object_remove_weak_pointer (G_OBJECT (offer->source),
|
||||
(gpointer *)&offer->source);
|
||||
offer->source = NULL;
|
||||
}
|
||||
|
||||
meta_display_sync_wayland_input_focus (meta_get_display ());
|
||||
g_slice_free (MetaWaylandDataOffer, offer);
|
||||
}
|
||||
|
||||
@ -203,6 +391,9 @@ meta_wayland_data_source_send_offer (MetaWaylandDataSource *source,
|
||||
wl_array_for_each (p, &priv->mime_types)
|
||||
wl_data_offer_send_offer (offer->resource, *p);
|
||||
|
||||
data_offer_update_action (offer);
|
||||
meta_wayland_data_source_set_current_offer (source, offer);
|
||||
|
||||
return offer->resource;
|
||||
}
|
||||
|
||||
@ -222,14 +413,27 @@ data_source_destroy (struct wl_client *client, struct wl_resource *resource)
|
||||
wl_resource_destroy (resource);
|
||||
}
|
||||
|
||||
static void
|
||||
data_source_set_actions (struct wl_client *client,
|
||||
struct wl_resource *resource,
|
||||
uint32_t dnd_actions)
|
||||
{
|
||||
MetaWaylandDataSource *source = wl_resource_get_user_data (resource);
|
||||
|
||||
meta_wayland_data_source_set_actions (source, dnd_actions);
|
||||
}
|
||||
|
||||
static struct wl_data_source_interface data_source_interface = {
|
||||
data_source_offer,
|
||||
data_source_destroy
|
||||
data_source_destroy,
|
||||
data_source_set_actions
|
||||
};
|
||||
|
||||
struct _MetaWaylandDragGrab {
|
||||
MetaWaylandPointerGrab generic;
|
||||
|
||||
MetaWaylandKeyboardGrab keyboard_grab;
|
||||
|
||||
MetaWaylandSeat *seat;
|
||||
struct wl_client *drag_client;
|
||||
|
||||
@ -248,6 +452,7 @@ struct _MetaWaylandDragGrab {
|
||||
struct wl_listener drag_origin_listener;
|
||||
|
||||
int drag_start_x, drag_start_y;
|
||||
ClutterModifierType buttons;
|
||||
};
|
||||
|
||||
static void
|
||||
@ -256,6 +461,7 @@ destroy_drag_focus (struct wl_listener *listener, void *data)
|
||||
MetaWaylandDragGrab *grab = wl_container_of (listener, grab, drag_focus_listener);
|
||||
|
||||
grab->drag_focus_data_device = NULL;
|
||||
grab->drag_focus = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
@ -285,6 +491,7 @@ meta_wayland_drag_grab_set_focus (MetaWaylandDragGrab *drag_grab,
|
||||
client = wl_resource_get_client (surface->resource);
|
||||
|
||||
data_device_resource = wl_resource_find_for_client (&seat->data_device.resource_list, client);
|
||||
meta_wayland_data_source_set_current_offer (drag_grab->drag_data_source, NULL);
|
||||
|
||||
if (drag_grab->drag_data_source && data_device_resource)
|
||||
offer = meta_wayland_data_source_send_offer (drag_grab->drag_data_source,
|
||||
@ -312,6 +519,22 @@ drag_grab_focus (MetaWaylandPointerGrab *grab,
|
||||
meta_wayland_drag_grab_set_focus (drag_grab, surface);
|
||||
}
|
||||
|
||||
static void
|
||||
data_source_update_user_dnd_action (MetaWaylandDataSource *source,
|
||||
ClutterModifierType modifiers)
|
||||
{
|
||||
uint32_t user_dnd_action = 0;
|
||||
|
||||
if (modifiers & CLUTTER_SHIFT_MASK)
|
||||
user_dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
|
||||
else if (modifiers & CLUTTER_CONTROL_MASK)
|
||||
user_dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
|
||||
else if (modifiers & (CLUTTER_MOD1_MASK | CLUTTER_BUTTON2_MASK))
|
||||
user_dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK;
|
||||
|
||||
meta_wayland_data_source_set_user_action (source, user_dnd_action);
|
||||
}
|
||||
|
||||
static void
|
||||
drag_grab_motion (MetaWaylandPointerGrab *grab,
|
||||
const ClutterEvent *event)
|
||||
@ -356,7 +579,15 @@ data_device_end_drag_grab (MetaWaylandDragGrab *drag_grab)
|
||||
|
||||
drag_grab->seat->data_device.current_grab = NULL;
|
||||
|
||||
meta_wayland_pointer_end_grab (drag_grab->generic.pointer);
|
||||
/* There might be other grabs created in result to DnD actions like popups
|
||||
* on "ask" actions, we must not reset those, only our own.
|
||||
*/
|
||||
if (drag_grab->generic.pointer->grab == (MetaWaylandPointerGrab *) drag_grab)
|
||||
{
|
||||
meta_wayland_pointer_end_grab (drag_grab->generic.pointer);
|
||||
meta_wayland_keyboard_end_grab (drag_grab->keyboard_grab.keyboard);
|
||||
}
|
||||
|
||||
g_slice_free (MetaWaylandDragGrab, drag_grab);
|
||||
}
|
||||
|
||||
@ -371,13 +602,23 @@ drag_grab_button (MetaWaylandPointerGrab *grab,
|
||||
if (drag_grab->generic.pointer->grab_button == clutter_event_get_button (event) &&
|
||||
event_type == CLUTTER_BUTTON_RELEASE)
|
||||
{
|
||||
MetaWaylandDataSource *data_source = drag_grab->drag_data_source;
|
||||
gboolean success = FALSE;
|
||||
|
||||
if (meta_wayland_data_source_has_target (drag_grab->drag_data_source))
|
||||
if (drag_grab->drag_focus &&
|
||||
meta_wayland_data_source_get_current_action (drag_grab->drag_data_source) &&
|
||||
meta_wayland_data_source_has_target (drag_grab->drag_data_source))
|
||||
{
|
||||
meta_wayland_surface_drag_dest_drop (drag_grab->drag_focus);
|
||||
meta_wayland_data_source_notify_drop_performed (data_source);
|
||||
success = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
meta_wayland_data_source_cancel (data_source);
|
||||
meta_wayland_data_source_set_current_offer (data_source, NULL);
|
||||
meta_wayland_data_device_set_dnd_source (&drag_grab->seat->data_device, NULL);
|
||||
}
|
||||
|
||||
/* Finish drag and let actor self-destruct */
|
||||
meta_dnd_actor_drag_finish (META_DND_ACTOR (drag_grab->feedback_actor),
|
||||
@ -396,6 +637,40 @@ static const MetaWaylandPointerGrabInterface drag_grab_interface = {
|
||||
drag_grab_button,
|
||||
};
|
||||
|
||||
static gboolean
|
||||
keyboard_drag_grab_key (MetaWaylandKeyboardGrab *grab,
|
||||
const ClutterEvent *event)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
keyboard_drag_grab_modifiers (MetaWaylandKeyboardGrab *grab,
|
||||
ClutterModifierType modifiers)
|
||||
{
|
||||
MetaWaylandDragGrab *drag_grab;
|
||||
|
||||
drag_grab = wl_container_of (grab, drag_grab, keyboard_grab);
|
||||
|
||||
/* The modifiers here just contain keyboard modifiers, mix it with the
|
||||
* mouse button modifiers we got when starting the drag operation.
|
||||
*/
|
||||
modifiers |= drag_grab->buttons;
|
||||
|
||||
if (drag_grab->drag_data_source)
|
||||
{
|
||||
data_source_update_user_dnd_action (drag_grab->drag_data_source, modifiers);
|
||||
|
||||
if (drag_grab->drag_focus)
|
||||
meta_wayland_surface_drag_dest_update (drag_grab->drag_focus);
|
||||
}
|
||||
}
|
||||
|
||||
static const MetaWaylandKeyboardGrabInterface keyboard_drag_grab_interface = {
|
||||
keyboard_drag_grab_key,
|
||||
keyboard_drag_grab_modifiers
|
||||
};
|
||||
|
||||
static void
|
||||
destroy_data_device_origin (struct wl_listener *listener, void *data)
|
||||
{
|
||||
@ -440,12 +715,16 @@ meta_wayland_data_device_start_drag (MetaWaylandDataDevice *data
|
||||
MetaWaylandSeat *seat = wl_container_of (data_device, seat, data_device);
|
||||
MetaWaylandDragGrab *drag_grab;
|
||||
ClutterPoint pos, stage_pos;
|
||||
ClutterModifierType modifiers;
|
||||
|
||||
data_device->current_grab = drag_grab = g_slice_new0 (MetaWaylandDragGrab);
|
||||
|
||||
drag_grab->generic.interface = funcs;
|
||||
drag_grab->generic.pointer = &seat->pointer;
|
||||
|
||||
drag_grab->keyboard_grab.interface = &keyboard_drag_grab_interface;
|
||||
drag_grab->keyboard_grab.keyboard = &seat->keyboard;
|
||||
|
||||
drag_grab->drag_client = client;
|
||||
drag_grab->seat = seat;
|
||||
|
||||
@ -460,6 +739,11 @@ meta_wayland_data_device_start_drag (MetaWaylandDataDevice *data
|
||||
drag_grab->drag_start_x = stage_pos.x;
|
||||
drag_grab->drag_start_y = stage_pos.y;
|
||||
|
||||
modifiers = clutter_input_device_get_modifier_state (seat->pointer.device);
|
||||
drag_grab->buttons = modifiers &
|
||||
(CLUTTER_BUTTON1_MASK | CLUTTER_BUTTON2_MASK | CLUTTER_BUTTON3_MASK |
|
||||
CLUTTER_BUTTON4_MASK | CLUTTER_BUTTON5_MASK);
|
||||
|
||||
g_object_weak_ref (G_OBJECT (source),
|
||||
drag_grab_data_source_destroyed,
|
||||
drag_grab);
|
||||
@ -467,6 +751,7 @@ meta_wayland_data_device_start_drag (MetaWaylandDataDevice *data
|
||||
drag_grab->drag_data_source = source;
|
||||
meta_wayland_data_device_set_dnd_source (data_device,
|
||||
drag_grab->drag_data_source);
|
||||
data_source_update_user_dnd_action (source, modifiers);
|
||||
|
||||
if (icon_surface)
|
||||
{
|
||||
@ -548,6 +833,10 @@ data_device_start_drag (struct wl_client *client,
|
||||
meta_wayland_data_device_start_drag (data_device, client,
|
||||
&drag_grab_interface,
|
||||
surface, drag_source, icon_surface);
|
||||
|
||||
meta_wayland_keyboard_set_focus (&seat->keyboard, NULL);
|
||||
meta_wayland_keyboard_start_grab (&seat->keyboard,
|
||||
&seat->data_device.current_grab->keyboard_grab);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -600,6 +889,34 @@ meta_wayland_source_cancel (MetaWaylandDataSource *source)
|
||||
wl_data_source_send_cancelled (source_wayland->resource);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_wayland_source_action (MetaWaylandDataSource *source,
|
||||
uint32_t action)
|
||||
{
|
||||
MetaWaylandDataSourceWayland *source_wayland =
|
||||
META_WAYLAND_DATA_SOURCE_WAYLAND (source);
|
||||
|
||||
wl_data_source_send_action (source_wayland->resource, action);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_wayland_source_drop_performed (MetaWaylandDataSource *source)
|
||||
{
|
||||
MetaWaylandDataSourceWayland *source_wayland =
|
||||
META_WAYLAND_DATA_SOURCE_WAYLAND (source);
|
||||
|
||||
wl_data_source_send_drop_performed (source_wayland->resource);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_wayland_source_drag_finished (MetaWaylandDataSource *source)
|
||||
{
|
||||
MetaWaylandDataSourceWayland *source_wayland =
|
||||
META_WAYLAND_DATA_SOURCE_WAYLAND (source);
|
||||
|
||||
wl_data_source_send_drag_finished (source_wayland->resource);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_wayland_source_finalize (GObject *object)
|
||||
{
|
||||
@ -623,6 +940,9 @@ meta_wayland_data_source_wayland_class_init (MetaWaylandDataSourceWaylandClass *
|
||||
data_source_class->send = meta_wayland_source_send;
|
||||
data_source_class->target = meta_wayland_source_target;
|
||||
data_source_class->cancel = meta_wayland_source_cancel;
|
||||
data_source_class->action = meta_wayland_source_action;
|
||||
data_source_class->drop_performed = meta_wayland_source_drop_performed;
|
||||
data_source_class->drag_finished = meta_wayland_source_drag_finished;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -647,6 +967,7 @@ meta_wayland_data_source_init (MetaWaylandDataSource *source)
|
||||
meta_wayland_data_source_get_instance_private (source);
|
||||
|
||||
wl_array_init (&priv->mime_types);
|
||||
priv->current_dnd_action = -1;
|
||||
}
|
||||
|
||||
static void
|
||||
@ -722,11 +1043,18 @@ meta_wayland_drag_dest_drop (MetaWaylandDataDevice *data_device,
|
||||
wl_data_device_send_drop (grab->drag_focus_data_device);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_wayland_drag_dest_update (MetaWaylandDataDevice *data_device,
|
||||
MetaWaylandSurface *surface)
|
||||
{
|
||||
}
|
||||
|
||||
static const MetaWaylandDragDestFuncs meta_wayland_drag_dest_funcs = {
|
||||
meta_wayland_drag_dest_focus_in,
|
||||
meta_wayland_drag_dest_focus_out,
|
||||
meta_wayland_drag_dest_motion,
|
||||
meta_wayland_drag_dest_drop
|
||||
meta_wayland_drag_dest_drop,
|
||||
meta_wayland_drag_dest_update
|
||||
};
|
||||
|
||||
const MetaWaylandDragDestFuncs *
|
||||
@ -912,6 +1240,12 @@ meta_wayland_data_device_set_keyboard_focus (MetaWaylandDataDevice *data_device)
|
||||
MetaWaylandDataSource *source;
|
||||
|
||||
focus_client = meta_wayland_keyboard_get_focus_client (&seat->keyboard);
|
||||
|
||||
if (focus_client == data_device->focus_client)
|
||||
return;
|
||||
|
||||
data_device->focus_client = focus_client;
|
||||
|
||||
if (!focus_client)
|
||||
return;
|
||||
|
||||
|
@ -45,6 +45,11 @@ struct _MetaWaylandDataSourceClass
|
||||
void (* target) (MetaWaylandDataSource *source,
|
||||
const gchar *mime_type);
|
||||
void (* cancel) (MetaWaylandDataSource *source);
|
||||
|
||||
void (* action) (MetaWaylandDataSource *source,
|
||||
uint32_t action);
|
||||
void (* drop_performed) (MetaWaylandDataSource *source);
|
||||
void (* drag_finished) (MetaWaylandDataSource *source);
|
||||
};
|
||||
|
||||
struct _MetaWaylandDataDevice
|
||||
@ -55,6 +60,7 @@ struct _MetaWaylandDataDevice
|
||||
struct wl_listener selection_data_source_listener;
|
||||
struct wl_list resource_list;
|
||||
MetaWaylandDragGrab *current_grab;
|
||||
struct wl_client *focus_client;
|
||||
|
||||
struct wl_signal selection_ownership_signal;
|
||||
struct wl_signal dnd_ownership_signal;
|
||||
@ -94,6 +100,17 @@ void meta_wayland_data_source_send (MetaWaylandDataSource *source,
|
||||
const gchar *mime_type,
|
||||
gint fd);
|
||||
|
||||
void meta_wayland_data_source_notify_finish (MetaWaylandDataSource *source);
|
||||
|
||||
uint32_t meta_wayland_data_source_get_actions (MetaWaylandDataSource *source);
|
||||
uint32_t meta_wayland_data_source_get_user_action (MetaWaylandDataSource *source);
|
||||
uint32_t meta_wayland_data_source_get_current_action (MetaWaylandDataSource *source);
|
||||
|
||||
void meta_wayland_data_source_set_actions (MetaWaylandDataSource *source,
|
||||
uint32_t dnd_actions);
|
||||
void meta_wayland_data_source_set_current_action (MetaWaylandDataSource *source,
|
||||
uint32_t action);
|
||||
|
||||
const MetaWaylandDragDestFuncs *
|
||||
meta_wayland_data_device_get_drag_dest_funcs (void);
|
||||
|
||||
|
@ -63,6 +63,7 @@
|
||||
|
||||
static void meta_wayland_keyboard_update_xkb_state (MetaWaylandKeyboard *keyboard);
|
||||
static void notify_modifiers (MetaWaylandKeyboard *keyboard);
|
||||
static guint evdev_code (const ClutterKeyEvent *event);
|
||||
|
||||
static void
|
||||
unbind_resource (struct wl_resource *resource)
|
||||
@ -264,7 +265,7 @@ notify_key (MetaWaylandKeyboard *keyboard,
|
||||
}
|
||||
|
||||
static void
|
||||
notify_modifiers (MetaWaylandKeyboard *keyboard)
|
||||
apply_modifiers (MetaWaylandKeyboard *keyboard)
|
||||
{
|
||||
struct xkb_state *state;
|
||||
struct wl_resource *resource;
|
||||
@ -289,6 +290,16 @@ notify_modifiers (MetaWaylandKeyboard *keyboard)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
notify_modifiers (MetaWaylandKeyboard *keyboard)
|
||||
{
|
||||
struct xkb_state *state;
|
||||
|
||||
state = keyboard->xkb_info.state;
|
||||
keyboard->grab->interface->modifiers (keyboard->grab,
|
||||
xkb_state_serialize_mods (state, XKB_STATE_MODS_EFFECTIVE));
|
||||
}
|
||||
|
||||
static void
|
||||
meta_wayland_keyboard_update_xkb_state (MetaWaylandKeyboard *keyboard)
|
||||
{
|
||||
@ -368,6 +379,33 @@ settings_changed (GSettings *settings,
|
||||
notify_key_repeat (keyboard);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
default_grab_key (MetaWaylandKeyboardGrab *grab,
|
||||
const ClutterEvent *event)
|
||||
{
|
||||
MetaWaylandKeyboard *keyboard = grab->keyboard;
|
||||
gboolean is_press = event->type == CLUTTER_KEY_PRESS;
|
||||
|
||||
/* Synthetic key events are for autorepeat. Ignore those, as
|
||||
* autorepeat in Wayland is done on the client side. */
|
||||
if (event->key.flags & CLUTTER_EVENT_FLAG_SYNTHETIC)
|
||||
return FALSE;
|
||||
|
||||
return notify_key (keyboard, event->key.time, evdev_code (&event->key), is_press);
|
||||
}
|
||||
|
||||
static void
|
||||
default_grab_modifiers (MetaWaylandKeyboardGrab *grab,
|
||||
ClutterModifierType modifiers)
|
||||
{
|
||||
apply_modifiers (grab->keyboard);
|
||||
}
|
||||
|
||||
static const MetaWaylandKeyboardGrabInterface default_keyboard_grab_interface = {
|
||||
default_grab_key,
|
||||
default_grab_modifiers
|
||||
};
|
||||
|
||||
void
|
||||
meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard,
|
||||
struct wl_display *display)
|
||||
@ -385,6 +423,10 @@ meta_wayland_keyboard_init (MetaWaylandKeyboard *keyboard,
|
||||
|
||||
keyboard->xkb_info.keymap_fd = -1;
|
||||
|
||||
keyboard->default_grab.interface = &default_keyboard_grab_interface;
|
||||
keyboard->default_grab.keyboard = keyboard;
|
||||
keyboard->grab = &keyboard->default_grab;
|
||||
|
||||
keyboard->settings = g_settings_new ("org.gnome.desktop.peripherals.keyboard");
|
||||
g_signal_connect (keyboard->settings, "changed",
|
||||
G_CALLBACK (settings_changed), keyboard);
|
||||
@ -461,7 +503,7 @@ meta_wayland_keyboard_handle_event (MetaWaylandKeyboard *keyboard,
|
||||
is_press ? "press" : "release",
|
||||
event->hardware_keycode);
|
||||
|
||||
handled = notify_key (keyboard, event->time, evdev_code (event), is_press);
|
||||
handled = keyboard->grab->interface->key (keyboard->grab, (const ClutterEvent *) event);
|
||||
|
||||
if (handled)
|
||||
meta_verbose ("Sent event to wayland client\n");
|
||||
@ -672,3 +714,18 @@ meta_wayland_keyboard_create_new_resource (MetaWaylandKeyboard *keyboard,
|
||||
wl_list_insert (&keyboard->resource_list, wl_resource_get_link (cr));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
meta_wayland_keyboard_start_grab (MetaWaylandKeyboard *keyboard,
|
||||
MetaWaylandKeyboardGrab *grab)
|
||||
{
|
||||
meta_wayland_keyboard_set_focus (keyboard, NULL);
|
||||
keyboard->grab = grab;
|
||||
grab->keyboard = keyboard;
|
||||
}
|
||||
|
||||
void
|
||||
meta_wayland_keyboard_end_grab (MetaWaylandKeyboard *keyboard)
|
||||
{
|
||||
keyboard->grab = &keyboard->default_grab;
|
||||
}
|
||||
|
@ -49,6 +49,20 @@
|
||||
#include <wayland-server.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
|
||||
struct _MetaWaylandKeyboardGrabInterface
|
||||
{
|
||||
gboolean (* key) (MetaWaylandKeyboardGrab *grab,
|
||||
const ClutterEvent *event);
|
||||
void (*modifiers) (MetaWaylandKeyboardGrab *grab,
|
||||
ClutterModifierType modifiers);
|
||||
};
|
||||
|
||||
struct _MetaWaylandKeyboardGrab
|
||||
{
|
||||
const MetaWaylandKeyboardGrabInterface *interface;
|
||||
MetaWaylandKeyboard *keyboard;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
struct xkb_keymap *keymap;
|
||||
@ -72,6 +86,9 @@ struct _MetaWaylandKeyboard
|
||||
MetaWaylandXkbInfo xkb_info;
|
||||
enum xkb_state_component mods_changed;
|
||||
|
||||
MetaWaylandKeyboardGrab *grab;
|
||||
MetaWaylandKeyboardGrab default_grab;
|
||||
|
||||
GSettings *settings;
|
||||
};
|
||||
|
||||
@ -100,4 +117,9 @@ void meta_wayland_keyboard_create_new_resource (MetaWaylandKeyboard *keyboard,
|
||||
struct wl_resource *seat_resource,
|
||||
uint32_t id);
|
||||
|
||||
void meta_wayland_keyboard_start_grab (MetaWaylandKeyboard *keyboard,
|
||||
MetaWaylandKeyboardGrab *grab);
|
||||
void meta_wayland_keyboard_end_grab (MetaWaylandKeyboard *keyboard);
|
||||
|
||||
|
||||
#endif /* META_WAYLAND_KEYBOARD_H */
|
||||
|
@ -2381,6 +2381,15 @@ meta_wayland_surface_drag_dest_drop (MetaWaylandSurface *surface)
|
||||
surface->dnd.funcs->drop (data_device, surface);
|
||||
}
|
||||
|
||||
void
|
||||
meta_wayland_surface_drag_dest_update (MetaWaylandSurface *surface)
|
||||
{
|
||||
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
|
||||
MetaWaylandDataDevice *data_device = &compositor->seat->data_device;
|
||||
|
||||
surface->dnd.funcs->update (data_device, surface);
|
||||
}
|
||||
|
||||
MetaWindow *
|
||||
meta_wayland_surface_get_toplevel_window (MetaWaylandSurface *surface)
|
||||
{
|
||||
|
@ -128,6 +128,8 @@ struct _MetaWaylandDragDestFuncs
|
||||
const ClutterEvent *event);
|
||||
void (* drop) (MetaWaylandDataDevice *data_device,
|
||||
MetaWaylandSurface *surface);
|
||||
void (* update) (MetaWaylandDataDevice *data_device,
|
||||
MetaWaylandSurface *surface);
|
||||
};
|
||||
|
||||
struct _MetaWaylandSurface
|
||||
@ -240,6 +242,7 @@ void meta_wayland_surface_drag_dest_motion (MetaWaylandSurface
|
||||
const ClutterEvent *event);
|
||||
void meta_wayland_surface_drag_dest_focus_out (MetaWaylandSurface *surface);
|
||||
void meta_wayland_surface_drag_dest_drop (MetaWaylandSurface *surface);
|
||||
void meta_wayland_surface_drag_dest_update (MetaWaylandSurface *surface);
|
||||
|
||||
void meta_wayland_surface_update_outputs (MetaWaylandSurface *surface);
|
||||
|
||||
|
@ -29,6 +29,8 @@ typedef struct _MetaWaylandPointerGrabInterface MetaWaylandPointerGrabInterface;
|
||||
typedef struct _MetaWaylandPopupGrab MetaWaylandPopupGrab;
|
||||
typedef struct _MetaWaylandPopup MetaWaylandPopup;
|
||||
typedef struct _MetaWaylandKeyboard MetaWaylandKeyboard;
|
||||
typedef struct _MetaWaylandKeyboardGrab MetaWaylandKeyboardGrab;
|
||||
typedef struct _MetaWaylandKeyboardGrabInterface MetaWaylandKeyboardGrabInterface;
|
||||
typedef struct _MetaWaylandTouch MetaWaylandTouch;
|
||||
typedef struct _MetaWaylandDragDestFuncs MetaWaylandDragDestFuncs;
|
||||
typedef struct _MetaWaylandDataOffer MetaWaylandDataOffer;
|
||||
|
@ -36,7 +36,7 @@
|
||||
|
||||
/* Global/master objects (version exported by wl_registry and negotiated through bind) */
|
||||
#define META_WL_COMPOSITOR_VERSION 3
|
||||
#define META_WL_DATA_DEVICE_MANAGER_VERSION 2
|
||||
#define META_WL_DATA_DEVICE_MANAGER_VERSION 3
|
||||
#define META_XDG_SHELL_VERSION 1
|
||||
#define META_WL_SHELL_VERSION 1
|
||||
#define META_WL_SEAT_VERSION 4
|
||||
|
@ -108,6 +108,7 @@ enum {
|
||||
ATOM_DND_ACTION_MOVE,
|
||||
ATOM_DND_ACTION_COPY,
|
||||
ATOM_DND_ACTION_ASK,
|
||||
ATOM_DND_ACTION_PRIVATE,
|
||||
N_DND_ATOMS
|
||||
};
|
||||
|
||||
@ -126,6 +127,7 @@ const gchar *atom_names[] = {
|
||||
"XdndActionMove",
|
||||
"XdndActionCopy",
|
||||
"XdndActionAsk",
|
||||
"XdndActionPrivate",
|
||||
NULL
|
||||
};
|
||||
|
||||
@ -135,6 +137,19 @@ G_DEFINE_TYPE (MetaWaylandDataSourceXWayland, meta_wayland_data_source_xwayland,
|
||||
META_TYPE_WAYLAND_DATA_SOURCE);
|
||||
|
||||
/* XDND helpers */
|
||||
static Atom
|
||||
action_to_atom (uint32_t action)
|
||||
{
|
||||
if (action & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY)
|
||||
return xdnd_atoms[ATOM_DND_ACTION_COPY];
|
||||
else if (action & WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE)
|
||||
return xdnd_atoms[ATOM_DND_ACTION_MOVE];
|
||||
else if (action & WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK)
|
||||
return xdnd_atoms[ATOM_DND_ACTION_ASK];
|
||||
else
|
||||
return None;
|
||||
}
|
||||
|
||||
static void
|
||||
xdnd_send_enter (MetaXWaylandSelection *selection_data,
|
||||
Window dest)
|
||||
@ -217,10 +232,21 @@ xdnd_send_position (MetaXWaylandSelection *selection_data,
|
||||
int x,
|
||||
int y)
|
||||
{
|
||||
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
|
||||
MetaSelectionBridge *selection = &selection_data->dnd.selection;
|
||||
MetaWaylandDataSource *source = compositor->seat->data_device.dnd_data_source;
|
||||
Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
|
||||
uint32_t action = 0, user_action, actions;
|
||||
XEvent xev = { 0 };
|
||||
|
||||
user_action = meta_wayland_data_source_get_user_action (source);
|
||||
actions = meta_wayland_data_source_get_actions (source);
|
||||
|
||||
if (user_action & actions)
|
||||
action = user_action;
|
||||
if (!action)
|
||||
action = actions;
|
||||
|
||||
xev.xclient.type = ClientMessage;
|
||||
xev.xclient.message_type = xdnd_atoms[ATOM_DND_POSITION];
|
||||
xev.xclient.format = 32;
|
||||
@ -230,7 +256,7 @@ xdnd_send_position (MetaXWaylandSelection *selection_data,
|
||||
xev.xclient.data.l[1] = 0;
|
||||
xev.xclient.data.l[2] = (x << 16) | y;
|
||||
xev.xclient.data.l[3] = time;
|
||||
xev.xclient.data.l[4] = xdnd_atoms[ATOM_DND_ACTION_COPY];
|
||||
xev.xclient.data.l[4] = action_to_atom (action);
|
||||
|
||||
XSendEvent (xdisplay, dest, False, NoEventMask, &xev);
|
||||
}
|
||||
@ -262,6 +288,8 @@ xdnd_send_finished (MetaXWaylandSelection *selection_data,
|
||||
{
|
||||
MetaDndBridge *selection = &selection_data->dnd;
|
||||
Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
|
||||
MetaWaylandDataSource *source = selection_data->dnd.selection.source;
|
||||
uint32_t action = 0;
|
||||
XEvent xev = { 0 };
|
||||
|
||||
xev.xclient.type = ClientMessage;
|
||||
@ -273,8 +301,9 @@ xdnd_send_finished (MetaXWaylandSelection *selection_data,
|
||||
|
||||
if (accepted)
|
||||
{
|
||||
action = meta_wayland_data_source_get_current_action (source);
|
||||
xev.xclient.data.l[1] = 1; /* Drop successful */
|
||||
xev.xclient.data.l[2] = xdnd_atoms[ATOM_DND_ACTION_COPY];
|
||||
xev.xclient.data.l[2] = action_to_atom (action);
|
||||
}
|
||||
|
||||
XSendEvent (xdisplay, dest, False, NoEventMask, &xev);
|
||||
@ -283,7 +312,7 @@ xdnd_send_finished (MetaXWaylandSelection *selection_data,
|
||||
static void
|
||||
xdnd_send_status (MetaXWaylandSelection *selection_data,
|
||||
Window dest,
|
||||
gboolean accepted)
|
||||
uint32_t action)
|
||||
{
|
||||
MetaDndBridge *selection = &selection_data->dnd;
|
||||
Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
|
||||
@ -296,12 +325,10 @@ xdnd_send_status (MetaXWaylandSelection *selection_data,
|
||||
|
||||
xev.xclient.data.l[0] = selection->dnd_window;
|
||||
xev.xclient.data.l[1] = 1 << 1; /* Bit 2: dest wants XdndPosition messages */
|
||||
xev.xclient.data.l[4] = action_to_atom (action);
|
||||
|
||||
if (accepted)
|
||||
{
|
||||
xev.xclient.data.l[1] |= 1 << 0; /* Bit 1: dest accepts the drop */
|
||||
xev.xclient.data.l[4] = xdnd_atoms[ATOM_DND_ACTION_COPY];
|
||||
}
|
||||
if (xev.xclient.data.l[4])
|
||||
xev.xclient.data.l[1] |= 1 << 0; /* Bit 1: dest accepts the drop */
|
||||
|
||||
XSendEvent (xdisplay, dest, False, NoEventMask, &xev);
|
||||
}
|
||||
@ -387,6 +414,32 @@ x11_selection_data_free (X11SelectionData *data)
|
||||
g_slice_free (X11SelectionData, data);
|
||||
}
|
||||
|
||||
static void
|
||||
x11_selection_data_send_finished (MetaSelectionBridge *selection,
|
||||
gboolean success)
|
||||
{
|
||||
uint32_t action = meta_wayland_data_source_get_current_action (selection->source);
|
||||
|
||||
if (!selection->x11_selection)
|
||||
return;
|
||||
|
||||
if (success && action == WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE)
|
||||
{
|
||||
Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
|
||||
|
||||
/* Request data deletion on the drag source */
|
||||
XConvertSelection (xdisplay,
|
||||
selection->selection_atom,
|
||||
gdk_x11_get_xatom_by_name ("DELETE"),
|
||||
gdk_x11_get_xatom_by_name ("_META_SELECTION"),
|
||||
selection->window,
|
||||
CurrentTime);
|
||||
}
|
||||
|
||||
xdnd_send_finished (selection->x11_selection->selection_data,
|
||||
selection->owner, success);
|
||||
}
|
||||
|
||||
static void
|
||||
x11_selection_data_finish (MetaSelectionBridge *selection,
|
||||
gboolean success)
|
||||
@ -395,13 +448,18 @@ x11_selection_data_finish (MetaSelectionBridge *selection,
|
||||
return;
|
||||
|
||||
if (selection == &selection->x11_selection->selection_data->dnd.selection)
|
||||
xdnd_send_finished (selection->x11_selection->selection_data,
|
||||
selection->owner, success);
|
||||
x11_selection_data_send_finished (selection, success);
|
||||
|
||||
g_clear_pointer (&selection->x11_selection,
|
||||
(GDestroyNotify) x11_selection_data_free);
|
||||
}
|
||||
|
||||
static void
|
||||
x11_selection_data_close (X11SelectionData *data)
|
||||
{
|
||||
g_output_stream_close (data->stream, data->cancellable, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
x11_data_write_cb (GObject *object,
|
||||
GAsyncResult *res,
|
||||
@ -410,27 +468,34 @@ x11_data_write_cb (GObject *object,
|
||||
MetaSelectionBridge *selection = user_data;
|
||||
X11SelectionData *data = selection->x11_selection;
|
||||
GError *error = NULL;
|
||||
gboolean success = TRUE;
|
||||
|
||||
g_output_stream_write_finish (G_OUTPUT_STREAM (object), res, &error);
|
||||
|
||||
if (data->incr)
|
||||
if (error)
|
||||
{
|
||||
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||
{
|
||||
g_error_free (error);
|
||||
return;
|
||||
}
|
||||
|
||||
g_warning ("Error writing from X11 selection: %s\n", error->message);
|
||||
g_error_free (error);
|
||||
success = FALSE;
|
||||
}
|
||||
|
||||
if (success && data->incr)
|
||||
{
|
||||
Display *xdisplay = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
|
||||
XDeleteProperty (xdisplay, selection->window,
|
||||
gdk_x11_get_xatom_by_name ("_META_SELECTION"));
|
||||
}
|
||||
|
||||
if (error)
|
||||
else
|
||||
{
|
||||
if (error->domain != G_IO_ERROR ||
|
||||
error->code != G_IO_ERROR_CANCELLED)
|
||||
g_warning ("Error writing from X11 selection: %s\n", error->message);
|
||||
|
||||
g_error_free (error);
|
||||
x11_selection_data_close (selection->x11_selection);
|
||||
x11_selection_data_finish (selection, success);
|
||||
}
|
||||
|
||||
if (!data->incr)
|
||||
x11_selection_data_finish (selection, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -687,6 +752,7 @@ meta_xwayland_selection_get_incr_chunk (MetaWaylandCompositor *compositor,
|
||||
else
|
||||
{
|
||||
/* Transfer has completed */
|
||||
x11_selection_data_close (selection->x11_selection);
|
||||
x11_selection_data_finish (selection, TRUE);
|
||||
}
|
||||
|
||||
@ -735,11 +801,15 @@ meta_x11_source_target (MetaWaylandDataSource *source,
|
||||
MetaWaylandDataSourceXWayland *source_xwayland =
|
||||
META_WAYLAND_DATA_SOURCE_XWAYLAND (source);
|
||||
MetaSelectionBridge *selection = source_xwayland->selection;
|
||||
uint32_t action = 0;
|
||||
|
||||
if (selection->selection_atom == xdnd_atoms[ATOM_DND_SELECTION])
|
||||
{
|
||||
if (mime_type)
|
||||
action = meta_wayland_data_source_get_current_action (source);
|
||||
|
||||
xdnd_send_status (compositor->xwayland_manager.selection_data,
|
||||
selection->owner, mime_type != NULL);
|
||||
selection->owner, action);
|
||||
}
|
||||
}
|
||||
|
||||
@ -750,10 +820,46 @@ meta_x11_source_cancel (MetaWaylandDataSource *source)
|
||||
META_WAYLAND_DATA_SOURCE_XWAYLAND (source);
|
||||
MetaSelectionBridge *selection = source_xwayland->selection;
|
||||
|
||||
x11_selection_data_send_finished (selection, FALSE);
|
||||
g_clear_pointer (&selection->x11_selection,
|
||||
(GDestroyNotify) x11_selection_data_free);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_x11_source_action (MetaWaylandDataSource *source,
|
||||
uint32_t action)
|
||||
{
|
||||
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
|
||||
MetaWaylandDataSourceXWayland *source_xwayland =
|
||||
META_WAYLAND_DATA_SOURCE_XWAYLAND (source);
|
||||
MetaSelectionBridge *selection = source_xwayland->selection;
|
||||
|
||||
if (selection->selection_atom == xdnd_atoms[ATOM_DND_SELECTION])
|
||||
{
|
||||
if (!meta_wayland_data_source_has_target (source))
|
||||
action = 0;
|
||||
|
||||
xdnd_send_status (compositor->xwayland_manager.selection_data,
|
||||
selection->owner, action);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
meta_x11_source_drop_performed (MetaWaylandDataSource *source)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
meta_x11_source_drag_finished (MetaWaylandDataSource *source)
|
||||
{
|
||||
MetaWaylandDataSourceXWayland *source_xwayland =
|
||||
META_WAYLAND_DATA_SOURCE_XWAYLAND (source);
|
||||
MetaSelectionBridge *selection = source_xwayland->selection;
|
||||
|
||||
if (selection->x11_selection)
|
||||
x11_selection_data_send_finished (selection, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
meta_wayland_data_source_xwayland_init (MetaWaylandDataSourceXWayland *source_xwayland)
|
||||
{
|
||||
@ -768,6 +874,9 @@ meta_wayland_data_source_xwayland_class_init (MetaWaylandDataSourceXWaylandClass
|
||||
data_source_class->send = meta_x11_source_send;
|
||||
data_source_class->target = meta_x11_source_target;
|
||||
data_source_class->cancel = meta_x11_source_cancel;
|
||||
data_source_class->action = meta_x11_source_action;
|
||||
data_source_class->drop_performed = meta_x11_source_drop_performed;
|
||||
data_source_class->drag_finished = meta_x11_source_drag_finished;
|
||||
}
|
||||
|
||||
static MetaWaylandDataSource *
|
||||
@ -831,11 +940,27 @@ meta_x11_drag_dest_drop (MetaWaylandDataDevice *data_device,
|
||||
meta_display_get_current_time_roundtrip (meta_get_display ()));
|
||||
}
|
||||
|
||||
static void
|
||||
meta_x11_drag_dest_update (MetaWaylandDataDevice *data_device,
|
||||
MetaWaylandSurface *surface)
|
||||
{
|
||||
MetaWaylandCompositor *compositor = meta_wayland_compositor_get_default ();
|
||||
MetaWaylandSeat *seat = compositor->seat;
|
||||
ClutterPoint pos;
|
||||
|
||||
clutter_input_device_get_coords (seat->pointer.device, NULL, &pos);
|
||||
xdnd_send_position (compositor->xwayland_manager.selection_data,
|
||||
compositor->xwayland_manager.selection_data->dnd.dnd_dest,
|
||||
clutter_get_current_event_time (),
|
||||
pos.x, pos.y);
|
||||
}
|
||||
|
||||
static const MetaWaylandDragDestFuncs meta_x11_drag_dest_funcs = {
|
||||
meta_x11_drag_dest_focus_in,
|
||||
meta_x11_drag_dest_focus_out,
|
||||
meta_x11_drag_dest_motion,
|
||||
meta_x11_drag_dest_drop
|
||||
meta_x11_drag_dest_drop,
|
||||
meta_x11_drag_dest_update
|
||||
};
|
||||
|
||||
const MetaWaylandDragDestFuncs *
|
||||
@ -1129,6 +1254,10 @@ meta_xwayland_selection_handle_selection_request (MetaWaylandCompositor *composi
|
||||
selection->timestamp);
|
||||
reply_selection_request (event, TRUE);
|
||||
}
|
||||
else if (data_source && event->target == gdk_x11_get_xatom_by_name ("DELETE"))
|
||||
{
|
||||
meta_wayland_data_source_notify_finish (data_source);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (data_source &&
|
||||
@ -1251,6 +1380,7 @@ meta_xwayland_selection_handle_client_message (MetaWaylandCompositor *compositor
|
||||
if (event->window == dnd->selection.window)
|
||||
{
|
||||
MetaWaylandDataSource *data_source;
|
||||
uint32_t action = 0;
|
||||
|
||||
data_source = compositor->seat->data_device.dnd_data_source;
|
||||
|
||||
@ -1263,6 +1393,19 @@ meta_xwayland_selection_handle_client_message (MetaWaylandCompositor *compositor
|
||||
meta_wayland_data_source_set_has_target (data_source,
|
||||
(event->data.l[1] & 1) != 0);
|
||||
|
||||
/* data.l[4] contains the action atom */
|
||||
if (event->data.l[4])
|
||||
{
|
||||
if (((Atom) event->data.l[4]) == xdnd_atoms[ATOM_DND_ACTION_COPY] ||
|
||||
((Atom) event->data.l[4]) == xdnd_atoms[ATOM_DND_ACTION_PRIVATE])
|
||||
action = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
|
||||
else if (((Atom) event->data.l[4]) == xdnd_atoms[ATOM_DND_ACTION_MOVE])
|
||||
action = WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
|
||||
else if (((Atom) event->data.l[4]) == xdnd_atoms[ATOM_DND_ACTION_ASK])
|
||||
action = WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK;
|
||||
}
|
||||
|
||||
meta_wayland_data_source_set_current_action (data_source, action);
|
||||
return TRUE;
|
||||
}
|
||||
else if (event->message_type == xdnd_atoms[ATOM_DND_FINISHED])
|
||||
@ -1271,8 +1414,7 @@ meta_xwayland_selection_handle_client_message (MetaWaylandCompositor *compositor
|
||||
if (compositor->seat->data_device.current_grab)
|
||||
return FALSE;
|
||||
|
||||
meta_wayland_data_device_set_dnd_source (&compositor->seat->data_device,
|
||||
NULL);
|
||||
meta_wayland_data_source_notify_finish (data_source);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
@ -1332,6 +1474,7 @@ meta_xwayland_selection_handle_client_message (MetaWaylandCompositor *compositor
|
||||
{
|
||||
ClutterEvent *motion;
|
||||
ClutterPoint pos;
|
||||
uint32_t action = 0;
|
||||
|
||||
motion = clutter_event_new (CLUTTER_MOTION);
|
||||
clutter_input_device_get_coords (seat->pointer.device, NULL, &pos);
|
||||
@ -1340,11 +1483,19 @@ meta_xwayland_selection_handle_client_message (MetaWaylandCompositor *compositor
|
||||
clutter_event_set_source_device (motion, seat->pointer.device);
|
||||
clutter_event_set_time (motion, dnd->last_motion_time);
|
||||
|
||||
if ((Atom) event->data.l[4] == xdnd_atoms[ATOM_DND_ACTION_COPY])
|
||||
action = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
|
||||
else if ((Atom) event->data.l[4] == xdnd_atoms[ATOM_DND_ACTION_MOVE])
|
||||
action = WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
|
||||
else if ((Atom) event->data.l[4] == xdnd_atoms[ATOM_DND_ACTION_ASK])
|
||||
action = WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK;
|
||||
|
||||
meta_wayland_data_source_set_actions (dnd->selection.source, action);
|
||||
|
||||
meta_wayland_surface_drag_dest_motion (drag_focus, motion);
|
||||
xdnd_send_status (compositor->xwayland_manager.selection_data,
|
||||
(Window) event->data.l[0],
|
||||
meta_wayland_data_source_has_target (
|
||||
dnd->selection.source));
|
||||
meta_wayland_data_source_get_current_action (dnd->selection.source));
|
||||
|
||||
clutter_event_free (motion);
|
||||
return TRUE;
|
||||
|
Reference in New Issue
Block a user