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