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