4 #define XDND_SOURCE_RESPONSE_MAX_DELAY 3000
6 #define VERSION_INFO(dragInfo) dragInfo->protocolVersion
8 #define XDND_PROPERTY_FORMAT 32
9 #define XDND_ACTION_DESCRIPTION_FORMAT 8
11 #define XDND_DEST_INFO(dragInfo) dragInfo->destInfo
12 #define XDND_SOURCE_WIN(dragInfo) dragInfo->destInfo->sourceWindow
13 #define XDND_DEST_VIEW(dragInfo) dragInfo->destInfo->destView
14 #define XDND_DEST_STATE(dragInfo) dragInfo->destInfo->state
15 #define XDND_SOURCE_TYPES(dragInfo) dragInfo->destInfo->sourceTypes
16 #define XDND_TYPE_LIST_AVAILABLE(dragInfo) dragInfo->destInfo->typeListAvailable
17 #define XDND_REQUIRED_TYPES(dragInfo) dragInfo->destInfo->requiredTypes
18 #define XDND_SOURCE_ACTION(dragInfo) dragInfo->sourceAction
19 #define XDND_DEST_ACTION(dragInfo) dragInfo->destinationAction
20 #define XDND_SOURCE_OPERATIONS(dragInfo) dragInfo->destInfo->sourceOperations
21 #define XDND_DROP_DATAS(dragInfo) dragInfo->destInfo->dropDatas
22 #define XDND_DROP_DATA_COUNT(dragInfo) dragInfo->destInfo->dropDataCount
23 #define XDND_DEST_VIEW_STORED(dragInfo) ((dragInfo->destInfo) != NULL)\
24 && ((dragInfo->destInfo->destView) != NULL)
27 static unsigned char XDNDversion
= XDND_VERSION
;
28 static WMHandlerID dndDestinationTimer
= NULL
;
31 static void* idleState(WMView
*destView
, XClientMessageEvent
*event
,
32 WMDraggingInfo
*info
);
33 static void* waitEnterState(WMView
*destView
, XClientMessageEvent
*event
,
34 WMDraggingInfo
*info
);
35 static void* inspectDropDataState(WMView
*destView
, XClientMessageEvent
*event
,
36 WMDraggingInfo
*info
);
37 static void* dropAllowedState(WMView
*destView
, XClientMessageEvent
*event
,
38 WMDraggingInfo
*info
);
39 static void* dropNotAllowedState(WMView
*destView
, XClientMessageEvent
*event
,
40 WMDraggingInfo
*info
);
41 static void* waitForDropDataState(WMView
*destView
, XClientMessageEvent
*event
,
42 WMDraggingInfo
*info
);
44 /* ----- Types & datas list ----- */
46 freeSourceTypeArrayItem(void *type
)
53 createSourceTypeArray(int initialSize
)
55 return WMCreateArrayWithDestructor(initialSize
, freeSourceTypeArrayItem
);
60 freeDropDataArrayItem(void* data
)
63 WMReleaseData((WMData
*) data
);
68 createDropDataArray(WMArray
*requiredTypes
)
70 if (requiredTypes
!= NULL
)
71 return WMCreateArrayWithDestructor(
72 WMGetArrayItemCount(requiredTypes
),
73 freeDropDataArrayItem
);
76 return WMCreateArray(0);
80 getTypesFromTypeList(WMScreen
*scr
, Window sourceWin
)
82 WMDraggingInfo
*info
= &scr
->dragInfo
;
87 unsigned long count
, remaining
;
88 unsigned char *data
= NULL
;
90 XGetWindowProperty(scr
->display
, sourceWin
, scr
->xdndTypeListAtom
,
91 0, 0x8000000L
, False
, XA_ATOM
, &dataType
, &format
,
92 &count
, &remaining
, &data
);
94 if (dataType
!=XA_ATOM
|| format
!=XDND_PROPERTY_FORMAT
|| count
==0 || !data
) {
98 return createSourceTypeArray(0);
101 typeList
= createSourceTypeArray(count
);
102 typeAtomList
= (Atom
*) data
;
103 for (i
=0; i
< count
; i
++) {
104 WMAddToArray(typeList
, XGetAtomName(scr
->display
, typeAtomList
[i
]));
114 getTypesFromThreeTypes(WMScreen
*scr
, XClientMessageEvent
*event
)
120 typeList
= createSourceTypeArray(3);
121 for (i
= 2; i
< 5; i
++) {
122 if (event
->data
.l
[i
] != None
) {
123 atom
= (Atom
)event
->data
.l
[i
];
124 WMAddToArray(typeList
, XGetAtomName(scr
->display
, atom
));
133 storeRequiredTypeList(WMDraggingInfo
*info
)
135 WMView
*destView
= XDND_DEST_VIEW(info
);
136 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
137 WMArray
*requiredTypes
;
139 /* First, see if the 3 source types are enough for dest requirements */
140 requiredTypes
= destView
->dragDestinationProcs
->requiredDataTypes(
142 W_ActionToOperation(scr
, XDND_SOURCE_ACTION(info
)),
143 XDND_SOURCE_TYPES(info
));
145 if (requiredTypes
== NULL
&& XDND_TYPE_LIST_AVAILABLE(info
)) {
146 /* None of the 3 source types fits, get the whole type list */
148 destView
->dragDestinationProcs
->requiredDataTypes(
150 W_ActionToOperation(scr
, XDND_SOURCE_ACTION(info
)),
151 getTypesFromTypeList(scr
, XDND_SOURCE_WIN(info
)));
155 XDND_REQUIRED_TYPES(info
) = requiredTypes
;
160 getNextRequestedDataType(WMDraggingInfo
*info
)
162 /* get the type of the first data not yet retrieved from selection */
165 if (XDND_REQUIRED_TYPES(info
) != NULL
) {
166 nextTypeIndex
= WMGetArrayItemCount(XDND_DROP_DATAS(info
));
167 return WMGetFromArray(XDND_REQUIRED_TYPES(info
), nextTypeIndex
);
168 /* NULL if no more type */
174 /* ----- Action list ----- */
177 sourceOperationList(WMScreen
*scr
, Window sourceWin
)
179 Atom dataType
, *actionList
;
181 unsigned long count
, remaining
;
182 unsigned char* actionDatas
= NULL
;
183 unsigned char* descriptionList
= NULL
;
184 WMArray
* operationArray
;
185 WMDragOperationItem
* operationItem
;
189 XGetWindowProperty(scr
->display
, sourceWin
, scr
->xdndActionListAtom
,
190 0, 0x8000000L
, False
, XA_ATOM
, &dataType
, &size
,
191 &count
, &remaining
, &actionDatas
);
193 if (dataType
!=XA_ATOM
|| size
!=XDND_PROPERTY_FORMAT
|| count
==0 || !actionDatas
) {
194 wwarning("Cannot read action list");
201 actionList
= (Atom
*)actionDatas
;
203 XGetWindowProperty(scr
->display
, sourceWin
, scr
->xdndActionDescriptionAtom
,
204 0, 0x8000000L
, False
, XA_STRING
, &dataType
, &size
,
205 &count
, &remaining
, &descriptionList
);
207 if (dataType
!=XA_STRING
|| size
!=XDND_ACTION_DESCRIPTION_FORMAT
||
208 count
==0 || !descriptionList
) {
209 wwarning("Cannot read action description list");
213 if (descriptionList
) {
214 XFree(descriptionList
);
219 operationArray
= WMCreateDragOperationArray(count
);
220 description
= descriptionList
;
222 for (i
=0; count
> 0; i
++) {
223 size
= strlen(description
);
224 operationItem
= WMCreateDragOperationItem(
225 W_ActionToOperation(scr
, actionList
[i
]),
226 wstrdup(description
));
228 WMAddToArray(operationArray
, operationItem
);
229 count
-= (size
+ 1); /* -1 : -NULL char */
231 /* next description */
232 description
= &(description
[size
+ 1]);
236 XFree(descriptionList
);
238 return operationArray
;
242 /* ----- Dragging Info ----- */
244 updateSourceWindow(WMDraggingInfo
*info
, XClientMessageEvent
*event
)
246 XDND_SOURCE_WIN(info
) = (Window
) event
->data
.l
[0];
251 findChildInWindow(Display
*dpy
, Window toplevel
, int x
, int y
)
258 if (!XQueryTree(dpy
, toplevel
, &foo
, &bar
,
259 &children
, &nchildren
) || children
== NULL
) {
263 /* first window that contains the point is the one */
264 for (i
= nchildren
-1; i
>= 0; i
--) {
265 XWindowAttributes attr
;
267 if (XGetWindowAttributes(dpy
, children
[i
], &attr
)
268 && attr
.map_state
== IsViewable
269 && x
>= attr
.x
&& y
>= attr
.y
270 && x
< attr
.x
+ attr
.width
&& y
< attr
.y
+ attr
.height
) {
274 child
= findChildInWindow(dpy
, tmp
, x
- attr
.x
, y
- attr
.y
);
290 findXdndViewInToplevel(WMView
* toplevel
, int x
, int y
)
292 WMScreen
*scr
= W_VIEW_SCREEN(toplevel
);
293 Window toplevelWin
= WMViewXID(toplevel
);
294 int xInToplevel
, yInToplevel
;
298 XTranslateCoordinates(scr
->display
, scr
->rootWin
, toplevelWin
,
299 x
, y
, &xInToplevel
, &yInToplevel
,
302 child
= findChildInWindow(scr
->display
, toplevelWin
,
303 xInToplevel
, yInToplevel
);
306 childView
= W_GetViewForXWindow(scr
->display
, child
);
308 /* if childView supports Xdnd, return childView */
309 if (childView
!= NULL
310 && childView
->dragDestinationProcs
!= NULL
)
318 /* Clear datas only used by current destination view */
320 freeDestinationViewInfos(WMDraggingInfo
*info
)
322 if (XDND_SOURCE_TYPES(info
) != NULL
) {
323 WMFreeArray(XDND_SOURCE_TYPES(info
));
324 XDND_SOURCE_TYPES(info
) = NULL
;
327 if (XDND_DROP_DATAS(info
) != NULL
) {
328 WMFreeArray(XDND_DROP_DATAS(info
));
329 XDND_DROP_DATAS(info
) = NULL
;
332 XDND_REQUIRED_TYPES(info
) = NULL
;
336 W_DragDestinationInfoClear(WMDraggingInfo
*info
)
338 W_DragDestinationStopTimer();
340 if (XDND_DEST_INFO(info
) != NULL
) {
341 freeDestinationViewInfos(info
);
343 wfree(XDND_DEST_INFO(info
));
344 XDND_DEST_INFO(info
) = NULL
;
349 initDestinationDragInfo(WMDraggingInfo
*info
)
351 XDND_DEST_INFO(info
) =
352 (W_DragDestinationInfo
*) wmalloc(sizeof(W_DragDestinationInfo
));
354 XDND_DEST_STATE(info
) = idleState
;
355 XDND_DEST_VIEW(info
) = NULL
;
357 XDND_SOURCE_TYPES(info
) = NULL
;
358 XDND_REQUIRED_TYPES(info
) = NULL
;
359 XDND_DROP_DATAS(info
) = NULL
;
364 W_DragDestinationStoreEnterMsgInfo(WMDraggingInfo
*info
,
365 WMView
*toplevel
, XClientMessageEvent
*event
)
367 WMScreen
*scr
= W_VIEW_SCREEN(toplevel
);
370 if (XDND_DEST_INFO(info
) == NULL
)
371 initDestinationDragInfo(info
);
373 updateSourceWindow(info
, event
);
375 /* store xdnd version for source */
376 info
->protocolVersion
= (event
->data
.l
[1] >> 24);
378 XDND_SOURCE_TYPES(info
) = getTypesFromThreeTypes(scr
, event
);
380 /* to use if the 3 types are not enough */
381 XDND_TYPE_LIST_AVAILABLE(info
) = (event
->data
.l
[1] & 1);
386 cancelDrop(WMView
*destView
, WMDraggingInfo
*info
);
389 suspendDropAuthorization(WMView
*destView
, WMDraggingInfo
*info
);
393 W_DragDestinationStorePositionMsgInfo(WMDraggingInfo
*info
,
394 WMView
*toplevel
, XClientMessageEvent
*event
)
396 int x
= event
->data
.l
[2] >> 16;
397 int y
= event
->data
.l
[2] & 0xffff;
401 newDestView
= findXdndViewInToplevel(toplevel
, x
, y
);
403 if (XDND_DEST_INFO(info
) == NULL
) {
404 initDestinationDragInfo(info
);
405 updateSourceWindow(info
, event
);
406 XDND_DEST_VIEW(info
) = newDestView
;
409 oldDestView
= XDND_DEST_VIEW(info
);
411 if (newDestView
!= oldDestView
) {
412 if (oldDestView
!= NULL
) {
413 suspendDropAuthorization(oldDestView
, info
);
414 XDND_DEST_STATE(info
) = dropNotAllowedState
;
417 updateSourceWindow(info
, event
);
418 XDND_DEST_VIEW(info
) = newDestView
;
420 if (newDestView
!= NULL
) {
421 if (XDND_DEST_STATE(info
) != waitEnterState
)
422 XDND_DEST_STATE(info
) = idleState
;
427 XDND_SOURCE_ACTION(info
) = event
->data
.l
[4];
429 /* note: source position is not stored */
432 /* ----- End of Dragging Info ----- */
435 /* ----- Messages ----- */
437 /* send a DnD message to the source window */
439 sendDnDClientMessage(WMView
*destView
, Atom message
,
445 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
446 WMDraggingInfo
*info
= &scr
->dragInfo
;
448 if (XDND_DEST_INFO(info
) != NULL
) {
449 if (! W_SendDnDClientMessage(scr
->display
,
450 XDND_SOURCE_WIN(info
),
458 W_DragDestinationInfoClear(info
);
465 storeDropData(WMView
*destView
, Atom selection
, Atom target
,
466 Time timestamp
, void *cdata
, WMData
*data
)
468 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
469 WMDraggingInfo
*info
= &(scr
->dragInfo
);
470 WMData
*dataToStore
= NULL
;
473 dataToStore
= WMRetainData(data
);
475 if (XDND_DEST_INFO(info
) != NULL
&& XDND_DROP_DATAS(info
) != NULL
) {
476 WMAddToArray(XDND_DROP_DATAS(info
), dataToStore
);
477 W_SendDnDClientMessage(scr
->display
, WMViewXID(destView
),
478 scr
->xdndSelectionAtom
,
486 requestDropDataInSelection(WMView
*destView
, char* type
)
488 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
491 if (!WMRequestSelection(destView
,
492 scr
->xdndSelectionAtom
,
493 XInternAtom(scr
->display
, type
, False
),
495 storeDropData
, NULL
)) {
496 wwarning("could not request data for dropped data");
508 requestDropData(WMDraggingInfo
*info
)
510 WMView
*destView
= XDND_DEST_VIEW(info
);
511 char* nextType
= getNextRequestedDataType(info
);
513 while ((nextType
!= NULL
)
514 && (!requestDropDataInSelection(destView
, nextType
)) ) {
515 /* store NULL if request failed, and try with next type */
516 WMAddToArray(XDND_DROP_DATAS(info
), NULL
);
517 nextType
= getNextRequestedDataType(info
);
520 /* remains types to retrieve ? */
521 return (nextType
!= NULL
);
526 concludeDrop(WMView
*destView
)
528 destView
->dragDestinationProcs
->concludeDragOperation(destView
);
532 /* send cancel message to the source */
534 cancelDrop(WMView
*destView
, WMDraggingInfo
*info
)
536 /* send XdndStatus with action None */
537 sendDnDClientMessage(destView
,
538 W_VIEW_SCREEN(destView
)->xdndStatusAtom
,
540 concludeDrop(destView
);
541 freeDestinationViewInfos(info
);
545 /* suspend drop, when dragged icon enter an unaware subview of destView */
547 suspendDropAuthorization(WMView
*destView
, WMDraggingInfo
*info
)
549 /* free datas that depend on destination behaviour */
550 /* (in short: only keep source's types) */
551 if (XDND_DROP_DATAS(info
) != NULL
) {
552 WMFreeArray(XDND_DROP_DATAS(info
));
553 XDND_DROP_DATAS(info
) = NULL
;
555 XDND_REQUIRED_TYPES(info
) = NULL
;
557 /* send XdndStatus with action None */
558 sendDnDClientMessage(destView
,
559 W_VIEW_SCREEN(destView
)->xdndStatusAtom
,
564 /* cancel drop on Enter message, if protocol version is nok */
566 W_DragDestinationCancelDropOnEnter(WMView
*toplevel
, WMDraggingInfo
*info
)
568 if (XDND_DEST_VIEW_STORED(info
))
569 cancelDrop(XDND_DEST_VIEW(info
), info
);
571 /* send XdndStatus with action None */
572 sendDnDClientMessage(toplevel
,
573 W_VIEW_SCREEN(toplevel
)->xdndStatusAtom
,
577 W_DragDestinationInfoClear(info
);
582 finishDrop(WMView
*destView
, WMDraggingInfo
*info
)
584 sendDnDClientMessage(destView
,
585 W_VIEW_SCREEN(destView
)->xdndFinishedAtom
,
587 concludeDrop(destView
);
588 W_DragDestinationInfoClear(info
);
593 getAllowedAction(WMView
*destView
, WMDraggingInfo
*info
)
595 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
597 return W_OperationToAction(scr
,
598 destView
->dragDestinationProcs
->allowedOperation(
600 W_ActionToOperation(scr
, XDND_SOURCE_ACTION(info
)),
601 XDND_SOURCE_TYPES(info
)));
605 /* send the action that can be performed,
606 and the limits outside wich the source must re-send
607 its position and action */
609 sendAllowedAction(WMView
*destView
, Atom action
)
611 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
612 WMPoint destPos
= WMGetViewScreenPosition(destView
);
613 WMSize destSize
= WMGetViewSize(destView
);
617 XTranslateCoordinates(scr
->display
, scr
->rootWin
, WMViewXID(destView
),
618 0, 0, &destX
, &destY
,
621 sendDnDClientMessage(destView
,
625 (destSize
.width
<< 16)|destSize
.height
,
631 checkActionAllowed(WMView
*destView
, WMDraggingInfo
* info
)
633 XDND_DEST_ACTION(info
) =
634 getAllowedAction(destView
, info
);
636 if (XDND_DEST_ACTION(info
) == None
) {
637 suspendDropAuthorization(destView
, info
);
638 return dropNotAllowedState
;
641 sendAllowedAction(destView
, XDND_DEST_ACTION(info
));
642 return dropAllowedState
;
646 checkDropAllowed(WMView
*destView
, XClientMessageEvent
*event
,
647 WMDraggingInfo
* info
)
649 storeRequiredTypeList(info
);
651 if (destView
->dragDestinationProcs
->inspectDropData
!= NULL
) {
652 XDND_DROP_DATAS(info
) = createDropDataArray(
653 XDND_REQUIRED_TYPES(info
));
655 /* store first available data */
656 if (requestDropData(info
))
657 return inspectDropDataState
;
659 /* no data retrieved, but inspect can allow it */
660 if (destView
->dragDestinationProcs
->inspectDropData(
662 XDND_DROP_DATAS(info
)))
663 return checkActionAllowed(destView
, info
);
665 suspendDropAuthorization(destView
, info
);
666 return dropNotAllowedState
;
669 return checkActionAllowed(destView
, info
);
673 getDropLocationInView(WMView
*view
)
675 Window rootWin
, childWin
;
680 location
= (WMPoint
*) wmalloc(sizeof(WMPoint
));
683 W_VIEW_SCREEN(view
)->display
,
684 WMViewXID(view
), &rootWin
, &childWin
,
686 &(location
->x
), &(location
->y
),
693 callPerformDragOperation(WMView
*destView
, WMDraggingInfo
*info
)
695 WMArray
*operationList
= NULL
;
696 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
697 WMPoint
* dropLocation
;
699 if (XDND_SOURCE_ACTION(info
) == scr
->xdndActionAsk
)
700 operationList
= sourceOperationList(scr
, XDND_SOURCE_WIN(info
));
702 dropLocation
= getDropLocationInView(destView
);
703 destView
->dragDestinationProcs
->performDragOperation(
705 XDND_DROP_DATAS(info
),
710 if (operationList
!= NULL
)
711 WMFreeArray(operationList
);
715 /* ----- Destination timer ----- */
717 dragSourceResponseTimeOut(void *destView
)
719 WMView
*view
= (WMView
*) destView
;
720 WMDraggingInfo
*info
;
722 wwarning("delay for drag source response expired");
724 info
= &(W_VIEW_SCREEN(view
)->dragInfo
);
725 if (XDND_DEST_VIEW_STORED(info
))
726 cancelDrop(view
, info
);
728 /* send XdndStatus with action None */
729 sendDnDClientMessage(view
,
730 W_VIEW_SCREEN(view
)->xdndStatusAtom
,
734 W_DragDestinationInfoClear(info
);
739 W_DragDestinationStopTimer()
741 if (dndDestinationTimer
!= NULL
) {
742 WMDeleteTimerHandler(dndDestinationTimer
);
743 dndDestinationTimer
= NULL
;
748 W_DragDestinationStartTimer(WMDraggingInfo
*info
)
750 W_DragDestinationStopTimer();
752 if (XDND_DEST_STATE(info
) != idleState
753 || XDND_DEST_VIEW(info
) == NULL
) {
754 /* note: info->destView == NULL means :
755 Enter message has been received, waiting for Position message */
757 dndDestinationTimer
= WMAddTimerHandler(
758 XDND_SOURCE_RESPONSE_MAX_DELAY
,
759 dragSourceResponseTimeOut
,
760 XDND_DEST_VIEW(info
));
763 /* ----- End of Destination timer ----- */
766 /* ----- Destination states ----- */
770 stateName(W_DndState
*state
)
773 return "no state defined";
775 if (state
== idleState
)
778 if (state
== waitEnterState
)
779 return "waitEnterState";
781 if (state
== inspectDropDataState
)
782 return "inspectDropDataState";
784 if (state
== dropAllowedState
)
785 return "dropAllowedState";
787 if (state
== dropNotAllowedState
)
788 return "dropNotAllowedState";
790 if (state
== waitForDropDataState
)
791 return "waitForDropDataState";
793 return "unknown state";
798 idleState(WMView
*destView
, XClientMessageEvent
*event
,
799 WMDraggingInfo
*info
)
804 scr
= W_VIEW_SCREEN(destView
);
805 sourceMsg
= event
->message_type
;
807 if (sourceMsg
== scr
->xdndPositionAtom
) {
808 destView
->dragDestinationProcs
->prepareForDragOperation(destView
);
810 if (XDND_SOURCE_TYPES(info
) != NULL
) {
811 /* enter message infos are available */
812 return checkDropAllowed(destView
, event
, info
);
815 /* waiting for enter message */
816 return waitEnterState
;
823 /* Source position and action are stored,
824 waiting for xdnd protocol version and source type */
826 waitEnterState(WMView
*destView
, XClientMessageEvent
*event
,
827 WMDraggingInfo
*info
)
829 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
830 Atom sourceMsg
= event
->message_type
;
832 if (sourceMsg
== scr
->xdndEnterAtom
) {
833 W_DragDestinationStoreEnterMsgInfo(info
, destView
, event
);
834 return checkDropAllowed(destView
, event
, info
);
837 return waitEnterState
;
841 /* We have requested a data, and have received it */
843 inspectDropDataState(WMView
*destView
, XClientMessageEvent
*event
,
844 WMDraggingInfo
*info
)
849 scr
= W_VIEW_SCREEN(destView
);
850 sourceMsg
= event
->message_type
;
852 if (sourceMsg
== scr
->xdndSelectionAtom
) {
853 /* a data has been retrieved, store next available */
854 if (requestDropData(info
))
855 return inspectDropDataState
;
857 /* all required (and available) datas are stored */
858 if (destView
->dragDestinationProcs
->inspectDropData(
860 XDND_DROP_DATAS(info
)))
861 return checkActionAllowed(destView
, info
);
863 suspendDropAuthorization(destView
, info
);
864 return dropNotAllowedState
;
867 return inspectDropDataState
;
872 dropNotAllowedState(WMView
*destView
, XClientMessageEvent
*event
,
873 WMDraggingInfo
*info
)
875 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
876 Atom sourceMsg
= event
->message_type
;
878 if (sourceMsg
== scr
->xdndDropAtom
) {
879 finishDrop(destView
, info
);
883 return dropNotAllowedState
;
888 dropAllowedState(WMView
*destView
, XClientMessageEvent
*event
,
889 WMDraggingInfo
*info
)
891 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
892 Atom sourceMsg
= event
->message_type
;
894 if (sourceMsg
== scr
->xdndDropAtom
) {
895 if (XDND_DROP_DATAS(info
) != NULL
) {
896 /* drop datas were cached with inspectDropData call */
897 callPerformDragOperation(destView
, info
);
899 XDND_DROP_DATAS(info
) = createDropDataArray(
900 XDND_REQUIRED_TYPES(info
));
902 /* store first available data */
903 if (requestDropData(info
))
904 return waitForDropDataState
;
906 /* no data retrieved */
907 callPerformDragOperation(destView
, info
);
910 finishDrop(destView
, info
);
914 return dropAllowedState
;
919 waitForDropDataState(WMView
*destView
, XClientMessageEvent
*event
,
920 WMDraggingInfo
*info
)
922 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
923 Atom sourceMsg
= event
->message_type
;
925 if (sourceMsg
== scr
->xdndSelectionAtom
) {
926 /* store next data */
927 if (requestDropData(info
))
928 return waitForDropDataState
;
930 /* all required (and available) datas are stored */
931 callPerformDragOperation(destView
, info
);
933 finishDrop(destView
, info
);
937 return waitForDropDataState
;
940 /* ----- End of Destination states ----- */
944 W_DragDestinationStateHandler(WMDraggingInfo
*info
, XClientMessageEvent
*event
)
947 W_DndState
* newState
;
949 if (XDND_DEST_VIEW_STORED(info
)) {
950 destView
= XDND_DEST_VIEW(info
);
951 if (XDND_DEST_STATE(info
) == NULL
)
952 XDND_DEST_STATE(info
) = idleState
;
956 printf("current dest state: %s\n",
957 stateName(XDND_DEST_STATE(info
)));
960 newState
= (W_DndState
*) XDND_DEST_STATE(info
)(destView
, event
, info
);
964 printf("new dest state: %s\n", stateName(newState
));
967 if (XDND_DEST_INFO(info
) != NULL
) {
968 XDND_DEST_STATE(info
) = newState
;
969 if (XDND_DEST_STATE(info
) != idleState
)
970 W_DragDestinationStartTimer(info
);
977 realizedObserver(void *self
, WMNotification
*notif
)
979 WMView
*view
= (WMView
*)WMGetNotificationObject(notif
);
980 WMScreen
*scr
= W_VIEW_SCREEN(view
);
982 XChangeProperty(scr
->display
, W_VIEW_DRAWABLE(view
),
984 XA_ATOM
, XDND_PROPERTY_FORMAT
, PropModeReplace
,
987 WMRemoveNotificationObserver(self
);
992 W_SetXdndAwareProperty(WMScreen
*scr
, WMView
*view
, Atom
*types
,
995 WMView
*toplevel
= W_TopLevelOfView(view
);
997 if (!toplevel
->flags
.xdndHintSet
) {
998 toplevel
->flags
.xdndHintSet
= 1;
1000 if (toplevel
->flags
.realized
) {
1001 XChangeProperty(scr
->display
, W_VIEW_DRAWABLE(toplevel
),
1002 scr
->xdndAwareAtom
, XA_ATOM
, XDND_PROPERTY_FORMAT
,
1003 PropModeReplace
, &XDNDversion
, 1);
1005 WMAddNotificationObserver(realizedObserver
,
1006 /* just use as an id */
1007 &view
->dragDestinationProcs
,
1008 WMViewRealizedNotification
,
1016 WMRegisterViewForDraggedTypes(WMView
*view
, WMArray
*acceptedTypes
)
1022 typeCount
= WMGetArrayItemCount(acceptedTypes
);
1023 types
= wmalloc(sizeof(Atom
)*(typeCount
+1));
1025 for (i
= 0; i
< typeCount
; i
++) {
1026 types
[i
] = XInternAtom(W_VIEW_SCREEN(view
)->display
,
1027 WMGetFromArray(acceptedTypes
, i
),
1032 view
->droppableTypes
= types
;
1033 /* WMFreeArray(acceptedTypes); */
1035 W_SetXdndAwareProperty(W_VIEW_SCREEN(view
), view
, types
, typeCount
);
1040 WMUnregisterViewDraggedTypes(WMView
*view
)
1042 if (view
->droppableTypes
!= NULL
)
1043 wfree(view
->droppableTypes
);
1044 view
->droppableTypes
= NULL
;
1049 requestedOperation: operation requested by the source
1050 sourceDataTypes: data types (mime-types strings) supported by the source
1051 (never NULL, destroyed when drop ends)
1052 return operation allowed by destination (self)
1054 static WMDragOperationType
1055 defAllowedOperation(WMView
*self
,
1056 WMDragOperationType requestedOperation
,
1057 WMArray
* sourceDataTypes
)
1059 /* no operation allowed */
1060 return WDOperationNone
;
1065 requestedOperation: operation requested by the source
1066 sourceDataTypes: data types (mime-types strings) supported by the source
1067 (never NULL, destroyed when drop ends)
1068 return data types (mime-types strings) required by destination (self)
1069 or NULL if no suitable data type is available (force
1070 to 2nd pass with full source type list).
1073 defRequiredDataTypes (WMView
*self
,
1074 WMDragOperationType requestedOperation
,
1075 WMArray
* sourceDataTypes
)
1077 /* no data type allowed (NULL even at 2nd pass) */
1083 Executed when the drag enters destination (self)
1086 defPrepareForDragOperation(WMView
*self
)
1092 Checks datas to be dropped (optional).
1093 dropDatas: datas (WMData*) required by destination (self)
1094 (given in same order as returned by requiredDataTypes).
1095 A NULL data means it couldn't be retreived.
1096 Destroyed when drop ends.
1097 return true if data array is ok
1099 /* Bool (*inspectDropData)(WMView *self, WMArray *dropDatas); */
1104 dropDatas: datas (WMData*) required by destination (self)
1105 (given in same order as returned by requiredDataTypes).
1106 A NULL data means it couldn't be retrivied.
1107 Destroyed when drop ends.
1108 operationList: if source operation is WDOperationAsk, contains
1109 operations (and associated texts) that can be asked
1110 to source. (destroyed after performDragOperation call)
1111 Otherwise this parameter is NULL.
1114 defPerformDragOperation(WMView
*self
, WMArray
*dropDatas
,
1115 WMArray
*operationList
, WMPoint
*dropLocation
)
1120 /* Executed after drop */
1122 defConcludeDragOperation(WMView
*self
)
1128 WMSetViewDragDestinationProcs(WMView
*view
, WMDragDestinationProcs
*procs
)
1130 if (view
->dragDestinationProcs
== NULL
) {
1131 view
->dragDestinationProcs
= wmalloc(sizeof(WMDragDestinationProcs
));
1133 free(view
->dragDestinationProcs
);
1136 *view
->dragDestinationProcs
= *procs
;
1138 /*XXX fill in non-implemented stuffs */
1139 if (procs
->allowedOperation
== NULL
) {
1140 view
->dragDestinationProcs
->allowedOperation
= defAllowedOperation
;
1142 if (procs
->allowedOperation
== NULL
) {
1143 view
->dragDestinationProcs
->requiredDataTypes
= defRequiredDataTypes
;
1146 /* note: inspectDropData can be NULL, if data consultation is not needed
1147 to give drop permission */
1149 if (procs
->prepareForDragOperation
== NULL
) {
1150 view
->dragDestinationProcs
->prepareForDragOperation
= defPrepareForDragOperation
;
1152 if (procs
->performDragOperation
== NULL
) {
1153 view
->dragDestinationProcs
->performDragOperation
= defPerformDragOperation
;
1155 if (procs
->concludeDragOperation
== NULL
) {
1156 view
->dragDestinationProcs
->concludeDragOperation
= defConcludeDragOperation
;