@ -27,6 +27,18 @@
# define E_COMP_WL
# include "e.h"
# if __clang__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wunused-parameter"
# elif (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) || __GNUC__ > 4
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wunused-parameter"
# endif
# define ALL_ACTIONS (WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY | \
WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE | \
WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK )
static void
_mime_types_free ( E_Comp_Wl_Data_Source * source )
{
@ -45,8 +57,12 @@ _e_comp_wl_data_offer_cb_accept(struct wl_client *client EINA_UNUSED, struct wl_
if ( ! ( offer = wl_resource_get_user_data ( resource ) ) )
return ;
if ( offer - > source )
offer - > source - > target ( offer - > source , serial , mime_type ) ;
/* Protect against untimely calls from older data offers */
if ( ( ! offer - > source ) | | ( offer ! = offer - > source - > offer ) )
return ;
offer - > source - > target ( offer - > source , serial , mime_type ) ;
offer - > source - > accepted = ! ! mime_type ;
}
static void
@ -74,30 +90,181 @@ _e_comp_wl_data_offer_cb_destroy(struct wl_client *client EINA_UNUSED, struct wl
}
static void
_e_comp_wl_data_offer_cb_finish ( struct wl_client * client EINA_UNUSED , struct wl_res ource * re source EINA_UNUSED )
data_source_notify_finish ( E_Comp_Wl_Data_S ource * source )
{
/* TODO: implement */
if ( ! source - > actions_set )
return ;
if ( source - > offer - > in_ask & &
wl_resource_get_version ( source - > resource ) > =
WL_DATA_SOURCE_ACTION_SINCE_VERSION ) {
wl_data_source_send_action ( source - > resource ,
source - > current_dnd_action ) ;
}
if ( wl_resource_get_version ( source - > resource ) > =
WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION ) {
wl_data_source_send_dnd_finished ( source - > resource ) ;
}
source - > offer = NULL ;
}
static void
_e_comp_wl_data_offer_cb_actions_set ( struct wl_client * client EINA_UNUSED , struct wl_resource * resource EINA_UNUSED , uint32_t actions EINA_UNUSED , uint32_t preferred_action EINA_UNUSED )
static uint32_t
data_offer_choose_action ( E_Comp_Wl_Data_Offer * offer )
{
/* TODO: implement */
uint32_t available_actions , preferred_action = 0 ;
uint32_t source_actions , offer_actions ;
if ( wl_resource_get_version ( offer - > resource ) > =
WL_DATA_OFFER_ACTION_SINCE_VERSION ) {
offer_actions = offer - > dnd_actions ;
preferred_action = offer - > preferred_dnd_action ;
} else {
offer_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY ;
}
if ( wl_resource_get_version ( offer - > source - > resource ) > =
WL_DATA_SOURCE_ACTION_SINCE_VERSION )
source_actions = offer - > source - > dnd_actions ;
else
source_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY ;
available_actions = offer_actions & source_actions ;
if ( ! available_actions )
return WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE ;
if ( //offer->source->seat &&
offer - > source - > compositor_action & available_actions )
return offer - > source - > compositor_action ;
/* If the dest side has a preferred DnD action, use it */
if ( ( preferred_action & available_actions ) ! = 0 )
return preferred_action ;
/* Use the first found action, in bit order */
return 1 < < ( ffs ( available_actions ) - 1 ) ;
}
/* called by wl_resource_destroy */
static void
_e_comp_wl_data_offer_cb_resource_destroy ( struct wl_resource * resource )
data_offer_update_action ( E_Comp_Wl_Data_Offer * offer )
{
E_Comp_Wl_Data_Offer * offer ;
uint32_t action ;
if ( ! ( offer = wl_resource_get_user_data ( resource ) ) )
return ;
if ( ! offer - > source | | ! offer - > source - > actions_set )
return ;
if ( offer - > source )
wl_list_remove ( & offer - > source_destroy_listener . link ) ;
action = data_offer_choose_action ( offer ) ;
if ( offer - > source - > current_dnd_action = = action )
return ;
offer - > source - > current_dnd_action = action ;
if ( offer - > in_ask )
return ;
if ( wl_resource_get_version ( offer - > source - > resource ) > =
WL_DATA_SOURCE_ACTION_SINCE_VERSION )
wl_data_source_send_action ( offer - > source - > resource , action ) ;
free ( offer ) ;
if ( wl_resource_get_version ( offer - > resource ) > =
WL_DATA_OFFER_ACTION_SINCE_VERSION )
wl_data_offer_send_action ( offer - > resource , action ) ;
}
static void
data_offer_set_actions ( struct wl_client * client ,
struct wl_resource * resource ,
uint32_t dnd_actions , uint32_t preferred_action )
{
E_Comp_Wl_Data_Offer * offer = wl_resource_get_user_data ( resource ) ;
if ( dnd_actions & ~ ALL_ACTIONS ) {
wl_resource_post_error ( offer - > resource ,
WL_DATA_OFFER_ERROR_INVALID_ACTION_MASK ,
" invalid action mask %x " , dnd_actions ) ;
return ;
}
if ( preferred_action & &
( ! ( preferred_action & dnd_actions ) | |
__builtin_popcount ( preferred_action ) > 1 ) ) {
wl_resource_post_error ( offer - > resource ,
WL_DATA_OFFER_ERROR_INVALID_ACTION ,
" invalid action %x " , preferred_action ) ;
return ;
}
offer - > dnd_actions = dnd_actions ;
offer - > preferred_dnd_action = preferred_action ;
data_offer_update_action ( offer ) ;
}
static void
data_offer_finish ( struct wl_client * client , struct wl_resource * resource )
{
E_Comp_Wl_Data_Offer * offer = wl_resource_get_user_data ( resource ) ;
if ( ! offer - > source | | offer - > source - > offer ! = offer )
return ;
/* Disallow finish while we have a grab driving drag-and-drop, or
* if the negotiation is not at the right stage
*/
if ( //offer->source->seat ||
! offer - > source - > accepted ) {
wl_resource_post_error ( offer - > resource ,
WL_DATA_OFFER_ERROR_INVALID_FINISH ,
" premature finish request " ) ;
return ;
}
switch ( offer - > source - > current_dnd_action ) {
case WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE :
case WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK :
wl_resource_post_error ( offer - > resource ,
WL_DATA_OFFER_ERROR_INVALID_OFFER ,
" offer finished with an invalid action " ) ;
return ;
default :
break ;
}
data_source_notify_finish ( offer - > source ) ;
}
/* called by wl_resource_destroy */
static void
_e_comp_wl_data_offer_cb_resource_destroy ( struct wl_resource * resource )
{
E_Comp_Wl_Data_Offer * offer = wl_resource_get_user_data ( resource ) ;
if ( ! offer - > source )
goto out ;
wl_list_remove ( & offer - > source_destroy_listener . link ) ;
if ( offer - > source - > offer ! = offer )
goto out ;
/* If the drag destination has version < 3, wl_data_offer.finish
* won ' t be called , so do this here as a safety net , because
* we still want the version > = 3 drag source to be happy .
*/
if ( wl_resource_get_version ( offer - > resource ) <
WL_DATA_OFFER_ACTION_SINCE_VERSION ) {
data_source_notify_finish ( offer - > source ) ;
} else if ( offer - > source - > resource & &
wl_resource_get_version ( offer - > source - > resource ) > =
WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION ) {
wl_data_source_send_cancelled ( offer - > source - > resource ) ;
}
offer - > source - > offer = NULL ;
out :
free ( offer ) ;
}
/* called by emission of source->destroy_signal */
@ -119,8 +286,8 @@ static const struct wl_data_offer_interface _e_data_offer_interface =
_e_comp_wl_data_offer_cb_accept ,
_e_comp_wl_data_offer_cb_receive ,
_e_comp_wl_data_offer_cb_destroy ,
_e_comp_wl_ data_offer_cb _finish,
_e_comp_wl_data_offer_cb_actions_set ,
data_offer_finish ,
data_offer_set_actions ,
} ;
static void
@ -146,9 +313,37 @@ _e_comp_wl_data_source_cb_destroy(struct wl_client *client EINA_UNUSED, struct w
}
static void
_e_comp_wl_data_source_cb_actions_set ( struct wl_client * client EINA_UNUSED , struct wl_resource * resource EINA_UNUSED , uint32_t actions EINA_UNUSED )
data_source_set_actions ( struct wl_client * client ,
struct wl_resource * resource ,
uint32_t dnd_actions )
{
/* TODO: implement */
E_Comp_Wl_Data_Source * source =
wl_resource_get_user_data ( resource ) ;
if ( source - > actions_set ) {
wl_resource_post_error ( source - > resource ,
WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK ,
" cannot set actions more than once " ) ;
return ;
}
if ( dnd_actions & ~ ALL_ACTIONS ) {
wl_resource_post_error ( source - > resource ,
WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK ,
" invalid action mask %x " , dnd_actions ) ;
return ;
}
/* FIXME
if ( source - > seat ) {
wl_resource_post_error ( source - > resource ,
WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK ,
" invalid action change after "
" wl_data_device.start_drag " ) ;
return ;
}
*/
source - > dnd_actions = dnd_actions ;
source - > actions_set = 1 ;
}
/* called by wl_resource_destroy */
@ -192,7 +387,7 @@ static const struct wl_data_source_interface _e_data_source_interface =
{
_e_comp_wl_data_source_cb_offer ,
_e_comp_wl_data_source_cb_destroy ,
_e_comp_wl_data_source_cb_actions_set ,
data_source_set_actions ,
} ;
static void
@ -224,7 +419,7 @@ _e_comp_wl_data_device_destroy_selection_data_source(struct wl_listener *listene
}
static struct wl_resource *
_e_comp_wl_data_device_data_offer_create ( E_Comp_Wl_Data_Source * source , struct wl_resource * data_device_res )
_e_comp_wl_data_device_data_offer_create ( E_Comp_Wl_Data_Source * source , struct wl_resource * data_device )
{
E_Comp_Wl_Data_Offer * offer ;
Eina_Iterator * it ;
@ -236,8 +431,8 @@ _e_comp_wl_data_device_data_offer_create(E_Comp_Wl_Data_Source *source, struct w
if ( ! offer ) return NULL ;
offer - > resource =
wl_resource_create ( wl_resource_get_client ( data_device_res ) ,
& wl_data_offer_interface , 1 , 0 ) ;
wl_resource_create ( wl_resource_get_client ( data_device ) ,
& wl_data_offer_interface , wl_resource_get_version ( data_device ) , 0 ) ;
if ( ! offer - > resource )
{
free ( offer ) ;
@ -248,17 +443,20 @@ _e_comp_wl_data_device_data_offer_create(E_Comp_Wl_Data_Source *source, struct w
& _e_data_offer_interface , offer ,
_e_comp_wl_data_offer_cb_resource_destroy ) ;
offer - > source = source ;
source - > offer = offer ;
offer - > source_destroy_listener . notify =
_e_comp_wl_data_offer_cb_source_destroy ;
wl_signal_add ( & source - > destroy_signal , & offer - > source_destroy_listener ) ;
wl_data_device_send_data_offer ( data_device_res , offer - > resource ) ;
wl_data_device_send_data_offer ( data_device , offer - > resource ) ;
it = eina_array_iterator_new ( source - > mime_types ) ;
EINA_ITERATOR_FOREACH ( it , t )
wl_data_offer_send_offer ( offer - > resource , t ) ;
eina_iterator_free ( it ) ;
data_offer_update_action ( offer ) ;
return offer - > resource ;
}
@ -270,7 +468,7 @@ _e_comp_wl_data_device_selection_set(void *data EINA_UNUSED, E_Comp_Wl_Data_Sour
sel_source = ( E_Comp_Wl_Data_Source * ) e_comp_wl - > selection . data_source ;
if ( sel_source )
if ( sel_source & & ( ( sel_source - > serial ! = serial ) | | ( sel_source ! = source ) ) )
{
if ( sel_source - > cancelled )
sel_source - > cancelled ( sel_source ) ;
@ -281,7 +479,7 @@ _e_comp_wl_data_device_selection_set(void *data EINA_UNUSED, E_Comp_Wl_Data_Sour
e_comp_wl - > selection . data_source = sel_source = source ;
e_comp_wl - > clipboard . xwl_owner = NULL ;
e_comp_wl - > selection . serial = serial ;
source - > serial = e_comp_wl - > selection . serial = serial ;
if ( e_comp_wl - > kbd . enabled )
focus = e_comp_wl - > kbd . focus ;
@ -315,13 +513,17 @@ _e_comp_wl_data_device_selection_set(void *data EINA_UNUSED, E_Comp_Wl_Data_Sour
static void
_e_comp_wl_data_device_drag_finished ( E_Drag * drag , int dropped )
{
Evas_Object * o ;
Evas_Object * o , * z ;
o = edje_object_part_swallow_get ( drag - > comp_object , " e.swallow.content " ) ;
if ( eina_streq ( evas_object_type_get ( o ) , " e_comp_object " ) )
edje_object_part_unswallow ( drag - > comp_object , o ) ;
else
e_zoomap_child_set ( o , NULL ) ;
{
z = o ;
o = e_zoomap_child_get ( z ) ;
e_zoomap_child_set ( z , NULL ) ;
}
evas_object_hide ( o ) ;
evas_object_pass_events_set ( o , 1 ) ;
if ( e_comp_wl - > drag ! = drag ) return ;
@ -343,11 +545,24 @@ _e_comp_wl_data_device_drag_finished(E_Drag *drag, int dropped)
# endif
{
struct wl_resource * res ;
E_Comp_Wl_Data_Source * data_source = e_comp_wl - > drag_source ;
res = e_comp_wl_data_find_for_client ( wl_resource_get_client ( e_comp_wl - > selection . target - > comp_data - > surface ) ) ;
if ( res )
{
wl_data_device_send_drop ( res ) ;
if ( data_source - > accepted & & data_source - > current_dnd_action )
{
wl_data_device_send_drop ( res ) ;
if ( wl_resource_get_version ( data_source - > resource ) > =
WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION )
wl_data_source_send_dnd_drop_performed ( data_source - > resource ) ;
data_source - > offer - > in_ask = data_source - > current_dnd_action = =
WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK ;
}
else if ( wl_resource_get_version ( data_source - > resource ) > =
WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION )
wl_data_source_send_cancelled ( data_source - > resource ) ;
wl_data_device_send_leave ( res ) ;
}
# ifndef HAVE_WAYLAND_ONLY
@ -364,6 +579,24 @@ _e_comp_wl_data_device_drag_finished(E_Drag *drag, int dropped)
}
}
static void
_e_comp_wl_data_device_drag_key ( E_Drag * drag EINA_UNUSED , Ecore_Event_Key * ev )
{
uint32_t compositor_action = 0 ;
const Evas_Modifier * m ;
E_Comp_Wl_Data_Source * drag_source = e_comp_wl - > drag_source ;
m = evas_key_modifier_get ( e_comp - > evas ) ;
if ( evas_key_modifier_is_set ( m , " Shift " ) )
compositor_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE ;
else if ( evas_key_modifier_is_set ( m , " Control " ) )
compositor_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY ;
if ( drag_source - > compositor_action = = compositor_action ) return ;
drag_source - > compositor_action = compositor_action ;
if ( drag_source - > offer )
data_offer_update_action ( drag_source - > offer ) ;
}
static void
_e_comp_wl_data_device_cb_drag_start ( struct wl_client * client , struct wl_resource * resource EINA_UNUSED , struct wl_resource * source_resource , struct wl_resource * origin_resource , struct wl_resource * icon_resource , uint32_t serial )
{
@ -409,6 +642,8 @@ _e_comp_wl_data_device_cb_drag_start(struct wl_client *client, struct wl_resourc
evas_pointer_canvas_xy_get ( e_comp - > evas , & x , & y ) ;
e_comp_wl - > drag = e_drag_new ( x , y , NULL , 0 , NULL , 0 , NULL ,
_e_comp_wl_data_device_drag_finished ) ;
e_drag_key_down_cb_set ( e_comp_wl - > drag , _e_comp_wl_data_device_drag_key ) ;
e_drag_key_up_cb_set ( e_comp_wl - > drag , _e_comp_wl_data_device_drag_key ) ;
e_comp_wl - > drag - > button_mask =
evas_pointer_button_down_mask_get ( e_comp - > evas ) ;
if ( ec )
@ -437,6 +672,12 @@ _e_comp_wl_data_device_cb_selection_set(struct wl_client *client EINA_UNUSED, st
DBG ( " Data Device Selection Set " ) ;
if ( ! source_resource ) return ;
if ( ! ( source = wl_resource_get_user_data ( source_resource ) ) ) return ;
if ( source - > actions_set ) {
wl_resource_post_error ( source_resource ,
WL_DATA_SOURCE_ERROR_INVALID_SOURCE ,
" cannot set drag-and-drop source as selection " ) ;
return ;
}
_e_comp_wl_data_device_selection_set ( e_comp - > wl_comp_data , source , serial ) ;
}
@ -471,7 +712,7 @@ _e_comp_wl_data_manager_cb_device_get(struct wl_client *client, struct wl_resour
/* try to create the data device resource */
res = wl_resource_create ( client , & wl_data_device_interface , 1 , id ) ;
res = wl_resource_create ( client , & wl_data_device_interface , wl_resource_get_version ( manager_resource ) , id ) ;
if ( ! res )
{
ERR ( " Could not create data device resource " ) ;
@ -510,7 +751,7 @@ _e_comp_wl_data_cb_bind_manager(struct wl_client *client, void *data EINA_UNUSED
/* try to create data manager resource */
e_comp_wl - > mgr . resource = res =
wl_resource_create ( client , & wl_data_device_manager_interface , 1 , id ) ;
wl_resource_create ( client , & wl_data_device_manager_interface , 3 , id ) ;
if ( ! res )
{
ERR ( " Could not create data device manager " ) ;
@ -702,13 +943,32 @@ e_comp_wl_data_device_send_enter(E_Client *ec)
if ( e_client_has_xwindow ( ec ) & &
e_client_has_xwindow ( e_comp_wl - > drag_client ) )
return ;
if ( e_comp_wl - > drag & & ( e_comp_wl - > drag - > object = = ec - > frame ) ) return ;
if ( ! e_client_has_xwindow ( ec ) )
{
E_Comp_Wl_Data_Source * drag_source = e_comp_wl - > drag_source ;
if ( drag_source & &
drag_source - > offer )
{
E_Comp_Wl_Data_Offer * offer ;
/* Unlink the offer from the source */
offer = drag_source - > offer ;
offer - > source = NULL ;
drag_source - > offer = NULL ;
drag_source - > accepted = 0 ;
wl_list_remove ( & offer - > source_destroy_listener . link ) ;
}
data_device_res =
e_comp_wl_data_find_for_client ( wl_resource_get_client ( ec - > comp_data - > surface ) ) ;
if ( ! data_device_res ) return ;
offer_res = e_comp_wl_data_device_send_offer ( ec ) ;
if ( e_comp_wl - > drag_source & & ( ! offer_res ) ) return ;
if ( offer_res )
{
if ( wl_resource_get_version ( offer_res ) > = WL_DATA_OFFER_SOURCE_ACTIONS_SINCE_VERSION )
wl_data_offer_send_source_actions ( offer_res , drag_source - > dnd_actions ) ;
}
}
e_comp_wl - > selection . target = ec ;
evas_object_event_callback_add ( ec - > frame , EVAS_CALLBACK_DEL ,
@ -770,6 +1030,7 @@ e_comp_wl_data_device_send_leave(E_Client *ec)
if ( e_client_has_xwindow ( ec ) & &
e_client_has_xwindow ( e_comp_wl - > drag_client ) )
return ;
if ( e_comp_wl - > drag & & ( e_comp_wl - > drag - > object = = ec - > frame ) ) return ;
evas_object_event_callback_del_full ( ec - > frame , EVAS_CALLBACK_DEL ,
_e_comp_wl_data_device_target_del , ec ) ;
if ( e_comp_wl - > selection . target = = ec )
@ -864,8 +1125,8 @@ e_comp_wl_data_manager_init(void)
{
/* try to create global data manager */
e_comp_wl - > mgr . global =
wl_global_create ( e_comp_wl - > wl . disp , & wl_data_device_manager_interface , 1 ,
e_comp - > wl_comp_data , _e_comp_wl_data_cb_bind_manager ) ;
wl_global_create ( e_comp_wl - > wl . disp , & wl_data_device_manager_interface , 3 ,
NULL , _e_comp_wl_data_cb_bind_manager ) ;
if ( ! e_comp_wl - > mgr . global )
{
ERR ( " Could not create global for data device manager " ) ;
@ -917,7 +1178,7 @@ e_comp_wl_data_manager_source_create(struct wl_client *client, struct wl_resourc
source - > cancelled = _e_comp_wl_data_source_cancelled_send ;
source - > resource =
wl_resource_create ( client , & wl_data_source_interface , 1 , id ) ;
wl_resource_create ( client , & wl_data_source_interface , wl_resource_get_version ( resource ) , id ) ;
if ( ! source - > resource )
{
ERR ( " Could not create data source resource " ) ;