6 #define XDND_SOURCE_RESPONSE_MAX_DELAY 3000
8 #define XDND_PROPERTY_FORMAT 32
9 #define XDND_ACTION_DESCRIPTION_FORMAT 8
11 #define XDND_SOURCE_VERSION(dragInfo) dragInfo->protocolVersion
12 #define XDND_DEST_INFO(dragInfo) dragInfo->destInfo
13 #define XDND_AWARE_VIEW(dragInfo) dragInfo->destInfo->xdndAwareView
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_ACTION_CHANGED(dragInfo) dragInfo->destInfo->sourceActionChanged
18 #define XDND_SOURCE_TYPES(dragInfo) dragInfo->destInfo->sourceTypes
19 #define XDND_TYPE_LIST_AVAILABLE(dragInfo) dragInfo->destInfo->typeListAvailable
20 #define XDND_REQUIRED_TYPES(dragInfo) dragInfo->destInfo->requiredTypes
21 #define XDND_SOURCE_ACTION(dragInfo) dragInfo->sourceAction
22 #define XDND_DEST_ACTION(dragInfo) dragInfo->destinationAction
23 #define XDND_SOURCE_OPERATIONS(dragInfo) dragInfo->destInfo->sourceOperations
24 #define XDND_DROP_DATAS(dragInfo) dragInfo->destInfo->dropDatas
25 #define XDND_DROP_DATA_COUNT(dragInfo) dragInfo->destInfo->dropDataCount
26 #define XDND_DEST_VIEW_IS_REGISTERED(dragInfo) ((dragInfo->destInfo) != NULL)\
27 && ((dragInfo->destInfo->destView->dragDestinationProcs) != NULL)
30 static unsigned char XDNDversion
= XDND_VERSION
;
31 static WMHandlerID dndDestinationTimer
= NULL
;
34 static void* idleState(WMView
*destView
, XClientMessageEvent
*event
,
35 WMDraggingInfo
*info
);
36 static void* waitEnterState(WMView
*destView
, XClientMessageEvent
*event
,
37 WMDraggingInfo
*info
);
38 static void* inspectDropDataState(WMView
*destView
, XClientMessageEvent
*event
,
39 WMDraggingInfo
*info
);
40 static void* dropAllowedState(WMView
*destView
, XClientMessageEvent
*event
,
41 WMDraggingInfo
*info
);
42 static void* dropNotAllowedState(WMView
*destView
, XClientMessageEvent
*event
,
43 WMDraggingInfo
*info
);
44 static void* waitForDropDataState(WMView
*destView
, XClientMessageEvent
*event
,
45 WMDraggingInfo
*info
);
47 /* ----- Types & datas list ----- */
49 freeSourceTypeArrayItem(void *type
)
56 createSourceTypeArray(int initialSize
)
58 return WMCreateArrayWithDestructor(initialSize
, freeSourceTypeArrayItem
);
63 freeDropDataArrayItem(void* data
)
66 WMReleaseData((WMData
*) data
);
71 createDropDataArray(WMArray
*requiredTypes
)
73 if (requiredTypes
!= NULL
)
74 return WMCreateArrayWithDestructor(
75 WMGetArrayItemCount(requiredTypes
),
76 freeDropDataArrayItem
);
79 return WMCreateArray(0);
83 getTypesFromTypeList(WMScreen
*scr
, Window sourceWin
)
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 stored 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 stored source types fits, but the whole type list
149 hasn't been retrieved yet. */
150 WMFreeArray(XDND_SOURCE_TYPES(info
));
151 XDND_SOURCE_TYPES(info
) = getTypesFromTypeList(
153 XDND_SOURCE_WIN(info
));
154 /* Don't retrieve the type list again */
155 XDND_TYPE_LIST_AVAILABLE(info
) = False
;
158 destView
->dragDestinationProcs
->requiredDataTypes(
160 W_ActionToOperation(scr
, XDND_SOURCE_ACTION(info
)),
161 XDND_SOURCE_TYPES(info
));
164 XDND_REQUIRED_TYPES(info
) = requiredTypes
;
169 getNextRequestedDataType(WMDraggingInfo
*info
)
171 /* get the type of the first data not yet retrieved from selection */
174 if (XDND_REQUIRED_TYPES(info
) != NULL
) {
175 nextTypeIndex
= WMGetArrayItemCount(XDND_DROP_DATAS(info
));
176 return WMGetFromArray(XDND_REQUIRED_TYPES(info
), nextTypeIndex
);
177 /* NULL if no more type */
183 /* ----- Action list ----- */
186 sourceOperationList(WMScreen
*scr
, Window sourceWin
)
188 Atom dataType
, *actionList
;
190 unsigned long count
, remaining
;
191 unsigned char* actionDatas
= NULL
;
192 unsigned char* descriptionList
= NULL
;
193 WMArray
* operationArray
;
194 WMDragOperationItem
* operationItem
;
198 XGetWindowProperty(scr
->display
, sourceWin
, scr
->xdndActionListAtom
,
199 0, 0x8000000L
, False
, XA_ATOM
, &dataType
, &size
,
200 &count
, &remaining
, &actionDatas
);
202 if (dataType
!=XA_ATOM
|| size
!=XDND_PROPERTY_FORMAT
|| count
==0 || !actionDatas
) {
203 wwarning("Cannot read action list");
210 actionList
= (Atom
*)actionDatas
;
212 XGetWindowProperty(scr
->display
, sourceWin
, scr
->xdndActionDescriptionAtom
,
213 0, 0x8000000L
, False
, XA_STRING
, &dataType
, &size
,
214 &count
, &remaining
, &descriptionList
);
216 if (dataType
!=XA_STRING
|| size
!=XDND_ACTION_DESCRIPTION_FORMAT
||
217 count
==0 || !descriptionList
) {
218 wwarning("Cannot read action description list");
222 if (descriptionList
) {
223 XFree(descriptionList
);
228 operationArray
= WMCreateDragOperationArray(count
);
229 description
= (char*)descriptionList
;
231 for (i
=0; count
> 0; i
++) {
232 size
= strlen(description
);
233 operationItem
= WMCreateDragOperationItem(
234 W_ActionToOperation(scr
, actionList
[i
]),
235 wstrdup(description
));
237 WMAddToArray(operationArray
, operationItem
);
238 count
-= (size
+ 1); /* -1 : -NULL char */
240 /* next description */
241 description
= &(description
[size
+ 1]);
245 XFree(descriptionList
);
247 return operationArray
;
251 /* ----- Dragging Info ----- */
253 updateSourceWindow(WMDraggingInfo
*info
, XClientMessageEvent
*event
)
255 XDND_SOURCE_WIN(info
) = (Window
) event
->data
.l
[0];
260 findChildInView(WMView
* parent
, int x
, int y
)
262 if (parent
->childrenList
== NULL
)
265 WMView
* child
= parent
->childrenList
;
268 && (! child
->flags
.mapped
269 || x
< WMGetViewPosition(child
).x
270 || x
> WMGetViewPosition(child
).x
+ WMGetViewSize(child
).width
271 || y
< WMGetViewPosition(child
).y
272 || y
> WMGetViewPosition(child
).y
+ WMGetViewSize(child
).height
))
274 child
= child
->nextSister
;
279 return findChildInView(child
,
280 x
- WMGetViewPosition(child
).x
,
281 y
- WMGetViewPosition(child
).y
);
287 findDestinationViewInToplevel(WMView
* toplevel
, int x
, int y
)
289 WMScreen
*scr
= W_VIEW_SCREEN(toplevel
);
290 Window toplevelWin
= WMViewXID(toplevel
);
291 int xInToplevel
, yInToplevel
;
295 XTranslateCoordinates(scr
->display
, scr
->rootWin
, toplevelWin
,
296 x
, y
, &xInToplevel
, &yInToplevel
,
298 return findChildInView(toplevel
, xInToplevel
, yInToplevel
);
302 /* Clear datas only used by current destination view */
304 freeDestinationViewInfos(WMDraggingInfo
*info
)
306 if (XDND_SOURCE_TYPES(info
) != NULL
) {
307 WMFreeArray(XDND_SOURCE_TYPES(info
));
308 XDND_SOURCE_TYPES(info
) = NULL
;
311 if (XDND_DROP_DATAS(info
) != NULL
) {
312 WMFreeArray(XDND_DROP_DATAS(info
));
313 XDND_DROP_DATAS(info
) = NULL
;
316 XDND_REQUIRED_TYPES(info
) = NULL
;
321 W_DragDestinationInfoClear(WMDraggingInfo
*info
)
323 W_DragDestinationStopTimer();
325 if (XDND_DEST_INFO(info
) != NULL
) {
326 freeDestinationViewInfos(info
);
328 wfree(XDND_DEST_INFO(info
));
329 XDND_DEST_INFO(info
) = NULL
;
335 initDestinationDragInfo(WMDraggingInfo
*info
, WMView
*destView
)
337 wassertr(destView
!= NULL
);
339 XDND_DEST_INFO(info
) =
340 (W_DragDestinationInfo
*) wmalloc(sizeof(W_DragDestinationInfo
));
342 XDND_DEST_STATE(info
) = idleState
;
343 XDND_DEST_VIEW(info
) = destView
;
345 XDND_SOURCE_ACTION_CHANGED(info
) = False
;
346 XDND_SOURCE_TYPES(info
) = NULL
;
347 XDND_REQUIRED_TYPES(info
) = NULL
;
348 XDND_DROP_DATAS(info
) = NULL
;
353 W_DragDestinationStoreEnterMsgInfo(WMDraggingInfo
*info
,
354 WMView
*toplevel
, XClientMessageEvent
*event
)
356 WMScreen
*scr
= W_VIEW_SCREEN(toplevel
);
358 if (XDND_DEST_INFO(info
) == NULL
)
359 initDestinationDragInfo(info
, toplevel
);
361 XDND_SOURCE_VERSION(info
) = (event
->data
.l
[1] >> 24);
362 XDND_AWARE_VIEW(info
) = toplevel
;
363 updateSourceWindow(info
, event
);
366 if (event->data.l[1] & 1)
367 /* XdndTypeList property is available */
368 /* XDND_SOURCE_TYPES(info) = getTypesFromTypeList(scr, XDND_SOURCE_WIN(info));
370 XDND_SOURCE_TYPES(info) = getTypesFromThreeTypes(scr, event);
372 XDND_SOURCE_TYPES(info
) = getTypesFromThreeTypes(scr
, event
);
374 /* to use if the 3 types are not enough */
375 XDND_TYPE_LIST_AVAILABLE(info
) = (event
->data
.l
[1] & 1);
380 W_DragDestinationStorePositionMsgInfo(WMDraggingInfo
*info
,
381 WMView
*toplevel
, XClientMessageEvent
*event
)
383 int x
= event
->data
.l
[2] >> 16;
384 int y
= event
->data
.l
[2] & 0xffff;
387 newDestView
= findDestinationViewInToplevel(toplevel
, x
, y
);
389 if (XDND_DEST_INFO(info
) == NULL
) {
390 initDestinationDragInfo(info
, newDestView
);
391 XDND_AWARE_VIEW(info
) = toplevel
;
392 updateSourceWindow(info
, event
);
394 if (newDestView
!= XDND_DEST_VIEW(info
)) {
395 updateSourceWindow(info
, event
);
396 XDND_DEST_VIEW(info
) = newDestView
;
397 XDND_SOURCE_ACTION_CHANGED(info
) = False
;
399 if (XDND_DEST_STATE(info
) != waitEnterState
)
400 XDND_DEST_STATE(info
) = idleState
;
402 XDND_SOURCE_ACTION_CHANGED(info
) = (XDND_SOURCE_ACTION(info
) != event
->data
.l
[4]);
406 XDND_SOURCE_ACTION(info
) = event
->data
.l
[4];
408 /* note: source position is not stored */
411 /* ----- End of Dragging Info ----- */
414 /* ----- Messages ----- */
416 /* send a DnD message to the source window */
418 sendDnDClientMessage(WMDraggingInfo
*info
, Atom message
,
424 if (! W_SendDnDClientMessage(W_VIEW_SCREEN(XDND_AWARE_VIEW(info
))->display
,
425 XDND_SOURCE_WIN(info
),
427 WMViewXID(XDND_AWARE_VIEW(info
)),
433 W_DragDestinationInfoClear(info
);
438 /* send a xdndStatus message to the source, with position and size
439 of the destination if it has no subwidget (requesting a position message
440 on every move otherwise) */
442 sendStatusMessage(WMView
*destView
, WMDraggingInfo
*info
, Atom action
)
446 data1
= (action
== None
) ? 0 : 1;
448 if (destView
->childrenList
== NULL
) {
449 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
451 WMSize destSize
= WMGetViewSize(destView
);
454 XTranslateCoordinates(scr
->display
, WMViewXID(destView
), scr
->rootWin
,
455 0, 0, &destX
, &destY
,
458 sendDnDClientMessage(info
,
459 W_VIEW_SCREEN(destView
)->xdndStatusAtom
,
462 (destSize
.width
<< 16)|destSize
.height
,
465 /* set bit 1 to request explicitly position message on every move */
468 sendDnDClientMessage(info
,
469 W_VIEW_SCREEN(destView
)->xdndStatusAtom
,
479 storeDropData(WMView
*destView
, Atom selection
, Atom target
,
480 Time timestamp
, void *cdata
, WMData
*data
)
482 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
483 WMDraggingInfo
*info
= &(scr
->dragInfo
);
484 WMData
*dataToStore
= NULL
;
487 dataToStore
= WMRetainData(data
);
489 if (XDND_DEST_INFO(info
) != NULL
&& XDND_DROP_DATAS(info
) != NULL
) {
490 WMAddToArray(XDND_DROP_DATAS(info
), dataToStore
);
491 W_SendDnDClientMessage(scr
->display
, WMViewXID(destView
),
492 scr
->xdndSelectionAtom
,
500 requestDropDataInSelection(WMView
*destView
, char* type
)
502 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
505 if (!WMRequestSelection(destView
,
506 scr
->xdndSelectionAtom
,
507 XInternAtom(scr
->display
, type
, False
),
509 storeDropData
, NULL
)) {
510 wwarning("could not request data for dropped data");
522 requestDropData(WMDraggingInfo
*info
)
524 WMView
*destView
= XDND_DEST_VIEW(info
);
525 char* nextType
= getNextRequestedDataType(info
);
527 while ((nextType
!= NULL
)
528 && (!requestDropDataInSelection(destView
, nextType
)) ) {
529 /* store NULL if request failed, and try with next type */
530 WMAddToArray(XDND_DROP_DATAS(info
), NULL
);
531 nextType
= getNextRequestedDataType(info
);
534 /* remains types to retrieve ? */
535 return (nextType
!= NULL
);
540 concludeDrop(WMView
*destView
)
542 destView
->dragDestinationProcs
->concludeDragOperation(destView
);
546 /* send cancel message to the source */
548 cancelDrop(WMView
*destView
, WMDraggingInfo
*info
)
550 sendStatusMessage(destView
, info
, None
);
551 concludeDrop(destView
);
552 freeDestinationViewInfos(info
);
556 /* suspend drop, when dragged icon enter an unregistered view
557 or a register view that doesn't accept the drop */
559 suspendDropAuthorization(WMView
*destView
, WMDraggingInfo
*info
)
561 sendStatusMessage(destView
, info
, None
);
563 /* Free datas that depend on destination behaviour */
564 if (XDND_DROP_DATAS(info
) != NULL
) {
565 WMFreeArray(XDND_DROP_DATAS(info
));
566 XDND_DROP_DATAS(info
) = NULL
;
569 XDND_REQUIRED_TYPES(info
) = NULL
;
573 /* cancel drop on Enter message, if protocol version is nok */
575 W_DragDestinationCancelDropOnEnter(WMView
*toplevel
, WMDraggingInfo
*info
)
577 if (XDND_DEST_VIEW_IS_REGISTERED(info
))
578 cancelDrop(XDND_DEST_VIEW(info
), info
);
580 sendStatusMessage(toplevel
, info
, None
);
582 W_DragDestinationInfoClear(info
);
587 finishDrop(WMView
*destView
, WMDraggingInfo
*info
)
589 sendDnDClientMessage(info
,
590 W_VIEW_SCREEN(destView
)->xdndFinishedAtom
,
592 concludeDrop(destView
);
593 W_DragDestinationInfoClear(info
);
598 getAllowedAction(WMView
*destView
, WMDraggingInfo
*info
)
600 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
602 return W_OperationToAction(scr
,
603 destView
->dragDestinationProcs
->allowedOperation(
605 W_ActionToOperation(scr
, XDND_SOURCE_ACTION(info
)),
606 XDND_SOURCE_TYPES(info
)));
611 checkActionAllowed(WMView
*destView
, WMDraggingInfo
* info
)
613 XDND_DEST_ACTION(info
) =
614 getAllowedAction(destView
, info
);
616 if (XDND_DEST_ACTION(info
) == None
) {
617 suspendDropAuthorization(destView
, info
);
618 return dropNotAllowedState
;
621 sendStatusMessage(destView
, info
, XDND_DEST_ACTION(info
));
622 return dropAllowedState
;
627 checkDropAllowed(WMView
*destView
, XClientMessageEvent
*event
,
628 WMDraggingInfo
* info
)
630 storeRequiredTypeList(info
);
632 if (destView
->dragDestinationProcs
->inspectDropData
!= NULL
) {
633 XDND_DROP_DATAS(info
) = createDropDataArray(
634 XDND_REQUIRED_TYPES(info
));
636 /* store first available data */
637 if (requestDropData(info
))
638 return inspectDropDataState
;
640 /* no data retrieved, but inspect can allow it */
641 if (destView
->dragDestinationProcs
->inspectDropData(
643 XDND_DROP_DATAS(info
)))
644 return checkActionAllowed(destView
, info
);
646 suspendDropAuthorization(destView
, info
);
647 return dropNotAllowedState
;
650 return checkActionAllowed(destView
, info
);
655 getDropLocationInView(WMView
*view
)
657 Window rootWin
, childWin
;
662 location
= (WMPoint
*) wmalloc(sizeof(WMPoint
));
665 W_VIEW_SCREEN(view
)->display
,
666 WMViewXID(view
), &rootWin
, &childWin
,
668 &(location
->x
), &(location
->y
),
676 callPerformDragOperation(WMView
*destView
, WMDraggingInfo
*info
)
678 WMArray
*operationList
= NULL
;
679 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
680 WMPoint
* dropLocation
;
682 if (XDND_SOURCE_ACTION(info
) == scr
->xdndActionAsk
)
683 operationList
= sourceOperationList(scr
, XDND_SOURCE_WIN(info
));
685 dropLocation
= getDropLocationInView(destView
);
686 destView
->dragDestinationProcs
->performDragOperation(
688 XDND_DROP_DATAS(info
),
693 if (operationList
!= NULL
)
694 WMFreeArray(operationList
);
698 /* ----- Destination timer ----- */
700 dragSourceResponseTimeOut(void *destView
)
702 WMView
*view
= (WMView
*) destView
;
703 WMDraggingInfo
*info
;
705 wwarning("delay for drag source response expired");
706 info
= &(W_VIEW_SCREEN(view
)->dragInfo
);
707 if (XDND_DEST_VIEW_IS_REGISTERED(info
))
708 cancelDrop(view
, info
);
710 sendStatusMessage(view
, info
, None
);
713 W_DragDestinationInfoClear(info
);
718 W_DragDestinationStopTimer()
720 if (dndDestinationTimer
!= NULL
) {
721 WMDeleteTimerHandler(dndDestinationTimer
);
722 dndDestinationTimer
= NULL
;
728 W_DragDestinationStartTimer(WMDraggingInfo
*info
)
730 W_DragDestinationStopTimer();
732 if (XDND_DEST_STATE(info
) != idleState
)
733 dndDestinationTimer
= WMAddTimerHandler(
734 XDND_SOURCE_RESPONSE_MAX_DELAY
,
735 dragSourceResponseTimeOut
,
736 XDND_DEST_VIEW(info
));
738 /* ----- End of Destination timer ----- */
741 /* ----- Destination states ----- */
745 stateName(W_DndState
*state
)
748 return "no state defined";
750 if (state
== idleState
)
753 if (state
== waitEnterState
)
754 return "waitEnterState";
756 if (state
== inspectDropDataState
)
757 return "inspectDropDataState";
759 if (state
== dropAllowedState
)
760 return "dropAllowedState";
762 if (state
== dropNotAllowedState
)
763 return "dropNotAllowedState";
765 if (state
== waitForDropDataState
)
766 return "waitForDropDataState";
768 return "unknown state";
774 idleState(WMView
*destView
, XClientMessageEvent
*event
,
775 WMDraggingInfo
*info
)
780 if (destView
->dragDestinationProcs
!= NULL
) {
781 scr
= W_VIEW_SCREEN(destView
);
782 sourceMsg
= event
->message_type
;
784 if (sourceMsg
== scr
->xdndPositionAtom
) {
785 destView
->dragDestinationProcs
->prepareForDragOperation(destView
);
787 if (XDND_SOURCE_TYPES(info
) != NULL
) {
788 /* enter message infos are available */
789 return checkDropAllowed(destView
, event
, info
);
792 /* waiting for enter message */
793 return waitEnterState
;
797 suspendDropAuthorization(destView
, info
);
802 /* Source position and action are stored,
803 waiting for xdnd protocol version and source type */
805 waitEnterState(WMView
*destView
, XClientMessageEvent
*event
,
806 WMDraggingInfo
*info
)
808 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
809 Atom sourceMsg
= event
->message_type
;
811 if (sourceMsg
== scr
->xdndEnterAtom
) {
812 W_DragDestinationStoreEnterMsgInfo(info
, destView
, event
);
813 return checkDropAllowed(destView
, event
, info
);
816 return waitEnterState
;
820 /* We have requested a data, and have received it */
822 inspectDropDataState(WMView
*destView
, XClientMessageEvent
*event
,
823 WMDraggingInfo
*info
)
828 scr
= W_VIEW_SCREEN(destView
);
829 sourceMsg
= event
->message_type
;
831 if (sourceMsg
== scr
->xdndSelectionAtom
) {
832 /* a data has been retrieved, store next available */
833 if (requestDropData(info
))
834 return inspectDropDataState
;
836 /* all required (and available) datas are stored */
837 if (destView
->dragDestinationProcs
->inspectDropData(
839 XDND_DROP_DATAS(info
)))
840 return checkActionAllowed(destView
, info
);
842 suspendDropAuthorization(destView
, info
);
843 return dropNotAllowedState
;
846 return inspectDropDataState
;
851 dropNotAllowedState(WMView
*destView
, XClientMessageEvent
*event
,
852 WMDraggingInfo
*info
)
854 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
855 Atom sourceMsg
= event
->message_type
;
857 if (sourceMsg
== scr
->xdndDropAtom
) {
858 finishDrop(destView
, info
);
862 if (sourceMsg
== scr
->xdndPositionAtom
) {
863 if (XDND_SOURCE_ACTION_CHANGED(info
)) {
864 return checkDropAllowed(destView
, event
, info
);
866 sendStatusMessage(destView
, info
, None
);
867 return dropNotAllowedState
;
871 return dropNotAllowedState
;
876 dropAllowedState(WMView
*destView
, XClientMessageEvent
*event
,
877 WMDraggingInfo
*info
)
879 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
880 Atom sourceMsg
= event
->message_type
;
882 if (sourceMsg
== scr
->xdndDropAtom
) {
883 if (XDND_DROP_DATAS(info
) != NULL
) {
884 /* drop datas were cached with inspectDropData call */
885 callPerformDragOperation(destView
, info
);
887 XDND_DROP_DATAS(info
) = createDropDataArray(
888 XDND_REQUIRED_TYPES(info
));
890 /* store first available data */
891 if (requestDropData(info
))
892 return waitForDropDataState
;
894 /* no data retrieved */
895 callPerformDragOperation(destView
, info
);
898 finishDrop(destView
, info
);
902 if (sourceMsg
== scr
->xdndPositionAtom
) {
903 if (XDND_SOURCE_ACTION_CHANGED(info
)) {
904 return checkDropAllowed(destView
, event
, info
);
906 sendStatusMessage(destView
, info
, XDND_DEST_ACTION(info
));
907 return dropAllowedState
;
911 return dropAllowedState
;
916 waitForDropDataState(WMView
*destView
, XClientMessageEvent
*event
,
917 WMDraggingInfo
*info
)
919 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
920 Atom sourceMsg
= event
->message_type
;
922 if (sourceMsg
== scr
->xdndSelectionAtom
) {
923 /* store next data */
924 if (requestDropData(info
))
925 return waitForDropDataState
;
927 /* all required (and available) datas are stored */
928 callPerformDragOperation(destView
, info
);
930 finishDrop(destView
, info
);
934 return waitForDropDataState
;
937 /* ----- End of Destination states ----- */
941 W_DragDestinationStateHandler(WMDraggingInfo
*info
, XClientMessageEvent
*event
)
944 W_DndState
* newState
;
946 wassertr(XDND_DEST_INFO(info
) != NULL
);
947 wassertr(XDND_DEST_VIEW(info
) != NULL
);
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
);
975 realizedObserver(void *self
, WMNotification
*notif
)
977 WMView
*view
= (WMView
*)WMGetNotificationObject(notif
);
978 WMScreen
*scr
= W_VIEW_SCREEN(view
);
980 XChangeProperty(scr
->display
, W_VIEW_DRAWABLE(view
),
982 XA_ATOM
, XDND_PROPERTY_FORMAT
, PropModeReplace
,
985 WMRemoveNotificationObserver(self
);
990 W_SetXdndAwareProperty(WMScreen
*scr
, WMView
*view
, Atom
*types
,
993 WMView
*toplevel
= W_TopLevelOfView(view
);
995 if (!toplevel
->flags
.xdndHintSet
) {
996 toplevel
->flags
.xdndHintSet
= 1;
998 if (toplevel
->flags
.realized
) {
999 XChangeProperty(scr
->display
, W_VIEW_DRAWABLE(toplevel
),
1000 scr
->xdndAwareAtom
, XA_ATOM
, XDND_PROPERTY_FORMAT
,
1001 PropModeReplace
, &XDNDversion
, 1);
1003 WMAddNotificationObserver(realizedObserver
,
1004 /* just use as an id */
1005 &view
->dragDestinationProcs
,
1006 WMViewRealizedNotification
,
1014 WMRegisterViewForDraggedTypes(WMView
*view
, WMArray
*acceptedTypes
)
1020 typeCount
= WMGetArrayItemCount(acceptedTypes
);
1021 types
= wmalloc(sizeof(Atom
)*(typeCount
+1));
1023 for (i
= 0; i
< typeCount
; i
++) {
1024 types
[i
] = XInternAtom(W_VIEW_SCREEN(view
)->display
,
1025 WMGetFromArray(acceptedTypes
, i
),
1030 view
->droppableTypes
= types
;
1031 /* WMFreeArray(acceptedTypes); */
1033 W_SetXdndAwareProperty(W_VIEW_SCREEN(view
), view
, types
, typeCount
);
1038 WMUnregisterViewDraggedTypes(WMView
*view
)
1040 if (view
->droppableTypes
!= NULL
)
1041 wfree(view
->droppableTypes
);
1042 view
->droppableTypes
= NULL
;
1047 requestedOperation: operation requested by the source
1048 sourceDataTypes: data types (mime-types strings) supported by the source
1049 (never NULL, destroyed when drop ends)
1050 return operation allowed by destination (self)
1052 static WMDragOperationType
1053 defAllowedOperation(WMView
*self
,
1054 WMDragOperationType requestedOperation
,
1055 WMArray
* sourceDataTypes
)
1057 /* no operation allowed */
1058 return WDOperationNone
;
1063 requestedOperation: operation requested by the source
1064 sourceDataTypes: data types (mime-types strings) supported by the source
1065 (never NULL, destroyed when drop ends)
1066 return data types (mime-types strings) required by destination (self)
1067 or NULL if no suitable data type is available (force
1068 to 2nd pass with full source type list).
1071 defRequiredDataTypes (WMView
*self
,
1072 WMDragOperationType requestedOperation
,
1073 WMArray
* sourceDataTypes
)
1075 /* no data type allowed (NULL even at 2nd pass) */
1081 Executed when the drag enters destination (self)
1084 defPrepareForDragOperation(WMView
*self
)
1090 Checks datas to be dropped (optional).
1091 dropDatas: datas (WMData*) required by destination (self)
1092 (given in same order as returned by requiredDataTypes).
1093 A NULL data means it couldn't be retreived.
1094 Destroyed when drop ends.
1095 return true if data array is ok
1097 /* Bool (*inspectDropData)(WMView *self, WMArray *dropDatas); */
1102 dropDatas: datas (WMData*) required by destination (self)
1103 (given in same order as returned by requiredDataTypes).
1104 A NULL data means it couldn't be retrieved.
1105 Destroyed when drop ends.
1106 operationList: if source operation is WDOperationAsk, contains
1107 operations (and associated texts) that can be asked
1108 to source. (destroyed after performDragOperation call)
1109 Otherwise this parameter is NULL.
1112 defPerformDragOperation(WMView
*self
, WMArray
*dropDatas
,
1113 WMArray
*operationList
, WMPoint
*dropLocation
)
1118 /* Executed after drop */
1120 defConcludeDragOperation(WMView
*self
)
1126 WMSetViewDragDestinationProcs(WMView
*view
, WMDragDestinationProcs
*procs
)
1128 if (view
->dragDestinationProcs
== NULL
) {
1129 view
->dragDestinationProcs
= wmalloc(sizeof(WMDragDestinationProcs
));
1131 free(view
->dragDestinationProcs
);
1134 *view
->dragDestinationProcs
= *procs
;
1136 /*XXX fill in non-implemented stuffs */
1137 if (procs
->allowedOperation
== NULL
) {
1138 view
->dragDestinationProcs
->allowedOperation
= defAllowedOperation
;
1140 if (procs
->allowedOperation
== NULL
) {
1141 view
->dragDestinationProcs
->requiredDataTypes
= defRequiredDataTypes
;
1144 /* note: inspectDropData can be NULL, if data consultation is not needed
1145 to give drop permission */
1147 if (procs
->prepareForDragOperation
== NULL
) {
1148 view
->dragDestinationProcs
->prepareForDragOperation
= defPrepareForDragOperation
;
1150 if (procs
->performDragOperation
== NULL
) {
1151 view
->dragDestinationProcs
->performDragOperation
= defPerformDragOperation
;
1153 if (procs
->concludeDragOperation
== NULL
) {
1154 view
->dragDestinationProcs
->concludeDragOperation
= defConcludeDragOperation
;