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
);
369 if (XDND_DEST_INFO(info
) == NULL
)
370 initDestinationDragInfo(info
);
372 updateSourceWindow(info
, event
);
374 /* store xdnd version for source */
375 info
->protocolVersion
= (event
->data
.l
[1] >> 24);
377 XDND_SOURCE_TYPES(info
) = getTypesFromThreeTypes(scr
, event
);
379 /* to use if the 3 types are not enough */
380 XDND_TYPE_LIST_AVAILABLE(info
) = (event
->data
.l
[1] & 1);
385 cancelDrop(WMView
*destView
, WMDraggingInfo
*info
);
388 suspendDropAuthorization(WMView
*destView
, WMDraggingInfo
*info
);
392 W_DragDestinationStorePositionMsgInfo(WMDraggingInfo
*info
,
393 WMView
*toplevel
, XClientMessageEvent
*event
)
395 int x
= event
->data
.l
[2] >> 16;
396 int y
= event
->data
.l
[2] & 0xffff;
400 newDestView
= findXdndViewInToplevel(toplevel
, x
, y
);
402 if (XDND_DEST_INFO(info
) == NULL
) {
403 initDestinationDragInfo(info
);
404 updateSourceWindow(info
, event
);
405 XDND_DEST_VIEW(info
) = newDestView
;
408 oldDestView
= XDND_DEST_VIEW(info
);
410 if (newDestView
!= oldDestView
) {
411 if (oldDestView
!= NULL
) {
412 suspendDropAuthorization(oldDestView
, info
);
413 XDND_DEST_STATE(info
) = dropNotAllowedState
;
416 updateSourceWindow(info
, event
);
417 XDND_DEST_VIEW(info
) = newDestView
;
419 if (newDestView
!= NULL
) {
420 if (XDND_DEST_STATE(info
) != waitEnterState
)
421 XDND_DEST_STATE(info
) = idleState
;
426 XDND_SOURCE_ACTION(info
) = event
->data
.l
[4];
428 /* note: source position is not stored */
431 /* ----- End of Dragging Info ----- */
434 /* ----- Messages ----- */
436 /* send a DnD message to the source window */
438 sendDnDClientMessage(WMView
*destView
, Atom message
,
444 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
445 WMDraggingInfo
*info
= &scr
->dragInfo
;
447 if (XDND_DEST_INFO(info
) != NULL
) {
448 if (! W_SendDnDClientMessage(scr
->display
,
449 XDND_SOURCE_WIN(info
),
457 W_DragDestinationInfoClear(info
);
464 storeDropData(WMView
*destView
, Atom selection
, Atom target
,
465 Time timestamp
, void *cdata
, WMData
*data
)
467 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
468 WMDraggingInfo
*info
= &(scr
->dragInfo
);
469 WMData
*dataToStore
= NULL
;
472 dataToStore
= WMRetainData(data
);
474 if (XDND_DEST_INFO(info
) != NULL
&& XDND_DROP_DATAS(info
) != NULL
) {
475 WMAddToArray(XDND_DROP_DATAS(info
), dataToStore
);
476 W_SendDnDClientMessage(scr
->display
, WMViewXID(destView
),
477 scr
->xdndSelectionAtom
,
485 requestDropDataInSelection(WMView
*destView
, char* type
)
487 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
490 if (!WMRequestSelection(destView
,
491 scr
->xdndSelectionAtom
,
492 XInternAtom(scr
->display
, type
, False
),
494 storeDropData
, NULL
)) {
495 wwarning("could not request data for dropped data");
507 requestDropData(WMDraggingInfo
*info
)
509 WMView
*destView
= XDND_DEST_VIEW(info
);
510 char* nextType
= getNextRequestedDataType(info
);
512 while ((nextType
!= NULL
)
513 && (!requestDropDataInSelection(destView
, nextType
)) ) {
514 /* store NULL if request failed, and try with next type */
515 WMAddToArray(XDND_DROP_DATAS(info
), NULL
);
516 nextType
= getNextRequestedDataType(info
);
519 /* remains types to retrieve ? */
520 return (nextType
!= NULL
);
525 concludeDrop(WMView
*destView
)
527 destView
->dragDestinationProcs
->concludeDragOperation(destView
);
531 /* send cancel message to the source */
533 cancelDrop(WMView
*destView
, WMDraggingInfo
*info
)
535 /* send XdndStatus with action None */
536 sendDnDClientMessage(destView
,
537 W_VIEW_SCREEN(destView
)->xdndStatusAtom
,
539 concludeDrop(destView
);
540 freeDestinationViewInfos(info
);
544 /* suspend drop, when dragged icon enter an unaware subview of destView */
546 suspendDropAuthorization(WMView
*destView
, WMDraggingInfo
*info
)
548 /* free datas that depend on destination behaviour */
549 /* (in short: only keep source's types) */
550 if (XDND_DROP_DATAS(info
) != NULL
) {
551 WMFreeArray(XDND_DROP_DATAS(info
));
552 XDND_DROP_DATAS(info
) = NULL
;
554 XDND_REQUIRED_TYPES(info
) = NULL
;
556 /* send XdndStatus with action None */
557 sendDnDClientMessage(destView
,
558 W_VIEW_SCREEN(destView
)->xdndStatusAtom
,
563 /* cancel drop on Enter message, if protocol version is nok */
565 W_DragDestinationCancelDropOnEnter(WMView
*toplevel
, WMDraggingInfo
*info
)
567 if (XDND_DEST_VIEW_STORED(info
))
568 cancelDrop(XDND_DEST_VIEW(info
), info
);
570 /* send XdndStatus with action None */
571 sendDnDClientMessage(toplevel
,
572 W_VIEW_SCREEN(toplevel
)->xdndStatusAtom
,
576 W_DragDestinationInfoClear(info
);
581 finishDrop(WMView
*destView
, WMDraggingInfo
*info
)
583 sendDnDClientMessage(destView
,
584 W_VIEW_SCREEN(destView
)->xdndFinishedAtom
,
586 concludeDrop(destView
);
587 W_DragDestinationInfoClear(info
);
592 getAllowedAction(WMView
*destView
, WMDraggingInfo
*info
)
594 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
596 return W_OperationToAction(scr
,
597 destView
->dragDestinationProcs
->allowedOperation(
599 W_ActionToOperation(scr
, XDND_SOURCE_ACTION(info
)),
600 XDND_SOURCE_TYPES(info
)));
604 /* send the action that can be performed,
605 and the limits outside wich the source must re-send
606 its position and action */
608 sendAllowedAction(WMView
*destView
, Atom action
)
610 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
611 /* // WMPoint destPos = WMGetViewScreenPosition(destView); */
612 WMSize destSize
= WMGetViewSize(destView
);
616 XTranslateCoordinates(scr
->display
, scr
->rootWin
, WMViewXID(destView
),
617 0, 0, &destX
, &destY
,
620 sendDnDClientMessage(destView
,
624 (destSize
.width
<< 16)|destSize
.height
,
630 checkActionAllowed(WMView
*destView
, WMDraggingInfo
* info
)
632 XDND_DEST_ACTION(info
) =
633 getAllowedAction(destView
, info
);
635 if (XDND_DEST_ACTION(info
) == None
) {
636 suspendDropAuthorization(destView
, info
);
637 return dropNotAllowedState
;
640 sendAllowedAction(destView
, XDND_DEST_ACTION(info
));
641 return dropAllowedState
;
645 checkDropAllowed(WMView
*destView
, XClientMessageEvent
*event
,
646 WMDraggingInfo
* info
)
648 storeRequiredTypeList(info
);
650 if (destView
->dragDestinationProcs
->inspectDropData
!= NULL
) {
651 XDND_DROP_DATAS(info
) = createDropDataArray(
652 XDND_REQUIRED_TYPES(info
));
654 /* store first available data */
655 if (requestDropData(info
))
656 return inspectDropDataState
;
658 /* no data retrieved, but inspect can allow it */
659 if (destView
->dragDestinationProcs
->inspectDropData(
661 XDND_DROP_DATAS(info
)))
662 return checkActionAllowed(destView
, info
);
664 suspendDropAuthorization(destView
, info
);
665 return dropNotAllowedState
;
668 return checkActionAllowed(destView
, info
);
672 getDropLocationInView(WMView
*view
)
674 Window rootWin
, childWin
;
679 location
= (WMPoint
*) wmalloc(sizeof(WMPoint
));
682 W_VIEW_SCREEN(view
)->display
,
683 WMViewXID(view
), &rootWin
, &childWin
,
685 &(location
->x
), &(location
->y
),
692 callPerformDragOperation(WMView
*destView
, WMDraggingInfo
*info
)
694 WMArray
*operationList
= NULL
;
695 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
696 WMPoint
* dropLocation
;
698 if (XDND_SOURCE_ACTION(info
) == scr
->xdndActionAsk
)
699 operationList
= sourceOperationList(scr
, XDND_SOURCE_WIN(info
));
701 dropLocation
= getDropLocationInView(destView
);
702 destView
->dragDestinationProcs
->performDragOperation(
704 XDND_DROP_DATAS(info
),
709 if (operationList
!= NULL
)
710 WMFreeArray(operationList
);
714 /* ----- Destination timer ----- */
716 dragSourceResponseTimeOut(void *destView
)
718 WMView
*view
= (WMView
*) destView
;
719 WMDraggingInfo
*info
;
721 wwarning("delay for drag source response expired");
723 info
= &(W_VIEW_SCREEN(view
)->dragInfo
);
724 if (XDND_DEST_VIEW_STORED(info
))
725 cancelDrop(view
, info
);
727 /* send XdndStatus with action None */
728 sendDnDClientMessage(view
,
729 W_VIEW_SCREEN(view
)->xdndStatusAtom
,
733 W_DragDestinationInfoClear(info
);
738 W_DragDestinationStopTimer()
740 if (dndDestinationTimer
!= NULL
) {
741 WMDeleteTimerHandler(dndDestinationTimer
);
742 dndDestinationTimer
= NULL
;
747 W_DragDestinationStartTimer(WMDraggingInfo
*info
)
749 W_DragDestinationStopTimer();
751 if (XDND_DEST_STATE(info
) != idleState
752 || XDND_DEST_VIEW(info
) == NULL
) {
753 /* note: info->destView == NULL means :
754 Enter message has been received, waiting for Position message */
756 dndDestinationTimer
= WMAddTimerHandler(
757 XDND_SOURCE_RESPONSE_MAX_DELAY
,
758 dragSourceResponseTimeOut
,
759 XDND_DEST_VIEW(info
));
762 /* ----- End of Destination timer ----- */
765 /* ----- Destination states ----- */
769 stateName(W_DndState
*state
)
772 return "no state defined";
774 if (state
== idleState
)
777 if (state
== waitEnterState
)
778 return "waitEnterState";
780 if (state
== inspectDropDataState
)
781 return "inspectDropDataState";
783 if (state
== dropAllowedState
)
784 return "dropAllowedState";
786 if (state
== dropNotAllowedState
)
787 return "dropNotAllowedState";
789 if (state
== waitForDropDataState
)
790 return "waitForDropDataState";
792 return "unknown state";
797 idleState(WMView
*destView
, XClientMessageEvent
*event
,
798 WMDraggingInfo
*info
)
803 scr
= W_VIEW_SCREEN(destView
);
804 sourceMsg
= event
->message_type
;
806 if (sourceMsg
== scr
->xdndPositionAtom
) {
807 destView
->dragDestinationProcs
->prepareForDragOperation(destView
);
809 if (XDND_SOURCE_TYPES(info
) != NULL
) {
810 /* enter message infos are available */
811 return checkDropAllowed(destView
, event
, info
);
814 /* waiting for enter message */
815 return waitEnterState
;
822 /* Source position and action are stored,
823 waiting for xdnd protocol version and source type */
825 waitEnterState(WMView
*destView
, XClientMessageEvent
*event
,
826 WMDraggingInfo
*info
)
828 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
829 Atom sourceMsg
= event
->message_type
;
831 if (sourceMsg
== scr
->xdndEnterAtom
) {
832 W_DragDestinationStoreEnterMsgInfo(info
, destView
, event
);
833 return checkDropAllowed(destView
, event
, info
);
836 return waitEnterState
;
840 /* We have requested a data, and have received it */
842 inspectDropDataState(WMView
*destView
, XClientMessageEvent
*event
,
843 WMDraggingInfo
*info
)
848 scr
= W_VIEW_SCREEN(destView
);
849 sourceMsg
= event
->message_type
;
851 if (sourceMsg
== scr
->xdndSelectionAtom
) {
852 /* a data has been retrieved, store next available */
853 if (requestDropData(info
))
854 return inspectDropDataState
;
856 /* all required (and available) datas are stored */
857 if (destView
->dragDestinationProcs
->inspectDropData(
859 XDND_DROP_DATAS(info
)))
860 return checkActionAllowed(destView
, info
);
862 suspendDropAuthorization(destView
, info
);
863 return dropNotAllowedState
;
866 return inspectDropDataState
;
871 dropNotAllowedState(WMView
*destView
, XClientMessageEvent
*event
,
872 WMDraggingInfo
*info
)
874 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
875 Atom sourceMsg
= event
->message_type
;
877 if (sourceMsg
== scr
->xdndDropAtom
) {
878 finishDrop(destView
, info
);
882 return dropNotAllowedState
;
887 dropAllowedState(WMView
*destView
, XClientMessageEvent
*event
,
888 WMDraggingInfo
*info
)
890 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
891 Atom sourceMsg
= event
->message_type
;
893 if (sourceMsg
== scr
->xdndDropAtom
) {
894 if (XDND_DROP_DATAS(info
) != NULL
) {
895 /* drop datas were cached with inspectDropData call */
896 callPerformDragOperation(destView
, info
);
898 XDND_DROP_DATAS(info
) = createDropDataArray(
899 XDND_REQUIRED_TYPES(info
));
901 /* store first available data */
902 if (requestDropData(info
))
903 return waitForDropDataState
;
905 /* no data retrieved */
906 callPerformDragOperation(destView
, info
);
909 finishDrop(destView
, info
);
913 return dropAllowedState
;
918 waitForDropDataState(WMView
*destView
, XClientMessageEvent
*event
,
919 WMDraggingInfo
*info
)
921 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
922 Atom sourceMsg
= event
->message_type
;
924 if (sourceMsg
== scr
->xdndSelectionAtom
) {
925 /* store next data */
926 if (requestDropData(info
))
927 return waitForDropDataState
;
929 /* all required (and available) datas are stored */
930 callPerformDragOperation(destView
, info
);
932 finishDrop(destView
, info
);
936 return waitForDropDataState
;
939 /* ----- End of Destination states ----- */
943 W_DragDestinationStateHandler(WMDraggingInfo
*info
, XClientMessageEvent
*event
)
946 W_DndState
* newState
;
948 if (XDND_DEST_VIEW_STORED(info
)) {
949 destView
= XDND_DEST_VIEW(info
);
950 if (XDND_DEST_STATE(info
) == NULL
)
951 XDND_DEST_STATE(info
) = idleState
;
955 printf("current dest state: %s\n",
956 stateName(XDND_DEST_STATE(info
)));
959 newState
= (W_DndState
*) XDND_DEST_STATE(info
)(destView
, event
, info
);
963 printf("new dest state: %s\n", stateName(newState
));
966 if (XDND_DEST_INFO(info
) != NULL
) {
967 XDND_DEST_STATE(info
) = newState
;
968 if (XDND_DEST_STATE(info
) != idleState
)
969 W_DragDestinationStartTimer(info
);
976 realizedObserver(void *self
, WMNotification
*notif
)
978 WMView
*view
= (WMView
*)WMGetNotificationObject(notif
);
979 WMScreen
*scr
= W_VIEW_SCREEN(view
);
981 XChangeProperty(scr
->display
, W_VIEW_DRAWABLE(view
),
983 XA_ATOM
, XDND_PROPERTY_FORMAT
, PropModeReplace
,
986 WMRemoveNotificationObserver(self
);
991 W_SetXdndAwareProperty(WMScreen
*scr
, WMView
*view
, Atom
*types
,
994 WMView
*toplevel
= W_TopLevelOfView(view
);
996 if (!toplevel
->flags
.xdndHintSet
) {
997 toplevel
->flags
.xdndHintSet
= 1;
999 if (toplevel
->flags
.realized
) {
1000 XChangeProperty(scr
->display
, W_VIEW_DRAWABLE(toplevel
),
1001 scr
->xdndAwareAtom
, XA_ATOM
, XDND_PROPERTY_FORMAT
,
1002 PropModeReplace
, &XDNDversion
, 1);
1004 WMAddNotificationObserver(realizedObserver
,
1005 /* just use as an id */
1006 &view
->dragDestinationProcs
,
1007 WMViewRealizedNotification
,
1015 WMRegisterViewForDraggedTypes(WMView
*view
, WMArray
*acceptedTypes
)
1021 typeCount
= WMGetArrayItemCount(acceptedTypes
);
1022 types
= wmalloc(sizeof(Atom
)*(typeCount
+1));
1024 for (i
= 0; i
< typeCount
; i
++) {
1025 types
[i
] = XInternAtom(W_VIEW_SCREEN(view
)->display
,
1026 WMGetFromArray(acceptedTypes
, i
),
1031 view
->droppableTypes
= types
;
1032 /* WMFreeArray(acceptedTypes); */
1034 W_SetXdndAwareProperty(W_VIEW_SCREEN(view
), view
, types
, typeCount
);
1039 WMUnregisterViewDraggedTypes(WMView
*view
)
1041 if (view
->droppableTypes
!= NULL
)
1042 wfree(view
->droppableTypes
);
1043 view
->droppableTypes
= NULL
;
1048 requestedOperation: operation requested by the source
1049 sourceDataTypes: data types (mime-types strings) supported by the source
1050 (never NULL, destroyed when drop ends)
1051 return operation allowed by destination (self)
1053 static WMDragOperationType
1054 defAllowedOperation(WMView
*self
,
1055 WMDragOperationType requestedOperation
,
1056 WMArray
* sourceDataTypes
)
1058 /* no operation allowed */
1059 return WDOperationNone
;
1064 requestedOperation: operation requested by the source
1065 sourceDataTypes: data types (mime-types strings) supported by the source
1066 (never NULL, destroyed when drop ends)
1067 return data types (mime-types strings) required by destination (self)
1068 or NULL if no suitable data type is available (force
1069 to 2nd pass with full source type list).
1072 defRequiredDataTypes (WMView
*self
,
1073 WMDragOperationType requestedOperation
,
1074 WMArray
* sourceDataTypes
)
1076 /* no data type allowed (NULL even at 2nd pass) */
1082 Executed when the drag enters destination (self)
1085 defPrepareForDragOperation(WMView
*self
)
1091 Checks datas to be dropped (optional).
1092 dropDatas: datas (WMData*) required by destination (self)
1093 (given in same order as returned by requiredDataTypes).
1094 A NULL data means it couldn't be retreived.
1095 Destroyed when drop ends.
1096 return true if data array is ok
1098 /* Bool (*inspectDropData)(WMView *self, WMArray *dropDatas); */
1103 dropDatas: datas (WMData*) required by destination (self)
1104 (given in same order as returned by requiredDataTypes).
1105 A NULL data means it couldn't be retrivied.
1106 Destroyed when drop ends.
1107 operationList: if source operation is WDOperationAsk, contains
1108 operations (and associated texts) that can be asked
1109 to source. (destroyed after performDragOperation call)
1110 Otherwise this parameter is NULL.
1113 defPerformDragOperation(WMView
*self
, WMArray
*dropDatas
,
1114 WMArray
*operationList
, WMPoint
*dropLocation
)
1119 /* Executed after drop */
1121 defConcludeDragOperation(WMView
*self
)
1127 WMSetViewDragDestinationProcs(WMView
*view
, WMDragDestinationProcs
*procs
)
1129 if (view
->dragDestinationProcs
== NULL
) {
1130 view
->dragDestinationProcs
= wmalloc(sizeof(WMDragDestinationProcs
));
1132 free(view
->dragDestinationProcs
);
1135 *view
->dragDestinationProcs
= *procs
;
1137 /*XXX fill in non-implemented stuffs */
1138 if (procs
->allowedOperation
== NULL
) {
1139 view
->dragDestinationProcs
->allowedOperation
= defAllowedOperation
;
1141 if (procs
->allowedOperation
== NULL
) {
1142 view
->dragDestinationProcs
->requiredDataTypes
= defRequiredDataTypes
;
1145 /* note: inspectDropData can be NULL, if data consultation is not needed
1146 to give drop permission */
1148 if (procs
->prepareForDragOperation
== NULL
) {
1149 view
->dragDestinationProcs
->prepareForDragOperation
= defPrepareForDragOperation
;
1151 if (procs
->performDragOperation
== NULL
) {
1152 view
->dragDestinationProcs
->performDragOperation
= defPerformDragOperation
;
1154 if (procs
->concludeDragOperation
== NULL
) {
1155 view
->dragDestinationProcs
->concludeDragOperation
= defConcludeDragOperation
;