5 #define XDND_SOURCE_RESPONSE_MAX_DELAY 3000
7 #define XDND_PROPERTY_FORMAT 32
8 #define XDND_ACTION_DESCRIPTION_FORMAT 8
10 #define XDND_SOURCE_VERSION(dragInfo) dragInfo->protocolVersion
11 #define XDND_DEST_INFO(dragInfo) dragInfo->destInfo
12 #define XDND_AWARE_VIEW(dragInfo) dragInfo->destInfo->xdndAwareView
13 #define XDND_SOURCE_WIN(dragInfo) dragInfo->destInfo->sourceWindow
14 #define XDND_DEST_VIEW(dragInfo) dragInfo->destInfo->destView
15 #define XDND_DEST_STATE(dragInfo) dragInfo->destInfo->state
16 #define XDND_SOURCE_ACTION_CHANGED(dragInfo) dragInfo->destInfo->sourceActionChanged
17 #define XDND_SOURCE_TYPES(dragInfo) dragInfo->destInfo->sourceTypes
18 #define XDND_TYPE_LIST_AVAILABLE(dragInfo) dragInfo->destInfo->typeListAvailable
19 #define XDND_REQUIRED_TYPES(dragInfo) dragInfo->destInfo->requiredTypes
20 #define XDND_SOURCE_ACTION(dragInfo) dragInfo->sourceAction
21 #define XDND_DEST_ACTION(dragInfo) dragInfo->destinationAction
22 #define XDND_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_IS_REGISTERED(dragInfo) ((dragInfo->destInfo) != NULL)\
26 && ((dragInfo->destInfo->destView->dragDestinationProcs) != NULL)
28 static const unsigned char XDNDversion
= XDND_VERSION
;
29 static WMHandlerID dndDestinationTimer
= NULL
;
31 static void *idleState(WMView
* destView
, XClientMessageEvent
* event
, WMDraggingInfo
* info
);
32 static void *waitEnterState(WMView
* destView
, XClientMessageEvent
* event
, WMDraggingInfo
* info
);
33 static void *inspectDropDataState(WMView
* destView
, XClientMessageEvent
* event
, WMDraggingInfo
* info
);
34 static void *dropAllowedState(WMView
* destView
, XClientMessageEvent
* event
, WMDraggingInfo
* info
);
35 static void *dropNotAllowedState(WMView
* destView
, XClientMessageEvent
* event
, WMDraggingInfo
* info
);
36 static void *waitForDropDataState(WMView
* destView
, XClientMessageEvent
* event
, WMDraggingInfo
* info
);
38 /* ----- Types & datas list ----- */
39 static void freeSourceTypeArrayItem(void *type
)
44 static WMArray
*createSourceTypeArray(int initialSize
)
46 return WMCreateArrayWithDestructor(initialSize
, freeSourceTypeArrayItem
);
49 static void freeDropDataArrayItem(void *data
)
52 WMReleaseData((WMData
*) data
);
55 static WMArray
*createDropDataArray(WMArray
* requiredTypes
)
57 if (requiredTypes
!= NULL
)
58 return WMCreateArrayWithDestructor(WMGetArrayItemCount(requiredTypes
), freeDropDataArrayItem
);
61 return WMCreateArray(0);
64 static WMArray
*getTypesFromTypeList(WMScreen
* scr
, Window sourceWin
)
70 unsigned long count
, remaining
;
71 unsigned char *data
= NULL
;
73 XGetWindowProperty(scr
->display
, sourceWin
, scr
->xdndTypeListAtom
,
74 0, 0x8000000L
, False
, XA_ATOM
, &dataType
, &format
, &count
, &remaining
, &data
);
76 if (dataType
!= XA_ATOM
|| format
!= XDND_PROPERTY_FORMAT
|| count
== 0 || !data
) {
80 return createSourceTypeArray(0);
83 typeList
= createSourceTypeArray(count
);
84 typeAtomList
= (Atom
*) data
;
85 for (i
= 0; i
< count
; i
++) {
86 WMAddToArray(typeList
, XGetAtomName(scr
->display
, typeAtomList
[i
]));
94 static WMArray
*getTypesFromThreeTypes(WMScreen
* scr
, XClientMessageEvent
* event
)
100 typeList
= createSourceTypeArray(3);
101 for (i
= 2; i
< 5; i
++) {
102 if (event
->data
.l
[i
] != None
) {
103 atom
= (Atom
) event
->data
.l
[i
];
104 WMAddToArray(typeList
, XGetAtomName(scr
->display
, atom
));
111 static void storeRequiredTypeList(WMDraggingInfo
* info
)
113 WMView
*destView
= XDND_DEST_VIEW(info
);
114 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
115 WMArray
*requiredTypes
;
117 /* First, see if the stored source types are enough for dest requirements */
118 requiredTypes
= destView
->dragDestinationProcs
->requiredDataTypes(destView
,
119 W_ActionToOperation(scr
,
122 XDND_SOURCE_TYPES(info
));
124 if (requiredTypes
== NULL
&& XDND_TYPE_LIST_AVAILABLE(info
)) {
125 /* None of the stored source types fits, but the whole type list
126 hasn't been retrieved yet. */
127 WMFreeArray(XDND_SOURCE_TYPES(info
));
128 XDND_SOURCE_TYPES(info
) = getTypesFromTypeList(scr
, XDND_SOURCE_WIN(info
));
129 /* Don't retrieve the type list again */
130 XDND_TYPE_LIST_AVAILABLE(info
) = False
;
133 destView
->dragDestinationProcs
->requiredDataTypes(destView
,
134 W_ActionToOperation(scr
,
137 XDND_SOURCE_TYPES(info
));
140 XDND_REQUIRED_TYPES(info
) = requiredTypes
;
143 static char *getNextRequestedDataType(WMDraggingInfo
* info
)
145 /* get the type of the first data not yet retrieved from selection */
148 if (XDND_REQUIRED_TYPES(info
) != NULL
) {
149 nextTypeIndex
= WMGetArrayItemCount(XDND_DROP_DATAS(info
));
150 return WMGetFromArray(XDND_REQUIRED_TYPES(info
), nextTypeIndex
);
151 /* NULL if no more type */
156 /* ----- Action list ----- */
158 static WMArray
*sourceOperationList(WMScreen
* scr
, Window sourceWin
)
160 Atom dataType
, *actionList
;
162 unsigned long count
, remaining
;
163 unsigned char *actionDatas
= NULL
;
164 unsigned char *descriptionList
= NULL
;
165 WMArray
*operationArray
;
166 WMDragOperationItem
*operationItem
;
170 XGetWindowProperty(scr
->display
, sourceWin
, scr
->xdndActionListAtom
,
171 0, 0x8000000L
, False
, XA_ATOM
, &dataType
, &size
, &count
, &remaining
, &actionDatas
);
173 if (dataType
!= XA_ATOM
|| size
!= XDND_PROPERTY_FORMAT
|| count
== 0 || !actionDatas
) {
174 wwarning("Cannot read action list");
181 actionList
= (Atom
*) actionDatas
;
183 XGetWindowProperty(scr
->display
, sourceWin
, scr
->xdndActionDescriptionAtom
,
184 0, 0x8000000L
, False
, XA_STRING
, &dataType
, &size
,
185 &count
, &remaining
, &descriptionList
);
187 if (dataType
!= XA_STRING
|| size
!= XDND_ACTION_DESCRIPTION_FORMAT
|| count
== 0 || !descriptionList
) {
188 wwarning("Cannot read action description list");
192 if (descriptionList
) {
193 XFree(descriptionList
);
198 operationArray
= WMCreateDragOperationArray(count
);
199 description
= (char *)descriptionList
;
201 for (i
= 0; count
> 0; i
++) {
202 size
= strlen(description
);
203 operationItem
= WMCreateDragOperationItem(W_ActionToOperation(scr
, actionList
[i
]),
204 wstrdup(description
));
206 WMAddToArray(operationArray
, operationItem
);
207 count
-= (size
+ 1); /* -1 : -NULL char */
209 /* next description */
210 description
= &(description
[size
+ 1]);
214 XFree(descriptionList
);
216 return operationArray
;
219 /* ----- Dragging Info ----- */
220 static void updateSourceWindow(WMDraggingInfo
* info
, XClientMessageEvent
* event
)
222 XDND_SOURCE_WIN(info
) = (Window
) event
->data
.l
[0];
225 static WMView
*findChildInView(WMView
* parent
, int x
, int y
)
227 if (parent
->childrenList
== NULL
)
230 WMView
*child
= parent
->childrenList
;
233 && (!child
->flags
.mapped
234 || x
< WMGetViewPosition(child
).x
235 || x
> WMGetViewPosition(child
).x
+ WMGetViewSize(child
).width
236 || y
< WMGetViewPosition(child
).y
237 || y
> WMGetViewPosition(child
).y
+ WMGetViewSize(child
).height
))
239 child
= child
->nextSister
;
244 return findChildInView(child
,
245 x
- WMGetViewPosition(child
).x
, y
- WMGetViewPosition(child
).y
);
249 static WMView
*findDestinationViewInToplevel(WMView
* toplevel
, int x
, int y
)
251 WMScreen
*scr
= W_VIEW_SCREEN(toplevel
);
252 Window toplevelWin
= WMViewXID(toplevel
);
253 int xInToplevel
, yInToplevel
;
256 XTranslateCoordinates(scr
->display
, scr
->rootWin
, toplevelWin
, x
, y
, &xInToplevel
, &yInToplevel
, &foo
);
257 return findChildInView(toplevel
, xInToplevel
, yInToplevel
);
260 /* Clear datas only used by current destination view */
261 static void freeDestinationViewInfos(WMDraggingInfo
* info
)
263 if (XDND_SOURCE_TYPES(info
) != NULL
) {
264 WMFreeArray(XDND_SOURCE_TYPES(info
));
265 XDND_SOURCE_TYPES(info
) = NULL
;
268 if (XDND_DROP_DATAS(info
) != NULL
) {
269 WMFreeArray(XDND_DROP_DATAS(info
));
270 XDND_DROP_DATAS(info
) = NULL
;
273 XDND_REQUIRED_TYPES(info
) = NULL
;
276 void W_DragDestinationInfoClear(WMDraggingInfo
* info
)
278 W_DragDestinationStopTimer();
280 if (XDND_DEST_INFO(info
) != NULL
) {
281 freeDestinationViewInfos(info
);
283 wfree(XDND_DEST_INFO(info
));
284 XDND_DEST_INFO(info
) = NULL
;
288 static void initDestinationDragInfo(WMDraggingInfo
* info
, WMView
* destView
)
290 wassertr(destView
!= NULL
);
292 XDND_DEST_INFO(info
) = (W_DragDestinationInfo
*) wmalloc(sizeof(W_DragDestinationInfo
));
294 XDND_DEST_STATE(info
) = idleState
;
295 XDND_DEST_VIEW(info
) = destView
;
297 XDND_SOURCE_ACTION_CHANGED(info
) = False
;
298 XDND_SOURCE_TYPES(info
) = NULL
;
299 XDND_REQUIRED_TYPES(info
) = NULL
;
300 XDND_DROP_DATAS(info
) = NULL
;
303 void W_DragDestinationStoreEnterMsgInfo(WMDraggingInfo
* info
, WMView
* toplevel
, XClientMessageEvent
* event
)
305 WMScreen
*scr
= W_VIEW_SCREEN(toplevel
);
307 if (XDND_DEST_INFO(info
) == NULL
)
308 initDestinationDragInfo(info
, toplevel
);
310 XDND_SOURCE_VERSION(info
) = (event
->data
.l
[1] >> 24);
311 XDND_AWARE_VIEW(info
) = toplevel
;
312 updateSourceWindow(info
, event
);
315 if (event
->data
.l
[1] & 1)
316 /* XdndTypeList property is available */
317 XDND_SOURCE_TYPES(info
) = getTypesFromTypeList(scr
, XDND_SOURCE_WIN(info
));
319 XDND_SOURCE_TYPES(info
) = getTypesFromThreeTypes(scr
, event
);
321 XDND_SOURCE_TYPES(info
) = getTypesFromThreeTypes(scr
, event
);
323 /* to use if the 3 types are not enough */
324 XDND_TYPE_LIST_AVAILABLE(info
) = (event
->data
.l
[1] & 1);
327 void W_DragDestinationStorePositionMsgInfo(WMDraggingInfo
* info
, WMView
* toplevel
, XClientMessageEvent
* event
)
329 int x
= event
->data
.l
[2] >> 16;
330 int y
= event
->data
.l
[2] & 0xffff;
333 newDestView
= findDestinationViewInToplevel(toplevel
, x
, y
);
335 if (XDND_DEST_INFO(info
) == NULL
) {
336 initDestinationDragInfo(info
, newDestView
);
337 XDND_AWARE_VIEW(info
) = toplevel
;
338 updateSourceWindow(info
, event
);
340 if (newDestView
!= XDND_DEST_VIEW(info
)) {
341 updateSourceWindow(info
, event
);
342 XDND_DEST_VIEW(info
) = newDestView
;
343 XDND_SOURCE_ACTION_CHANGED(info
) = False
;
345 if (XDND_DEST_STATE(info
) != waitEnterState
)
346 XDND_DEST_STATE(info
) = idleState
;
348 XDND_SOURCE_ACTION_CHANGED(info
) = (XDND_SOURCE_ACTION(info
) != event
->data
.l
[4]);
352 XDND_SOURCE_ACTION(info
) = event
->data
.l
[4];
354 /* note: source position is not stored */
357 /* ----- End of Dragging Info ----- */
359 /* ----- Messages ----- */
361 /* send a DnD message to the source window */
363 sendDnDClientMessage(WMDraggingInfo
* info
, Atom message
,
364 unsigned long data1
, unsigned long data2
, unsigned long data3
, unsigned long data4
)
366 if (!W_SendDnDClientMessage(W_VIEW_SCREEN(XDND_AWARE_VIEW(info
))->display
,
367 XDND_SOURCE_WIN(info
),
368 message
, WMViewXID(XDND_AWARE_VIEW(info
)), data1
, data2
, data3
, data4
)) {
370 W_DragDestinationInfoClear(info
);
374 /* send a xdndStatus message to the source, with position and size
375 of the destination if it has no subwidget (requesting a position message
376 on every move otherwise) */
377 static void sendStatusMessage(WMView
* destView
, WMDraggingInfo
* info
, Atom action
)
381 data1
= (action
== None
) ? 0 : 1;
383 if (destView
->childrenList
== NULL
) {
384 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
386 WMSize destSize
= WMGetViewSize(destView
);
389 XTranslateCoordinates(scr
->display
, WMViewXID(destView
), scr
->rootWin
, 0, 0, &destX
, &destY
, &foo
);
391 sendDnDClientMessage(info
,
392 W_VIEW_SCREEN(destView
)->xdndStatusAtom
,
394 (destX
<< 16) | destY
, (destSize
.width
<< 16) | destSize
.height
, action
);
396 /* set bit 1 to request explicitly position message on every move */
399 sendDnDClientMessage(info
, W_VIEW_SCREEN(destView
)->xdndStatusAtom
, data1
, 0, 0, action
);
404 storeDropData(WMView
* destView
, Atom selection
, Atom target
, Time timestamp
, void *cdata
, WMData
* data
)
406 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
407 WMDraggingInfo
*info
= &(scr
->dragInfo
);
408 WMData
*dataToStore
= NULL
;
410 /* Parameter not used, but tell the compiler that it is ok */
417 dataToStore
= WMRetainData(data
);
419 if (XDND_DEST_INFO(info
) != NULL
&& XDND_DROP_DATAS(info
) != NULL
) {
420 WMAddToArray(XDND_DROP_DATAS(info
), dataToStore
);
421 W_SendDnDClientMessage(scr
->display
, WMViewXID(destView
),
422 scr
->xdndSelectionAtom
, WMViewXID(destView
), 0, 0, 0, 0);
426 static Bool
requestDropDataInSelection(WMView
* destView
, const char *type
)
428 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
431 if (!WMRequestSelection(destView
,
432 scr
->xdndSelectionAtom
,
433 XInternAtom(scr
->display
, type
, False
),
434 CurrentTime
, storeDropData
, NULL
)) {
435 wwarning("could not request data for dropped data");
445 static Bool
requestDropData(WMDraggingInfo
* info
)
447 WMView
*destView
= XDND_DEST_VIEW(info
);
448 char *nextType
= getNextRequestedDataType(info
);
450 while ((nextType
!= NULL
)
451 && (!requestDropDataInSelection(destView
, nextType
))) {
452 /* store NULL if request failed, and try with next type */
453 WMAddToArray(XDND_DROP_DATAS(info
), NULL
);
454 nextType
= getNextRequestedDataType(info
);
457 /* remains types to retrieve ? */
458 return (nextType
!= NULL
);
461 static void concludeDrop(WMView
* destView
)
463 destView
->dragDestinationProcs
->concludeDragOperation(destView
);
466 /* send cancel message to the source */
467 static void cancelDrop(WMView
* destView
, WMDraggingInfo
* info
)
469 sendStatusMessage(destView
, info
, None
);
470 concludeDrop(destView
);
471 freeDestinationViewInfos(info
);
474 /* suspend drop, when dragged icon enter an unregistered view
475 or a register view that doesn't accept the drop */
476 static void suspendDropAuthorization(WMView
* destView
, WMDraggingInfo
* info
)
478 sendStatusMessage(destView
, info
, None
);
480 /* Free datas that depend on destination behaviour */
481 if (XDND_DROP_DATAS(info
) != NULL
) {
482 WMFreeArray(XDND_DROP_DATAS(info
));
483 XDND_DROP_DATAS(info
) = NULL
;
486 XDND_REQUIRED_TYPES(info
) = NULL
;
489 /* cancel drop on Enter message, if protocol version is nok */
490 void W_DragDestinationCancelDropOnEnter(WMView
* toplevel
, WMDraggingInfo
* info
)
492 if (XDND_DEST_VIEW_IS_REGISTERED(info
))
493 cancelDrop(XDND_DEST_VIEW(info
), info
);
495 sendStatusMessage(toplevel
, info
, None
);
497 W_DragDestinationInfoClear(info
);
500 static void finishDrop(WMView
* destView
, WMDraggingInfo
* info
)
502 sendDnDClientMessage(info
, W_VIEW_SCREEN(destView
)->xdndFinishedAtom
, 0, 0, 0, 0);
503 concludeDrop(destView
);
504 W_DragDestinationInfoClear(info
);
507 static Atom
getAllowedAction(WMView
* destView
, WMDraggingInfo
* info
)
509 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
511 return W_OperationToAction(scr
,
512 destView
->dragDestinationProcs
->allowedOperation(destView
,
513 W_ActionToOperation(scr
,
516 XDND_SOURCE_TYPES(info
)));
519 static void *checkActionAllowed(WMView
* destView
, WMDraggingInfo
* info
)
521 XDND_DEST_ACTION(info
) = getAllowedAction(destView
, info
);
523 if (XDND_DEST_ACTION(info
) == None
) {
524 suspendDropAuthorization(destView
, info
);
525 return dropNotAllowedState
;
528 sendStatusMessage(destView
, info
, XDND_DEST_ACTION(info
));
529 return dropAllowedState
;
532 static void *checkDropAllowed(WMView
*destView
, WMDraggingInfo
*info
)
534 storeRequiredTypeList(info
);
536 if (destView
->dragDestinationProcs
->inspectDropData
!= NULL
) {
537 XDND_DROP_DATAS(info
) = createDropDataArray(XDND_REQUIRED_TYPES(info
));
539 /* store first available data */
540 if (requestDropData(info
))
541 return inspectDropDataState
;
543 /* no data retrieved, but inspect can allow it */
544 if (destView
->dragDestinationProcs
->inspectDropData(destView
, XDND_DROP_DATAS(info
)))
545 return checkActionAllowed(destView
, info
);
547 suspendDropAuthorization(destView
, info
);
548 return dropNotAllowedState
;
551 return checkActionAllowed(destView
, info
);
554 static WMPoint
*getDropLocationInView(WMView
* view
)
556 Window rootWin
, childWin
;
561 location
= (WMPoint
*) wmalloc(sizeof(WMPoint
));
563 XQueryPointer(W_VIEW_SCREEN(view
)->display
,
564 WMViewXID(view
), &rootWin
, &childWin
, &rootX
, &rootY
, &(location
->x
), &(location
->y
), &mask
);
569 static void callPerformDragOperation(WMView
* destView
, WMDraggingInfo
* info
)
571 WMArray
*operationList
= NULL
;
572 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
573 WMPoint
*dropLocation
;
575 if (XDND_SOURCE_ACTION(info
) == scr
->xdndActionAsk
)
576 operationList
= sourceOperationList(scr
, XDND_SOURCE_WIN(info
));
578 dropLocation
= getDropLocationInView(destView
);
579 destView
->dragDestinationProcs
->performDragOperation(destView
,
580 XDND_DROP_DATAS(info
), operationList
, dropLocation
);
583 if (operationList
!= NULL
)
584 WMFreeArray(operationList
);
587 /* ----- Destination timer ----- */
588 static void dragSourceResponseTimeOut(void *destView
)
590 WMView
*view
= (WMView
*) destView
;
591 WMDraggingInfo
*info
;
593 wwarning("delay for drag source response expired");
594 info
= &(W_VIEW_SCREEN(view
)->dragInfo
);
595 if (XDND_DEST_VIEW_IS_REGISTERED(info
))
596 cancelDrop(view
, info
);
598 sendStatusMessage(view
, info
, None
);
601 W_DragDestinationInfoClear(info
);
604 void W_DragDestinationStopTimer()
606 if (dndDestinationTimer
!= NULL
) {
607 WMDeleteTimerHandler(dndDestinationTimer
);
608 dndDestinationTimer
= NULL
;
612 void W_DragDestinationStartTimer(WMDraggingInfo
* info
)
614 W_DragDestinationStopTimer();
616 if (XDND_DEST_STATE(info
) != idleState
)
617 dndDestinationTimer
= WMAddTimerHandler(XDND_SOURCE_RESPONSE_MAX_DELAY
,
618 dragSourceResponseTimeOut
, XDND_DEST_VIEW(info
));
621 /* ----- End of Destination timer ----- */
623 /* ----- Destination states ----- */
626 static const char *stateName(W_DndState
* state
)
629 return "no state defined";
631 if (state
== idleState
)
634 if (state
== waitEnterState
)
635 return "waitEnterState";
637 if (state
== inspectDropDataState
)
638 return "inspectDropDataState";
640 if (state
== dropAllowedState
)
641 return "dropAllowedState";
643 if (state
== dropNotAllowedState
)
644 return "dropNotAllowedState";
646 if (state
== waitForDropDataState
)
647 return "waitForDropDataState";
649 return "unknown state";
653 static void *idleState(WMView
* destView
, XClientMessageEvent
* event
, WMDraggingInfo
* info
)
658 if (destView
->dragDestinationProcs
!= NULL
) {
659 scr
= W_VIEW_SCREEN(destView
);
660 sourceMsg
= event
->message_type
;
662 if (sourceMsg
== scr
->xdndPositionAtom
) {
663 destView
->dragDestinationProcs
->prepareForDragOperation(destView
);
665 if (XDND_SOURCE_TYPES(info
) != NULL
) {
666 /* enter message infos are available */
667 return checkDropAllowed(destView
, info
);
670 /* waiting for enter message */
671 return waitEnterState
;
675 suspendDropAuthorization(destView
, info
);
679 /* Source position and action are stored,
680 waiting for xdnd protocol version and source type */
681 static void *waitEnterState(WMView
* destView
, XClientMessageEvent
* event
, WMDraggingInfo
* info
)
683 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
684 Atom sourceMsg
= event
->message_type
;
686 if (sourceMsg
== scr
->xdndEnterAtom
) {
687 W_DragDestinationStoreEnterMsgInfo(info
, destView
, event
);
688 return checkDropAllowed(destView
, info
);
691 return waitEnterState
;
694 /* We have requested a data, and have received it */
695 static void *inspectDropDataState(WMView
* destView
, XClientMessageEvent
* event
, WMDraggingInfo
* info
)
700 scr
= W_VIEW_SCREEN(destView
);
701 sourceMsg
= event
->message_type
;
703 if (sourceMsg
== scr
->xdndSelectionAtom
) {
704 /* a data has been retrieved, store next available */
705 if (requestDropData(info
))
706 return inspectDropDataState
;
708 /* all required (and available) datas are stored */
709 if (destView
->dragDestinationProcs
->inspectDropData(destView
, XDND_DROP_DATAS(info
)))
710 return checkActionAllowed(destView
, info
);
712 suspendDropAuthorization(destView
, info
);
713 return dropNotAllowedState
;
716 return inspectDropDataState
;
719 static void *dropNotAllowedState(WMView
* destView
, XClientMessageEvent
* event
, WMDraggingInfo
* info
)
721 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
722 Atom sourceMsg
= event
->message_type
;
724 if (sourceMsg
== scr
->xdndDropAtom
) {
725 finishDrop(destView
, info
);
729 if (sourceMsg
== scr
->xdndPositionAtom
) {
730 if (XDND_SOURCE_ACTION_CHANGED(info
)) {
731 return checkDropAllowed(destView
, info
);
733 sendStatusMessage(destView
, info
, None
);
734 return dropNotAllowedState
;
738 return dropNotAllowedState
;
741 static void *dropAllowedState(WMView
* destView
, XClientMessageEvent
* event
, WMDraggingInfo
* info
)
743 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
744 Atom sourceMsg
= event
->message_type
;
746 if (sourceMsg
== scr
->xdndDropAtom
) {
747 if (XDND_DROP_DATAS(info
) != NULL
) {
748 /* drop datas were cached with inspectDropData call */
749 callPerformDragOperation(destView
, info
);
751 XDND_DROP_DATAS(info
) = createDropDataArray(XDND_REQUIRED_TYPES(info
));
753 /* store first available data */
754 if (requestDropData(info
))
755 return waitForDropDataState
;
757 /* no data retrieved */
758 callPerformDragOperation(destView
, info
);
761 finishDrop(destView
, info
);
765 if (sourceMsg
== scr
->xdndPositionAtom
) {
766 if (XDND_SOURCE_ACTION_CHANGED(info
)) {
767 return checkDropAllowed(destView
, info
);
769 sendStatusMessage(destView
, info
, XDND_DEST_ACTION(info
));
770 return dropAllowedState
;
774 return dropAllowedState
;
777 static void *waitForDropDataState(WMView
* destView
, XClientMessageEvent
* event
, WMDraggingInfo
* info
)
779 WMScreen
*scr
= W_VIEW_SCREEN(destView
);
780 Atom sourceMsg
= event
->message_type
;
782 if (sourceMsg
== scr
->xdndSelectionAtom
) {
783 /* store next data */
784 if (requestDropData(info
))
785 return waitForDropDataState
;
787 /* all required (and available) datas are stored */
788 callPerformDragOperation(destView
, info
);
790 finishDrop(destView
, info
);
794 return waitForDropDataState
;
797 /* ----- End of Destination states ----- */
799 void W_DragDestinationStateHandler(WMDraggingInfo
* info
, XClientMessageEvent
* event
)
802 W_DndState
*newState
;
804 wassertr(XDND_DEST_INFO(info
) != NULL
);
805 wassertr(XDND_DEST_VIEW(info
) != NULL
);
807 destView
= XDND_DEST_VIEW(info
);
808 if (XDND_DEST_STATE(info
) == NULL
)
809 XDND_DEST_STATE(info
) = idleState
;
813 printf("current dest state: %s\n", stateName(XDND_DEST_STATE(info
)));
816 newState
= (W_DndState
*) XDND_DEST_STATE(info
) (destView
, event
, info
);
820 printf("new dest state: %s\n", stateName(newState
));
823 if (XDND_DEST_INFO(info
) != NULL
) {
824 XDND_DEST_STATE(info
) = newState
;
825 if (XDND_DEST_STATE(info
) != idleState
)
826 W_DragDestinationStartTimer(info
);
830 static void realizedObserver(void *self
, WMNotification
* notif
)
832 WMView
*view
= (WMView
*) WMGetNotificationObject(notif
);
833 WMScreen
*scr
= W_VIEW_SCREEN(view
);
835 XChangeProperty(scr
->display
, W_VIEW_DRAWABLE(view
),
836 scr
->xdndAwareAtom
, XA_ATOM
, XDND_PROPERTY_FORMAT
, PropModeReplace
, &XDNDversion
, 1);
838 WMRemoveNotificationObserver(self
);
841 static void W_SetXdndAwareProperty(WMScreen
*scr
, WMView
*view
)
843 WMView
*toplevel
= W_TopLevelOfView(view
);
845 if (!toplevel
->flags
.xdndHintSet
) {
846 toplevel
->flags
.xdndHintSet
= 1;
848 if (toplevel
->flags
.realized
) {
849 XChangeProperty(scr
->display
, W_VIEW_DRAWABLE(toplevel
),
850 scr
->xdndAwareAtom
, XA_ATOM
, XDND_PROPERTY_FORMAT
,
851 PropModeReplace
, &XDNDversion
, 1);
853 WMAddNotificationObserver(realizedObserver
,
854 /* just use as an id */
855 &view
->dragDestinationProcs
,
856 WMViewRealizedNotification
, toplevel
);
861 void WMRegisterViewForDraggedTypes(WMView
* view
, WMArray
* acceptedTypes
)
867 typeCount
= WMGetArrayItemCount(acceptedTypes
);
868 types
= wmalloc(sizeof(Atom
) * (typeCount
+ 1));
870 for (i
= 0; i
< typeCount
; i
++) {
871 types
[i
] = XInternAtom(W_VIEW_SCREEN(view
)->display
, WMGetFromArray(acceptedTypes
, i
), False
);
875 view
->droppableTypes
= types
;
876 /* WMFreeArray(acceptedTypes); */
878 W_SetXdndAwareProperty(W_VIEW_SCREEN(view
), view
);
881 void WMUnregisterViewDraggedTypes(WMView
* view
)
883 if (view
->droppableTypes
!= NULL
)
884 wfree(view
->droppableTypes
);
885 view
->droppableTypes
= NULL
;
889 requestedOperation: operation requested by the source
890 sourceDataTypes: data types (mime-types strings) supported by the source
891 (never NULL, destroyed when drop ends)
892 return operation allowed by destination (self)
894 static WMDragOperationType
895 defAllowedOperation(WMView
* self
, WMDragOperationType requestedOperation
, WMArray
* sourceDataTypes
)
897 /* Parameter not used, but tell the compiler that it is ok */
899 (void) requestedOperation
;
900 (void) sourceDataTypes
;
902 /* no operation allowed */
903 return WDOperationNone
;
907 requestedOperation: operation requested by the source
908 sourceDataTypes: data types (mime-types strings) supported by the source
909 (never NULL, destroyed when drop ends)
910 return data types (mime-types strings) required by destination (self)
911 or NULL if no suitable data type is available (force
912 to 2nd pass with full source type list).
914 static WMArray
*defRequiredDataTypes(WMView
* self
,
915 WMDragOperationType requestedOperation
, WMArray
* sourceDataTypes
)
917 /* Parameter not used, but tell the compiler that it is ok */
919 (void) requestedOperation
;
920 (void) sourceDataTypes
;
922 /* no data type allowed (NULL even at 2nd pass) */
927 Executed when the drag enters destination (self)
929 static void defPrepareForDragOperation(WMView
* self
)
931 /* Parameter not used, but tell the compiler that it is ok */
936 Checks datas to be dropped (optional).
937 dropDatas: datas (WMData*) required by destination (self)
938 (given in same order as returned by requiredDataTypes).
939 A NULL data means it couldn't be retreived.
940 Destroyed when drop ends.
941 return true if data array is ok
943 /* Bool (*inspectDropData)(WMView *self, WMArray *dropDatas); */
947 dropDatas: datas (WMData*) required by destination (self)
948 (given in same order as returned by requiredDataTypes).
949 A NULL data means it couldn't be retrieved.
950 Destroyed when drop ends.
951 operationList: if source operation is WDOperationAsk, contains
952 operations (and associated texts) that can be asked
953 to source. (destroyed after performDragOperation call)
954 Otherwise this parameter is NULL.
957 defPerformDragOperation(WMView
* self
, WMArray
* dropDatas
, WMArray
* operationList
, WMPoint
* dropLocation
)
959 /* Parameter not used, but tell the compiler that it is ok */
962 (void) operationList
;
966 /* Executed after drop */
967 static void defConcludeDragOperation(WMView
* self
)
969 /* Parameter not used, but tell the compiler that it is ok */
973 void WMSetViewDragDestinationProcs(WMView
* view
, WMDragDestinationProcs
* procs
)
975 if (view
->dragDestinationProcs
== NULL
) {
976 view
->dragDestinationProcs
= wmalloc(sizeof(WMDragDestinationProcs
));
978 free(view
->dragDestinationProcs
);
981 *view
->dragDestinationProcs
= *procs
;
983 /*XXX fill in non-implemented stuffs */
984 if (procs
->allowedOperation
== NULL
) {
985 view
->dragDestinationProcs
->allowedOperation
= defAllowedOperation
;
987 if (procs
->allowedOperation
== NULL
) {
988 view
->dragDestinationProcs
->requiredDataTypes
= defRequiredDataTypes
;
991 /* note: inspectDropData can be NULL, if data consultation is not needed
992 to give drop permission */
994 if (procs
->prepareForDragOperation
== NULL
) {
995 view
->dragDestinationProcs
->prepareForDragOperation
= defPrepareForDragOperation
;
997 if (procs
->performDragOperation
== NULL
) {
998 view
->dragDestinationProcs
->performDragOperation
= defPerformDragOperation
;
1000 if (procs
->concludeDragOperation
== NULL
) {
1001 view
->dragDestinationProcs
->concludeDragOperation
= defConcludeDragOperation
;