@ -190,7 +190,7 @@ dnd_redraw_handler(struct widget *widget, void *data)
struct dnd * dnd = data ;
struct rectangle allocation ;
cairo_t * cr ;
cairo_surface_t * surface ;
cairo_surface_t * surface , * item_surface ;
unsigned int i ;
surface = window_get_surface ( dnd - > window ) ;
@ -210,7 +210,13 @@ dnd_redraw_handler(struct widget *widget, void *data)
for ( i = 0 ; i < ARRAY_LENGTH ( dnd - > items ) ; i + + ) {
if ( ! dnd - > items [ i ] )
continue ;
cairo_set_source_surface ( cr , dnd - > items [ i ] - > surface ,
if ( dnd - > current_drag & & dnd - > items [ i ] = = dnd - > current_drag - > item )
item_surface = dnd - > current_drag - > translucent ;
else
item_surface = dnd - > items [ i ] - > surface ;
cairo_set_source_surface ( cr , item_surface ,
dnd - > items [ i ] - > x + allocation . x ,
dnd - > items [ i ] - > y + allocation . y ) ;
cairo_paint ( cr ) ;
@ -266,6 +272,30 @@ dnd_get_item(struct dnd *dnd, int32_t x, int32_t y)
return NULL ;
}
static int
lookup_dnd_cursor ( uint32_t dnd_action )
{
if ( dnd_action = = WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE )
return CURSOR_DND_MOVE ;
else if ( dnd_action = = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY )
return CURSOR_DND_COPY ;
return CURSOR_DND_FORBIDDEN ;
}
static void
dnd_drag_update_cursor ( struct dnd_drag * dnd_drag )
{
int cursor ;
if ( dnd_drag - > mime_type = = NULL )
cursor = CURSOR_DND_FORBIDDEN ;
else
cursor = lookup_dnd_cursor ( dnd_drag - > dnd_action ) ;
input_set_pointer_image ( dnd_drag - > input , cursor ) ;
}
static void
dnd_drag_update_surface ( struct dnd_drag * dnd_drag )
{
@ -293,6 +323,7 @@ data_source_target(void *data,
dnd_drag - > mime_type = mime_type ;
dnd_drag_update_surface ( dnd_drag ) ;
dnd_drag_update_cursor ( dnd_drag ) ;
}
static void
@ -326,13 +357,27 @@ data_source_send(void *data, struct wl_data_source *source,
}
static void
dnd_drag_destroy ( struct dnd_drag * dnd_drag )
dnd_drag_destroy ( struct dnd_drag * dnd_drag , bool delete_item )
{
struct dnd * dnd = dnd_drag - > dnd ;
unsigned int i ;
wl_data_source_destroy ( dnd_drag - > data_source ) ;
/* Destroy the item that has been dragged out */
cairo_surface_destroy ( dnd_drag - > item - > surface ) ;
free ( dnd_drag - > item ) ;
if ( delete_item ) {
for ( i = 0 ; i < ARRAY_LENGTH ( dnd - > items ) ; i + + ) {
if ( dnd_drag - > item = = dnd - > items [ i ] ) {
dnd - > items [ i ] = NULL ;
break ;
}
}
/* Destroy the item that has been dragged out */
cairo_surface_destroy ( dnd_drag - > item - > surface ) ;
free ( dnd_drag - > item ) ;
}
dnd - > current_drag = NULL ;
wl_surface_destroy ( dnd_drag - > drag_surface ) ;
@ -345,11 +390,13 @@ static void
data_source_cancelled ( void * data , struct wl_data_source * source )
{
struct dnd_drag * dnd_drag = data ;
struct dnd * dnd = dnd_drag - > dnd ;
/* The 'cancelled' event means that the source is no longer in
* use by the drag ( or current selection ) . We need to clean
* up the drag object created and the local state . */
dnd_drag_destroy ( dnd_drag ) ;
dnd_drag_destroy ( dnd_drag , false ) ;
window_schedule_redraw ( dnd - > window ) ;
}
static void
@ -361,11 +408,17 @@ static void
data_source_dnd_finished ( void * data , struct wl_data_source * source )
{
struct dnd_drag * dnd_drag = data ;
struct dnd * dnd = dnd_drag - > dnd ;
bool delete_item ;
/* The operation is already finished, we can destroy all
* related data .
*/
dnd_drag_destroy ( dnd_drag ) ;
delete_item =
dnd_drag - > dnd_action = = WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE ;
/* The operation is already finished, we can destroy all
* related data .
*/
dnd_drag_destroy ( dnd_drag , delete_item ) ;
window_schedule_redraw ( dnd - > window ) ;
}
static void
@ -375,6 +428,7 @@ data_source_action(void *data, struct wl_data_source *source, uint32_t dnd_actio
dnd_drag - > dnd_action = dnd_action ;
dnd_drag_update_surface ( dnd_drag ) ;
dnd_drag_update_cursor ( dnd_drag ) ;
}
static const struct wl_data_source_listener data_source_listener = {
@ -432,6 +486,7 @@ create_drag_source(struct dnd *dnd,
unsigned int i ;
uint32_t serial ;
cairo_surface_t * icon ;
uint32_t actions ;
widget_get_allocation ( dnd - > widget , & allocation ) ;
item = dnd_get_item ( dnd , x , y ) ;
@ -449,12 +504,8 @@ create_drag_source(struct dnd *dnd,
dnd_drag - > dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE ;
dnd_drag - > mime_type = NULL ;
for ( i = 0 ; i < ARRAY_LENGTH ( dnd - > items ) ; i + + ) {
if ( item = = dnd - > items [ i ] ) {
dnd - > items [ i ] = 0 ;
break ;
}
}
actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE |
WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY ;
display = window_get_display ( dnd - > window ) ;
compositor = display_get_compositor ( display ) ;
@ -462,6 +513,21 @@ create_drag_source(struct dnd *dnd,
dnd_drag - > drag_surface =
wl_compositor_create_surface ( compositor ) ;
if ( display_get_data_device_manager_version ( display ) <
WL_DATA_SOURCE_SET_ACTIONS_SINCE_VERSION ) {
/* Data sources version < 3 will not get action
* nor dnd_finished events , as we can ' t honor
* the " move " action at the time of finishing
* drag - and - drop , do it preemptively here .
*/
for ( i = 0 ; i < ARRAY_LENGTH ( dnd - > items ) ; i + + ) {
if ( item = = dnd - > items [ i ] ) {
dnd - > items [ i ] = NULL ;
break ;
}
}
}
if ( dnd - > self_only ) {
dnd_drag - > data_source = NULL ;
} else {
@ -478,8 +544,7 @@ create_drag_source(struct dnd *dnd,
if ( display_get_data_device_manager_version ( display ) > =
WL_DATA_SOURCE_SET_ACTIONS_SINCE_VERSION ) {
wl_data_source_set_actions ( dnd_drag - > data_source ,
WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE ) ;
wl_data_source_set_actions ( dnd_drag - > data_source , actions ) ;
}
wl_data_device_start_drag ( input_get_data_device ( input ) ,
@ -591,8 +656,6 @@ dnd_enter_handler(struct widget *widget,
struct dnd * dnd = data ;
struct pointer * new_pointer = malloc ( sizeof * new_pointer ) ;
dnd - > current_drag = NULL ;
if ( new_pointer ) {
new_pointer - > input = input ;
new_pointer - > dragging = false ;
@ -703,7 +766,6 @@ dnd_drop_handler(struct window *window, struct input *input,
message . x_offset = dnd - > current_drag - > x_offset ;
message . y_offset = dnd - > current_drag - > y_offset ;
dnd_receive_func ( & message , sizeof message , x , y , dnd ) ;
dnd - > current_drag = NULL ;
} else {
fprintf ( stderr , " ignoring drop from another client \n " ) ;
}