Compare commits
	
		
			5 Commits
		
	
	
		
			3.23.1
			...
			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