1 /* $Header: /cvsroot/lesstif/lesstif/test/extra/daniel/Dnd.c,v 1.2 2002/05/15 10:55:06 amai Exp $ */
2 
3 /***********************************************************/
4 /* Copyright 1996 Daniel Dardailler.
5 Permission to use, copy, modify, distribute, and sell this software
6 for any purpose is hereby granted without fee, provided that the above
7 copyright notice appear in all copies and that both that copyright
8 notice and this permission notice appear in supporting documentation,
9 and that the name of Daniel Dardailler not be used in advertising or
10 publicity pertaining to distribution of the software without specific,
11 written prior permission.  Daniel Dardailler makes no representations
12 about the suitability of this software for any purpose.  It is
13 provided "as is" without express or implied warranty.
14 ************************************************************/
15 
16 /***********************************************************/
17 /* Motif Drag&Drop Dynamic Protocol messaging API code */
18 /* Only requires Xlib layer - not MT safe */
19 /* Author: Daniel Dardailler, daniel@x.org */
20 /***********************************************************/
21 
22 #include <stdio.h>
23 
24 #include "DndP.h"
25 
26 static Atom atom_message_type, atom_receiver_info, atom_src_property_type;
27 
_DndByteOrder(void)28 unsigned char _DndByteOrder (void)
29 {
30     static unsigned char byte_order = 0;
31 
32     if (!byte_order) {
33 	unsigned int endian = 1;
34 	byte_order = (*((char *)&endian))?'l':'B';
35     }
36     return byte_order ;
37 }
38 
39 
40 static void
InitAtoms(Display * dpy)41 InitAtoms(Display * dpy)
42 {
43     if (atom_message_type) return ; /* already Initialized */
44 
45     /* Init atoms used in the com */
46     atom_message_type =  XInternAtom(dpy,
47 				    "_MOTIF_DRAG_AND_DROP_MESSAGE", False);
48     atom_src_property_type = XInternAtom(dpy,
49 					"_MOTIF_DRAG_INITIATOR_INFO", False);
50     atom_receiver_info = XInternAtom(dpy, "_MOTIF_DRAG_RECEIVER_INFO", False);
51 }
52 
53 
54 
55 /* Position the _MOTIF_DRAG_INITIATOR_INFO property on the source window.
56    Called by the source of the drag to indicate the
57    supported target list (thru the index scheme) */
58 extern void
DndWriteSourceProperty(Display * dpy,Window window,Atom dnd_selection,Atom * targets,unsigned short num_targets)59 DndWriteSourceProperty(Display * dpy,
60 		       Window window, Atom dnd_selection,
61 		       Atom * targets, unsigned short num_targets)
62 {
63     DndSrcProp src_prop ;
64 
65     InitAtoms(dpy);
66 
67     src_prop.byte_order = _DndByteOrder() ;
68     src_prop.protocol_version = DND_PROTOCOL_VERSION;
69     src_prop.target_index = _DndTargetsToIndex(dpy, targets, num_targets);
70     if (src_prop.target_index == -1) return ;
71     src_prop.selection = dnd_selection ;
72 
73     /* write the buffer to the property */
74     XChangeProperty (dpy, window, dnd_selection, atom_src_property_type,
75 		     8, PropModeReplace, (unsigned char *)&src_prop,
76 		     sizeof(DndSrcProp));
77 }
78 
79 extern void
DndReadSourceProperty(Display * dpy,Window window,Atom dnd_selection,Atom ** targets,unsigned short * num_targets)80 DndReadSourceProperty(Display * dpy,
81 		      Window window, Atom dnd_selection,
82 		      Atom ** targets, unsigned short * num_targets)
83 {
84     DndSrcProp * src_prop = NULL;
85     Atom type ;
86     int format ;
87     unsigned long bytesafter, lengthRtn;
88 
89     InitAtoms(dpy);
90 
91     if ((XGetWindowProperty (dpy, window, dnd_selection, 0L, 100000L,
92 			    False, atom_src_property_type, &type,
93 			    &format, &lengthRtn, &bytesafter,
94 			    (unsigned char **) &src_prop) != Success)
95 	|| (type == None)) {
96 	printf("No property - DndReadSourceProperty return 0 \n");
97 	*num_targets = 0;
98 	return ;
99     }
100 
101     if (src_prop->byte_order != _DndByteOrder()) {
102 	SWAP2BYTES(src_prop->target_index);
103 	SWAP4BYTES(src_prop->selection);
104     }
105 
106     *num_targets = _DndIndexToTargets(dpy, src_prop->target_index, targets);
107 
108     XFree((char*)src_prop);
109 }
110 
111 
112 /* Position the _MOTIF_DRAG_RECEIVER_INFO property on the dropsite window.
113    Called by the receiver of the drop to indicate the
114    supported protocol style : dynamic, drop_only or none */
115 extern void
DndWriteReceiverProperty(Display * dpy,Window window,unsigned char protocol_style)116 DndWriteReceiverProperty(Display * dpy, Window window,
117 			 unsigned char protocol_style)
118 {
119     DndReceiverProp receiver_prop ;
120 
121     InitAtoms(dpy);
122 
123     receiver_prop.byte_order = _DndByteOrder() ;
124     receiver_prop.protocol_version = DND_PROTOCOL_VERSION;
125     receiver_prop.protocol_style = protocol_style ;
126     receiver_prop.proxy_window =  None ;
127     receiver_prop.num_drop_sites = 0 ;
128     receiver_prop.total_size = sizeof(DndReceiverProp);
129 
130     /* write the buffer to the property */
131     XChangeProperty (dpy, window, atom_receiver_info, atom_receiver_info,
132 		     8, PropModeReplace,
133 		     (unsigned char *)&receiver_prop,
134 		     sizeof(DndReceiverProp));
135 }
136 
137 
138 /* protocol style equiv (preregister stuff really) */
139 #define DND_DRAG_DROP_ONLY_EQUIV 3
140 #define DND_DRAG_DYNAMIC_EQUIV1  2
141 #define DND_DRAG_DYNAMIC_EQUIV2  4
142 
143 extern void
DndReadReceiverProperty(Display * dpy,Window window,unsigned char * protocol_style)144 DndReadReceiverProperty(Display * dpy, Window window,
145 			unsigned char * protocol_style)
146 {
147     DndReceiverProp *receiver_prop = NULL ;
148     Atom type ;
149     int format ;
150     unsigned long bytesafter, lengthRtn;
151 
152     InitAtoms(dpy);
153 
154     if ((XGetWindowProperty (dpy, window,
155 			    atom_receiver_info, /* _MOTIF_DRAG_RECEIVER_INFO */
156 			    0L, 100000L, False, atom_receiver_info,
157 			    &type, &format, &lengthRtn, &bytesafter,
158 			    (unsigned char **) &receiver_prop) != Success)
159 	|| (type == None)) {
160 	/* no property => no d&d */
161 	*protocol_style = DND_DRAG_NONE ;
162 	return ;
163     }
164 
165     /* in dynamic we don't really care about byte swapping since
166        the pertinent info is all expressed in one byte quantities */
167     *protocol_style = receiver_prop->protocol_style;
168 
169     /* do the equiv stuff for Motif pre-register */
170     if (*protocol_style == DND_DRAG_DROP_ONLY_EQUIV)
171 	*protocol_style = DND_DRAG_DROP_ONLY ;
172     else
173     if (*protocol_style == DND_DRAG_DYNAMIC_EQUIV1 ||
174 	*protocol_style == DND_DRAG_DYNAMIC_EQUIV2)
175 	*protocol_style = DND_DRAG_DYNAMIC ;
176 
177     XFree((void *)receiver_prop) ;
178 
179 }
180 
181 /* Produce a client message to be sent by the caller */
182 extern void
DndFillClientMessage(Display * dpy,Window window,XClientMessageEvent * cm,DndData * dnd_data,char receiver)183 DndFillClientMessage(Display * dpy, Window window,
184 		     XClientMessageEvent *cm,
185 		     DndData * dnd_data,
186 		     char receiver)
187 {
188     DndMessage * dnd_message = (DndMessage*)&cm->data.b[0] ;
189 
190     InitAtoms(dpy);
191 
192     cm->display = dpy;
193     cm->type = ClientMessage;
194     cm->serial = LastKnownRequestProcessed(dpy);
195     cm->send_event = True;
196     cm->window = window;
197     cm->format = 8;
198     cm->message_type = atom_message_type ;/* _MOTIF_DRAG_AND_DROP_MESSAGE */
199 
200     dnd_message->reason = dnd_data->reason | DND_SET_EVENT_TYPE(receiver);
201 
202     dnd_message->byte_order = _DndByteOrder();
203 
204     /* we're filling in flags with more stuff that necessary,
205        depending on the reason, but it doesn't matter */
206     dnd_message->flags = 0 ;
207     dnd_message->flags |= DND_SET_STATUS(dnd_data->status) ;
208     dnd_message->flags |= DND_SET_OPERATION(dnd_data->operation) ;
209     dnd_message->flags |= DND_SET_OPERATIONS(dnd_data->operations) ;
210     dnd_message->flags |= DND_SET_COMPLETION(dnd_data->completion) ;
211 
212     dnd_message->time = dnd_data->time ;
213 
214     switch(dnd_data->reason) {
215     case DND_DROP_SITE_LEAVE: break ;
216     case DND_TOP_LEVEL_ENTER:
217     case DND_TOP_LEVEL_LEAVE:
218 	dnd_message->data.top.src_window = dnd_data->src_window ;
219 	dnd_message->data.top.property = dnd_data->property ;
220 	break ; /* cannot fall thru since the byte layout is different in
221 		   both set of messages, see top and pot union stuff */
222 
223     case DND_DRAG_MOTION:
224     case DND_OPERATION_CHANGED:
225     case DND_DROP_SITE_ENTER:
226     case DND_DROP_START:
227 	dnd_message->data.pot.x = dnd_data->x ; /* mouse position */
228 	dnd_message->data.pot.y = dnd_data->y ;
229 	dnd_message->data.pot.src_window = dnd_data->src_window ;
230 	dnd_message->data.pot.property = dnd_data->property ;
231 	break ;
232     default:
233 	printf("DndWriteClientMessage default: warning\n");
234 	break ;
235     }
236 
237 }
238 
239 extern Bool
DndParseClientMessage(XClientMessageEvent * cm,DndData * dnd_data,char * receiver)240 DndParseClientMessage(XClientMessageEvent *cm, DndData * dnd_data,
241 		      char * receiver)
242 {
243     DndMessage * dnd_message = (DndMessage*)&cm->data.b[0] ;
244 
245     InitAtoms(cm->display);
246 
247     if (cm->message_type != atom_message_type) {
248 	printf("Invalid _MOTIF_DRAG_AND_DROP_MESSAGE - DndReadClientMessage fails\n");
249 	return False ;
250     }
251 
252     if (dnd_message->byte_order != _DndByteOrder()) {
253 	SWAP2BYTES(dnd_message->flags);
254 	SWAP4BYTES(dnd_message->time);
255     } /* do the rest in the switch */
256 
257     dnd_data->reason = dnd_message->reason  ;
258     if (DND_GET_EVENT_TYPE(dnd_data->reason))
259 	*receiver = 1 ;
260     else
261 	*receiver = 0 ;
262     dnd_data->reason &= DND_CLEAR_EVENT_TYPE ;
263 
264     dnd_data->time = dnd_message->time ;
265 
266     /* we're reading in more stuff that necessary. but who cares */
267     dnd_data->status = DND_GET_STATUS(dnd_message->flags) ;
268     dnd_data->operation = DND_GET_OPERATION(dnd_message->flags) ;
269     dnd_data->operations = DND_GET_OPERATIONS(dnd_message->flags) ;
270     dnd_data->completion = DND_GET_COMPLETION(dnd_message->flags) ;
271 
272     switch(dnd_data->reason) {
273     case DND_TOP_LEVEL_ENTER:
274     case DND_TOP_LEVEL_LEAVE:
275 	if (dnd_message->byte_order != _DndByteOrder()) {
276 	    SWAP4BYTES(dnd_message->data.top.src_window);
277 	    SWAP4BYTES(dnd_message->data.top.property);
278 	}
279 	dnd_data->src_window = dnd_message->data.top.src_window ;
280 	dnd_data->property = dnd_message->data.top.property ;
281 	break ; /* cannot fall thru, see above comment in write msg */
282 
283     case DND_DRAG_MOTION:
284     case DND_OPERATION_CHANGED:
285     case DND_DROP_SITE_ENTER:
286     case DND_DROP_START:
287 	if (dnd_message->byte_order != _DndByteOrder()) {
288 	    SWAP2BYTES(dnd_message->data.pot.x);
289 	    SWAP2BYTES(dnd_message->data.pot.y);
290 	    SWAP4BYTES(dnd_message->data.pot.property);
291 	    SWAP4BYTES(dnd_message->data.pot.src_window);
292 	}
293 	dnd_data->x = dnd_message->data.pot.x ;
294 	dnd_data->y = dnd_message->data.pot.y ;
295 	dnd_data->property = dnd_message->data.pot.property ;
296 	dnd_data->src_window = dnd_message->data.pot.src_window ;
297 	break ;
298 
299     case DND_DROP_SITE_LEAVE:
300         break;
301     default:
302 	printf("DndReadClientMessage default: warning\n");
303 	break ;
304     }
305 
306     return True ;
307 }
308