Include screen.h in dialog.h for definition of WScreen
[wmaker-crm.git] / WINGs / dragdestination.c
bloba78814058c7dc9b4f8fe6159e24247cff8fd65ef
2 #include "WINGsP.h"
3 #include <X11/Xatom.h>
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_DROP_DATAS(dragInfo) dragInfo->destInfo->dropDatas
23 #define XDND_DEST_VIEW_IS_REGISTERED(dragInfo) ((dragInfo->destInfo) != NULL)\
24 && ((dragInfo->destInfo->destView->dragDestinationProcs) != NULL)
26 static const unsigned char XDNDversion = XDND_VERSION;
27 static WMHandlerID dndDestinationTimer = NULL;
29 static void *idleState(WMView * destView, XClientMessageEvent * event, WMDraggingInfo * info);
30 static void *waitEnterState(WMView * destView, XClientMessageEvent * event, WMDraggingInfo * info);
31 static void *inspectDropDataState(WMView * destView, XClientMessageEvent * event, WMDraggingInfo * info);
32 static void *dropAllowedState(WMView * destView, XClientMessageEvent * event, WMDraggingInfo * info);
33 static void *dropNotAllowedState(WMView * destView, XClientMessageEvent * event, WMDraggingInfo * info);
34 static void *waitForDropDataState(WMView * destView, XClientMessageEvent * event, WMDraggingInfo * info);
36 /* ----- Types & datas list ----- */
37 static void freeSourceTypeArrayItem(void *type)
39 XFree(type);
42 static WMArray *createSourceTypeArray(int initialSize)
44 return WMCreateArrayWithDestructor(initialSize, freeSourceTypeArrayItem);
47 static void freeDropDataArrayItem(void *data)
49 if (data != NULL)
50 WMReleaseData((WMData *) data);
53 static WMArray *createDropDataArray(WMArray * requiredTypes)
55 if (requiredTypes != NULL)
56 return WMCreateArrayWithDestructor(WMGetArrayItemCount(requiredTypes), freeDropDataArrayItem);
58 else
59 return WMCreateArray(0);
62 static WMArray *getTypesFromTypeList(WMScreen * scr, Window sourceWin)
64 Atom dataType;
65 Atom *typeAtomList;
66 WMArray *typeList;
67 int i, format;
68 unsigned long count, remaining;
69 unsigned char *data = NULL;
71 XGetWindowProperty(scr->display, sourceWin, scr->xdndTypeListAtom,
72 0, 0x8000000L, False, XA_ATOM, &dataType, &format, &count, &remaining, &data);
74 if (dataType != XA_ATOM || format != XDND_PROPERTY_FORMAT || count == 0 || !data) {
75 if (data) {
76 XFree(data);
78 return createSourceTypeArray(0);
81 typeList = createSourceTypeArray(count);
82 typeAtomList = (Atom *) data;
83 for (i = 0; i < count; i++) {
84 WMAddToArray(typeList, XGetAtomName(scr->display, typeAtomList[i]));
87 XFree(data);
89 return typeList;
92 static WMArray *getTypesFromThreeTypes(WMScreen * scr, XClientMessageEvent * event)
94 WMArray *typeList;
95 Atom atom;
96 int i;
98 typeList = createSourceTypeArray(3);
99 for (i = 2; i < 5; i++) {
100 if (event->data.l[i] != None) {
101 atom = (Atom) event->data.l[i];
102 WMAddToArray(typeList, XGetAtomName(scr->display, atom));
106 return typeList;
109 static void storeRequiredTypeList(WMDraggingInfo * info)
111 WMView *destView = XDND_DEST_VIEW(info);
112 WMScreen *scr = W_VIEW_SCREEN(destView);
113 WMArray *requiredTypes;
115 /* First, see if the stored source types are enough for dest requirements */
116 requiredTypes = destView->dragDestinationProcs->requiredDataTypes(destView,
117 W_ActionToOperation(scr,
118 XDND_SOURCE_ACTION
119 (info)),
120 XDND_SOURCE_TYPES(info));
122 if (requiredTypes == NULL && XDND_TYPE_LIST_AVAILABLE(info)) {
123 /* None of the stored source types fits, but the whole type list
124 hasn't been retrieved yet. */
125 WMFreeArray(XDND_SOURCE_TYPES(info));
126 XDND_SOURCE_TYPES(info) = getTypesFromTypeList(scr, XDND_SOURCE_WIN(info));
127 /* Don't retrieve the type list again */
128 XDND_TYPE_LIST_AVAILABLE(info) = False;
130 requiredTypes =
131 destView->dragDestinationProcs->requiredDataTypes(destView,
132 W_ActionToOperation(scr,
133 XDND_SOURCE_ACTION
134 (info)),
135 XDND_SOURCE_TYPES(info));
138 XDND_REQUIRED_TYPES(info) = requiredTypes;
141 static char *getNextRequestedDataType(WMDraggingInfo * info)
143 /* get the type of the first data not yet retrieved from selection */
144 int nextTypeIndex;
146 if (XDND_REQUIRED_TYPES(info) != NULL) {
147 nextTypeIndex = WMGetArrayItemCount(XDND_DROP_DATAS(info));
148 return WMGetFromArray(XDND_REQUIRED_TYPES(info), nextTypeIndex);
149 /* NULL if no more type */
150 } else
151 return NULL;
154 /* ----- Action list ----- */
156 static WMArray *sourceOperationList(WMScreen * scr, Window sourceWin)
158 Atom dataType, *actionList;
159 int i, size;
160 unsigned long count, remaining;
161 unsigned char *actionDatas = NULL;
162 unsigned char *descriptionList = NULL;
163 WMArray *operationArray;
164 WMDragOperationItem *operationItem;
165 char *description;
167 remaining = 0;
168 XGetWindowProperty(scr->display, sourceWin, scr->xdndActionListAtom,
169 0, 0x8000000L, False, XA_ATOM, &dataType, &size, &count, &remaining, &actionDatas);
171 if (dataType != XA_ATOM || size != XDND_PROPERTY_FORMAT || count == 0 || !actionDatas) {
172 wwarning("Cannot read action list");
173 if (actionDatas) {
174 XFree(actionDatas);
176 return NULL;
179 actionList = (Atom *) actionDatas;
181 XGetWindowProperty(scr->display, sourceWin, scr->xdndActionDescriptionAtom,
182 0, 0x8000000L, False, XA_STRING, &dataType, &size,
183 &count, &remaining, &descriptionList);
185 if (dataType != XA_STRING || size != XDND_ACTION_DESCRIPTION_FORMAT || count == 0 || !descriptionList) {
186 wwarning("Cannot read action description list");
187 if (actionList) {
188 XFree(actionList);
190 if (descriptionList) {
191 XFree(descriptionList);
193 return NULL;
196 operationArray = WMCreateDragOperationArray(count);
197 description = (char *)descriptionList;
199 for (i = 0; count > 0; i++) {
200 size = strlen(description);
201 operationItem = WMCreateDragOperationItem(W_ActionToOperation(scr, actionList[i]),
202 wstrdup(description));
204 WMAddToArray(operationArray, operationItem);
205 count -= (size + 1); /* -1 : -NULL char */
207 /* next description */
208 description = &(description[size + 1]);
211 XFree(actionList);
212 XFree(descriptionList);
214 return operationArray;
217 /* ----- Dragging Info ----- */
218 static void updateSourceWindow(WMDraggingInfo * info, XClientMessageEvent * event)
220 XDND_SOURCE_WIN(info) = (Window) event->data.l[0];
223 static WMView *findChildInView(WMView * parent, int x, int y)
225 if (parent->childrenList == NULL)
226 return parent;
227 else {
228 WMView *child = parent->childrenList;
230 while (child != NULL
231 && (!child->flags.mapped
232 || x < WMGetViewPosition(child).x
233 || x > WMGetViewPosition(child).x + WMGetViewSize(child).width
234 || y < WMGetViewPosition(child).y
235 || y > WMGetViewPosition(child).y + WMGetViewSize(child).height))
237 child = child->nextSister;
239 if (child == NULL)
240 return parent;
241 else
242 return findChildInView(child,
243 x - WMGetViewPosition(child).x, y - WMGetViewPosition(child).y);
247 static WMView *findDestinationViewInToplevel(WMView * toplevel, int x, int y)
249 WMScreen *scr = W_VIEW_SCREEN(toplevel);
250 Window toplevelWin = WMViewXID(toplevel);
251 int xInToplevel, yInToplevel;
252 Window foo;
254 XTranslateCoordinates(scr->display, scr->rootWin, toplevelWin, x, y, &xInToplevel, &yInToplevel, &foo);
255 return findChildInView(toplevel, xInToplevel, yInToplevel);
258 /* Clear datas only used by current destination view */
259 static void freeDestinationViewInfos(WMDraggingInfo * info)
261 if (XDND_SOURCE_TYPES(info) != NULL) {
262 WMFreeArray(XDND_SOURCE_TYPES(info));
263 XDND_SOURCE_TYPES(info) = NULL;
266 if (XDND_DROP_DATAS(info) != NULL) {
267 WMFreeArray(XDND_DROP_DATAS(info));
268 XDND_DROP_DATAS(info) = NULL;
271 XDND_REQUIRED_TYPES(info) = NULL;
274 void W_DragDestinationInfoClear(WMDraggingInfo * info)
276 W_DragDestinationStopTimer();
278 if (XDND_DEST_INFO(info) != NULL) {
279 freeDestinationViewInfos(info);
281 wfree(XDND_DEST_INFO(info));
282 XDND_DEST_INFO(info) = NULL;
286 static void initDestinationDragInfo(WMDraggingInfo * info, WMView * destView)
288 wassertr(destView != NULL);
290 XDND_DEST_INFO(info) = (W_DragDestinationInfo *) wmalloc(sizeof(W_DragDestinationInfo));
292 XDND_DEST_STATE(info) = idleState;
293 XDND_DEST_VIEW(info) = destView;
295 XDND_SOURCE_ACTION_CHANGED(info) = False;
296 XDND_SOURCE_TYPES(info) = NULL;
297 XDND_REQUIRED_TYPES(info) = NULL;
298 XDND_DROP_DATAS(info) = NULL;
301 void W_DragDestinationStoreEnterMsgInfo(WMDraggingInfo * info, WMView * toplevel, XClientMessageEvent * event)
303 WMScreen *scr = W_VIEW_SCREEN(toplevel);
305 if (XDND_DEST_INFO(info) == NULL)
306 initDestinationDragInfo(info, toplevel);
308 XDND_SOURCE_VERSION(info) = (event->data.l[1] >> 24);
309 XDND_AWARE_VIEW(info) = toplevel;
310 updateSourceWindow(info, event);
312 #if 0
313 if (event->data.l[1] & 1)
314 /* XdndTypeList property is available */
315 XDND_SOURCE_TYPES(info) = getTypesFromTypeList(scr, XDND_SOURCE_WIN(info));
316 else
317 XDND_SOURCE_TYPES(info) = getTypesFromThreeTypes(scr, event);
318 #endif
319 XDND_SOURCE_TYPES(info) = getTypesFromThreeTypes(scr, event);
321 /* to use if the 3 types are not enough */
322 XDND_TYPE_LIST_AVAILABLE(info) = (event->data.l[1] & 1);
325 void W_DragDestinationStorePositionMsgInfo(WMDraggingInfo * info, WMView * toplevel, XClientMessageEvent * event)
327 int x = event->data.l[2] >> 16;
328 int y = event->data.l[2] & 0xffff;
329 WMView *newDestView;
331 newDestView = findDestinationViewInToplevel(toplevel, x, y);
333 if (XDND_DEST_INFO(info) == NULL) {
334 initDestinationDragInfo(info, newDestView);
335 XDND_AWARE_VIEW(info) = toplevel;
336 updateSourceWindow(info, event);
337 } else {
338 if (newDestView != XDND_DEST_VIEW(info)) {
339 updateSourceWindow(info, event);
340 XDND_DEST_VIEW(info) = newDestView;
341 XDND_SOURCE_ACTION_CHANGED(info) = False;
343 if (XDND_DEST_STATE(info) != waitEnterState)
344 XDND_DEST_STATE(info) = idleState;
345 } else {
346 XDND_SOURCE_ACTION_CHANGED(info) = (XDND_SOURCE_ACTION(info) != event->data.l[4]);
350 XDND_SOURCE_ACTION(info) = event->data.l[4];
352 /* note: source position is not stored */
355 /* ----- End of Dragging Info ----- */
357 /* ----- Messages ----- */
359 /* send a DnD message to the source window */
360 static void
361 sendDnDClientMessage(WMDraggingInfo * info, Atom message,
362 unsigned long data1, unsigned long data2, unsigned long data3, unsigned long data4)
364 if (!W_SendDnDClientMessage(W_VIEW_SCREEN(XDND_AWARE_VIEW(info))->display,
365 XDND_SOURCE_WIN(info),
366 message, WMViewXID(XDND_AWARE_VIEW(info)), data1, data2, data3, data4)) {
367 /* drop failed */
368 W_DragDestinationInfoClear(info);
372 /* send a xdndStatus message to the source, with position and size
373 of the destination if it has no subwidget (requesting a position message
374 on every move otherwise) */
375 static void sendStatusMessage(WMView * destView, WMDraggingInfo * info, Atom action)
377 unsigned long data1;
379 data1 = (action == None) ? 0 : 1;
381 if (destView->childrenList == NULL) {
382 WMScreen *scr = W_VIEW_SCREEN(destView);
383 int destX, destY;
384 WMSize destSize = WMGetViewSize(destView);
385 Window foo;
387 XTranslateCoordinates(scr->display, WMViewXID(destView), scr->rootWin, 0, 0, &destX, &destY, &foo);
389 sendDnDClientMessage(info,
390 W_VIEW_SCREEN(destView)->xdndStatusAtom,
391 data1,
392 (destX << 16) | destY, (destSize.width << 16) | destSize.height, action);
393 } else {
394 /* set bit 1 to request explicitly position message on every move */
395 data1 = data1 | 2;
397 sendDnDClientMessage(info, W_VIEW_SCREEN(destView)->xdndStatusAtom, data1, 0, 0, action);
401 static void
402 storeDropData(WMView * destView, Atom selection, Atom target, Time timestamp, void *cdata, WMData * data)
404 WMScreen *scr = W_VIEW_SCREEN(destView);
405 WMDraggingInfo *info = &(scr->dragInfo);
406 WMData *dataToStore = NULL;
408 /* Parameter not used, but tell the compiler that it is ok */
409 (void) selection;
410 (void) target;
411 (void) timestamp;
412 (void) cdata;
414 if (data != NULL)
415 dataToStore = WMRetainData(data);
417 if (XDND_DEST_INFO(info) != NULL && XDND_DROP_DATAS(info) != NULL) {
418 WMAddToArray(XDND_DROP_DATAS(info), dataToStore);
419 W_SendDnDClientMessage(scr->display, WMViewXID(destView),
420 scr->xdndSelectionAtom, WMViewXID(destView), 0, 0, 0, 0);
424 static Bool requestDropDataInSelection(WMView * destView, const char *type)
426 WMScreen *scr = W_VIEW_SCREEN(destView);
428 if (type != NULL) {
429 if (!WMRequestSelection(destView,
430 scr->xdndSelectionAtom,
431 XInternAtom(scr->display, type, False),
432 CurrentTime, storeDropData, NULL)) {
433 wwarning("could not request data for dropped data");
434 return False;
437 return True;
440 return False;
443 static Bool requestDropData(WMDraggingInfo * info)
445 WMView *destView = XDND_DEST_VIEW(info);
446 char *nextType = getNextRequestedDataType(info);
448 while ((nextType != NULL)
449 && (!requestDropDataInSelection(destView, nextType))) {
450 /* store NULL if request failed, and try with next type */
451 WMAddToArray(XDND_DROP_DATAS(info), NULL);
452 nextType = getNextRequestedDataType(info);
455 /* remains types to retrieve ? */
456 return (nextType != NULL);
459 static void concludeDrop(WMView * destView)
461 destView->dragDestinationProcs->concludeDragOperation(destView);
464 /* send cancel message to the source */
465 static void cancelDrop(WMView * destView, WMDraggingInfo * info)
467 sendStatusMessage(destView, info, None);
468 concludeDrop(destView);
469 freeDestinationViewInfos(info);
472 /* suspend drop, when dragged icon enter an unregistered view
473 or a register view that doesn't accept the drop */
474 static void suspendDropAuthorization(WMView * destView, WMDraggingInfo * info)
476 sendStatusMessage(destView, info, None);
478 /* Free datas that depend on destination behaviour */
479 if (XDND_DROP_DATAS(info) != NULL) {
480 WMFreeArray(XDND_DROP_DATAS(info));
481 XDND_DROP_DATAS(info) = NULL;
484 XDND_REQUIRED_TYPES(info) = NULL;
487 /* cancel drop on Enter message, if protocol version is nok */
488 void W_DragDestinationCancelDropOnEnter(WMView * toplevel, WMDraggingInfo * info)
490 if (XDND_DEST_VIEW_IS_REGISTERED(info))
491 cancelDrop(XDND_DEST_VIEW(info), info);
492 else
493 sendStatusMessage(toplevel, info, None);
495 W_DragDestinationInfoClear(info);
498 static void finishDrop(WMView * destView, WMDraggingInfo * info)
500 sendDnDClientMessage(info, W_VIEW_SCREEN(destView)->xdndFinishedAtom, 0, 0, 0, 0);
501 concludeDrop(destView);
502 W_DragDestinationInfoClear(info);
505 static Atom getAllowedAction(WMView * destView, WMDraggingInfo * info)
507 WMScreen *scr = W_VIEW_SCREEN(destView);
509 return W_OperationToAction(scr,
510 destView->dragDestinationProcs->allowedOperation(destView,
511 W_ActionToOperation(scr,
512 XDND_SOURCE_ACTION
513 (info)),
514 XDND_SOURCE_TYPES(info)));
517 static void *checkActionAllowed(WMView * destView, WMDraggingInfo * info)
519 XDND_DEST_ACTION(info) = getAllowedAction(destView, info);
521 if (XDND_DEST_ACTION(info) == None) {
522 suspendDropAuthorization(destView, info);
523 return dropNotAllowedState;
526 sendStatusMessage(destView, info, XDND_DEST_ACTION(info));
527 return dropAllowedState;
530 static void *checkDropAllowed(WMView *destView, WMDraggingInfo *info)
532 storeRequiredTypeList(info);
534 if (destView->dragDestinationProcs->inspectDropData != NULL) {
535 XDND_DROP_DATAS(info) = createDropDataArray(XDND_REQUIRED_TYPES(info));
537 /* store first available data */
538 if (requestDropData(info))
539 return inspectDropDataState;
541 /* no data retrieved, but inspect can allow it */
542 if (destView->dragDestinationProcs->inspectDropData(destView, XDND_DROP_DATAS(info)))
543 return checkActionAllowed(destView, info);
545 suspendDropAuthorization(destView, info);
546 return dropNotAllowedState;
549 return checkActionAllowed(destView, info);
552 static WMPoint *getDropLocationInView(WMView * view)
554 Window rootWin, childWin;
555 int rootX, rootY;
556 unsigned int mask;
557 WMPoint *location;
559 location = (WMPoint *) wmalloc(sizeof(WMPoint));
561 XQueryPointer(W_VIEW_SCREEN(view)->display,
562 WMViewXID(view), &rootWin, &childWin, &rootX, &rootY, &(location->x), &(location->y), &mask);
564 return location;
567 static void callPerformDragOperation(WMView * destView, WMDraggingInfo * info)
569 WMArray *operationList = NULL;
570 WMScreen *scr = W_VIEW_SCREEN(destView);
571 WMPoint *dropLocation;
573 if (XDND_SOURCE_ACTION(info) == scr->xdndActionAsk)
574 operationList = sourceOperationList(scr, XDND_SOURCE_WIN(info));
576 dropLocation = getDropLocationInView(destView);
577 destView->dragDestinationProcs->performDragOperation(destView,
578 XDND_DROP_DATAS(info), operationList, dropLocation);
580 wfree(dropLocation);
581 if (operationList != NULL)
582 WMFreeArray(operationList);
585 /* ----- Destination timer ----- */
586 static void dragSourceResponseTimeOut(void *destView)
588 WMView *view = (WMView *) destView;
589 WMDraggingInfo *info;
591 wwarning("delay for drag source response expired");
592 info = &(W_VIEW_SCREEN(view)->dragInfo);
593 if (XDND_DEST_VIEW_IS_REGISTERED(info))
594 cancelDrop(view, info);
595 else {
596 sendStatusMessage(view, info, None);
599 W_DragDestinationInfoClear(info);
602 void W_DragDestinationStopTimer(void)
604 if (dndDestinationTimer != NULL) {
605 WMDeleteTimerHandler(dndDestinationTimer);
606 dndDestinationTimer = NULL;
610 void W_DragDestinationStartTimer(WMDraggingInfo * info)
612 W_DragDestinationStopTimer();
614 if (XDND_DEST_STATE(info) != idleState)
615 dndDestinationTimer = WMAddTimerHandler(XDND_SOURCE_RESPONSE_MAX_DELAY,
616 dragSourceResponseTimeOut, XDND_DEST_VIEW(info));
619 /* ----- End of Destination timer ----- */
621 /* ----- Destination states ----- */
623 #ifdef XDND_DEBUG
624 static const char *stateName(W_DndState * state)
626 if (state == NULL)
627 return "no state defined";
629 if (state == idleState)
630 return "idleState";
632 if (state == waitEnterState)
633 return "waitEnterState";
635 if (state == inspectDropDataState)
636 return "inspectDropDataState";
638 if (state == dropAllowedState)
639 return "dropAllowedState";
641 if (state == dropNotAllowedState)
642 return "dropNotAllowedState";
644 if (state == waitForDropDataState)
645 return "waitForDropDataState";
647 return "unknown state";
649 #endif
651 static void *idleState(WMView * destView, XClientMessageEvent * event, WMDraggingInfo * info)
653 WMScreen *scr;
654 Atom sourceMsg;
656 if (destView->dragDestinationProcs != NULL) {
657 scr = W_VIEW_SCREEN(destView);
658 sourceMsg = event->message_type;
660 if (sourceMsg == scr->xdndPositionAtom) {
661 destView->dragDestinationProcs->prepareForDragOperation(destView);
663 if (XDND_SOURCE_TYPES(info) != NULL) {
664 /* enter message infos are available */
665 return checkDropAllowed(destView, info);
668 /* waiting for enter message */
669 return waitEnterState;
673 suspendDropAuthorization(destView, info);
674 return idleState;
677 /* Source position and action are stored,
678 waiting for xdnd protocol version and source type */
679 static void *waitEnterState(WMView * destView, XClientMessageEvent * event, WMDraggingInfo * info)
681 WMScreen *scr = W_VIEW_SCREEN(destView);
682 Atom sourceMsg = event->message_type;
684 if (sourceMsg == scr->xdndEnterAtom) {
685 W_DragDestinationStoreEnterMsgInfo(info, destView, event);
686 return checkDropAllowed(destView, info);
689 return waitEnterState;
692 /* We have requested a data, and have received it */
693 static void *inspectDropDataState(WMView * destView, XClientMessageEvent * event, WMDraggingInfo * info)
695 WMScreen *scr;
696 Atom sourceMsg;
698 scr = W_VIEW_SCREEN(destView);
699 sourceMsg = event->message_type;
701 if (sourceMsg == scr->xdndSelectionAtom) {
702 /* a data has been retrieved, store next available */
703 if (requestDropData(info))
704 return inspectDropDataState;
706 /* all required (and available) datas are stored */
707 if (destView->dragDestinationProcs->inspectDropData(destView, XDND_DROP_DATAS(info)))
708 return checkActionAllowed(destView, info);
710 suspendDropAuthorization(destView, info);
711 return dropNotAllowedState;
714 return inspectDropDataState;
717 static void *dropNotAllowedState(WMView * destView, XClientMessageEvent * event, WMDraggingInfo * info)
719 WMScreen *scr = W_VIEW_SCREEN(destView);
720 Atom sourceMsg = event->message_type;
722 if (sourceMsg == scr->xdndDropAtom) {
723 finishDrop(destView, info);
724 return idleState;
727 if (sourceMsg == scr->xdndPositionAtom) {
728 if (XDND_SOURCE_ACTION_CHANGED(info)) {
729 return checkDropAllowed(destView, info);
730 } else {
731 sendStatusMessage(destView, info, None);
732 return dropNotAllowedState;
736 return dropNotAllowedState;
739 static void *dropAllowedState(WMView * destView, XClientMessageEvent * event, WMDraggingInfo * info)
741 WMScreen *scr = W_VIEW_SCREEN(destView);
742 Atom sourceMsg = event->message_type;
744 if (sourceMsg == scr->xdndDropAtom) {
745 if (XDND_DROP_DATAS(info) != NULL) {
746 /* drop datas were cached with inspectDropData call */
747 callPerformDragOperation(destView, info);
748 } else {
749 XDND_DROP_DATAS(info) = createDropDataArray(XDND_REQUIRED_TYPES(info));
751 /* store first available data */
752 if (requestDropData(info))
753 return waitForDropDataState;
755 /* no data retrieved */
756 callPerformDragOperation(destView, info);
759 finishDrop(destView, info);
760 return idleState;
763 if (sourceMsg == scr->xdndPositionAtom) {
764 if (XDND_SOURCE_ACTION_CHANGED(info)) {
765 return checkDropAllowed(destView, info);
766 } else {
767 sendStatusMessage(destView, info, XDND_DEST_ACTION(info));
768 return dropAllowedState;
772 return dropAllowedState;
775 static void *waitForDropDataState(WMView * destView, XClientMessageEvent * event, WMDraggingInfo * info)
777 WMScreen *scr = W_VIEW_SCREEN(destView);
778 Atom sourceMsg = event->message_type;
780 if (sourceMsg == scr->xdndSelectionAtom) {
781 /* store next data */
782 if (requestDropData(info))
783 return waitForDropDataState;
785 /* all required (and available) datas are stored */
786 callPerformDragOperation(destView, info);
788 finishDrop(destView, info);
789 return idleState;
792 return waitForDropDataState;
795 /* ----- End of Destination states ----- */
797 void W_DragDestinationStateHandler(WMDraggingInfo * info, XClientMessageEvent * event)
799 WMView *destView;
800 W_DndState *newState;
802 wassertr(XDND_DEST_INFO(info) != NULL);
803 wassertr(XDND_DEST_VIEW(info) != NULL);
805 destView = XDND_DEST_VIEW(info);
806 if (XDND_DEST_STATE(info) == NULL)
807 XDND_DEST_STATE(info) = idleState;
809 #ifdef XDND_DEBUG
811 printf("current dest state: %s\n", stateName(XDND_DEST_STATE(info)));
812 #endif
814 newState = (W_DndState *) XDND_DEST_STATE(info) (destView, event, info);
816 #ifdef XDND_DEBUG
818 printf("new dest state: %s\n", stateName(newState));
819 #endif
821 if (XDND_DEST_INFO(info) != NULL) {
822 XDND_DEST_STATE(info) = newState;
823 if (XDND_DEST_STATE(info) != idleState)
824 W_DragDestinationStartTimer(info);
828 static void realizedObserver(void *self, WMNotification * notif)
830 WMView *view = (WMView *) WMGetNotificationObject(notif);
831 WMScreen *scr = W_VIEW_SCREEN(view);
833 XChangeProperty(scr->display, W_VIEW_DRAWABLE(view),
834 scr->xdndAwareAtom, XA_ATOM, XDND_PROPERTY_FORMAT, PropModeReplace, &XDNDversion, 1);
836 WMRemoveNotificationObserver(self);
839 static void W_SetXdndAwareProperty(WMScreen *scr, WMView *view)
841 WMView *toplevel = W_TopLevelOfView(view);
843 if (!toplevel->flags.xdndHintSet) {
844 toplevel->flags.xdndHintSet = 1;
846 if (toplevel->flags.realized) {
847 XChangeProperty(scr->display, W_VIEW_DRAWABLE(toplevel),
848 scr->xdndAwareAtom, XA_ATOM, XDND_PROPERTY_FORMAT,
849 PropModeReplace, &XDNDversion, 1);
850 } else {
851 WMAddNotificationObserver(realizedObserver,
852 /* just use as an id */
853 &view->dragDestinationProcs,
854 WMViewRealizedNotification, toplevel);
859 void WMRegisterViewForDraggedTypes(WMView * view, WMArray * acceptedTypes)
861 Atom *types;
862 int typeCount;
863 int i;
865 typeCount = WMGetArrayItemCount(acceptedTypes);
866 types = wmalloc(sizeof(Atom) * (typeCount + 1));
868 for (i = 0; i < typeCount; i++) {
869 types[i] = XInternAtom(W_VIEW_SCREEN(view)->display, WMGetFromArray(acceptedTypes, i), False);
871 types[i] = 0;
873 view->droppableTypes = types;
874 /* WMFreeArray(acceptedTypes); */
876 W_SetXdndAwareProperty(W_VIEW_SCREEN(view), view);
879 void WMUnregisterViewDraggedTypes(WMView * view)
881 if (view->droppableTypes != NULL)
882 wfree(view->droppableTypes);
883 view->droppableTypes = NULL;
887 requestedOperation: operation requested by the source
888 sourceDataTypes: data types (mime-types strings) supported by the source
889 (never NULL, destroyed when drop ends)
890 return operation allowed by destination (self)
892 static WMDragOperationType
893 defAllowedOperation(WMView * self, WMDragOperationType requestedOperation, WMArray * sourceDataTypes)
895 /* Parameter not used, but tell the compiler that it is ok */
896 (void) self;
897 (void) requestedOperation;
898 (void) sourceDataTypes;
900 /* no operation allowed */
901 return WDOperationNone;
905 requestedOperation: operation requested by the source
906 sourceDataTypes: data types (mime-types strings) supported by the source
907 (never NULL, destroyed when drop ends)
908 return data types (mime-types strings) required by destination (self)
909 or NULL if no suitable data type is available (force
910 to 2nd pass with full source type list).
912 static WMArray *defRequiredDataTypes(WMView * self,
913 WMDragOperationType requestedOperation, WMArray * sourceDataTypes)
915 /* Parameter not used, but tell the compiler that it is ok */
916 (void) self;
917 (void) requestedOperation;
918 (void) sourceDataTypes;
920 /* no data type allowed (NULL even at 2nd pass) */
921 return NULL;
925 Executed when the drag enters destination (self)
927 static void defPrepareForDragOperation(WMView * self)
929 /* Parameter not used, but tell the compiler that it is ok */
930 (void) self;
934 Checks datas to be dropped (optional).
935 dropDatas: datas (WMData*) required by destination (self)
936 (given in same order as returned by requiredDataTypes).
937 A NULL data means it couldn't be retreived.
938 Destroyed when drop ends.
939 return true if data array is ok
941 /* Bool (*inspectDropData)(WMView *self, WMArray *dropDatas); */
944 Process drop
945 dropDatas: datas (WMData*) required by destination (self)
946 (given in same order as returned by requiredDataTypes).
947 A NULL data means it couldn't be retrieved.
948 Destroyed when drop ends.
949 operationList: if source operation is WDOperationAsk, contains
950 operations (and associated texts) that can be asked
951 to source. (destroyed after performDragOperation call)
952 Otherwise this parameter is NULL.
954 static void
955 defPerformDragOperation(WMView * self, WMArray * dropDatas, WMArray * operationList, WMPoint * dropLocation)
957 /* Parameter not used, but tell the compiler that it is ok */
958 (void) self;
959 (void) dropDatas;
960 (void) operationList;
961 (void) dropLocation;
964 /* Executed after drop */
965 static void defConcludeDragOperation(WMView * self)
967 /* Parameter not used, but tell the compiler that it is ok */
968 (void) self;
971 void WMSetViewDragDestinationProcs(WMView * view, WMDragDestinationProcs * procs)
973 if (view->dragDestinationProcs == NULL) {
974 view->dragDestinationProcs = wmalloc(sizeof(WMDragDestinationProcs));
977 *view->dragDestinationProcs = *procs;
979 /*XXX fill in non-implemented stuffs */
980 if (procs->allowedOperation == NULL) {
981 view->dragDestinationProcs->allowedOperation = defAllowedOperation;
983 if (procs->allowedOperation == NULL) {
984 view->dragDestinationProcs->requiredDataTypes = defRequiredDataTypes;
987 /* note: inspectDropData can be NULL, if data consultation is not needed
988 to give drop permission */
990 if (procs->prepareForDragOperation == NULL) {
991 view->dragDestinationProcs->prepareForDragOperation = defPrepareForDragOperation;
993 if (procs->performDragOperation == NULL) {
994 view->dragDestinationProcs->performDragOperation = defPerformDragOperation;
996 if (procs->concludeDragOperation == NULL) {
997 view->dragDestinationProcs->concludeDragOperation = defConcludeDragOperation;