5 #define XDND_SOURCE_RESPONSE_MAX_DELAY 3000
7 #define XDND_PROPERTY_FORMAT 32
8 #define XDND_ACTION_DESCRIPTION_FORMAT 8
10 #define XDND_SOURCE_VERSION(dragInfo) dragInfo->protocolVersion
11 #define XDND_DEST_INFO(dragInfo) dragInfo->destInfo
12 #define XDND_AWARE_VIEW(dragInfo) dragInfo->destInfo->xdndAwareView
13 #define XDND_SOURCE_WIN(dragInfo) dragInfo->destInfo->sourceWindow
14 #define XDND_DEST_VIEW(dragInfo) dragInfo->destInfo->destView
15 #define XDND_DEST_STATE(dragInfo) dragInfo->destInfo->state
16 #define XDND_SOURCE_ACTION_CHANGED(dragInfo) dragInfo->destInfo->sourceActionChanged
17 #define XDND_SOURCE_TYPES(dragInfo) dragInfo->destInfo->sourceTypes
18 #define XDND_TYPE_LIST_AVAILABLE(dragInfo) dragInfo->destInfo->typeListAvailable
19 #define XDND_REQUIRED_TYPES(dragInfo) dragInfo->destInfo->requiredTypes
20 #define XDND_SOURCE_ACTION(dragInfo) dragInfo->sourceAction
21 #define XDND_DEST_ACTION(dragInfo) dragInfo->destinationAction
22 #define XDND_DROP_DATAS(dragInfo) dragInfo->destInfo->dropDatas
23 #define XDND_DEST_VIEW_IS_REGISTERED(dragInfo) ((dragInfo->destInfo) != NULL)\
24 && ((dragInfo->destInfo->destView->dragDestinationProcs) != NULL)
26 static const unsigned char XDNDversion
= XDND_VERSION
;
27 static WMHandlerID dndDestinationTimer
= NULL
;
29 static void *idleState(WMView
* destView
, XClientMessageEvent
* event
, WMDraggingInfo
* info
);
30 static void *waitEnterState(WMView
* destView
, XClientMessageEvent
* event
, WMDraggingInfo
* info
);
31 static void *inspectDropDataState(WMView
* destView
, XClientMessageEvent
* event
, WMDraggingInfo
* info
);
32 static void *dropAllowedState(WMView
* destView
, XClientMessageEvent
* event
, WMDraggingInfo
* info
);
33 static void *dropNotAllowedState(WMView
* destView
, XClientMessageEvent
* event
, WMDraggingInfo
* info
);
34 static void *waitForDropDataState(WMView
* destView
, XClientMessageEvent
* event
, WMDraggingInfo
* info
);
36 /* ----- Types & datas list ----- */
37 static void freeSourceTypeArrayItem(void *type
)
42 static WMArray
*createSourceTypeArray(int initialSize
)
44 return WMCreateArrayWithDestructor(initialSize
, freeSourceTypeArrayItem
);
47 static void freeDropDataArrayItem(void *data
)
50 WMReleaseData((WMData
*) data
);
53 static WMArray
*createDropDataArray(WMArray
* requiredTypes
)
55 if (requiredTypes
!= NULL
)
56 return WMCreateArrayWithDestructor(WMGetArrayItemCount(requiredTypes
), freeDropDataArrayItem
);
59 return WMCreateArray(0);
62 static WMArray
*getTypesFromTypeList(WMScreen
* scr
, Window sourceWin
)
68 unsigned long count
, remaining
;
69 unsigned char *data
= NULL
;
71 XGetWindowProperty(scr
->display
, sourceWin
, scr
->xdndTypeListAtom
,
72 0, 0x8000000L
, False
, XA_ATOM
, &dataType
, &format
, &count
, &remaining
, &data
);
74 if (dataType
!= XA_ATOM
|| format
!= XDND_PROPERTY_FORMAT
|| count
== 0 || !data
) {
78 return createSourceTypeArray(0);
81 typeList
= createSourceTypeArray(count
);
82 typeAtomList
= (Atom
*) data
;
83 for (i
= 0; i
< count
; i
++) {
84 WMAddToArray(typeList
, XGetAtomName(scr
->display
, typeAtomList
[i
]));
92 static WMArray
*getTypesFromThreeTypes(WMScreen
* scr
, XClientMessageEvent
* event
)
98 typeList
= createSourceTypeArray(3);
99 for (i
= 2; i
< 5; i
++) {
100 if (event
->data
.l
[i
] != None
) {
101 atom
= (Atom
) event
->data
.l
[i
];
102 WMAddToArray(typeList
, XGetAtomName(scr
->display
, atom
));
109 static void storeRequiredTypeList(WMDraggingInfo
* info
)
111 WMView
*destView
= XDND_DEST_VIEW(info
);
112 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
113 WMArray
*requiredTypes
;
115 /* First, see if the stored source types are enough for dest requirements */
116 requiredTypes
= destView
->dragDestinationProcs
->requiredDataTypes(destView
,
117 W_ActionToOperation(scr
,
120 XDND_SOURCE_TYPES(info
));
122 if (requiredTypes
== NULL
&& XDND_TYPE_LIST_AVAILABLE(info
)) {
123 /* None of the stored source types fits, but the whole type list
124 hasn't been retrieved yet. */
125 WMFreeArray(XDND_SOURCE_TYPES(info
));
126 XDND_SOURCE_TYPES(info
) = getTypesFromTypeList(scr
, XDND_SOURCE_WIN(info
));
127 /* Don't retrieve the type list again */
128 XDND_TYPE_LIST_AVAILABLE(info
) = False
;
131 destView
->dragDestinationProcs
->requiredDataTypes(destView
,
132 W_ActionToOperation(scr
,
135 XDND_SOURCE_TYPES(info
));
138 XDND_REQUIRED_TYPES(info
) = requiredTypes
;
141 static char *getNextRequestedDataType(WMDraggingInfo
* info
)
143 /* get the type of the first data not yet retrieved from selection */
146 if (XDND_REQUIRED_TYPES(info
) != NULL
) {
147 nextTypeIndex
= WMGetArrayItemCount(XDND_DROP_DATAS(info
));
148 return WMGetFromArray(XDND_REQUIRED_TYPES(info
), nextTypeIndex
);
149 /* NULL if no more type */
154 /* ----- Action list ----- */
156 static WMArray
*sourceOperationList(WMScreen
* scr
, Window sourceWin
)
158 Atom dataType
, *actionList
;
160 unsigned long count
, remaining
;
161 unsigned char *actionDatas
= NULL
;
162 unsigned char *descriptionList
= NULL
;
163 WMArray
*operationArray
;
164 WMDragOperationItem
*operationItem
;
168 XGetWindowProperty(scr
->display
, sourceWin
, scr
->xdndActionListAtom
,
169 0, 0x8000000L
, False
, XA_ATOM
, &dataType
, &size
, &count
, &remaining
, &actionDatas
);
171 if (dataType
!= XA_ATOM
|| size
!= XDND_PROPERTY_FORMAT
|| count
== 0 || !actionDatas
) {
172 wwarning("Cannot read action list");
179 actionList
= (Atom
*) actionDatas
;
181 XGetWindowProperty(scr
->display
, sourceWin
, scr
->xdndActionDescriptionAtom
,
182 0, 0x8000000L
, False
, XA_STRING
, &dataType
, &size
,
183 &count
, &remaining
, &descriptionList
);
185 if (dataType
!= XA_STRING
|| size
!= XDND_ACTION_DESCRIPTION_FORMAT
|| count
== 0 || !descriptionList
) {
186 wwarning("Cannot read action description list");
190 if (descriptionList
) {
191 XFree(descriptionList
);
196 operationArray
= WMCreateDragOperationArray(count
);
197 description
= (char *)descriptionList
;
199 for (i
= 0; count
> 0; i
++) {
200 size
= strlen(description
);
201 operationItem
= WMCreateDragOperationItem(W_ActionToOperation(scr
, actionList
[i
]),
202 wstrdup(description
));
204 WMAddToArray(operationArray
, operationItem
);
205 count
-= (size
+ 1); /* -1 : -NULL char */
207 /* next description */
208 description
= &(description
[size
+ 1]);
212 XFree(descriptionList
);
214 return operationArray
;
217 /* ----- Dragging Info ----- */
218 static void updateSourceWindow(WMDraggingInfo
* info
, XClientMessageEvent
* event
)
220 XDND_SOURCE_WIN(info
) = (Window
) event
->data
.l
[0];
223 static WMView
*findChildInView(WMView
* parent
, int x
, int y
)
225 if (parent
->childrenList
== NULL
)
228 WMView
*child
= parent
->childrenList
;
231 && (!child
->flags
.mapped
232 || x
< WMGetViewPosition(child
).x
233 || x
> WMGetViewPosition(child
).x
+ WMGetViewSize(child
).width
234 || y
< WMGetViewPosition(child
).y
235 || y
> WMGetViewPosition(child
).y
+ WMGetViewSize(child
).height
))
237 child
= child
->nextSister
;
242 return findChildInView(child
,
243 x
- WMGetViewPosition(child
).x
, y
- WMGetViewPosition(child
).y
);
247 static WMView
*findDestinationViewInToplevel(WMView
* toplevel
, int x
, int y
)
249 WMScreen
*scr
= W_VIEW_SCREEN(toplevel
);
250 Window toplevelWin
= WMViewXID(toplevel
);
251 int xInToplevel
, yInToplevel
;
254 XTranslateCoordinates(scr
->display
, scr
->rootWin
, toplevelWin
, x
, y
, &xInToplevel
, &yInToplevel
, &foo
);
255 return findChildInView(toplevel
, xInToplevel
, yInToplevel
);
258 /* Clear datas only used by current destination view */
259 static void freeDestinationViewInfos(WMDraggingInfo
* info
)
261 if (XDND_SOURCE_TYPES(info
) != NULL
) {
262 WMFreeArray(XDND_SOURCE_TYPES(info
));
263 XDND_SOURCE_TYPES(info
) = NULL
;
266 if (XDND_DROP_DATAS(info
) != NULL
) {
267 WMFreeArray(XDND_DROP_DATAS(info
));
268 XDND_DROP_DATAS(info
) = NULL
;
271 XDND_REQUIRED_TYPES(info
) = NULL
;
274 void W_DragDestinationInfoClear(WMDraggingInfo
* info
)
276 W_DragDestinationStopTimer();
278 if (XDND_DEST_INFO(info
) != NULL
) {
279 freeDestinationViewInfos(info
);
281 wfree(XDND_DEST_INFO(info
));
282 XDND_DEST_INFO(info
) = NULL
;
286 static void initDestinationDragInfo(WMDraggingInfo
* info
, WMView
* destView
)
288 wassertr(destView
!= NULL
);
290 XDND_DEST_INFO(info
) = (W_DragDestinationInfo
*) wmalloc(sizeof(W_DragDestinationInfo
));
292 XDND_DEST_STATE(info
) = idleState
;
293 XDND_DEST_VIEW(info
) = destView
;
295 XDND_SOURCE_ACTION_CHANGED(info
) = False
;
296 XDND_SOURCE_TYPES(info
) = NULL
;
297 XDND_REQUIRED_TYPES(info
) = NULL
;
298 XDND_DROP_DATAS(info
) = NULL
;
301 void W_DragDestinationStoreEnterMsgInfo(WMDraggingInfo
* info
, WMView
* toplevel
, XClientMessageEvent
* event
)
303 WMScreen
*scr
= W_VIEW_SCREEN(toplevel
);
305 if (XDND_DEST_INFO(info
) == NULL
)
306 initDestinationDragInfo(info
, toplevel
);
308 XDND_SOURCE_VERSION(info
) = (event
->data
.l
[1] >> 24);
309 XDND_AWARE_VIEW(info
) = toplevel
;
310 updateSourceWindow(info
, event
);
313 if (event
->data
.l
[1] & 1)
314 /* XdndTypeList property is available */
315 XDND_SOURCE_TYPES(info
) = getTypesFromTypeList(scr
, XDND_SOURCE_WIN(info
));
317 XDND_SOURCE_TYPES(info
) = getTypesFromThreeTypes(scr
, event
);
319 XDND_SOURCE_TYPES(info
) = getTypesFromThreeTypes(scr
, event
);
321 /* to use if the 3 types are not enough */
322 XDND_TYPE_LIST_AVAILABLE(info
) = (event
->data
.l
[1] & 1);
325 void W_DragDestinationStorePositionMsgInfo(WMDraggingInfo
* info
, WMView
* toplevel
, XClientMessageEvent
* event
)
327 int x
= event
->data
.l
[2] >> 16;
328 int y
= event
->data
.l
[2] & 0xffff;
331 newDestView
= findDestinationViewInToplevel(toplevel
, x
, y
);
333 if (XDND_DEST_INFO(info
) == NULL
) {
334 initDestinationDragInfo(info
, newDestView
);
335 XDND_AWARE_VIEW(info
) = toplevel
;
336 updateSourceWindow(info
, event
);
338 if (newDestView
!= XDND_DEST_VIEW(info
)) {
339 updateSourceWindow(info
, event
);
340 XDND_DEST_VIEW(info
) = newDestView
;
341 XDND_SOURCE_ACTION_CHANGED(info
) = False
;
343 if (XDND_DEST_STATE(info
) != waitEnterState
)
344 XDND_DEST_STATE(info
) = idleState
;
346 XDND_SOURCE_ACTION_CHANGED(info
) = (XDND_SOURCE_ACTION(info
) != event
->data
.l
[4]);
350 XDND_SOURCE_ACTION(info
) = event
->data
.l
[4];
352 /* note: source position is not stored */
355 /* ----- End of Dragging Info ----- */
357 /* ----- Messages ----- */
359 /* send a DnD message to the source window */
361 sendDnDClientMessage(WMDraggingInfo
* info
, Atom message
,
362 unsigned long data1
, unsigned long data2
, unsigned long data3
, unsigned long data4
)
364 if (!W_SendDnDClientMessage(W_VIEW_SCREEN(XDND_AWARE_VIEW(info
))->display
,
365 XDND_SOURCE_WIN(info
),
366 message
, WMViewXID(XDND_AWARE_VIEW(info
)), data1
, data2
, data3
, data4
)) {
368 W_DragDestinationInfoClear(info
);
372 /* send a xdndStatus message to the source, with position and size
373 of the destination if it has no subwidget (requesting a position message
374 on every move otherwise) */
375 static void sendStatusMessage(WMView
* destView
, WMDraggingInfo
* info
, Atom action
)
379 data1
= (action
== None
) ? 0 : 1;
381 if (destView
->childrenList
== NULL
) {
382 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
384 WMSize destSize
= WMGetViewSize(destView
);
387 XTranslateCoordinates(scr
->display
, WMViewXID(destView
), scr
->rootWin
, 0, 0, &destX
, &destY
, &foo
);
389 sendDnDClientMessage(info
,
390 W_VIEW_SCREEN(destView
)->xdndStatusAtom
,
392 (destX
<< 16) | destY
, (destSize
.width
<< 16) | destSize
.height
, action
);
394 /* set bit 1 to request explicitly position message on every move */
397 sendDnDClientMessage(info
, W_VIEW_SCREEN(destView
)->xdndStatusAtom
, data1
, 0, 0, action
);
402 storeDropData(WMView
* destView
, Atom selection
, Atom target
, Time timestamp
, void *cdata
, WMData
* data
)
404 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
405 WMDraggingInfo
*info
= &(scr
->dragInfo
);
406 WMData
*dataToStore
= NULL
;
408 /* Parameter not used, but tell the compiler that it is ok */
415 dataToStore
= WMRetainData(data
);
417 if (XDND_DEST_INFO(info
) != NULL
&& XDND_DROP_DATAS(info
) != NULL
) {
418 WMAddToArray(XDND_DROP_DATAS(info
), dataToStore
);
419 W_SendDnDClientMessage(scr
->display
, WMViewXID(destView
),
420 scr
->xdndSelectionAtom
, WMViewXID(destView
), 0, 0, 0, 0);
424 static Bool
requestDropDataInSelection(WMView
* destView
, const char *type
)
426 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
429 if (!WMRequestSelection(destView
,
430 scr
->xdndSelectionAtom
,
431 XInternAtom(scr
->display
, type
, False
),
432 CurrentTime
, storeDropData
, NULL
)) {
433 wwarning("could not request data for dropped data");
443 static Bool
requestDropData(WMDraggingInfo
* info
)
445 WMView
*destView
= XDND_DEST_VIEW(info
);
446 char *nextType
= getNextRequestedDataType(info
);
448 while ((nextType
!= NULL
)
449 && (!requestDropDataInSelection(destView
, nextType
))) {
450 /* store NULL if request failed, and try with next type */
451 WMAddToArray(XDND_DROP_DATAS(info
), NULL
);
452 nextType
= getNextRequestedDataType(info
);
455 /* remains types to retrieve ? */
456 return (nextType
!= NULL
);
459 static void concludeDrop(WMView
* destView
)
461 destView
->dragDestinationProcs
->concludeDragOperation(destView
);
464 /* send cancel message to the source */
465 static void cancelDrop(WMView
* destView
, WMDraggingInfo
* info
)
467 sendStatusMessage(destView
, info
, None
);
468 concludeDrop(destView
);
469 freeDestinationViewInfos(info
);
472 /* suspend drop, when dragged icon enter an unregistered view
473 or a register view that doesn't accept the drop */
474 static void suspendDropAuthorization(WMView
* destView
, WMDraggingInfo
* info
)
476 sendStatusMessage(destView
, info
, None
);
478 /* Free datas that depend on destination behaviour */
479 if (XDND_DROP_DATAS(info
) != NULL
) {
480 WMFreeArray(XDND_DROP_DATAS(info
));
481 XDND_DROP_DATAS(info
) = NULL
;
484 XDND_REQUIRED_TYPES(info
) = NULL
;
487 /* cancel drop on Enter message, if protocol version is nok */
488 void W_DragDestinationCancelDropOnEnter(WMView
* toplevel
, WMDraggingInfo
* info
)
490 if (XDND_DEST_VIEW_IS_REGISTERED(info
))
491 cancelDrop(XDND_DEST_VIEW(info
), info
);
493 sendStatusMessage(toplevel
, info
, None
);
495 W_DragDestinationInfoClear(info
);
498 static void finishDrop(WMView
* destView
, WMDraggingInfo
* info
)
500 sendDnDClientMessage(info
, W_VIEW_SCREEN(destView
)->xdndFinishedAtom
, 0, 0, 0, 0);
501 concludeDrop(destView
);
502 W_DragDestinationInfoClear(info
);
505 static Atom
getAllowedAction(WMView
* destView
, WMDraggingInfo
* info
)
507 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
509 return W_OperationToAction(scr
,
510 destView
->dragDestinationProcs
->allowedOperation(destView
,
511 W_ActionToOperation(scr
,
514 XDND_SOURCE_TYPES(info
)));
517 static void *checkActionAllowed(WMView
* destView
, WMDraggingInfo
* info
)
519 XDND_DEST_ACTION(info
) = getAllowedAction(destView
, info
);
521 if (XDND_DEST_ACTION(info
) == None
) {
522 suspendDropAuthorization(destView
, info
);
523 return dropNotAllowedState
;
526 sendStatusMessage(destView
, info
, XDND_DEST_ACTION(info
));
527 return dropAllowedState
;
530 static void *checkDropAllowed(WMView
*destView
, WMDraggingInfo
*info
)
532 storeRequiredTypeList(info
);
534 if (destView
->dragDestinationProcs
->inspectDropData
!= NULL
) {
535 XDND_DROP_DATAS(info
) = createDropDataArray(XDND_REQUIRED_TYPES(info
));
537 /* store first available data */
538 if (requestDropData(info
))
539 return inspectDropDataState
;
541 /* no data retrieved, but inspect can allow it */
542 if (destView
->dragDestinationProcs
->inspectDropData(destView
, XDND_DROP_DATAS(info
)))
543 return checkActionAllowed(destView
, info
);
545 suspendDropAuthorization(destView
, info
);
546 return dropNotAllowedState
;
549 return checkActionAllowed(destView
, info
);
552 static WMPoint
*getDropLocationInView(WMView
* view
)
554 Window rootWin
, childWin
;
559 location
= (WMPoint
*) wmalloc(sizeof(WMPoint
));
561 XQueryPointer(W_VIEW_SCREEN(view
)->display
,
562 WMViewXID(view
), &rootWin
, &childWin
, &rootX
, &rootY
, &(location
->x
), &(location
->y
), &mask
);
567 static void callPerformDragOperation(WMView
* destView
, WMDraggingInfo
* info
)
569 WMArray
*operationList
= NULL
;
570 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
571 WMPoint
*dropLocation
;
573 if (XDND_SOURCE_ACTION(info
) == scr
->xdndActionAsk
)
574 operationList
= sourceOperationList(scr
, XDND_SOURCE_WIN(info
));
576 dropLocation
= getDropLocationInView(destView
);
577 destView
->dragDestinationProcs
->performDragOperation(destView
,
578 XDND_DROP_DATAS(info
), operationList
, dropLocation
);
581 if (operationList
!= NULL
)
582 WMFreeArray(operationList
);
585 /* ----- Destination timer ----- */
586 static void dragSourceResponseTimeOut(void *destView
)
588 WMView
*view
= (WMView
*) destView
;
589 WMDraggingInfo
*info
;
591 wwarning("delay for drag source response expired");
592 info
= &(W_VIEW_SCREEN(view
)->dragInfo
);
593 if (XDND_DEST_VIEW_IS_REGISTERED(info
))
594 cancelDrop(view
, info
);
596 sendStatusMessage(view
, info
, None
);
599 W_DragDestinationInfoClear(info
);
602 void W_DragDestinationStopTimer()
604 if (dndDestinationTimer
!= NULL
) {
605 WMDeleteTimerHandler(dndDestinationTimer
);
606 dndDestinationTimer
= NULL
;
610 void W_DragDestinationStartTimer(WMDraggingInfo
* info
)
612 W_DragDestinationStopTimer();
614 if (XDND_DEST_STATE(info
) != idleState
)
615 dndDestinationTimer
= WMAddTimerHandler(XDND_SOURCE_RESPONSE_MAX_DELAY
,
616 dragSourceResponseTimeOut
, XDND_DEST_VIEW(info
));
619 /* ----- End of Destination timer ----- */
621 /* ----- Destination states ----- */
624 static const char *stateName(W_DndState
* state
)
627 return "no state defined";
629 if (state
== idleState
)
632 if (state
== waitEnterState
)
633 return "waitEnterState";
635 if (state
== inspectDropDataState
)
636 return "inspectDropDataState";
638 if (state
== dropAllowedState
)
639 return "dropAllowedState";
641 if (state
== dropNotAllowedState
)
642 return "dropNotAllowedState";
644 if (state
== waitForDropDataState
)
645 return "waitForDropDataState";
647 return "unknown state";
651 static void *idleState(WMView
* destView
, XClientMessageEvent
* event
, WMDraggingInfo
* info
)
656 if (destView
->dragDestinationProcs
!= NULL
) {
657 scr
= W_VIEW_SCREEN(destView
);
658 sourceMsg
= event
->message_type
;
660 if (sourceMsg
== scr
->xdndPositionAtom
) {
661 destView
->dragDestinationProcs
->prepareForDragOperation(destView
);
663 if (XDND_SOURCE_TYPES(info
) != NULL
) {
664 /* enter message infos are available */
665 return checkDropAllowed(destView
, info
);
668 /* waiting for enter message */
669 return waitEnterState
;
673 suspendDropAuthorization(destView
, info
);
677 /* Source position and action are stored,
678 waiting for xdnd protocol version and source type */
679 static void *waitEnterState(WMView
* destView
, XClientMessageEvent
* event
, WMDraggingInfo
* info
)
681 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
682 Atom sourceMsg
= event
->message_type
;
684 if (sourceMsg
== scr
->xdndEnterAtom
) {
685 W_DragDestinationStoreEnterMsgInfo(info
, destView
, event
);
686 return checkDropAllowed(destView
, info
);
689 return waitEnterState
;
692 /* We have requested a data, and have received it */
693 static void *inspectDropDataState(WMView
* destView
, XClientMessageEvent
* event
, WMDraggingInfo
* info
)
698 scr
= W_VIEW_SCREEN(destView
);
699 sourceMsg
= event
->message_type
;
701 if (sourceMsg
== scr
->xdndSelectionAtom
) {
702 /* a data has been retrieved, store next available */
703 if (requestDropData(info
))
704 return inspectDropDataState
;
706 /* all required (and available) datas are stored */
707 if (destView
->dragDestinationProcs
->inspectDropData(destView
, XDND_DROP_DATAS(info
)))
708 return checkActionAllowed(destView
, info
);
710 suspendDropAuthorization(destView
, info
);
711 return dropNotAllowedState
;
714 return inspectDropDataState
;
717 static void *dropNotAllowedState(WMView
* destView
, XClientMessageEvent
* event
, WMDraggingInfo
* info
)
719 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
720 Atom sourceMsg
= event
->message_type
;
722 if (sourceMsg
== scr
->xdndDropAtom
) {
723 finishDrop(destView
, info
);
727 if (sourceMsg
== scr
->xdndPositionAtom
) {
728 if (XDND_SOURCE_ACTION_CHANGED(info
)) {
729 return checkDropAllowed(destView
, info
);
731 sendStatusMessage(destView
, info
, None
);
732 return dropNotAllowedState
;
736 return dropNotAllowedState
;
739 static void *dropAllowedState(WMView
* destView
, XClientMessageEvent
* event
, WMDraggingInfo
* info
)
741 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
742 Atom sourceMsg
= event
->message_type
;
744 if (sourceMsg
== scr
->xdndDropAtom
) {
745 if (XDND_DROP_DATAS(info
) != NULL
) {
746 /* drop datas were cached with inspectDropData call */
747 callPerformDragOperation(destView
, info
);
749 XDND_DROP_DATAS(info
) = createDropDataArray(XDND_REQUIRED_TYPES(info
));
751 /* store first available data */
752 if (requestDropData(info
))
753 return waitForDropDataState
;
755 /* no data retrieved */
756 callPerformDragOperation(destView
, info
);
759 finishDrop(destView
, info
);
763 if (sourceMsg
== scr
->xdndPositionAtom
) {
764 if (XDND_SOURCE_ACTION_CHANGED(info
)) {
765 return checkDropAllowed(destView
, info
);
767 sendStatusMessage(destView
, info
, XDND_DEST_ACTION(info
));
768 return dropAllowedState
;
772 return dropAllowedState
;
775 static void *waitForDropDataState(WMView
* destView
, XClientMessageEvent
* event
, WMDraggingInfo
* info
)
777 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
778 Atom sourceMsg
= event
->message_type
;
780 if (sourceMsg
== scr
->xdndSelectionAtom
) {
781 /* store next data */
782 if (requestDropData(info
))
783 return waitForDropDataState
;
785 /* all required (and available) datas are stored */
786 callPerformDragOperation(destView
, info
);
788 finishDrop(destView
, info
);
792 return waitForDropDataState
;
795 /* ----- End of Destination states ----- */
797 void W_DragDestinationStateHandler(WMDraggingInfo
* info
, XClientMessageEvent
* event
)
800 W_DndState
*newState
;
802 wassertr(XDND_DEST_INFO(info
) != NULL
);
803 wassertr(XDND_DEST_VIEW(info
) != NULL
);
805 destView
= XDND_DEST_VIEW(info
);
806 if (XDND_DEST_STATE(info
) == NULL
)
807 XDND_DEST_STATE(info
) = idleState
;
811 printf("current dest state: %s\n", stateName(XDND_DEST_STATE(info
)));
814 newState
= (W_DndState
*) XDND_DEST_STATE(info
) (destView
, event
, info
);
818 printf("new dest state: %s\n", stateName(newState
));
821 if (XDND_DEST_INFO(info
) != NULL
) {
822 XDND_DEST_STATE(info
) = newState
;
823 if (XDND_DEST_STATE(info
) != idleState
)
824 W_DragDestinationStartTimer(info
);
828 static void realizedObserver(void *self
, WMNotification
* notif
)
830 WMView
*view
= (WMView
*) WMGetNotificationObject(notif
);
831 WMScreen
*scr
= W_VIEW_SCREEN(view
);
833 XChangeProperty(scr
->display
, W_VIEW_DRAWABLE(view
),
834 scr
->xdndAwareAtom
, XA_ATOM
, XDND_PROPERTY_FORMAT
, PropModeReplace
, &XDNDversion
, 1);
836 WMRemoveNotificationObserver(self
);
839 static void W_SetXdndAwareProperty(WMScreen
*scr
, WMView
*view
)
841 WMView
*toplevel
= W_TopLevelOfView(view
);
843 if (!toplevel
->flags
.xdndHintSet
) {
844 toplevel
->flags
.xdndHintSet
= 1;
846 if (toplevel
->flags
.realized
) {
847 XChangeProperty(scr
->display
, W_VIEW_DRAWABLE(toplevel
),
848 scr
->xdndAwareAtom
, XA_ATOM
, XDND_PROPERTY_FORMAT
,
849 PropModeReplace
, &XDNDversion
, 1);
851 WMAddNotificationObserver(realizedObserver
,
852 /* just use as an id */
853 &view
->dragDestinationProcs
,
854 WMViewRealizedNotification
, toplevel
);
859 void WMRegisterViewForDraggedTypes(WMView
* view
, WMArray
* acceptedTypes
)
865 typeCount
= WMGetArrayItemCount(acceptedTypes
);
866 types
= wmalloc(sizeof(Atom
) * (typeCount
+ 1));
868 for (i
= 0; i
< typeCount
; i
++) {
869 types
[i
] = XInternAtom(W_VIEW_SCREEN(view
)->display
, WMGetFromArray(acceptedTypes
, i
), False
);
873 view
->droppableTypes
= types
;
874 /* WMFreeArray(acceptedTypes); */
876 W_SetXdndAwareProperty(W_VIEW_SCREEN(view
), view
);
879 void WMUnregisterViewDraggedTypes(WMView
* view
)
881 if (view
->droppableTypes
!= NULL
)
882 wfree(view
->droppableTypes
);
883 view
->droppableTypes
= NULL
;
887 requestedOperation: operation requested by the source
888 sourceDataTypes: data types (mime-types strings) supported by the source
889 (never NULL, destroyed when drop ends)
890 return operation allowed by destination (self)
892 static WMDragOperationType
893 defAllowedOperation(WMView
* self
, WMDragOperationType requestedOperation
, WMArray
* sourceDataTypes
)
895 /* Parameter not used, but tell the compiler that it is ok */
897 (void) requestedOperation
;
898 (void) sourceDataTypes
;
900 /* no operation allowed */
901 return WDOperationNone
;
905 requestedOperation: operation requested by the source
906 sourceDataTypes: data types (mime-types strings) supported by the source
907 (never NULL, destroyed when drop ends)
908 return data types (mime-types strings) required by destination (self)
909 or NULL if no suitable data type is available (force
910 to 2nd pass with full source type list).
912 static WMArray
*defRequiredDataTypes(WMView
* self
,
913 WMDragOperationType requestedOperation
, WMArray
* sourceDataTypes
)
915 /* Parameter not used, but tell the compiler that it is ok */
917 (void) requestedOperation
;
918 (void) sourceDataTypes
;
920 /* no data type allowed (NULL even at 2nd pass) */
925 Executed when the drag enters destination (self)
927 static void defPrepareForDragOperation(WMView
* self
)
929 /* Parameter not used, but tell the compiler that it is ok */
934 Checks datas to be dropped (optional).
935 dropDatas: datas (WMData*) required by destination (self)
936 (given in same order as returned by requiredDataTypes).
937 A NULL data means it couldn't be retreived.
938 Destroyed when drop ends.
939 return true if data array is ok
941 /* Bool (*inspectDropData)(WMView *self, WMArray *dropDatas); */
945 dropDatas: datas (WMData*) required by destination (self)
946 (given in same order as returned by requiredDataTypes).
947 A NULL data means it couldn't be retrieved.
948 Destroyed when drop ends.
949 operationList: if source operation is WDOperationAsk, contains
950 operations (and associated texts) that can be asked
951 to source. (destroyed after performDragOperation call)
952 Otherwise this parameter is NULL.
955 defPerformDragOperation(WMView
* self
, WMArray
* dropDatas
, WMArray
* operationList
, WMPoint
* dropLocation
)
957 /* Parameter not used, but tell the compiler that it is ok */
960 (void) operationList
;
964 /* Executed after drop */
965 static void defConcludeDragOperation(WMView
* self
)
967 /* Parameter not used, but tell the compiler that it is ok */
971 void WMSetViewDragDestinationProcs(WMView
* view
, WMDragDestinationProcs
* procs
)
973 if (view
->dragDestinationProcs
== NULL
) {
974 view
->dragDestinationProcs
= wmalloc(sizeof(WMDragDestinationProcs
));
977 *view
->dragDestinationProcs
= *procs
;
979 /*XXX fill in non-implemented stuffs */
980 if (procs
->allowedOperation
== NULL
) {
981 view
->dragDestinationProcs
->allowedOperation
= defAllowedOperation
;
983 if (procs
->allowedOperation
== NULL
) {
984 view
->dragDestinationProcs
->requiredDataTypes
= defRequiredDataTypes
;
987 /* note: inspectDropData can be NULL, if data consultation is not needed
988 to give drop permission */
990 if (procs
->prepareForDragOperation
== NULL
) {
991 view
->dragDestinationProcs
->prepareForDragOperation
= defPrepareForDragOperation
;
993 if (procs
->performDragOperation
== NULL
) {
994 view
->dragDestinationProcs
->performDragOperation
= defPerformDragOperation
;
996 if (procs
->concludeDragOperation
== NULL
) {
997 view
->dragDestinationProcs
->concludeDragOperation
= defConcludeDragOperation
;