6 #define XDND_SOURCE_RESPONSE_MAX_DELAY 3000
8 #define VERSION_INFO(dragInfo) dragInfo->protocolVersion
10 #define XDND_PROPERTY_FORMAT 32
11 #define XDND_ACTION_DESCRIPTION_FORMAT 8
13 #define XDND_DEST_INFO(dragInfo) dragInfo->destInfo
14 #define XDND_SOURCE_WIN(dragInfo) dragInfo->destInfo->sourceWindow
15 #define XDND_DEST_VIEW(dragInfo) dragInfo->destInfo->destView
16 #define XDND_DEST_STATE(dragInfo) dragInfo->destInfo->state
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_SOURCE_OPERATIONS(dragInfo) dragInfo->destInfo->sourceOperations
23 #define XDND_DROP_DATAS(dragInfo) dragInfo->destInfo->dropDatas
24 #define XDND_DROP_DATA_COUNT(dragInfo) dragInfo->destInfo->dropDataCount
25 #define XDND_DEST_VIEW_STORED(dragInfo) ((dragInfo->destInfo) != NULL)\
26 && ((dragInfo->destInfo->destView) != NULL)
29 static unsigned char XDNDversion
= XDND_VERSION
;
30 static WMHandlerID dndDestinationTimer
= NULL
;
33 static void* idleState(WMView
*destView
, XClientMessageEvent
*event
,
34 WMDraggingInfo
*info
);
35 static void* waitEnterState(WMView
*destView
, XClientMessageEvent
*event
,
36 WMDraggingInfo
*info
);
37 static void* inspectDropDataState(WMView
*destView
, XClientMessageEvent
*event
,
38 WMDraggingInfo
*info
);
39 static void* dropAllowedState(WMView
*destView
, XClientMessageEvent
*event
,
40 WMDraggingInfo
*info
);
41 static void* dropNotAllowedState(WMView
*destView
, XClientMessageEvent
*event
,
42 WMDraggingInfo
*info
);
43 static void* waitForDropDataState(WMView
*destView
, XClientMessageEvent
*event
,
44 WMDraggingInfo
*info
);
46 /* ----- Types & datas list ----- */
48 freeSourceTypeArrayItem(void *type
)
55 createSourceTypeArray(int initialSize
)
57 return WMCreateArrayWithDestructor(initialSize
, freeSourceTypeArrayItem
);
62 freeDropDataArrayItem(void* data
)
65 WMReleaseData((WMData
*) data
);
70 createDropDataArray(WMArray
*requiredTypes
)
72 if (requiredTypes
!= NULL
)
73 return WMCreateArrayWithDestructor(
74 WMGetArrayItemCount(requiredTypes
),
75 freeDropDataArrayItem
);
78 return WMCreateArray(0);
82 getTypesFromTypeList(WMScreen
*scr
, Window sourceWin
)
84 /* // WMDraggingInfo *info = &scr->dragInfo;*/
89 unsigned long count
, remaining
;
90 unsigned char *data
= NULL
;
92 XGetWindowProperty(scr
->display
, sourceWin
, scr
->xdndTypeListAtom
,
93 0, 0x8000000L
, False
, XA_ATOM
, &dataType
, &format
,
94 &count
, &remaining
, &data
);
96 if (dataType
!=XA_ATOM
|| format
!=XDND_PROPERTY_FORMAT
|| count
==0 || !data
) {
100 return createSourceTypeArray(0);
103 typeList
= createSourceTypeArray(count
);
104 typeAtomList
= (Atom
*) data
;
105 for (i
=0; i
< count
; i
++) {
106 WMAddToArray(typeList
, XGetAtomName(scr
->display
, typeAtomList
[i
]));
116 getTypesFromThreeTypes(WMScreen
*scr
, XClientMessageEvent
*event
)
122 typeList
= createSourceTypeArray(3);
123 for (i
= 2; i
< 5; i
++) {
124 if (event
->data
.l
[i
] != None
) {
125 atom
= (Atom
)event
->data
.l
[i
];
126 WMAddToArray(typeList
, XGetAtomName(scr
->display
, atom
));
135 storeRequiredTypeList(WMDraggingInfo
*info
)
137 WMView
*destView
= XDND_DEST_VIEW(info
);
138 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
139 WMArray
*requiredTypes
;
141 /* First, see if the 3 source types are enough for dest requirements */
142 requiredTypes
= destView
->dragDestinationProcs
->requiredDataTypes(
144 W_ActionToOperation(scr
, XDND_SOURCE_ACTION(info
)),
145 XDND_SOURCE_TYPES(info
));
147 if (requiredTypes
== NULL
&& XDND_TYPE_LIST_AVAILABLE(info
)) {
148 /* None of the 3 source types fits, get the whole type list */
150 destView
->dragDestinationProcs
->requiredDataTypes(
152 W_ActionToOperation(scr
, XDND_SOURCE_ACTION(info
)),
153 getTypesFromTypeList(scr
, XDND_SOURCE_WIN(info
)));
157 XDND_REQUIRED_TYPES(info
) = requiredTypes
;
162 getNextRequestedDataType(WMDraggingInfo
*info
)
164 /* get the type of the first data not yet retrieved from selection */
167 if (XDND_REQUIRED_TYPES(info
) != NULL
) {
168 nextTypeIndex
= WMGetArrayItemCount(XDND_DROP_DATAS(info
));
169 return WMGetFromArray(XDND_REQUIRED_TYPES(info
), nextTypeIndex
);
170 /* NULL if no more type */
176 /* ----- Action list ----- */
179 sourceOperationList(WMScreen
*scr
, Window sourceWin
)
181 Atom dataType
, *actionList
;
183 unsigned long count
, remaining
;
184 unsigned char* actionDatas
= NULL
;
185 unsigned char* descriptionList
= NULL
;
186 WMArray
* operationArray
;
187 WMDragOperationItem
* operationItem
;
191 XGetWindowProperty(scr
->display
, sourceWin
, scr
->xdndActionListAtom
,
192 0, 0x8000000L
, False
, XA_ATOM
, &dataType
, &size
,
193 &count
, &remaining
, &actionDatas
);
195 if (dataType
!=XA_ATOM
|| size
!=XDND_PROPERTY_FORMAT
|| count
==0 || !actionDatas
) {
196 wwarning("Cannot read action list");
203 actionList
= (Atom
*)actionDatas
;
205 XGetWindowProperty(scr
->display
, sourceWin
, scr
->xdndActionDescriptionAtom
,
206 0, 0x8000000L
, False
, XA_STRING
, &dataType
, &size
,
207 &count
, &remaining
, &descriptionList
);
209 if (dataType
!=XA_STRING
|| size
!=XDND_ACTION_DESCRIPTION_FORMAT
||
210 count
==0 || !descriptionList
) {
211 wwarning("Cannot read action description list");
215 if (descriptionList
) {
216 XFree(descriptionList
);
221 operationArray
= WMCreateDragOperationArray(count
);
222 description
= descriptionList
;
224 for (i
=0; count
> 0; i
++) {
225 size
= strlen(description
);
226 operationItem
= WMCreateDragOperationItem(
227 W_ActionToOperation(scr
, actionList
[i
]),
228 wstrdup(description
));
230 WMAddToArray(operationArray
, operationItem
);
231 count
-= (size
+ 1); /* -1 : -NULL char */
233 /* next description */
234 description
= &(description
[size
+ 1]);
238 XFree(descriptionList
);
240 return operationArray
;
244 /* ----- Dragging Info ----- */
246 updateSourceWindow(WMDraggingInfo
*info
, XClientMessageEvent
*event
)
248 XDND_SOURCE_WIN(info
) = (Window
) event
->data
.l
[0];
253 findChildInWindow(Display
*dpy
, Window toplevel
, int x
, int y
)
260 if (!XQueryTree(dpy
, toplevel
, &foo
, &bar
,
261 &children
, &nchildren
) || children
== NULL
) {
265 /* first window that contains the point is the one */
266 for (i
= nchildren
-1; i
>= 0; i
--) {
267 XWindowAttributes attr
;
269 if (XGetWindowAttributes(dpy
, children
[i
], &attr
)
270 && attr
.map_state
== IsViewable
271 && x
>= attr
.x
&& y
>= attr
.y
272 && x
< attr
.x
+ attr
.width
&& y
< attr
.y
+ attr
.height
) {
276 child
= findChildInWindow(dpy
, tmp
, x
- attr
.x
, y
- attr
.y
);
292 findXdndViewInToplevel(WMView
* toplevel
, int x
, int y
)
294 WMScreen
*scr
= W_VIEW_SCREEN(toplevel
);
295 Window toplevelWin
= WMViewXID(toplevel
);
296 int xInToplevel
, yInToplevel
;
300 XTranslateCoordinates(scr
->display
, scr
->rootWin
, toplevelWin
,
301 x
, y
, &xInToplevel
, &yInToplevel
,
304 child
= findChildInWindow(scr
->display
, toplevelWin
,
305 xInToplevel
, yInToplevel
);
308 childView
= W_GetViewForXWindow(scr
->display
, child
);
310 /* if childView supports Xdnd, return childView */
311 if (childView
!= NULL
312 && childView
->dragDestinationProcs
!= NULL
)
320 /* Clear datas only used by current destination view */
322 freeDestinationViewInfos(WMDraggingInfo
*info
)
324 if (XDND_SOURCE_TYPES(info
) != NULL
) {
325 WMFreeArray(XDND_SOURCE_TYPES(info
));
326 XDND_SOURCE_TYPES(info
) = NULL
;
329 if (XDND_DROP_DATAS(info
) != NULL
) {
330 WMFreeArray(XDND_DROP_DATAS(info
));
331 XDND_DROP_DATAS(info
) = NULL
;
334 XDND_REQUIRED_TYPES(info
) = NULL
;
338 W_DragDestinationInfoClear(WMDraggingInfo
*info
)
340 W_DragDestinationStopTimer();
342 if (XDND_DEST_INFO(info
) != NULL
) {
343 freeDestinationViewInfos(info
);
345 wfree(XDND_DEST_INFO(info
));
346 XDND_DEST_INFO(info
) = NULL
;
351 initDestinationDragInfo(WMDraggingInfo
*info
)
353 XDND_DEST_INFO(info
) =
354 (W_DragDestinationInfo
*) wmalloc(sizeof(W_DragDestinationInfo
));
356 XDND_DEST_STATE(info
) = idleState
;
357 XDND_DEST_VIEW(info
) = NULL
;
359 XDND_SOURCE_TYPES(info
) = NULL
;
360 XDND_REQUIRED_TYPES(info
) = NULL
;
361 XDND_DROP_DATAS(info
) = NULL
;
366 W_DragDestinationStoreEnterMsgInfo(WMDraggingInfo
*info
,
367 WMView
*toplevel
, XClientMessageEvent
*event
)
369 WMScreen
*scr
= W_VIEW_SCREEN(toplevel
);
371 if (XDND_DEST_INFO(info
) == NULL
)
372 initDestinationDragInfo(info
);
374 updateSourceWindow(info
, event
);
376 /* store xdnd version for source */
377 info
->protocolVersion
= (event
->data
.l
[1] >> 24);
379 XDND_SOURCE_TYPES(info
) = getTypesFromThreeTypes(scr
, event
);
381 /* to use if the 3 types are not enough */
382 XDND_TYPE_LIST_AVAILABLE(info
) = (event
->data
.l
[1] & 1);
387 cancelDrop(WMView
*destView
, WMDraggingInfo
*info
);
390 suspendDropAuthorization(WMView
*destView
, WMDraggingInfo
*info
);
394 W_DragDestinationStorePositionMsgInfo(WMDraggingInfo
*info
,
395 WMView
*toplevel
, XClientMessageEvent
*event
)
397 int x
= event
->data
.l
[2] >> 16;
398 int y
= event
->data
.l
[2] & 0xffff;
402 newDestView
= findXdndViewInToplevel(toplevel
, x
, y
);
404 if (XDND_DEST_INFO(info
) == NULL
) {
405 initDestinationDragInfo(info
);
406 updateSourceWindow(info
, event
);
407 XDND_DEST_VIEW(info
) = newDestView
;
410 oldDestView
= XDND_DEST_VIEW(info
);
412 if (newDestView
!= oldDestView
) {
413 if (oldDestView
!= NULL
) {
414 suspendDropAuthorization(oldDestView
, info
);
415 XDND_DEST_STATE(info
) = dropNotAllowedState
;
418 updateSourceWindow(info
, event
);
419 XDND_DEST_VIEW(info
) = newDestView
;
421 if (newDestView
!= NULL
) {
422 if (XDND_DEST_STATE(info
) != waitEnterState
)
423 XDND_DEST_STATE(info
) = idleState
;
428 XDND_SOURCE_ACTION(info
) = event
->data
.l
[4];
430 /* note: source position is not stored */
433 /* ----- End of Dragging Info ----- */
436 /* ----- Messages ----- */
438 /* send a DnD message to the source window */
440 sendDnDClientMessage(WMView
*destView
, Atom message
,
446 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
447 WMDraggingInfo
*info
= &scr
->dragInfo
;
449 if (XDND_DEST_INFO(info
) != NULL
) {
450 if (! W_SendDnDClientMessage(scr
->display
,
451 XDND_SOURCE_WIN(info
),
459 W_DragDestinationInfoClear(info
);
466 storeDropData(WMView
*destView
, Atom selection
, Atom target
,
467 Time timestamp
, void *cdata
, WMData
*data
)
469 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
470 WMDraggingInfo
*info
= &(scr
->dragInfo
);
471 WMData
*dataToStore
= NULL
;
474 dataToStore
= WMRetainData(data
);
476 if (XDND_DEST_INFO(info
) != NULL
&& XDND_DROP_DATAS(info
) != NULL
) {
477 WMAddToArray(XDND_DROP_DATAS(info
), dataToStore
);
478 W_SendDnDClientMessage(scr
->display
, WMViewXID(destView
),
479 scr
->xdndSelectionAtom
,
487 requestDropDataInSelection(WMView
*destView
, char* type
)
489 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
492 if (!WMRequestSelection(destView
,
493 scr
->xdndSelectionAtom
,
494 XInternAtom(scr
->display
, type
, False
),
496 storeDropData
, NULL
)) {
497 wwarning("could not request data for dropped data");
509 requestDropData(WMDraggingInfo
*info
)
511 WMView
*destView
= XDND_DEST_VIEW(info
);
512 char* nextType
= getNextRequestedDataType(info
);
514 while ((nextType
!= NULL
)
515 && (!requestDropDataInSelection(destView
, nextType
)) ) {
516 /* store NULL if request failed, and try with next type */
517 WMAddToArray(XDND_DROP_DATAS(info
), NULL
);
518 nextType
= getNextRequestedDataType(info
);
521 /* remains types to retrieve ? */
522 return (nextType
!= NULL
);
527 concludeDrop(WMView
*destView
)
529 destView
->dragDestinationProcs
->concludeDragOperation(destView
);
533 /* send cancel message to the source */
535 cancelDrop(WMView
*destView
, WMDraggingInfo
*info
)
537 /* send XdndStatus with action None */
538 sendDnDClientMessage(destView
,
539 W_VIEW_SCREEN(destView
)->xdndStatusAtom
,
541 concludeDrop(destView
);
542 freeDestinationViewInfos(info
);
546 /* suspend drop, when dragged icon enter an unaware subview of destView */
548 suspendDropAuthorization(WMView
*destView
, WMDraggingInfo
*info
)
550 /* free datas that depend on destination behaviour */
551 /* (in short: only keep source's types) */
552 if (XDND_DROP_DATAS(info
) != NULL
) {
553 WMFreeArray(XDND_DROP_DATAS(info
));
554 XDND_DROP_DATAS(info
) = NULL
;
556 XDND_REQUIRED_TYPES(info
) = NULL
;
558 /* send XdndStatus with action None */
559 sendDnDClientMessage(destView
,
560 W_VIEW_SCREEN(destView
)->xdndStatusAtom
,
565 /* cancel drop on Enter message, if protocol version is nok */
567 W_DragDestinationCancelDropOnEnter(WMView
*toplevel
, WMDraggingInfo
*info
)
569 if (XDND_DEST_VIEW_STORED(info
))
570 cancelDrop(XDND_DEST_VIEW(info
), info
);
572 /* send XdndStatus with action None */
573 sendDnDClientMessage(toplevel
,
574 W_VIEW_SCREEN(toplevel
)->xdndStatusAtom
,
578 W_DragDestinationInfoClear(info
);
583 finishDrop(WMView
*destView
, WMDraggingInfo
*info
)
585 sendDnDClientMessage(destView
,
586 W_VIEW_SCREEN(destView
)->xdndFinishedAtom
,
588 concludeDrop(destView
);
589 W_DragDestinationInfoClear(info
);
594 getAllowedAction(WMView
*destView
, WMDraggingInfo
*info
)
596 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
598 return W_OperationToAction(scr
,
599 destView
->dragDestinationProcs
->allowedOperation(
601 W_ActionToOperation(scr
, XDND_SOURCE_ACTION(info
)),
602 XDND_SOURCE_TYPES(info
)));
606 /* send the action that can be performed,
607 and the limits outside wich the source must re-send
608 its position and action */
610 sendAllowedAction(WMView
*destView
, Atom action
)
612 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
613 /* // WMPoint destPos = WMGetViewScreenPosition(destView); */
614 WMSize destSize
= WMGetViewSize(destView
);
618 XTranslateCoordinates(scr
->display
, scr
->rootWin
, WMViewXID(destView
),
619 0, 0, &destX
, &destY
,
622 sendDnDClientMessage(destView
,
626 (destSize
.width
<< 16)|destSize
.height
,
632 checkActionAllowed(WMView
*destView
, WMDraggingInfo
* info
)
634 XDND_DEST_ACTION(info
) =
635 getAllowedAction(destView
, info
);
637 if (XDND_DEST_ACTION(info
) == None
) {
638 suspendDropAuthorization(destView
, info
);
639 return dropNotAllowedState
;
642 sendAllowedAction(destView
, XDND_DEST_ACTION(info
));
643 return dropAllowedState
;
647 checkDropAllowed(WMView
*destView
, XClientMessageEvent
*event
,
648 WMDraggingInfo
* info
)
650 storeRequiredTypeList(info
);
652 if (destView
->dragDestinationProcs
->inspectDropData
!= NULL
) {
653 XDND_DROP_DATAS(info
) = createDropDataArray(
654 XDND_REQUIRED_TYPES(info
));
656 /* store first available data */
657 if (requestDropData(info
))
658 return inspectDropDataState
;
660 /* no data retrieved, but inspect can allow it */
661 if (destView
->dragDestinationProcs
->inspectDropData(
663 XDND_DROP_DATAS(info
)))
664 return checkActionAllowed(destView
, info
);
666 suspendDropAuthorization(destView
, info
);
667 return dropNotAllowedState
;
670 return checkActionAllowed(destView
, info
);
674 getDropLocationInView(WMView
*view
)
676 Window rootWin
, childWin
;
681 location
= (WMPoint
*) wmalloc(sizeof(WMPoint
));
684 W_VIEW_SCREEN(view
)->display
,
685 WMViewXID(view
), &rootWin
, &childWin
,
687 &(location
->x
), &(location
->y
),
694 callPerformDragOperation(WMView
*destView
, WMDraggingInfo
*info
)
696 WMArray
*operationList
= NULL
;
697 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
698 WMPoint
* dropLocation
;
700 if (XDND_SOURCE_ACTION(info
) == scr
->xdndActionAsk
)
701 operationList
= sourceOperationList(scr
, XDND_SOURCE_WIN(info
));
703 dropLocation
= getDropLocationInView(destView
);
704 destView
->dragDestinationProcs
->performDragOperation(
706 XDND_DROP_DATAS(info
),
711 if (operationList
!= NULL
)
712 WMFreeArray(operationList
);
716 /* ----- Destination timer ----- */
718 dragSourceResponseTimeOut(void *destView
)
720 WMView
*view
= (WMView
*) destView
;
721 WMDraggingInfo
*info
;
723 wwarning("delay for drag source response expired");
725 info
= &(W_VIEW_SCREEN(view
)->dragInfo
);
726 if (XDND_DEST_VIEW_STORED(info
))
727 cancelDrop(view
, info
);
729 /* send XdndStatus with action None */
730 sendDnDClientMessage(view
,
731 W_VIEW_SCREEN(view
)->xdndStatusAtom
,
735 W_DragDestinationInfoClear(info
);
740 W_DragDestinationStopTimer()
742 if (dndDestinationTimer
!= NULL
) {
743 WMDeleteTimerHandler(dndDestinationTimer
);
744 dndDestinationTimer
= NULL
;
749 W_DragDestinationStartTimer(WMDraggingInfo
*info
)
751 W_DragDestinationStopTimer();
753 if (XDND_DEST_STATE(info
) != idleState
754 || XDND_DEST_VIEW(info
) == NULL
) {
755 /* note: info->destView == NULL means :
756 Enter message has been received, waiting for Position message */
758 dndDestinationTimer
= WMAddTimerHandler(
759 XDND_SOURCE_RESPONSE_MAX_DELAY
,
760 dragSourceResponseTimeOut
,
761 XDND_DEST_VIEW(info
));
764 /* ----- End of Destination timer ----- */
767 /* ----- Destination states ----- */
771 stateName(W_DndState
*state
)
774 return "no state defined";
776 if (state
== idleState
)
779 if (state
== waitEnterState
)
780 return "waitEnterState";
782 if (state
== inspectDropDataState
)
783 return "inspectDropDataState";
785 if (state
== dropAllowedState
)
786 return "dropAllowedState";
788 if (state
== dropNotAllowedState
)
789 return "dropNotAllowedState";
791 if (state
== waitForDropDataState
)
792 return "waitForDropDataState";
794 return "unknown state";
799 idleState(WMView
*destView
, XClientMessageEvent
*event
,
800 WMDraggingInfo
*info
)
805 scr
= W_VIEW_SCREEN(destView
);
806 sourceMsg
= event
->message_type
;
808 if (sourceMsg
== scr
->xdndPositionAtom
) {
809 destView
->dragDestinationProcs
->prepareForDragOperation(destView
);
811 if (XDND_SOURCE_TYPES(info
) != NULL
) {
812 /* enter message infos are available */
813 return checkDropAllowed(destView
, event
, info
);
816 /* waiting for enter message */
817 return waitEnterState
;
824 /* Source position and action are stored,
825 waiting for xdnd protocol version and source type */
827 waitEnterState(WMView
*destView
, XClientMessageEvent
*event
,
828 WMDraggingInfo
*info
)
830 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
831 Atom sourceMsg
= event
->message_type
;
833 if (sourceMsg
== scr
->xdndEnterAtom
) {
834 W_DragDestinationStoreEnterMsgInfo(info
, destView
, event
);
835 return checkDropAllowed(destView
, event
, info
);
838 return waitEnterState
;
842 /* We have requested a data, and have received it */
844 inspectDropDataState(WMView
*destView
, XClientMessageEvent
*event
,
845 WMDraggingInfo
*info
)
850 scr
= W_VIEW_SCREEN(destView
);
851 sourceMsg
= event
->message_type
;
853 if (sourceMsg
== scr
->xdndSelectionAtom
) {
854 /* a data has been retrieved, store next available */
855 if (requestDropData(info
))
856 return inspectDropDataState
;
858 /* all required (and available) datas are stored */
859 if (destView
->dragDestinationProcs
->inspectDropData(
861 XDND_DROP_DATAS(info
)))
862 return checkActionAllowed(destView
, info
);
864 suspendDropAuthorization(destView
, info
);
865 return dropNotAllowedState
;
868 return inspectDropDataState
;
873 dropNotAllowedState(WMView
*destView
, XClientMessageEvent
*event
,
874 WMDraggingInfo
*info
)
876 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
877 Atom sourceMsg
= event
->message_type
;
879 if (sourceMsg
== scr
->xdndDropAtom
) {
880 finishDrop(destView
, info
);
884 return dropNotAllowedState
;
889 dropAllowedState(WMView
*destView
, XClientMessageEvent
*event
,
890 WMDraggingInfo
*info
)
892 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
893 Atom sourceMsg
= event
->message_type
;
895 if (sourceMsg
== scr
->xdndDropAtom
) {
896 if (XDND_DROP_DATAS(info
) != NULL
) {
897 /* drop datas were cached with inspectDropData call */
898 callPerformDragOperation(destView
, info
);
900 XDND_DROP_DATAS(info
) = createDropDataArray(
901 XDND_REQUIRED_TYPES(info
));
903 /* store first available data */
904 if (requestDropData(info
))
905 return waitForDropDataState
;
907 /* no data retrieved */
908 callPerformDragOperation(destView
, info
);
911 finishDrop(destView
, info
);
915 return dropAllowedState
;
920 waitForDropDataState(WMView
*destView
, XClientMessageEvent
*event
,
921 WMDraggingInfo
*info
)
923 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
924 Atom sourceMsg
= event
->message_type
;
926 if (sourceMsg
== scr
->xdndSelectionAtom
) {
927 /* store next data */
928 if (requestDropData(info
))
929 return waitForDropDataState
;
931 /* all required (and available) datas are stored */
932 callPerformDragOperation(destView
, info
);
934 finishDrop(destView
, info
);
938 return waitForDropDataState
;
941 /* ----- End of Destination states ----- */
945 W_DragDestinationStateHandler(WMDraggingInfo
*info
, XClientMessageEvent
*event
)
948 W_DndState
* newState
;
950 if (XDND_DEST_VIEW_STORED(info
)) {
951 destView
= XDND_DEST_VIEW(info
);
952 if (XDND_DEST_STATE(info
) == NULL
)
953 XDND_DEST_STATE(info
) = idleState
;
957 printf("current dest state: %s\n",
958 stateName(XDND_DEST_STATE(info
)));
961 newState
= (W_DndState
*) XDND_DEST_STATE(info
)(destView
, event
, info
);
965 printf("new dest state: %s\n", stateName(newState
));
968 if (XDND_DEST_INFO(info
) != NULL
) {
969 XDND_DEST_STATE(info
) = newState
;
970 if (XDND_DEST_STATE(info
) != idleState
)
971 W_DragDestinationStartTimer(info
);
978 realizedObserver(void *self
, WMNotification
*notif
)
980 WMView
*view
= (WMView
*)WMGetNotificationObject(notif
);
981 WMScreen
*scr
= W_VIEW_SCREEN(view
);
983 XChangeProperty(scr
->display
, W_VIEW_DRAWABLE(view
),
985 XA_ATOM
, XDND_PROPERTY_FORMAT
, PropModeReplace
,
988 WMRemoveNotificationObserver(self
);
993 W_SetXdndAwareProperty(WMScreen
*scr
, WMView
*view
, Atom
*types
,
996 WMView
*toplevel
= W_TopLevelOfView(view
);
998 if (!toplevel
->flags
.xdndHintSet
) {
999 toplevel
->flags
.xdndHintSet
= 1;
1001 if (toplevel
->flags
.realized
) {
1002 XChangeProperty(scr
->display
, W_VIEW_DRAWABLE(toplevel
),
1003 scr
->xdndAwareAtom
, XA_ATOM
, XDND_PROPERTY_FORMAT
,
1004 PropModeReplace
, &XDNDversion
, 1);
1006 WMAddNotificationObserver(realizedObserver
,
1007 /* just use as an id */
1008 &view
->dragDestinationProcs
,
1009 WMViewRealizedNotification
,
1017 WMRegisterViewForDraggedTypes(WMView
*view
, WMArray
*acceptedTypes
)
1023 typeCount
= WMGetArrayItemCount(acceptedTypes
);
1024 types
= wmalloc(sizeof(Atom
)*(typeCount
+1));
1026 for (i
= 0; i
< typeCount
; i
++) {
1027 types
[i
] = XInternAtom(W_VIEW_SCREEN(view
)->display
,
1028 WMGetFromArray(acceptedTypes
, i
),
1033 view
->droppableTypes
= types
;
1034 /* WMFreeArray(acceptedTypes); */
1036 W_SetXdndAwareProperty(W_VIEW_SCREEN(view
), view
, types
, typeCount
);
1041 WMUnregisterViewDraggedTypes(WMView
*view
)
1043 if (view
->droppableTypes
!= NULL
)
1044 wfree(view
->droppableTypes
);
1045 view
->droppableTypes
= NULL
;
1050 requestedOperation: operation requested by the source
1051 sourceDataTypes: data types (mime-types strings) supported by the source
1052 (never NULL, destroyed when drop ends)
1053 return operation allowed by destination (self)
1055 static WMDragOperationType
1056 defAllowedOperation(WMView
*self
,
1057 WMDragOperationType requestedOperation
,
1058 WMArray
* sourceDataTypes
)
1060 /* no operation allowed */
1061 return WDOperationNone
;
1066 requestedOperation: operation requested by the source
1067 sourceDataTypes: data types (mime-types strings) supported by the source
1068 (never NULL, destroyed when drop ends)
1069 return data types (mime-types strings) required by destination (self)
1070 or NULL if no suitable data type is available (force
1071 to 2nd pass with full source type list).
1074 defRequiredDataTypes (WMView
*self
,
1075 WMDragOperationType requestedOperation
,
1076 WMArray
* sourceDataTypes
)
1078 /* no data type allowed (NULL even at 2nd pass) */
1084 Executed when the drag enters destination (self)
1087 defPrepareForDragOperation(WMView
*self
)
1093 Checks datas to be dropped (optional).
1094 dropDatas: datas (WMData*) required by destination (self)
1095 (given in same order as returned by requiredDataTypes).
1096 A NULL data means it couldn't be retreived.
1097 Destroyed when drop ends.
1098 return true if data array is ok
1100 /* Bool (*inspectDropData)(WMView *self, WMArray *dropDatas); */
1105 dropDatas: datas (WMData*) required by destination (self)
1106 (given in same order as returned by requiredDataTypes).
1107 A NULL data means it couldn't be retrivied.
1108 Destroyed when drop ends.
1109 operationList: if source operation is WDOperationAsk, contains
1110 operations (and associated texts) that can be asked
1111 to source. (destroyed after performDragOperation call)
1112 Otherwise this parameter is NULL.
1115 defPerformDragOperation(WMView
*self
, WMArray
*dropDatas
,
1116 WMArray
*operationList
, WMPoint
*dropLocation
)
1121 /* Executed after drop */
1123 defConcludeDragOperation(WMView
*self
)
1129 WMSetViewDragDestinationProcs(WMView
*view
, WMDragDestinationProcs
*procs
)
1131 if (view
->dragDestinationProcs
== NULL
) {
1132 view
->dragDestinationProcs
= wmalloc(sizeof(WMDragDestinationProcs
));
1134 free(view
->dragDestinationProcs
);
1137 *view
->dragDestinationProcs
= *procs
;
1139 /*XXX fill in non-implemented stuffs */
1140 if (procs
->allowedOperation
== NULL
) {
1141 view
->dragDestinationProcs
->allowedOperation
= defAllowedOperation
;
1143 if (procs
->allowedOperation
== NULL
) {
1144 view
->dragDestinationProcs
->requiredDataTypes
= defRequiredDataTypes
;
1147 /* note: inspectDropData can be NULL, if data consultation is not needed
1148 to give drop permission */
1150 if (procs
->prepareForDragOperation
== NULL
) {
1151 view
->dragDestinationProcs
->prepareForDragOperation
= defPrepareForDragOperation
;
1153 if (procs
->performDragOperation
== NULL
) {
1154 view
->dragDestinationProcs
->performDragOperation
= defPerformDragOperation
;
1156 if (procs
->concludeDragOperation
== NULL
) {
1157 view
->dragDestinationProcs
->concludeDragOperation
= defConcludeDragOperation
;