1 /* |
|
2 * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved. |
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 * |
|
5 * This code is free software; you can redistribute it and/or modify it |
|
6 * under the terms of the GNU General Public License version 2 only, as |
|
7 * published by the Free Software Foundation. Sun designates this |
|
8 * particular file as subject to the "Classpath" exception as provided |
|
9 * by Sun in the LICENSE file that accompanied this code. |
|
10 * |
|
11 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 * version 2 for more details (a copy is included in the LICENSE file that |
|
15 * accompanied this code). |
|
16 * |
|
17 * You should have received a copy of the GNU General Public License version |
|
18 * 2 along with this work; if not, write to the Free Software Foundation, |
|
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 * |
|
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
|
22 * CA 95054 USA or visit www.sun.com if you need additional information or |
|
23 * have any questions. |
|
24 */ |
|
25 |
|
26 #ifdef HEADLESS |
|
27 #error This file should not be included in headless library |
|
28 #endif |
|
29 |
|
30 #include "awt_dnd.h" |
|
31 |
|
32 #include "jlong.h" |
|
33 |
|
34 #include "awt_DataTransferer.h" |
|
35 #include "awt_MToolkit.h" |
|
36 |
|
37 #include "java_awt_dnd_DnDConstants.h" |
|
38 #include "java_awt_event_MouseEvent.h" |
|
39 |
|
40 #include "sun_awt_motif_MComponentPeer.h" |
|
41 #include "awt_xembed.h" |
|
42 |
|
43 #define DT_INITIAL_STATE 0 |
|
44 #define DT_ENTERED_STATE 1 |
|
45 #define DT_OVER_STATE 2 |
|
46 |
|
47 extern struct ComponentIDs componentIDs; |
|
48 extern struct MComponentPeerIDs mComponentPeerIDs; |
|
49 |
|
50 /**************************** XEmbed server DnD support ***********************/ |
|
51 extern void |
|
52 set_xembed_drop_target(JNIEnv* env, jobject server); |
|
53 extern void |
|
54 remove_xembed_drop_target(JNIEnv* env, jobject server); |
|
55 extern Boolean |
|
56 is_xembed_client(Window window); |
|
57 |
|
58 DECLARE_JAVA_CLASS(MEmbedCanvasPeerClass, "sun/awt/motif/MEmbedCanvasPeer"); |
|
59 /******************************************************************************/ |
|
60 |
|
61 typedef enum { |
|
62 EventSuccess, /* Event is successfully processed. */ |
|
63 EventFailure /* Failed to process the event. */ |
|
64 } EventStatus; |
|
65 |
|
66 typedef enum { |
|
67 EnterEvent, /* XdndEnter, TOP_LEVEL_ENTER */ |
|
68 MotionEvent, /* XdndPosition, DRAG_MOTION, OPERATION_CHANGED */ |
|
69 LeaveEvent, /* XdndLeave, TOP_LEVEL_LEAVE */ |
|
70 DropEvent, /* XdndDrop, DROP_START */ |
|
71 UnknownEvent |
|
72 } EventType; |
|
73 |
|
74 static Protocol source_protocol = NO_PROTOCOL; |
|
75 static unsigned int source_protocol_version = 0; |
|
76 static Window source_window = None; |
|
77 static Atom source_atom = None; |
|
78 static long source_window_mask = None; |
|
79 static jint source_actions = java_awt_dnd_DnDConstants_ACTION_NONE; |
|
80 /* |
|
81 * According to XDnD protocol, XdndActionList is optional. |
|
82 * In case if XdndActionList is not set on the source, the list of drop actions |
|
83 * supported by the source is constructed as follows: |
|
84 * - "copy" is always included; |
|
85 * - "move" is included if at least one XdndPosition message received |
|
86 * after the latest XdndEnter passed XdndActionMove in data.l[4]; |
|
87 * - "link" is included if at least one XdndPosition message received |
|
88 * after the latest XdndEnter passed XdndActionLink in data.l[4]. |
|
89 * We use a boolean flag to signal that we are building the list of drop actions |
|
90 * supported by the source. |
|
91 */ |
|
92 static Boolean track_source_actions = False; |
|
93 static jint user_action = java_awt_dnd_DnDConstants_ACTION_NONE; |
|
94 static jlongArray source_data_types = NULL; |
|
95 static Atom* source_data_types_native = NULL; |
|
96 static unsigned int source_data_types_count = 0; |
|
97 static int source_x = 0; |
|
98 static int source_y = 0; |
|
99 static jobject target_component = NULL; |
|
100 /* |
|
101 * The Motif DnD protocol prescribes that DROP_START message should always be |
|
102 * preceeded with TOP_LEVEL_LEAVE message. We need to cleanup on TOP_LEVEL_LEAVE |
|
103 * message, but DROP_START wouldn't be processed properly. |
|
104 * To resolve this issue we postpone cleanup using a boolean flag this flag is |
|
105 * set when we receive the TOP_LEVEL_LEAVE message and cleared when the next |
|
106 * client message arrives if that message is not DROP_START. If that message is |
|
107 * a DROP_START message, the flag is cleared after the DROP_START is processed. |
|
108 */ |
|
109 static Boolean motif_top_level_leave_postponed = False; |
|
110 /* |
|
111 * We store a postponed TOP_LEVEL_LEAVE message here. |
|
112 */ |
|
113 static XClientMessageEvent motif_top_level_leave_postponed_event; |
|
114 |
|
115 /* Forward declarations */ |
|
116 static Window get_root_for_window(Window window); |
|
117 static Window get_outer_canvas_for_window(Window window); |
|
118 static Boolean register_drop_site(Widget outer_canvas, XtPointer componentRef); |
|
119 static Boolean is_xdnd_drag_message_type(unsigned long message_type); |
|
120 static Boolean register_xdnd_drop_site(Display* dpy, Window toplevel, |
|
121 Window window); |
|
122 |
|
123 /**************************** JNI stuff ***************************************/ |
|
124 |
|
125 DECLARE_JAVA_CLASS(dtcp_clazz, "sun/awt/motif/X11DropTargetContextPeer") |
|
126 |
|
127 static void |
|
128 dt_postDropTargetEvent(JNIEnv* env, jobject component, int x, int y, |
|
129 jint dropAction, jint event_id, |
|
130 XClientMessageEvent* event) { |
|
131 DECLARE_STATIC_VOID_JAVA_METHOD(dtcp_postDropTargetEventToPeer, dtcp_clazz, |
|
132 "postDropTargetEventToPeer", |
|
133 "(Ljava/awt/Component;IIII[JJI)V"); |
|
134 |
|
135 { |
|
136 void* copy = NULL; |
|
137 |
|
138 if (event != NULL) { |
|
139 /* |
|
140 * For XDnD messages we append the information from the latest |
|
141 * XdndEnter to the context. It is done to be able to reconstruct |
|
142 * XdndEnter for an XEmbed client. |
|
143 */ |
|
144 Boolean isXDnDMessage = |
|
145 is_xdnd_drag_message_type(event->message_type); |
|
146 |
|
147 if (isXDnDMessage) { |
|
148 copy = malloc(sizeof(XClientMessageEvent) + |
|
149 4 * sizeof(long)); |
|
150 } else { |
|
151 copy = malloc(sizeof(XClientMessageEvent)); |
|
152 } |
|
153 |
|
154 if (copy == NULL) { |
|
155 DTRACE_PRINTLN2("%s:%d malloc failed.", __FILE__, __LINE__); |
|
156 return; |
|
157 } |
|
158 |
|
159 memcpy(copy, event, sizeof(XClientMessageEvent)); |
|
160 |
|
161 if (isXDnDMessage) { |
|
162 size_t msgSize = sizeof(XClientMessageEvent); |
|
163 long data1 = source_protocol_version << XDND_PROTOCOL_SHIFT; |
|
164 long * appended_data; |
|
165 if (source_data_types_native != NULL && |
|
166 source_data_types_count > 3) { |
|
167 |
|
168 data1 |= XDND_DATA_TYPES_BIT; |
|
169 } |
|
170 |
|
171 appended_data = (long*)((char*)copy + msgSize); |
|
172 appended_data[0] = data1; |
|
173 appended_data[1] = source_data_types_count > 0 ? |
|
174 source_data_types_native[0] : 0; |
|
175 appended_data[2] = source_data_types_count > 1 ? |
|
176 source_data_types_native[1] : 0; |
|
177 appended_data[3] = source_data_types_count > 2 ? |
|
178 source_data_types_native[2] : 0; |
|
179 } |
|
180 } |
|
181 |
|
182 DASSERT(!JNU_IsNull(env, component)); |
|
183 |
|
184 (*env)->CallStaticVoidMethod(env, clazz, dtcp_postDropTargetEventToPeer, |
|
185 component, x, y, dropAction, |
|
186 source_actions, source_data_types, |
|
187 ptr_to_jlong(copy), event_id); |
|
188 } |
|
189 } |
|
190 |
|
191 /******************************************************************************/ |
|
192 |
|
193 /********************* Embedded drop site list support ************************/ |
|
194 |
|
195 struct EmbeddedDropSiteListEntryRec; |
|
196 |
|
197 typedef struct EmbeddedDropSiteListEntryRec EmbeddedDropSiteListEntry; |
|
198 |
|
199 struct EmbeddedDropSiteListEntryRec { |
|
200 Window toplevel; |
|
201 Window root; |
|
202 /* |
|
203 * We select for PropertyNotify events on the toplevel, so we need to |
|
204 * restore the event mask when we are done with this toplevel. |
|
205 */ |
|
206 long event_mask; |
|
207 unsigned int embedded_sites_count; |
|
208 Window* embedded_sites; |
|
209 EmbeddedDropSiteListEntry* next; |
|
210 }; |
|
211 |
|
212 static EmbeddedDropSiteListEntry* embedded_drop_site_list = NULL; |
|
213 |
|
214 struct EmbeddedDropSiteProtocolListEntryRec; |
|
215 |
|
216 typedef struct EmbeddedDropSiteProtocolListEntryRec EmbeddedDropSiteProtocolListEntry; |
|
217 |
|
218 struct EmbeddedDropSiteProtocolListEntryRec { |
|
219 Window window; |
|
220 Window proxy; |
|
221 /* |
|
222 * We override the XdndAware property on the toplevel, so we should keep its |
|
223 * original contents - the XDnD protocol version supported by the browser. |
|
224 * This is needed to adjust XDnD messages forwarded to the browser. |
|
225 */ |
|
226 unsigned int protocol_version; |
|
227 /* True if the toplevel was already registered as a drag receiver and |
|
228 we just changed the proxy. False, otherwise */ |
|
229 Boolean overriden; |
|
230 EmbeddedDropSiteProtocolListEntry* next; |
|
231 }; |
|
232 |
|
233 static EmbeddedDropSiteProtocolListEntry* embedded_motif_protocol_list = NULL; |
|
234 static EmbeddedDropSiteProtocolListEntry* embedded_xdnd_protocol_list = NULL; |
|
235 |
|
236 typedef enum { |
|
237 RegFailure, /* Proxy registration failed */ |
|
238 RegSuccess, /* The new drop site is registered with the new proxy */ |
|
239 RegOverride, /* The new proxy is set for the existing drop site */ |
|
240 RegAlreadyRegistered /* This proxy is already set for this drop site */ |
|
241 } ProxyRegistrationStatus; |
|
242 |
|
243 /* Forward declarations. */ |
|
244 static EmbeddedDropSiteProtocolListEntry* |
|
245 get_xdnd_protocol_entry_for_toplevel(Window toplevel); |
|
246 static EmbeddedDropSiteProtocolListEntry* |
|
247 get_motif_protocol_entry_for_toplevel(Window toplevel); |
|
248 static void remove_xdnd_protocol_entry_for_toplevel(Window toplevel); |
|
249 static void remove_motif_protocol_entry_for_toplevel(Window toplevel); |
|
250 |
|
251 /* |
|
252 * Registers the toplevel as a Motif drag receiver if it is not registered yet, |
|
253 * sets the specified new_proxy for it and returns the previous proxy in old_proxy. |
|
254 * Does nothing if the new_proxy is already set as a proxy for this toplevel. |
|
255 * Returns the completion status. |
|
256 */ |
|
257 static ProxyRegistrationStatus |
|
258 set_motif_proxy(Display* dpy, Window toplevel, Window new_proxy, Window *old_proxy) { |
|
259 Boolean override = False; |
|
260 |
|
261 Atom type; |
|
262 int format; |
|
263 unsigned long nitems; |
|
264 unsigned long after; |
|
265 unsigned char* data; |
|
266 unsigned char ret; |
|
267 |
|
268 DASSERT(old_proxy != NULL); |
|
269 |
|
270 *old_proxy = None; |
|
271 |
|
272 data = NULL; |
|
273 ret = checked_XGetWindowProperty(dpy, toplevel, |
|
274 _XA_MOTIF_DRAG_RECEIVER_INFO, 0, 0xFFFF, |
|
275 False, AnyPropertyType, &type, &format, |
|
276 &nitems, &after, &data); |
|
277 |
|
278 /* Check if toplevel is a valid window. */ |
|
279 if (ret != Success) { |
|
280 return RegFailure; |
|
281 } |
|
282 |
|
283 if (ret == Success && data != NULL && type != None && format == 8 |
|
284 && nitems >= MOTIF_RECEIVER_INFO_SIZE) { |
|
285 unsigned char byte_order = read_card8((char*)data, 0); |
|
286 void* p = (char*)data + 4; |
|
287 |
|
288 /* Browser and plugin have different byte orders - report failure for now. */ |
|
289 if (MOTIF_BYTE_ORDER != byte_order) { |
|
290 XFree(data); |
|
291 return RegFailure; |
|
292 } |
|
293 |
|
294 *old_proxy = read_card32((char*)data, 4, byte_order); |
|
295 |
|
296 /* If the proxy is already set to the specified window - return. */ |
|
297 if (*old_proxy == new_proxy) { |
|
298 XFree(data); |
|
299 return RegAlreadyRegistered; |
|
300 } |
|
301 |
|
302 /* replace the proxy window */ |
|
303 write_card32(&p, new_proxy); |
|
304 |
|
305 override = True; |
|
306 } else { |
|
307 void* p; |
|
308 |
|
309 if (ret == Success) { |
|
310 XFree(data); |
|
311 data = NULL; |
|
312 } |
|
313 |
|
314 data = malloc(MOTIF_RECEIVER_INFO_SIZE); |
|
315 |
|
316 if (data == NULL) { |
|
317 DTRACE_PRINTLN2("%s:%d malloc failed.", __FILE__, __LINE__); |
|
318 return RegFailure; |
|
319 } |
|
320 |
|
321 p = data; |
|
322 |
|
323 write_card8(&p, MOTIF_BYTE_ORDER); |
|
324 write_card8(&p, MOTIF_DND_PROTOCOL_VERSION); /* protocol version */ |
|
325 write_card8(&p, MOTIF_DYNAMIC_STYLE); /* protocol style */ |
|
326 write_card8(&p, 0); /* pad */ |
|
327 write_card32(&p, new_proxy); /* proxy window */ |
|
328 write_card16(&p, 0); /* num_drop_sites */ |
|
329 write_card16(&p, 0); /* pad */ |
|
330 write_card32(&p, MOTIF_RECEIVER_INFO_SIZE); |
|
331 } |
|
332 |
|
333 ret = checked_XChangeProperty(dpy, toplevel, |
|
334 _XA_MOTIF_DRAG_RECEIVER_INFO, |
|
335 _XA_MOTIF_DRAG_RECEIVER_INFO, 8, |
|
336 PropModeReplace, (unsigned char*)data, |
|
337 MOTIF_RECEIVER_INFO_SIZE); |
|
338 |
|
339 if (data != NULL) { |
|
340 XFree(data); |
|
341 data = NULL; |
|
342 } |
|
343 |
|
344 if (ret == Success) { |
|
345 if (override) { |
|
346 return RegOverride; |
|
347 } else { |
|
348 return RegSuccess; |
|
349 } |
|
350 } else { |
|
351 return RegFailure; |
|
352 } |
|
353 } |
|
354 |
|
355 /* |
|
356 * Registers the toplevel as a XDnD drag receiver if it is not registered yet, |
|
357 * sets the specified new_proxy for it and returns the previous proxy in |
|
358 * old_proxy and the original XDnD protocol version in old_version. |
|
359 * Does nothing if the new_proxy is already set as a proxy for this toplevel. |
|
360 * Returns the completion status. |
|
361 */ |
|
362 static ProxyRegistrationStatus |
|
363 set_xdnd_proxy(Display* dpy, Window toplevel, Window new_proxy, |
|
364 Window* old_proxy, unsigned int* old_version) { |
|
365 Atom version_atom = XDND_PROTOCOL_VERSION; |
|
366 Window xdnd_proxy = None; |
|
367 Boolean override = False; |
|
368 |
|
369 Atom type; |
|
370 int format; |
|
371 unsigned long nitems; |
|
372 unsigned long after; |
|
373 unsigned char* data; |
|
374 unsigned char ret; |
|
375 |
|
376 DASSERT(old_proxy != NULL); |
|
377 |
|
378 *old_proxy = None; |
|
379 |
|
380 data = NULL; |
|
381 ret = checked_XGetWindowProperty(dpy, toplevel, XA_XdndAware, 0, 1, |
|
382 False, AnyPropertyType, &type, &format, |
|
383 &nitems, &after, &data); |
|
384 |
|
385 if (ret != Success) { |
|
386 return RegFailure; |
|
387 } |
|
388 |
|
389 if (ret == Success && data != NULL && type == XA_ATOM) { |
|
390 unsigned int protocol_version = *((unsigned int*)data); |
|
391 |
|
392 override = True; |
|
393 *old_version = protocol_version; |
|
394 |
|
395 /* XdndProxy is not supported for prior to XDnD version 4 */ |
|
396 if (protocol_version >= 4) { |
|
397 int status; |
|
398 |
|
399 XFree(data); |
|
400 |
|
401 data = NULL; |
|
402 status = XGetWindowProperty(dpy, toplevel, XA_XdndProxy, 0, 1, |
|
403 False, XA_WINDOW, &type, &format, |
|
404 &nitems, &after, &data); |
|
405 |
|
406 if (status == Success && data != NULL && type == XA_WINDOW) { |
|
407 xdnd_proxy = *((Window*)data); |
|
408 |
|
409 if (xdnd_proxy != None) { |
|
410 XFree(data); |
|
411 |
|
412 data = NULL; |
|
413 status = XGetWindowProperty(dpy, xdnd_proxy, XA_XdndProxy, |
|
414 0, 1, False, XA_WINDOW, &type, |
|
415 &format, &nitems, &after, &data); |
|
416 |
|
417 if (status != Success || data == NULL || type != XA_WINDOW || |
|
418 *((Window*)data) != xdnd_proxy) { |
|
419 /* Ignore invalid proxy. */ |
|
420 xdnd_proxy = None; |
|
421 } |
|
422 } |
|
423 |
|
424 if (xdnd_proxy != None) { |
|
425 XFree(data); |
|
426 |
|
427 data = NULL; |
|
428 status = XGetWindowProperty(dpy, xdnd_proxy, XA_XdndAware, |
|
429 0, 1, False, AnyPropertyType, |
|
430 &type, &format, &nitems, &after, |
|
431 &data); |
|
432 |
|
433 if (status == Success && data != NULL && type == XA_ATOM) { |
|
434 unsigned int proxy_version = *((unsigned int*)data); |
|
435 |
|
436 if (proxy_version != protocol_version) { |
|
437 /* Ignore invalid proxy. */ |
|
438 xdnd_proxy = None; |
|
439 } |
|
440 } else { |
|
441 /* Ignore invalid proxy. */ |
|
442 xdnd_proxy = None; |
|
443 } |
|
444 } |
|
445 } |
|
446 |
|
447 *old_proxy = xdnd_proxy; |
|
448 } |
|
449 } |
|
450 |
|
451 XFree(data); |
|
452 |
|
453 /* If the proxy is already set to the specified window - return. */ |
|
454 if (xdnd_proxy == new_proxy) { |
|
455 return RegAlreadyRegistered; |
|
456 } |
|
457 |
|
458 /* The proxy window must have the XdndAware set, as XDnD protocol prescribes |
|
459 to check the proxy window for XdndAware. */ |
|
460 ret = checked_XChangeProperty(dpy, new_proxy, XA_XdndAware, XA_ATOM, 32, |
|
461 PropModeReplace, |
|
462 (unsigned char*)&version_atom, 1); |
|
463 |
|
464 if (ret != Success) { |
|
465 return RegFailure; |
|
466 } |
|
467 |
|
468 /* The proxy window must have the XdndProxy set to point to itself. */ |
|
469 ret = checked_XChangeProperty(dpy, new_proxy, XA_XdndProxy, XA_WINDOW, 32, |
|
470 PropModeReplace, |
|
471 (unsigned char*)&new_proxy, 1); |
|
472 |
|
473 if (ret != Success) { |
|
474 return RegFailure; |
|
475 } |
|
476 |
|
477 ret = checked_XChangeProperty(dpy, toplevel, XA_XdndAware, XA_ATOM, 32, |
|
478 PropModeReplace, |
|
479 (unsigned char*)&version_atom, 1); |
|
480 |
|
481 if (ret != Success) { |
|
482 return RegFailure; |
|
483 } |
|
484 |
|
485 ret = checked_XChangeProperty(dpy, toplevel, XA_XdndProxy, XA_WINDOW, 32, |
|
486 PropModeReplace, |
|
487 (unsigned char*)&new_proxy, 1); |
|
488 |
|
489 if (ret == Success) { |
|
490 if (override) { |
|
491 return RegOverride; |
|
492 } else { |
|
493 return RegSuccess; |
|
494 } |
|
495 } else { |
|
496 return RegFailure; |
|
497 } |
|
498 } |
|
499 |
|
500 /* |
|
501 * 'toplevel' is the browser toplevel window. To register a drop site on the |
|
502 * plugin window we set the proxy for the browser toplevel window to point to |
|
503 * the awt_root_shell window. |
|
504 * |
|
505 * We assume that only one JVM per browser instance is possible. This |
|
506 * assumption is true with the current plugin implementation - it creates a |
|
507 * single JVM for all plugin instances created by the given plugin factory. |
|
508 * |
|
509 * When a client message event for the browser toplevel window is received, we |
|
510 * will iterate over drop sites registered with this toplevel and determine if |
|
511 * the mouse pointer is currently over one of them (there could be several |
|
512 * plugin windows in one browser window - for example if an HTML page contains |
|
513 * frames and several frames contain a plugin object). |
|
514 * |
|
515 * If the pointer is not over any of the plugin drop sites the client message |
|
516 * will be resent to the browser, otherwise it will be processed normally. |
|
517 */ |
|
518 static EmbeddedDropSiteListEntry* |
|
519 awt_dnd_dt_init_proxy(Display* dpy, Window root, Window toplevel, Window window) { |
|
520 Window awt_root_window = get_awt_root_window(); |
|
521 Window motif_proxy = None; |
|
522 Boolean motif_override = False; |
|
523 unsigned long event_mask = 0; |
|
524 |
|
525 if (awt_root_window == None) { |
|
526 return NULL; |
|
527 } |
|
528 |
|
529 /* Grab server, since we are working with the window that belongs to |
|
530 another client. REMIND: ungrab when done!!! */ |
|
531 XGrabServer(dpy); |
|
532 |
|
533 { |
|
534 ProxyRegistrationStatus motif_status = RegFailure; |
|
535 |
|
536 motif_status = set_motif_proxy(dpy, toplevel, awt_root_window, &motif_proxy); |
|
537 |
|
538 switch (motif_status) { |
|
539 case RegFailure: |
|
540 case RegAlreadyRegistered: |
|
541 XUngrabServer(dpy); |
|
542 /* Workaround for bug 5039226 */ |
|
543 XSync(dpy, False); |
|
544 return NULL; |
|
545 case RegOverride: |
|
546 motif_override = True; |
|
547 break; |
|
548 case RegSuccess: |
|
549 motif_override = False; |
|
550 break; |
|
551 default: |
|
552 DASSERT(False); |
|
553 } |
|
554 |
|
555 |
|
556 } |
|
557 |
|
558 { |
|
559 XWindowAttributes xwa; |
|
560 XGetWindowAttributes(dpy, toplevel, &xwa); |
|
561 event_mask = xwa.your_event_mask; |
|
562 if ((event_mask & PropertyChangeMask) == 0) { |
|
563 XSelectInput(dpy, toplevel, event_mask | PropertyChangeMask); |
|
564 } |
|
565 } |
|
566 |
|
567 XUngrabServer(dpy); |
|
568 /* Workaround for bug 5039226 */ |
|
569 XSync(dpy, False); |
|
570 |
|
571 /* Add protocol specific entries for the toplevel. */ |
|
572 { |
|
573 EmbeddedDropSiteProtocolListEntry* motif_entry = NULL; |
|
574 |
|
575 motif_entry = malloc(sizeof(EmbeddedDropSiteProtocolListEntry)); |
|
576 |
|
577 if (motif_entry == NULL) { |
|
578 return NULL; |
|
579 } |
|
580 |
|
581 motif_entry->window = toplevel; |
|
582 motif_entry->proxy = motif_proxy; |
|
583 motif_entry->protocol_version = 0; |
|
584 motif_entry->overriden = motif_override; |
|
585 motif_entry->next = embedded_motif_protocol_list; |
|
586 embedded_motif_protocol_list = motif_entry; |
|
587 } |
|
588 |
|
589 { |
|
590 EmbeddedDropSiteListEntry* entry = NULL; |
|
591 Window* sites = NULL; |
|
592 |
|
593 entry = malloc(sizeof(EmbeddedDropSiteListEntry)); |
|
594 |
|
595 if (entry == NULL) { |
|
596 return NULL; |
|
597 } |
|
598 |
|
599 sites = malloc(sizeof(Window)); |
|
600 |
|
601 if (sites == NULL) { |
|
602 free(entry); |
|
603 return NULL; |
|
604 } |
|
605 |
|
606 sites[0] = window; |
|
607 |
|
608 entry->toplevel = toplevel; |
|
609 entry->root = root; |
|
610 entry->event_mask = event_mask; |
|
611 entry->embedded_sites_count = 1; |
|
612 entry->embedded_sites = sites; |
|
613 entry->next = NULL; |
|
614 |
|
615 return entry; |
|
616 } |
|
617 } |
|
618 |
|
619 static void |
|
620 register_xdnd_embedder(Display* dpy, EmbeddedDropSiteListEntry* entry, long window) { |
|
621 Window awt_root_window = get_awt_root_window(); |
|
622 Window toplevel = entry->toplevel; |
|
623 Window xdnd_proxy = None; |
|
624 unsigned int xdnd_protocol_version = 0; |
|
625 Boolean xdnd_override = False; |
|
626 Boolean register_xdnd = True; |
|
627 Boolean motif_overriden = False; |
|
628 |
|
629 EmbeddedDropSiteProtocolListEntry* motif_entry = embedded_motif_protocol_list; |
|
630 while (motif_entry != NULL) { |
|
631 if (motif_entry->window == toplevel) { |
|
632 motif_overriden = motif_entry->overriden; |
|
633 break; |
|
634 } |
|
635 motif_entry = motif_entry->next; |
|
636 } |
|
637 |
|
638 /* |
|
639 * First check if the window is an XEmbed client. |
|
640 * In this case we don't have to setup a proxy on the toplevel, |
|
641 * instead we register the XDnD drop site on the embedded window. |
|
642 */ |
|
643 if (isXEmbedActiveByWindow(window)) { |
|
644 register_xdnd_drop_site(dpy, toplevel, window); |
|
645 return; |
|
646 } |
|
647 |
|
648 /* |
|
649 * By default, we register a drop site that supports both dnd |
|
650 * protocols. This approach is not appropriate in plugin |
|
651 * scenario if the browser doesn't support XDnD. If we forcibly set |
|
652 * XdndAware on the browser toplevel, any drag source that supports both |
|
653 * protocols and prefers XDnD will be unable to drop anything on the |
|
654 * browser. |
|
655 * The solution for this problem is not to register XDnD drop site |
|
656 * if the browser supports only Motif DnD. |
|
657 */ |
|
658 if (motif_overriden) { |
|
659 int status; |
|
660 Atom type; |
|
661 int format; |
|
662 unsigned long nitems; |
|
663 unsigned long after; |
|
664 unsigned char* data; |
|
665 |
|
666 data = NULL; |
|
667 status = XGetWindowProperty(dpy, toplevel, XA_XdndAware, 0, 1, |
|
668 False, AnyPropertyType, &type, &format, |
|
669 &nitems, &after, &data); |
|
670 |
|
671 XFree(data); |
|
672 data = NULL; |
|
673 |
|
674 if (type != XA_ATOM) { |
|
675 register_xdnd = False; |
|
676 } |
|
677 } |
|
678 |
|
679 if (register_xdnd) { |
|
680 ProxyRegistrationStatus xdnd_status; |
|
681 /* Grab server, since we are working with the window that belongs to |
|
682 another client. REMIND: ungrab when done!!! */ |
|
683 XGrabServer(dpy); |
|
684 |
|
685 xdnd_status = |
|
686 set_xdnd_proxy(dpy, toplevel, awt_root_window, &xdnd_proxy, |
|
687 &xdnd_protocol_version); |
|
688 |
|
689 XUngrabServer(dpy); |
|
690 |
|
691 switch (xdnd_status) { |
|
692 case RegFailure: |
|
693 case RegAlreadyRegistered: |
|
694 return; |
|
695 case RegOverride: |
|
696 xdnd_override = True; |
|
697 break; |
|
698 case RegSuccess: |
|
699 xdnd_override = False; |
|
700 break; |
|
701 default: |
|
702 DASSERT(False); |
|
703 } |
|
704 |
|
705 { |
|
706 EmbeddedDropSiteProtocolListEntry* xdnd_entry = NULL; |
|
707 |
|
708 xdnd_entry = malloc(sizeof(EmbeddedDropSiteProtocolListEntry)); |
|
709 |
|
710 if (xdnd_entry == NULL) { |
|
711 return; |
|
712 } |
|
713 |
|
714 xdnd_entry->window = toplevel; |
|
715 xdnd_entry->proxy = xdnd_proxy; |
|
716 xdnd_entry->protocol_version = xdnd_protocol_version; |
|
717 xdnd_entry->overriden = xdnd_override; |
|
718 xdnd_entry->next = embedded_xdnd_protocol_list; |
|
719 embedded_xdnd_protocol_list = xdnd_entry; |
|
720 } |
|
721 } |
|
722 } |
|
723 |
|
724 /* |
|
725 * If embedded_drop_site_list already contains an entry with the specified |
|
726 * 'toplevel', the method registers the specified 'window' as an embedded drop |
|
727 * site for this 'toplevel' and returns True. |
|
728 * Otherwise, it checks if the 'toplevel' is a registered drop site for adds |
|
729 * (window, component) pair to the list and returns True |
|
730 * if completes successfully. |
|
731 */ |
|
732 static Boolean |
|
733 add_to_embedded_drop_site_list(Display* dpy, Window root, Window toplevel, |
|
734 Window window) { |
|
735 EmbeddedDropSiteListEntry* entry = embedded_drop_site_list; |
|
736 |
|
737 while (entry != NULL) { |
|
738 if (entry->toplevel == toplevel) { |
|
739 void* p = realloc(entry->embedded_sites, |
|
740 sizeof(Window) * |
|
741 (entry->embedded_sites_count + 1)); |
|
742 if (p == NULL) { |
|
743 return False; |
|
744 } |
|
745 entry->embedded_sites = p; |
|
746 entry->embedded_sites[entry->embedded_sites_count++] = window; |
|
747 |
|
748 register_xdnd_embedder(dpy, entry, window); |
|
749 |
|
750 return True; |
|
751 } |
|
752 entry = entry->next; |
|
753 } |
|
754 |
|
755 entry = awt_dnd_dt_init_proxy(dpy, root, toplevel, window); |
|
756 |
|
757 if (entry == NULL) { |
|
758 return False; |
|
759 } |
|
760 |
|
761 register_xdnd_embedder(dpy, entry, window); |
|
762 |
|
763 entry->next = embedded_drop_site_list; |
|
764 embedded_drop_site_list = entry; |
|
765 |
|
766 return True; |
|
767 } |
|
768 |
|
769 /* |
|
770 * Removes the window from the list of embedded drop sites for the toplevel. |
|
771 * Returns True if the window was successfully removed, False otherwise. |
|
772 */ |
|
773 static Boolean |
|
774 remove_from_embedded_drop_site_list(Display* dpy, Window toplevel, Window window) { |
|
775 EmbeddedDropSiteListEntry* entry = embedded_drop_site_list; |
|
776 EmbeddedDropSiteListEntry* prev = NULL; |
|
777 |
|
778 while (entry != NULL) { |
|
779 if (entry->toplevel == toplevel) { |
|
780 unsigned int idx; |
|
781 |
|
782 for (idx = 0; idx < entry->embedded_sites_count; idx++) { |
|
783 if (entry->embedded_sites[idx] == window) { |
|
784 int tail = entry->embedded_sites_count - idx - 1; |
|
785 if (tail > 0) { |
|
786 memmove(entry->embedded_sites + idx, |
|
787 entry->embedded_sites + idx + 1, |
|
788 tail * sizeof(Window)); |
|
789 } |
|
790 entry->embedded_sites_count--; |
|
791 |
|
792 /* If the list of embedded drop sites for this toplevel |
|
793 becomes empty - restore the original proxies and remove |
|
794 the entry. */ |
|
795 if (entry->embedded_sites_count == 0) { |
|
796 Widget w = XtWindowToWidget(dpy, toplevel); |
|
797 |
|
798 if (w != NULL) { |
|
799 JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4); |
|
800 Widget copy = w; |
|
801 jobject peer = findPeer(&w); |
|
802 |
|
803 if (!JNU_IsNull(env, peer) && |
|
804 (*env)->IsInstanceOf(env, peer, |
|
805 get_MEmbedCanvasPeerClass(env)) == JNI_TRUE) { |
|
806 remove_xembed_drop_target(env, peer); |
|
807 } |
|
808 } else { |
|
809 EmbeddedDropSiteProtocolListEntry* xdnd_entry = |
|
810 get_xdnd_protocol_entry_for_toplevel(toplevel); |
|
811 EmbeddedDropSiteProtocolListEntry* motif_entry = |
|
812 get_motif_protocol_entry_for_toplevel(toplevel); |
|
813 |
|
814 if (xdnd_entry != NULL) { |
|
815 if (xdnd_entry->overriden == True) { |
|
816 XChangeProperty(dpy, toplevel, XA_XdndAware, |
|
817 XA_ATOM, 32, |
|
818 PropModeReplace, |
|
819 (unsigned char*)&xdnd_entry->protocol_version, |
|
820 1); |
|
821 |
|
822 XChangeProperty(dpy, toplevel, XA_XdndProxy, |
|
823 XA_WINDOW, 32, |
|
824 PropModeReplace, |
|
825 (unsigned char*)&xdnd_entry->proxy, 1); |
|
826 } else { |
|
827 XDeleteProperty(dpy, toplevel, XA_XdndAware); |
|
828 XDeleteProperty(dpy, toplevel, XA_XdndProxy); |
|
829 } |
|
830 remove_xdnd_protocol_entry_for_toplevel(toplevel); |
|
831 } |
|
832 |
|
833 if (motif_entry != NULL) { |
|
834 if (motif_entry->overriden == True) { |
|
835 /* Request status */ |
|
836 int status; |
|
837 |
|
838 Atom type; |
|
839 int format; |
|
840 unsigned long nitems; |
|
841 unsigned long after; |
|
842 unsigned char* data; |
|
843 |
|
844 data = NULL; |
|
845 status = XGetWindowProperty(dpy, toplevel, |
|
846 _XA_MOTIF_DRAG_RECEIVER_INFO, 0, 0xFFFF, |
|
847 False, AnyPropertyType, &type, &format, |
|
848 &nitems, &after, &data); |
|
849 |
|
850 if (status == Success && data != NULL && type != None && |
|
851 format == 8 && nitems >= MOTIF_RECEIVER_INFO_SIZE) { |
|
852 unsigned char byte_order = read_card8((char*)data, 0); |
|
853 void* p = (char*)data + 4; |
|
854 |
|
855 DASSERT(MOTIF_BYTE_ORDER == byte_order); |
|
856 |
|
857 if (MOTIF_BYTE_ORDER == byte_order) { |
|
858 /* restore the original proxy window */ |
|
859 write_card32(&p, motif_entry->proxy); |
|
860 |
|
861 XChangeProperty(dpy, toplevel, |
|
862 _XA_MOTIF_DRAG_RECEIVER_INFO, |
|
863 _XA_MOTIF_DRAG_RECEIVER_INFO, 8, |
|
864 PropModeReplace, |
|
865 (unsigned char*)data, |
|
866 MOTIF_RECEIVER_INFO_SIZE); |
|
867 } |
|
868 } |
|
869 |
|
870 if (status == Success) { |
|
871 XFree(data); |
|
872 } |
|
873 } else { |
|
874 XDeleteProperty(dpy, toplevel, _XA_MOTIF_DRAG_RECEIVER_INFO); |
|
875 } |
|
876 |
|
877 remove_motif_protocol_entry_for_toplevel(toplevel); |
|
878 } |
|
879 |
|
880 if ((entry->event_mask & PropertyChangeMask) == 0) { |
|
881 XSelectInput(dpy, toplevel, entry->event_mask); |
|
882 } |
|
883 } |
|
884 |
|
885 if (prev == NULL) { |
|
886 embedded_drop_site_list = entry->next; |
|
887 } else { |
|
888 prev->next = entry->next; |
|
889 } |
|
890 |
|
891 free(entry); |
|
892 } |
|
893 return True; |
|
894 } |
|
895 } |
|
896 return False; |
|
897 } |
|
898 prev = entry; |
|
899 entry = entry->next; |
|
900 } |
|
901 return False; |
|
902 } |
|
903 |
|
904 static EmbeddedDropSiteListEntry* |
|
905 get_entry_for_toplevel(Window toplevel) { |
|
906 EmbeddedDropSiteListEntry* entry = embedded_drop_site_list; |
|
907 |
|
908 while (entry != NULL) { |
|
909 if (entry->toplevel == toplevel) { |
|
910 return entry; |
|
911 } |
|
912 entry = entry->next; |
|
913 } |
|
914 return NULL; |
|
915 } |
|
916 |
|
917 static EmbeddedDropSiteProtocolListEntry* |
|
918 get_motif_protocol_entry_for_toplevel(Window toplevel) { |
|
919 EmbeddedDropSiteProtocolListEntry* entry = embedded_motif_protocol_list; |
|
920 |
|
921 while (entry != NULL) { |
|
922 if (entry->window == toplevel) { |
|
923 return entry; |
|
924 } |
|
925 entry = entry->next; |
|
926 } |
|
927 return NULL; |
|
928 } |
|
929 |
|
930 static EmbeddedDropSiteProtocolListEntry* |
|
931 get_xdnd_protocol_entry_for_toplevel(Window toplevel) { |
|
932 EmbeddedDropSiteProtocolListEntry* entry = embedded_xdnd_protocol_list; |
|
933 |
|
934 while (entry != NULL) { |
|
935 if (entry->window == toplevel) { |
|
936 return entry; |
|
937 } |
|
938 entry = entry->next; |
|
939 } |
|
940 return NULL; |
|
941 } |
|
942 |
|
943 static void |
|
944 remove_motif_protocol_entry_for_toplevel(Window toplevel) { |
|
945 EmbeddedDropSiteProtocolListEntry* entry = embedded_motif_protocol_list; |
|
946 EmbeddedDropSiteProtocolListEntry* prev_entry = NULL; |
|
947 |
|
948 while (entry != NULL) { |
|
949 if (entry->window == toplevel) { |
|
950 if (prev_entry != NULL) { |
|
951 prev_entry->next = entry->next; |
|
952 } else { |
|
953 embedded_motif_protocol_list = entry->next; |
|
954 } |
|
955 free(entry); |
|
956 } |
|
957 entry = entry->next; |
|
958 prev_entry = entry; |
|
959 } |
|
960 } |
|
961 |
|
962 static void |
|
963 remove_xdnd_protocol_entry_for_toplevel(Window toplevel) { |
|
964 EmbeddedDropSiteProtocolListEntry* entry = embedded_xdnd_protocol_list; |
|
965 EmbeddedDropSiteProtocolListEntry* prev_entry = NULL; |
|
966 |
|
967 while (entry != NULL) { |
|
968 if (entry->window == toplevel) { |
|
969 if (prev_entry != NULL) { |
|
970 prev_entry->next = entry->next; |
|
971 } else { |
|
972 embedded_xdnd_protocol_list = entry->next; |
|
973 } |
|
974 free(entry); |
|
975 } |
|
976 entry = entry->next; |
|
977 } |
|
978 } |
|
979 |
|
980 static Boolean |
|
981 is_embedding_toplevel(Window toplevel) { |
|
982 return get_entry_for_toplevel(toplevel) != NULL; |
|
983 } |
|
984 |
|
985 static Window |
|
986 get_embedded_window(Display* dpy, Window toplevel, int x, int y) { |
|
987 EmbeddedDropSiteListEntry* entry = get_entry_for_toplevel(toplevel); |
|
988 |
|
989 if (entry != NULL) { |
|
990 unsigned int idx; |
|
991 |
|
992 for (idx = 0; idx < entry->embedded_sites_count; idx++) { |
|
993 Window site = entry->embedded_sites[idx]; |
|
994 Window child = None; |
|
995 int x_return, y_return; |
|
996 |
|
997 if (XTranslateCoordinates(dpy, entry->root, site, x, y, |
|
998 &x_return, &y_return, &child)) { |
|
999 if (x_return >= 0 && y_return >= 0) { |
|
1000 XWindowAttributes xwa; |
|
1001 XGetWindowAttributes(dpy, site, &xwa); |
|
1002 if (xwa.map_state != IsUnmapped && |
|
1003 x_return < xwa.width && y_return < xwa.height) { |
|
1004 return site; |
|
1005 } |
|
1006 } |
|
1007 } |
|
1008 } |
|
1009 } |
|
1010 |
|
1011 return None; |
|
1012 } |
|
1013 |
|
1014 /* |
|
1015 * If the toplevel is not an embedding toplevel does nothing and returns False. |
|
1016 * Otherwise, sets xdnd_proxy for the specified toplevel to the 'proxy_window', |
|
1017 * xdnd_protocol_version to 'version', xdnd_override to 'override', returns True. |
|
1018 */ |
|
1019 static Boolean |
|
1020 set_xdnd_proxy_for_toplevel(Window toplevel, Window proxy_window, |
|
1021 unsigned int version, Boolean override) { |
|
1022 EmbeddedDropSiteProtocolListEntry* entry = |
|
1023 get_xdnd_protocol_entry_for_toplevel(toplevel); |
|
1024 |
|
1025 if (entry == NULL) { |
|
1026 return False; |
|
1027 } |
|
1028 |
|
1029 entry->proxy = proxy_window; |
|
1030 entry->protocol_version = version; |
|
1031 entry->overriden = override; |
|
1032 |
|
1033 return True; |
|
1034 } |
|
1035 |
|
1036 /* |
|
1037 * If the toplevel is not an embedding toplevel does nothing and returns False. |
|
1038 * Otherwise, sets motif_proxy for the specified toplevel to the proxy_window, |
|
1039 * motif_override to 'override' and returns True. |
|
1040 */ |
|
1041 static Boolean |
|
1042 set_motif_proxy_for_toplevel(Window toplevel, Window proxy_window, Boolean override) { |
|
1043 EmbeddedDropSiteProtocolListEntry* entry = |
|
1044 get_motif_protocol_entry_for_toplevel(toplevel); |
|
1045 |
|
1046 if (entry == NULL) { |
|
1047 return False; |
|
1048 } |
|
1049 |
|
1050 entry->proxy = proxy_window; |
|
1051 entry->overriden = override; |
|
1052 |
|
1053 return True; |
|
1054 } |
|
1055 |
|
1056 /* |
|
1057 * Forwards a drag notification to the embedding toplevel modifying the event |
|
1058 * to match the protocol version supported by the toplevel. |
|
1059 * Returns True if the event is sent, False otherwise. |
|
1060 */ |
|
1061 static Boolean |
|
1062 forward_client_message_to_toplevel(Window toplevel, XClientMessageEvent* event) { |
|
1063 EmbeddedDropSiteProtocolListEntry* protocol_entry = NULL; |
|
1064 Window proxy = None; |
|
1065 |
|
1066 if (event->message_type == _XA_MOTIF_DRAG_AND_DROP_MESSAGE) { |
|
1067 protocol_entry = get_motif_protocol_entry_for_toplevel(toplevel); |
|
1068 } else { |
|
1069 /* Assume XDnD */ |
|
1070 protocol_entry = get_xdnd_protocol_entry_for_toplevel(toplevel); |
|
1071 if (protocol_entry != NULL) { |
|
1072 /* Adjust the event to match the XDnD protocol version. */ |
|
1073 unsigned int version = protocol_entry->protocol_version; |
|
1074 if (event->message_type == XA_XdndEnter) { |
|
1075 unsigned int min_version = source_protocol_version < version ? |
|
1076 source_protocol_version : version; |
|
1077 event->data.l[1] = min_version << XDND_PROTOCOL_SHIFT; |
|
1078 event->data.l[1] |= source_data_types_count > 3 ? XDND_DATA_TYPES_BIT : 0; |
|
1079 } |
|
1080 } |
|
1081 } |
|
1082 |
|
1083 if (protocol_entry == NULL) { |
|
1084 return False; |
|
1085 } |
|
1086 |
|
1087 if (!protocol_entry->overriden) { |
|
1088 return False; |
|
1089 } |
|
1090 proxy = protocol_entry->proxy; |
|
1091 |
|
1092 if (proxy == None) { |
|
1093 proxy = toplevel; |
|
1094 } |
|
1095 |
|
1096 event->window = toplevel; |
|
1097 |
|
1098 XSendEvent(event->display, proxy, False, NoEventMask, (XEvent*)event); |
|
1099 |
|
1100 return True; |
|
1101 } |
|
1102 |
|
1103 /******************************************************************************/ |
|
1104 |
|
1105 /********************* Drop site list support *********************************/ |
|
1106 |
|
1107 struct DropSiteListEntryRec; |
|
1108 |
|
1109 typedef struct DropSiteListEntryRec DropSiteListEntry; |
|
1110 |
|
1111 struct DropSiteListEntryRec { |
|
1112 Window window; |
|
1113 Window root; |
|
1114 /* |
|
1115 * The closest to the root ancestor with WM_STATE property set. |
|
1116 * Normally toplevel == window. |
|
1117 * In plugin scenario toplevel is the browser toplevel window. |
|
1118 */ |
|
1119 Window toplevel; |
|
1120 /* |
|
1121 * Java top-level position is the outer canvas position, not the shell |
|
1122 * window position. We need to keep the outer canvas ID (and the root ID) to |
|
1123 * translate from mouse position root coordinates to the Java component |
|
1124 * coordinates. |
|
1125 */ |
|
1126 Window outer_canvas; |
|
1127 jobject component; |
|
1128 DropSiteListEntry* next; |
|
1129 }; |
|
1130 |
|
1131 static DropSiteListEntry* drop_site_list = NULL; |
|
1132 |
|
1133 /* |
|
1134 * If drop_site_list already contains an entry with the same window, |
|
1135 * does nothing and returns False. |
|
1136 * Otherwise, adds a new entry the list and returns True |
|
1137 * if completes successfully. |
|
1138 */ |
|
1139 static Boolean |
|
1140 add_to_drop_site_list(Window window, Window root, Window toplevel, |
|
1141 Window outer_canvas, jobject component) { |
|
1142 DropSiteListEntry* entry = drop_site_list; |
|
1143 |
|
1144 while (entry != NULL) { |
|
1145 if (entry->window == window) { |
|
1146 return False; |
|
1147 } |
|
1148 entry = entry->next; |
|
1149 } |
|
1150 |
|
1151 entry = malloc(sizeof(DropSiteListEntry)); |
|
1152 |
|
1153 if (entry == NULL) { |
|
1154 return False; |
|
1155 } |
|
1156 |
|
1157 entry->window = window; |
|
1158 entry->root = root; |
|
1159 entry->toplevel = toplevel; |
|
1160 entry->outer_canvas = outer_canvas; |
|
1161 entry->component = component; |
|
1162 entry->next = drop_site_list; |
|
1163 drop_site_list = entry; |
|
1164 |
|
1165 return True; |
|
1166 } |
|
1167 |
|
1168 /* |
|
1169 * Returns True if the list entry for the specified window has been successfully |
|
1170 * removed from the list. Otherwise, returns False. |
|
1171 */ |
|
1172 static Boolean |
|
1173 remove_from_drop_site_list(Window window) { |
|
1174 DropSiteListEntry* entry = drop_site_list; |
|
1175 DropSiteListEntry* prev = NULL; |
|
1176 |
|
1177 while (entry != NULL) { |
|
1178 if (entry->window == window) { |
|
1179 if (prev != NULL) { |
|
1180 prev->next = entry->next; |
|
1181 } else { |
|
1182 drop_site_list = entry->next; |
|
1183 } |
|
1184 free(entry); |
|
1185 return True; |
|
1186 } |
|
1187 prev = entry; |
|
1188 entry = entry->next; |
|
1189 } |
|
1190 |
|
1191 return False; |
|
1192 } |
|
1193 |
|
1194 static jobject |
|
1195 get_component_for_window(Window window) { |
|
1196 DropSiteListEntry* entry = drop_site_list; |
|
1197 |
|
1198 while (entry != NULL) { |
|
1199 if (entry->window == window) { |
|
1200 return entry->component; |
|
1201 } |
|
1202 entry = entry->next; |
|
1203 } |
|
1204 |
|
1205 return NULL; |
|
1206 } |
|
1207 |
|
1208 static Window |
|
1209 get_root_for_window(Window window) { |
|
1210 DropSiteListEntry* entry = drop_site_list; |
|
1211 |
|
1212 while (entry != NULL) { |
|
1213 if (entry->window == window) { |
|
1214 return entry->root; |
|
1215 } |
|
1216 entry = entry->next; |
|
1217 } |
|
1218 |
|
1219 return None; |
|
1220 } |
|
1221 |
|
1222 static Window |
|
1223 get_toplevel_for_window(Window window) { |
|
1224 DropSiteListEntry* entry = drop_site_list; |
|
1225 |
|
1226 while (entry != NULL) { |
|
1227 if (entry->window == window) { |
|
1228 return entry->toplevel; |
|
1229 } |
|
1230 entry = entry->next; |
|
1231 } |
|
1232 |
|
1233 return None; |
|
1234 } |
|
1235 |
|
1236 static Window |
|
1237 get_outer_canvas_for_window(Window window) { |
|
1238 DropSiteListEntry* entry = drop_site_list; |
|
1239 |
|
1240 while (entry != NULL) { |
|
1241 if (entry->window == window) { |
|
1242 return entry->outer_canvas; |
|
1243 } |
|
1244 entry = entry->next; |
|
1245 } |
|
1246 |
|
1247 return None; |
|
1248 } |
|
1249 /******************************************************************************/ |
|
1250 |
|
1251 /******************* Delayed drop site registration stuff *********************/ |
|
1252 struct DelayedRegistrationEntryRec; |
|
1253 |
|
1254 typedef struct DelayedRegistrationEntryRec DelayedRegistrationEntry; |
|
1255 |
|
1256 struct DelayedRegistrationEntryRec { |
|
1257 Widget outer_canvas; |
|
1258 jobject component; |
|
1259 XtIntervalId timer; |
|
1260 DelayedRegistrationEntry* next; |
|
1261 }; |
|
1262 |
|
1263 static DelayedRegistrationEntry* delayed_registration_list = NULL; |
|
1264 |
|
1265 static const int DELAYED_REGISTRATION_PERIOD = 500; |
|
1266 |
|
1267 /* Timer callback. */ |
|
1268 static void |
|
1269 register_drop_site_later(XtPointer client_data, XtIntervalId* id); |
|
1270 |
|
1271 /* |
|
1272 * Enqueues the specified widget and component for delayed drop site |
|
1273 * registration. If this widget has already been registered, does nothing and |
|
1274 * returns False. Otherwise, schedules a timer callback that will repeatedly |
|
1275 * attempt to register the drop site until the registration succeeds. |
|
1276 * To remove this widget from the queue of delayed registration call |
|
1277 * remove_delayed_registration_entry(). |
|
1278 * |
|
1279 * The caller must own AWT_LOCK. |
|
1280 */ |
|
1281 static Boolean |
|
1282 add_delayed_registration_entry(Widget outer_canvas, XtPointer componentRef) { |
|
1283 DelayedRegistrationEntry* entry = delayed_registration_list; |
|
1284 |
|
1285 if (outer_canvas == NULL || componentRef == NULL) { |
|
1286 return False; |
|
1287 } |
|
1288 |
|
1289 while (entry != NULL && entry->outer_canvas != outer_canvas) { |
|
1290 entry = entry->next; |
|
1291 } |
|
1292 |
|
1293 if (entry != NULL) { |
|
1294 return False; |
|
1295 } |
|
1296 |
|
1297 entry = malloc(sizeof(DelayedRegistrationEntry)); |
|
1298 |
|
1299 if (entry == NULL) { |
|
1300 return False; |
|
1301 } |
|
1302 |
|
1303 entry->outer_canvas = outer_canvas; |
|
1304 entry->component = componentRef; |
|
1305 entry->timer = XtAppAddTimeOut(awt_appContext, DELAYED_REGISTRATION_PERIOD, |
|
1306 register_drop_site_later, entry); |
|
1307 entry->next = delayed_registration_list; |
|
1308 delayed_registration_list = entry; |
|
1309 |
|
1310 return True; |
|
1311 } |
|
1312 |
|
1313 /* |
|
1314 * Unregisters the timer callback and removes this widget from the queue of |
|
1315 * delayed drop site registration. |
|
1316 * |
|
1317 * The caller must own AWT_LOCK. |
|
1318 */ |
|
1319 static Boolean |
|
1320 remove_delayed_registration_entry(Widget outer_canvas) { |
|
1321 DelayedRegistrationEntry* entry = delayed_registration_list; |
|
1322 DelayedRegistrationEntry* prev = NULL; |
|
1323 |
|
1324 if (outer_canvas == NULL) { |
|
1325 return False; |
|
1326 } |
|
1327 |
|
1328 while (entry != NULL && entry->outer_canvas != outer_canvas) { |
|
1329 prev = entry; |
|
1330 entry = entry->next; |
|
1331 } |
|
1332 |
|
1333 if (entry == NULL) { |
|
1334 return False; |
|
1335 } |
|
1336 |
|
1337 if (prev != NULL) { |
|
1338 prev->next = entry->next; |
|
1339 } else { |
|
1340 delayed_registration_list = entry->next; |
|
1341 } |
|
1342 |
|
1343 if (entry->timer) { |
|
1344 XtRemoveTimeOut(entry->timer); |
|
1345 entry->timer = (XtIntervalId)0; |
|
1346 } |
|
1347 |
|
1348 free(entry); |
|
1349 |
|
1350 return True; |
|
1351 } |
|
1352 |
|
1353 static void |
|
1354 register_drop_site_later(XtPointer client_data, XtIntervalId* id) { |
|
1355 DelayedRegistrationEntry* entry = (DelayedRegistrationEntry*)client_data; |
|
1356 |
|
1357 if (XtIsRealized(entry->outer_canvas) && |
|
1358 register_drop_site(entry->outer_canvas, entry->component)) { |
|
1359 remove_delayed_registration_entry(entry->outer_canvas); |
|
1360 } else { |
|
1361 entry->timer = XtAppAddTimeOut(awt_appContext, DELAYED_REGISTRATION_PERIOD, |
|
1362 register_drop_site_later, entry); |
|
1363 } |
|
1364 } |
|
1365 /******************************************************************************/ |
|
1366 |
|
1367 static void |
|
1368 awt_dnd_cleanup() { |
|
1369 JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4); |
|
1370 |
|
1371 if (!JNU_IsNull(env, target_component)) { |
|
1372 /* Trigger dragExit */ |
|
1373 /* |
|
1374 * Note: we pass NULL native context. This indicates that response |
|
1375 * shouldn't be sent to the source. |
|
1376 */ |
|
1377 dt_postDropTargetEvent(env, target_component, 0, 0, |
|
1378 java_awt_dnd_DnDConstants_ACTION_NONE, |
|
1379 java_awt_event_MouseEvent_MOUSE_EXITED, |
|
1380 NULL); |
|
1381 } |
|
1382 |
|
1383 if (motif_top_level_leave_postponed) { |
|
1384 XClientMessageEvent* leave = &motif_top_level_leave_postponed_event; |
|
1385 if (leave->type == ClientMessage) { |
|
1386 Window win = leave->window; |
|
1387 if (is_embedding_toplevel(win)) { |
|
1388 forward_client_message_to_toplevel(win, leave); |
|
1389 } |
|
1390 } |
|
1391 } |
|
1392 |
|
1393 if (source_window != None) { |
|
1394 XSelectInput(awt_display, source_window, source_window_mask); |
|
1395 } |
|
1396 |
|
1397 source_protocol = NO_PROTOCOL; |
|
1398 source_protocol_version = 0; |
|
1399 source_window = None; |
|
1400 source_atom = None; |
|
1401 source_window_mask = 0; |
|
1402 source_actions = java_awt_dnd_DnDConstants_ACTION_NONE; |
|
1403 track_source_actions = False; |
|
1404 (*env)->DeleteGlobalRef(env, source_data_types); |
|
1405 source_data_types = NULL; |
|
1406 if (source_data_types_native != NULL) { |
|
1407 free(source_data_types_native); |
|
1408 source_data_types_native = NULL; |
|
1409 } |
|
1410 source_data_types_count = 0; |
|
1411 source_x = 0; |
|
1412 source_y = 0; |
|
1413 target_component = NULL; |
|
1414 motif_top_level_leave_postponed = False; |
|
1415 memset(&motif_top_level_leave_postponed_event, 0, |
|
1416 sizeof(XClientMessageEvent)); |
|
1417 } |
|
1418 |
|
1419 static jlongArray |
|
1420 get_data_types_array(JNIEnv* env, Atom* types, unsigned int types_count) { |
|
1421 jlongArray array = NULL; |
|
1422 jboolean isCopy; |
|
1423 jlong* jTargets; |
|
1424 #ifndef _LP64 /* Atom and jlong are different sizes in the 32-bit build */ |
|
1425 unsigned int i; |
|
1426 #endif |
|
1427 |
|
1428 if ((*env)->PushLocalFrame(env, 1) < 0) { |
|
1429 return NULL; |
|
1430 } |
|
1431 |
|
1432 array = (*env)->NewLongArray(env, types_count); |
|
1433 |
|
1434 if (JNU_IsNull(env, array)) { |
|
1435 return NULL; |
|
1436 } |
|
1437 |
|
1438 if (types_count == 0) { |
|
1439 return array; |
|
1440 } |
|
1441 |
|
1442 jTargets = (*env)->GetLongArrayElements(env, array, &isCopy); |
|
1443 if (jTargets == NULL) { |
|
1444 (*env)->PopLocalFrame(env, NULL); |
|
1445 return NULL; |
|
1446 } |
|
1447 |
|
1448 #ifdef _LP64 |
|
1449 memcpy(jTargets, types, types_count * sizeof(Atom)); |
|
1450 #else |
|
1451 for (i = 0; i < types_count; i++) { |
|
1452 jTargets[i] = (types[i] & 0xFFFFFFFFLU); |
|
1453 } |
|
1454 #endif |
|
1455 |
|
1456 (*env)->ReleaseLongArrayElements(env, array, jTargets, 0); |
|
1457 |
|
1458 array = (*env)->NewGlobalRef(env, array); |
|
1459 |
|
1460 (*env)->PopLocalFrame(env, NULL); |
|
1461 |
|
1462 return array; |
|
1463 } |
|
1464 |
|
1465 static Boolean |
|
1466 is_xdnd_drag_message_type(unsigned long message_type) { |
|
1467 return message_type == XA_XdndEnter || |
|
1468 message_type == XA_XdndPosition || |
|
1469 message_type == XA_XdndLeave || |
|
1470 message_type == XA_XdndDrop ? True : False; |
|
1471 } |
|
1472 |
|
1473 /* |
|
1474 * Returns EventConsume if the event should be consumed, |
|
1475 * EventPassAlong otherwise. |
|
1476 */ |
|
1477 static EventStatus |
|
1478 handle_xdnd_enter(XClientMessageEvent* event) { |
|
1479 JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4); |
|
1480 Display* dpy = event->display; |
|
1481 long* event_data = event->data.l; |
|
1482 Window source_win = None; |
|
1483 long source_win_mask = 0; |
|
1484 unsigned int protocol_version = 0; |
|
1485 unsigned int data_types_count = 0; |
|
1486 Atom* data_types = NULL; |
|
1487 jlongArray java_data_types = NULL; |
|
1488 jint actions = java_awt_dnd_DnDConstants_ACTION_NONE; |
|
1489 Boolean track = False; |
|
1490 |
|
1491 DTRACE_PRINTLN5("%s:%d XdndEnter comp=%X src_win=%ld protocol=%d.", |
|
1492 __FILE__, __LINE__, |
|
1493 target_component, source_window, source_protocol); |
|
1494 |
|
1495 if (!JNU_IsNull(env, target_component) || source_window != None || |
|
1496 source_protocol != NO_PROTOCOL) { |
|
1497 DTRACE_PRINTLN2("%s:%d XdndEnter rejected - invalid state.", |
|
1498 __FILE__, __LINE__); |
|
1499 return EventFailure; |
|
1500 } |
|
1501 |
|
1502 /* |
|
1503 * NOTE: the component can be NULL if the event was sent to the embedding |
|
1504 * toplevel. |
|
1505 */ |
|
1506 if (JNU_IsNull(env, get_component_for_window(event->window)) && |
|
1507 !is_embedding_toplevel(event->window)) { |
|
1508 DTRACE_PRINTLN2("%s:%d XdndEnter rejected - window is not a registered drop site.", |
|
1509 __FILE__, __LINE__); |
|
1510 return EventFailure; |
|
1511 } |
|
1512 |
|
1513 protocol_version = |
|
1514 (event_data[1] & XDND_PROTOCOL_MASK) >> XDND_PROTOCOL_SHIFT; |
|
1515 |
|
1516 /* XDnD compliance only requires supporting version 3 and up. */ |
|
1517 if (protocol_version < XDND_MIN_PROTOCOL_VERSION) { |
|
1518 DTRACE_PRINTLN2("%s:%d XdndEnter rejected - invalid protocol version.", |
|
1519 __FILE__, __LINE__); |
|
1520 return EventFailure; |
|
1521 } |
|
1522 |
|
1523 /* Ignore the source if the protocol version is higher than we support. */ |
|
1524 if (protocol_version > XDND_PROTOCOL_VERSION) { |
|
1525 DTRACE_PRINTLN2("%s:%d XdndEnter rejected - invalid protocol version.", |
|
1526 __FILE__, __LINE__); |
|
1527 return EventFailure; |
|
1528 } |
|
1529 |
|
1530 source_win = event_data[0]; |
|
1531 |
|
1532 /* Extract the list of supported actions. */ |
|
1533 if (protocol_version < 2) { |
|
1534 /* Prior to XDnD version 2 only COPY action was supported. */ |
|
1535 actions = java_awt_dnd_DnDConstants_ACTION_COPY; |
|
1536 } else { |
|
1537 unsigned char ret; |
|
1538 Atom type; |
|
1539 int format; |
|
1540 unsigned long nitems; |
|
1541 unsigned long after; |
|
1542 unsigned char *data; |
|
1543 |
|
1544 data = NULL; |
|
1545 ret = checked_XGetWindowProperty(dpy, source_win, XA_XdndActionList, |
|
1546 0, 0xFFFF, False, XA_ATOM, &type, |
|
1547 &format, &nitems, &after, &data); |
|
1548 |
|
1549 /* Ignore the source if the window is destroyed. */ |
|
1550 if (ret == BadWindow) { |
|
1551 DTRACE_PRINTLN2("%s:%d XdndEnter rejected - invalid window.", |
|
1552 __FILE__, __LINE__); |
|
1553 return EventFailure; |
|
1554 } |
|
1555 |
|
1556 if (ret == Success) { |
|
1557 if (type == XA_ATOM && format == 32) { |
|
1558 unsigned int i; |
|
1559 Atom* action_atoms = (Atom*)data; |
|
1560 |
|
1561 for (i = 0; i < nitems; i++) { |
|
1562 actions |= xdnd_to_java_action(action_atoms[i]); |
|
1563 } |
|
1564 } |
|
1565 |
|
1566 /* |
|
1567 * According to XDnD protocol, XdndActionList is optional. |
|
1568 * If XdndActionList is not set we try to guess which actions are |
|
1569 * supported. |
|
1570 */ |
|
1571 if (type == None) { |
|
1572 actions = java_awt_dnd_DnDConstants_ACTION_COPY; |
|
1573 track = True; |
|
1574 } |
|
1575 |
|
1576 XFree(data); |
|
1577 } |
|
1578 } |
|
1579 |
|
1580 /* Extract the available data types. */ |
|
1581 if (event_data[1] & XDND_DATA_TYPES_BIT) { |
|
1582 unsigned char ret; |
|
1583 Atom type; |
|
1584 int format; |
|
1585 unsigned long nitems; |
|
1586 unsigned long after; |
|
1587 unsigned char *data; |
|
1588 |
|
1589 data = NULL; |
|
1590 ret = checked_XGetWindowProperty(dpy, source_win, XA_XdndTypeList, |
|
1591 0, 0xFFFF, False, XA_ATOM, &type, |
|
1592 &format, &nitems, &after, &data); |
|
1593 |
|
1594 /* Ignore the source if the window is destroyed. */ |
|
1595 if (ret == BadWindow) { |
|
1596 DTRACE_PRINTLN2("%s:%d XdndEnter rejected - invalid window.", |
|
1597 __FILE__, __LINE__); |
|
1598 return EventFailure; |
|
1599 } |
|
1600 |
|
1601 if (ret == Success) { |
|
1602 if (type == XA_ATOM && format == 32 && nitems > 0) { |
|
1603 data_types_count = nitems; |
|
1604 data_types = (Atom*)malloc(data_types_count * sizeof(Atom)); |
|
1605 |
|
1606 if (data_types == NULL) { |
|
1607 XFree(data); |
|
1608 DTRACE_PRINTLN2("%s:%d XdndEnter rejected - malloc fails.", |
|
1609 __FILE__, __LINE__); |
|
1610 return EventFailure; |
|
1611 } |
|
1612 |
|
1613 memcpy((void *)data_types, (void *)data, |
|
1614 data_types_count * sizeof(Atom)); |
|
1615 } |
|
1616 |
|
1617 XFree(data); |
|
1618 } |
|
1619 } else { |
|
1620 int i; |
|
1621 data_types = (Atom*)malloc(3 * sizeof (Atom)); |
|
1622 if (data_types == NULL) { |
|
1623 DTRACE_PRINTLN2("%s:%d XdndEnter rejected - malloc fails.", |
|
1624 __FILE__, __LINE__); |
|
1625 return EventFailure; |
|
1626 } |
|
1627 for (i = 0; i < 3; i++) { |
|
1628 Atom j; |
|
1629 if ((j = event_data[2 + i]) != None) { |
|
1630 data_types[data_types_count++] = j; |
|
1631 } |
|
1632 } |
|
1633 } |
|
1634 |
|
1635 java_data_types = get_data_types_array(env, data_types, data_types_count); |
|
1636 |
|
1637 if (JNU_IsNull(env, java_data_types)) { |
|
1638 DTRACE_PRINTLN2("%s:%d XdndEnter rejected - cannot create types array.", |
|
1639 __FILE__, __LINE__); |
|
1640 free((char*)data_types); |
|
1641 return EventFailure; |
|
1642 } |
|
1643 |
|
1644 /* |
|
1645 * Select for StructureNotifyMask to receive DestroyNotify in case of source |
|
1646 * crash. |
|
1647 */ |
|
1648 { |
|
1649 unsigned char ret; |
|
1650 XWindowAttributes xwa; |
|
1651 |
|
1652 XGetWindowAttributes(dpy, source_win, &xwa); |
|
1653 |
|
1654 source_win_mask = xwa.your_event_mask; |
|
1655 |
|
1656 ret = checked_XSelectInput(dpy, source_win, |
|
1657 (source_win_mask | StructureNotifyMask)); |
|
1658 |
|
1659 if (ret == BadWindow) { |
|
1660 DTRACE_PRINTLN2("%s:%d XdndEnter rejected - invalid window.", |
|
1661 __FILE__, __LINE__); |
|
1662 free((char*)data_types); |
|
1663 (*env)->DeleteGlobalRef(env, java_data_types); |
|
1664 return EventFailure; |
|
1665 } |
|
1666 } |
|
1667 |
|
1668 /* Update the global state. */ |
|
1669 source_protocol = XDND_PROTOCOL; |
|
1670 source_protocol_version = protocol_version; |
|
1671 source_window = source_win; |
|
1672 source_window_mask = source_win_mask; |
|
1673 source_actions = actions; |
|
1674 track_source_actions = track; |
|
1675 source_data_types = java_data_types; |
|
1676 source_data_types_native = data_types; |
|
1677 source_data_types_count = data_types_count; |
|
1678 |
|
1679 DTRACE_PRINTLN5("%s:%d XdndEnter handled src_win=%ld protocol=%d fmt=%d.", |
|
1680 __FILE__, __LINE__, |
|
1681 source_window, source_protocol, data_types_count); |
|
1682 |
|
1683 return EventSuccess; |
|
1684 } |
|
1685 |
|
1686 /* |
|
1687 * Returns EventConsume if the event should be consumed, |
|
1688 * EventPassAlong otherwise. |
|
1689 */ |
|
1690 static EventStatus |
|
1691 handle_xdnd_position(XClientMessageEvent* event) { |
|
1692 JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4); |
|
1693 long* event_data = event->data.l; |
|
1694 Window source_win = None; |
|
1695 Time time_stamp = CurrentTime; |
|
1696 Atom action_atom = None; |
|
1697 jint action = java_awt_dnd_DnDConstants_ACTION_NONE; |
|
1698 int x = 0; |
|
1699 int y = 0; |
|
1700 jint java_event_id = 0; |
|
1701 jobject component = NULL; |
|
1702 Window receiver = None; |
|
1703 |
|
1704 DTRACE_PRINTLN5("%s:%d XdndPosition comp=%X src_win=%ld protocol=%d.", |
|
1705 __FILE__, __LINE__, |
|
1706 target_component, source_window, source_protocol); |
|
1707 |
|
1708 if (source_protocol != XDND_PROTOCOL) { |
|
1709 DTRACE_PRINTLN2("%s:%d XdndPosition rejected - invalid state.", |
|
1710 __FILE__, __LINE__); |
|
1711 return EventFailure; |
|
1712 } |
|
1713 |
|
1714 source_win = event_data[0]; |
|
1715 |
|
1716 /* Ignore XDnD messages from all other windows. */ |
|
1717 if (source_window != source_win) { |
|
1718 DTRACE_PRINTLN4("%s:%d XdndPosition rejected - invalid source window cur=%ld this=%ld.", |
|
1719 __FILE__, __LINE__, source_window, source_win); |
|
1720 return EventFailure; |
|
1721 } |
|
1722 |
|
1723 x = event_data[2] >> 16; |
|
1724 y = event_data[2] & 0xFFFF; |
|
1725 |
|
1726 component = get_component_for_window(event->window); |
|
1727 |
|
1728 if (JNU_IsNull(env, component)) { |
|
1729 /* |
|
1730 * The window must be the embedding toplevel, since otherwise we would reject the |
|
1731 * XdndEnter and never get to this point. |
|
1732 */ |
|
1733 DASSERT(is_embedding_toplevel(event->window)); |
|
1734 |
|
1735 receiver = get_embedded_window(event->display, event->window, x, y); |
|
1736 |
|
1737 if (receiver != None) { |
|
1738 component = get_component_for_window(receiver); |
|
1739 } |
|
1740 } else { |
|
1741 receiver = event->window; |
|
1742 } |
|
1743 |
|
1744 /* Translate mouse position from root coordinates |
|
1745 to the target window coordinates. */ |
|
1746 if (receiver != None) { |
|
1747 Window child = None; |
|
1748 XTranslateCoordinates(event->display, |
|
1749 get_root_for_window(receiver), |
|
1750 get_outer_canvas_for_window(receiver), |
|
1751 x, y, &x, &y, &child); |
|
1752 } |
|
1753 |
|
1754 /* Time stamp - new in XDnD version 1. */ |
|
1755 if (source_protocol_version > 0) { |
|
1756 time_stamp = event_data[3]; |
|
1757 } |
|
1758 |
|
1759 /* User action - new in XDnD version 1. */ |
|
1760 if (source_protocol_version > 1) { |
|
1761 action_atom = event_data[4]; |
|
1762 } else { |
|
1763 /* The default action is XdndActionCopy */ |
|
1764 action_atom = XA_XdndActionCopy; |
|
1765 } |
|
1766 |
|
1767 action = xdnd_to_java_action(action_atom); |
|
1768 |
|
1769 if (track_source_actions) { |
|
1770 source_actions |= action; |
|
1771 } |
|
1772 |
|
1773 if (JNU_IsNull(env, component)) { |
|
1774 if (!JNU_IsNull(env, target_component)) { |
|
1775 dt_postDropTargetEvent(env, target_component, x, y, |
|
1776 java_awt_dnd_DnDConstants_ACTION_NONE, |
|
1777 java_awt_event_MouseEvent_MOUSE_EXITED, |
|
1778 NULL); |
|
1779 } |
|
1780 } else { |
|
1781 if (JNU_IsNull(env, target_component)) { |
|
1782 java_event_id = java_awt_event_MouseEvent_MOUSE_ENTERED; |
|
1783 } else { |
|
1784 java_event_id = java_awt_event_MouseEvent_MOUSE_DRAGGED; |
|
1785 } |
|
1786 |
|
1787 dt_postDropTargetEvent(env, component, x, y, action, |
|
1788 java_event_id, event); |
|
1789 } |
|
1790 |
|
1791 user_action = action; |
|
1792 source_x = x; |
|
1793 source_y = y; |
|
1794 target_component = component; |
|
1795 |
|
1796 return EventSuccess; |
|
1797 } |
|
1798 |
|
1799 /* |
|
1800 * Returns EventConsume if the event should be consumed, |
|
1801 * EventPassAlong otherwise. |
|
1802 */ |
|
1803 static EventStatus |
|
1804 handle_xdnd_leave(XClientMessageEvent* event) { |
|
1805 JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4); |
|
1806 long* event_data = event->data.l; |
|
1807 Window source_win = None; |
|
1808 |
|
1809 if (source_protocol != XDND_PROTOCOL) { |
|
1810 DTRACE_PRINTLN2("%s:%d XdndLeave rejected - invalid state.", |
|
1811 __FILE__, __LINE__); |
|
1812 return EventFailure; |
|
1813 } |
|
1814 |
|
1815 source_win = event_data[0]; |
|
1816 |
|
1817 /* Ignore XDnD messages from all other windows. */ |
|
1818 if (source_window != source_win) { |
|
1819 DTRACE_PRINTLN4("%s:%d XdndLeave rejected - invalid source window cur=%ld this=%ld.", |
|
1820 __FILE__, __LINE__, source_window, source_win); |
|
1821 return EventFailure; |
|
1822 } |
|
1823 |
|
1824 awt_dnd_cleanup(); |
|
1825 |
|
1826 return EventSuccess; |
|
1827 } |
|
1828 |
|
1829 /* |
|
1830 * Returns EventConsume if the event should be consumed, |
|
1831 * EventPassAlong otherwise. |
|
1832 */ |
|
1833 static EventStatus |
|
1834 handle_xdnd_drop(XClientMessageEvent* event) { |
|
1835 JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4); |
|
1836 long* event_data = event->data.l; |
|
1837 Window source_win = None; |
|
1838 |
|
1839 DTRACE_PRINTLN5("%s:%d XdndDrop comp=%X src_win=%ld protocol=%d.", |
|
1840 __FILE__, __LINE__, |
|
1841 target_component, source_window, source_protocol); |
|
1842 |
|
1843 if (source_protocol != XDND_PROTOCOL) { |
|
1844 DTRACE_PRINTLN2("%s:%d XdndDrop rejected - invalid state.", |
|
1845 __FILE__, __LINE__); |
|
1846 return EventFailure; |
|
1847 } |
|
1848 |
|
1849 source_win = event_data[0]; |
|
1850 |
|
1851 /* Ignore XDnD messages from all other windows. */ |
|
1852 if (source_window != source_win) { |
|
1853 DTRACE_PRINTLN4("%s:%d XdndDrop rejected - invalid source window cur=%ld this=%ld.", |
|
1854 __FILE__, __LINE__, source_window, source_win); |
|
1855 return EventFailure; |
|
1856 } |
|
1857 |
|
1858 if (!JNU_IsNull(env, target_component)) { |
|
1859 dt_postDropTargetEvent(env, target_component, source_x, source_y, user_action, |
|
1860 java_awt_event_MouseEvent_MOUSE_RELEASED, event); |
|
1861 } |
|
1862 |
|
1863 return EventSuccess; |
|
1864 } |
|
1865 |
|
1866 /* |
|
1867 * Returns EventPassAlong if the event should be passed to the original proxy. |
|
1868 * TOP_LEVEL_ENTER should be passed to the original proxy only if the event is |
|
1869 * invalid. |
|
1870 */ |
|
1871 static EventStatus |
|
1872 handle_motif_top_level_enter(XClientMessageEvent* event) { |
|
1873 JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4); |
|
1874 Display* dpy = event->display; |
|
1875 char* event_data = event->data.b; |
|
1876 unsigned char event_byte_order = 0; |
|
1877 Window source_win = None; |
|
1878 long source_win_mask = 0; |
|
1879 unsigned int protocol_version = MOTIF_DND_PROTOCOL_VERSION; |
|
1880 Atom property_atom = None; |
|
1881 unsigned int data_types_count = 0; |
|
1882 Atom* data_types = NULL; |
|
1883 jlongArray java_data_types = NULL; |
|
1884 |
|
1885 DTRACE_PRINTLN5("%s:%d TOP_LEVEL_ENTER comp=%X src_win=%ld protocol=%d.", |
|
1886 __FILE__, __LINE__, |
|
1887 target_component, source_window, source_protocol); |
|
1888 |
|
1889 if (!JNU_IsNull(env, target_component) || source_window != None || |
|
1890 source_protocol != NO_PROTOCOL) { |
|
1891 DTRACE_PRINTLN2("%s:%d TOP_LEVEL_ENTER rejected - invalid state.", |
|
1892 __FILE__, __LINE__); |
|
1893 return EventFailure; |
|
1894 } |
|
1895 |
|
1896 if (JNU_IsNull(env, get_component_for_window(event->window)) && |
|
1897 !is_embedding_toplevel(event->window)) { |
|
1898 DTRACE_PRINTLN2("%s:%d TOP_LEVEL_ENTER rejected - window is not a registered drop site.", |
|
1899 __FILE__, __LINE__); |
|
1900 return EventFailure; |
|
1901 } |
|
1902 |
|
1903 event_byte_order = read_card8(event_data, 1); |
|
1904 source_win = read_card32(event_data, 8, event_byte_order); |
|
1905 property_atom = read_card32(event_data, 12, event_byte_order); |
|
1906 |
|
1907 /* Extract the available data types. */ |
|
1908 { |
|
1909 unsigned char ret; |
|
1910 Atom type; |
|
1911 int format; |
|
1912 unsigned long nitems; |
|
1913 unsigned long after; |
|
1914 unsigned char *data; |
|
1915 |
|
1916 data = NULL; |
|
1917 ret = checked_XGetWindowProperty(dpy, source_win, property_atom, 0, |
|
1918 0xFFFF, False, |
|
1919 _XA_MOTIF_DRAG_INITIATOR_INFO, &type, |
|
1920 &format, &nitems, &after, &data); |
|
1921 |
|
1922 /* Ignore the source if the window is destroyed. */ |
|
1923 if (ret == BadWindow) { |
|
1924 DTRACE_PRINTLN2("%s:%d TOP_LEVEL_ENTER rejected - invalid window.", |
|
1925 __FILE__, __LINE__); |
|
1926 return EventFailure; |
|
1927 } |
|
1928 |
|
1929 if (ret == BadAtom) { |
|
1930 DTRACE_PRINTLN2("%s:%d TOP_LEVEL_ENTER rejected - invalid property atom.", |
|
1931 __FILE__, __LINE__); |
|
1932 return EventFailure; |
|
1933 } |
|
1934 |
|
1935 if (ret == Success) { |
|
1936 if (type == _XA_MOTIF_DRAG_INITIATOR_INFO && format == 8 && |
|
1937 nitems == MOTIF_INITIATOR_INFO_SIZE) { |
|
1938 unsigned char property_byte_order = read_card8((char*)data, 0); |
|
1939 int index = read_card16((char*)data, 2, property_byte_order); |
|
1940 |
|
1941 protocol_version = read_card8((char*)data, 1); |
|
1942 |
|
1943 if (protocol_version > MOTIF_DND_PROTOCOL_VERSION) { |
|
1944 DTRACE_PRINTLN3("%s:%d TOP_LEVEL_ENTER rejected - invalid protocol version: %d.", |
|
1945 __FILE__, __LINE__, protocol_version); |
|
1946 XFree(data); |
|
1947 return EventFailure; |
|
1948 } |
|
1949 |
|
1950 get_target_list_for_index(dpy, index, &data_types, &data_types_count); |
|
1951 } |
|
1952 |
|
1953 XFree(data); |
|
1954 } |
|
1955 } |
|
1956 |
|
1957 java_data_types = get_data_types_array(env, data_types, data_types_count); |
|
1958 |
|
1959 if (JNU_IsNull(env, java_data_types)) { |
|
1960 DTRACE_PRINTLN2("%s:%d TOP_LEVEL_ENTER rejected - cannot create types array.", |
|
1961 __FILE__, __LINE__); |
|
1962 free((char*)data_types); |
|
1963 return EventFailure; |
|
1964 } |
|
1965 |
|
1966 /* |
|
1967 * Select for StructureNotifyMask to receive DestroyNotify in case of source |
|
1968 * crash. |
|
1969 */ |
|
1970 { |
|
1971 unsigned char ret; |
|
1972 XWindowAttributes xwa; |
|
1973 |
|
1974 XGetWindowAttributes(dpy, source_win, &xwa); |
|
1975 |
|
1976 source_win_mask = xwa.your_event_mask; |
|
1977 |
|
1978 ret = checked_XSelectInput(dpy, source_win, |
|
1979 (source_win_mask | StructureNotifyMask)); |
|
1980 |
|
1981 if (ret == BadWindow) { |
|
1982 DTRACE_PRINTLN2("%s:%d XdndEnter rejected - invalid window.", |
|
1983 __FILE__, __LINE__); |
|
1984 free((char*)data_types); |
|
1985 (*env)->DeleteGlobalRef(env, java_data_types); |
|
1986 return EventFailure; |
|
1987 } |
|
1988 } |
|
1989 |
|
1990 source_protocol = MOTIF_DND_PROTOCOL; |
|
1991 source_protocol_version = protocol_version; |
|
1992 source_window = source_win; |
|
1993 source_atom = property_atom; |
|
1994 source_window_mask = source_win_mask; |
|
1995 /* |
|
1996 * TOP_LEVEL_ENTER doesn't communicate the list of supported actions |
|
1997 * They are provided in DRAG_MOTION. |
|
1998 */ |
|
1999 source_actions = java_awt_dnd_DnDConstants_ACTION_NONE; |
|
2000 track_source_actions = False; |
|
2001 source_data_types = java_data_types; |
|
2002 source_data_types_native = data_types; |
|
2003 source_data_types_count = data_types_count; |
|
2004 DTRACE_PRINTLN6("%s:%d TOP_LEVEL_ENTER comp=%d src_win=%ld protocol=%d fmt=%d.", |
|
2005 __FILE__, __LINE__, |
|
2006 target_component, source_window, source_protocol, data_types_count); |
|
2007 |
|
2008 return EventSuccess; |
|
2009 } |
|
2010 |
|
2011 /* |
|
2012 * Returns EventPassAlong if the event should be passed to the original proxy. |
|
2013 * DRAG_MOTION event shouldn't be passed to the original proxy only if it is |
|
2014 * a valid event and the mouse coordinates passed in it specify the point over |
|
2015 * a Java component in this JVM. |
|
2016 */ |
|
2017 static EventStatus |
|
2018 handle_motif_drag_motion(XClientMessageEvent* event) { |
|
2019 JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4); |
|
2020 char* event_data = event->data.b; |
|
2021 unsigned char event_reason = 0; |
|
2022 unsigned char event_byte_order = 0; |
|
2023 Window source_win = None; |
|
2024 CARD16 flags = 0; |
|
2025 unsigned char motif_action = 0; |
|
2026 unsigned char motif_actions = 0; |
|
2027 jint java_action = java_awt_dnd_DnDConstants_ACTION_NONE; |
|
2028 jint java_actions = java_awt_dnd_DnDConstants_ACTION_NONE; |
|
2029 int x = 0; |
|
2030 int y = 0; |
|
2031 jint java_event_id = 0; |
|
2032 jobject component = NULL; |
|
2033 |
|
2034 DTRACE_PRINTLN5("%s:%d DRAG_MOTION comp=%X src_win=%ld protocol=%d.", |
|
2035 __FILE__, __LINE__, |
|
2036 target_component, source_window, source_protocol); |
|
2037 |
|
2038 if (source_protocol != MOTIF_DND_PROTOCOL) { |
|
2039 DTRACE_PRINTLN2("%s:%d DRAG_MOTION rejected - invalid state.", |
|
2040 __FILE__, __LINE__); |
|
2041 return EventFailure; |
|
2042 } |
|
2043 |
|
2044 event_reason = read_card8(event_data, 0) & MOTIF_MESSAGE_REASON_MASK; |
|
2045 event_byte_order = read_card8(event_data, 1); |
|
2046 |
|
2047 flags = read_card16(event_data, 2, event_byte_order); |
|
2048 |
|
2049 motif_action = (flags & MOTIF_DND_ACTION_MASK) >> MOTIF_DND_ACTION_SHIFT; |
|
2050 motif_actions = (flags & MOTIF_DND_ACTIONS_MASK) >> MOTIF_DND_ACTIONS_SHIFT; |
|
2051 |
|
2052 java_action = motif_to_java_actions(motif_action); |
|
2053 java_actions = motif_to_java_actions(motif_actions); |
|
2054 |
|
2055 /* Append source window id to the event data, so that we can send the |
|
2056 response properly. */ |
|
2057 { |
|
2058 Window win = source_window; |
|
2059 void* p = &event->data.b[12]; |
|
2060 if (event_byte_order != MOTIF_BYTE_ORDER) { |
|
2061 SWAP4BYTES(win); |
|
2062 } |
|
2063 write_card32(&p, (CARD32)win); |
|
2064 } |
|
2065 |
|
2066 component = get_component_for_window(event->window); |
|
2067 |
|
2068 if (event_reason == OPERATION_CHANGED) { |
|
2069 /* OPERATION_CHANGED event doesn't provide coordinates, so we use |
|
2070 previously stored position and component ref. */ |
|
2071 x = source_x; |
|
2072 y = source_y; |
|
2073 |
|
2074 if (JNU_IsNull(env, component)) { |
|
2075 component = target_component; |
|
2076 } |
|
2077 } else { |
|
2078 Window receiver = None; |
|
2079 |
|
2080 x = read_card16(event_data, 8, event_byte_order); |
|
2081 y = read_card16(event_data, 10, event_byte_order); |
|
2082 |
|
2083 if (JNU_IsNull(env, component)) { |
|
2084 /* |
|
2085 * The window must be the embedding toplevel, since otherwise we |
|
2086 * would reject the TOP_LEVEL_ENTER and never get to this point. |
|
2087 */ |
|
2088 DASSERT(is_embedding_toplevel(event->window)); |
|
2089 |
|
2090 receiver = get_embedded_window(event->display, event->window, x, y); |
|
2091 |
|
2092 if (receiver != None) { |
|
2093 component = get_component_for_window(receiver); |
|
2094 } |
|
2095 } else { |
|
2096 receiver = event->window; |
|
2097 } |
|
2098 |
|
2099 /* Translate mouse position from root coordinates |
|
2100 to the target window coordinates. */ |
|
2101 if (receiver != None) { |
|
2102 Window child = None; |
|
2103 XTranslateCoordinates(event->display, |
|
2104 get_root_for_window(receiver), |
|
2105 get_outer_canvas_for_window(receiver), |
|
2106 x, y, &x, &y, &child); |
|
2107 } |
|
2108 } |
|
2109 |
|
2110 if (JNU_IsNull(env, component)) { |
|
2111 if (!JNU_IsNull(env, target_component)) { |
|
2112 /* Triggers dragExit */ |
|
2113 dt_postDropTargetEvent(env, target_component, x, y, |
|
2114 java_awt_dnd_DnDConstants_ACTION_NONE, |
|
2115 java_awt_event_MouseEvent_MOUSE_EXITED, |
|
2116 NULL); |
|
2117 } |
|
2118 } else { |
|
2119 if (JNU_IsNull(env, target_component)) { |
|
2120 /* Triggers dragEnter */ |
|
2121 java_event_id = java_awt_event_MouseEvent_MOUSE_ENTERED; |
|
2122 } else { |
|
2123 /* Triggers dragOver */ |
|
2124 java_event_id = java_awt_event_MouseEvent_MOUSE_DRAGGED; |
|
2125 } |
|
2126 |
|
2127 dt_postDropTargetEvent(env, component, x, y, java_action, java_event_id, |
|
2128 event); |
|
2129 } |
|
2130 |
|
2131 source_actions = java_actions; |
|
2132 track_source_actions = False; |
|
2133 user_action = java_action; |
|
2134 source_x = x; |
|
2135 source_y = y; |
|
2136 target_component = component; |
|
2137 |
|
2138 return EventSuccess; |
|
2139 } |
|
2140 |
|
2141 /* |
|
2142 * Returns EventPassAlong if the event should be passed to the original proxy. |
|
2143 * TOP_LEVEL_LEAVE should be passed to the original proxy only if the event |
|
2144 * is invalid. |
|
2145 */ |
|
2146 static EventStatus |
|
2147 handle_motif_top_level_leave(XClientMessageEvent* event) { |
|
2148 JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4); |
|
2149 char* event_data = event->data.b; |
|
2150 unsigned char event_byte_order = 0; |
|
2151 Window source_win = None; |
|
2152 |
|
2153 DTRACE_PRINTLN5("%s:%d TOP_LEVEL_LEAVE comp=%X src_win=%ld protocol=%d.", |
|
2154 __FILE__, __LINE__, |
|
2155 target_component, source_window, source_protocol); |
|
2156 |
|
2157 if (source_protocol != MOTIF_DND_PROTOCOL) { |
|
2158 DTRACE_PRINTLN2("%s:%d TOP_LEVEL_LEAVE rejected - invalid state.", |
|
2159 __FILE__, __LINE__); |
|
2160 return EventFailure; |
|
2161 } |
|
2162 |
|
2163 event_byte_order = read_card8(event_data, 1); |
|
2164 source_win = read_card32(event_data, 8, event_byte_order); |
|
2165 |
|
2166 /* Ignore Motif DnD messages from all other windows. */ |
|
2167 if (source_window != source_win) { |
|
2168 DTRACE_PRINTLN4("%s:%d TOP_LEVEL_LEAVE rejected - invalid source window cur=%ld this=%ld.", |
|
2169 __FILE__, __LINE__, source_window, source_win); |
|
2170 return EventFailure; |
|
2171 } |
|
2172 |
|
2173 /* |
|
2174 * Postpone upcall to java, so that we can abort it in case |
|
2175 * if drop immediatelly follows (see BugTraq ID 4395290). |
|
2176 * Send a dummy ClientMessage event to guarantee that a postponed java |
|
2177 * upcall will be processed. |
|
2178 */ |
|
2179 motif_top_level_leave_postponed = True; |
|
2180 { |
|
2181 XClientMessageEvent dummy; |
|
2182 Window proxy; |
|
2183 |
|
2184 dummy.display = event->display; |
|
2185 dummy.type = ClientMessage; |
|
2186 dummy.window = event->window; |
|
2187 dummy.format = 32; |
|
2188 dummy.message_type = None; |
|
2189 |
|
2190 /* |
|
2191 * If this is an embedded drop site, the event should go to the |
|
2192 * awt_root_window as this is a proxy for all embedded drop sites. |
|
2193 * Otherwise the event should go to the event->window, as we don't use |
|
2194 * proxies for normal drop sites. |
|
2195 */ |
|
2196 if (is_embedding_toplevel(event->window)) { |
|
2197 proxy = get_awt_root_window(); |
|
2198 } else { |
|
2199 proxy = event->window; |
|
2200 } |
|
2201 |
|
2202 XSendEvent(event->display, proxy, False, NoEventMask, |
|
2203 (XEvent*)&dummy); |
|
2204 } |
|
2205 |
|
2206 return EventSuccess; |
|
2207 } |
|
2208 |
|
2209 /* |
|
2210 * Returns EventPassAlong if the event should be passed to the original proxy. |
|
2211 * DROP_START event shouldn't be passed to the original proxy only if it is |
|
2212 * a valid event and the mouse coordinates passed in it specify the point over |
|
2213 * a Java component in this JVM. |
|
2214 */ |
|
2215 static EventStatus |
|
2216 handle_motif_drop_start(XClientMessageEvent* event) { |
|
2217 JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4); |
|
2218 char* event_data = event->data.b; |
|
2219 unsigned char event_byte_order = 0; |
|
2220 Window source_win = None; |
|
2221 Atom property_atom = None; |
|
2222 CARD16 flags = 0; |
|
2223 unsigned char motif_action = 0; |
|
2224 unsigned char motif_actions = 0; |
|
2225 jint java_action = java_awt_dnd_DnDConstants_ACTION_NONE; |
|
2226 jint java_actions = java_awt_dnd_DnDConstants_ACTION_NONE; |
|
2227 int x = 0; |
|
2228 int y = 0; |
|
2229 jobject component = NULL; |
|
2230 Window receiver = None; |
|
2231 |
|
2232 DTRACE_PRINTLN5("%s:%d DROP_START comp=%X src_win=%ld protocol=%d.", |
|
2233 __FILE__, __LINE__, |
|
2234 target_component, source_window, source_protocol); |
|
2235 |
|
2236 if (source_protocol != MOTIF_DND_PROTOCOL) { |
|
2237 DTRACE_PRINTLN2("%s:%d DROP_START rejected - invalid state.", |
|
2238 __FILE__, __LINE__); |
|
2239 return EventFailure; |
|
2240 } |
|
2241 |
|
2242 event_byte_order = read_card8(event_data, 1); |
|
2243 source_win = read_card32(event_data, 16, event_byte_order); |
|
2244 |
|
2245 /* Ignore Motif DnD messages from all other windows. */ |
|
2246 if (source_window != source_win) { |
|
2247 DTRACE_PRINTLN4("%s:%d DROP_START rejected - invalid source window cur=%ld this=%ld.", |
|
2248 __FILE__, __LINE__, source_window, source_win); |
|
2249 return EventFailure; |
|
2250 } |
|
2251 |
|
2252 property_atom = read_card32(event_data, 12, event_byte_order); |
|
2253 |
|
2254 flags = read_card16(event_data, 2, event_byte_order); |
|
2255 |
|
2256 motif_action = (flags & MOTIF_DND_ACTION_MASK) >> MOTIF_DND_ACTION_SHIFT; |
|
2257 motif_actions = (flags & MOTIF_DND_ACTIONS_MASK) >> MOTIF_DND_ACTIONS_SHIFT; |
|
2258 |
|
2259 java_action = motif_to_java_actions(motif_action); |
|
2260 java_actions = motif_to_java_actions(motif_actions); |
|
2261 |
|
2262 x = read_card16(event_data, 8, event_byte_order); |
|
2263 y = read_card16(event_data, 10, event_byte_order); |
|
2264 |
|
2265 source_actions = java_actions; |
|
2266 |
|
2267 component = get_component_for_window(event->window); |
|
2268 |
|
2269 if (JNU_IsNull(env, component)) { |
|
2270 /* |
|
2271 * The window must be the embedding toplevel, since otherwise we would reject the |
|
2272 * TOP_LEVEL_ENTER and never get to this point. |
|
2273 */ |
|
2274 DASSERT(is_embedding_toplevel(event->window)); |
|
2275 |
|
2276 receiver = get_embedded_window(event->display, event->window, x, y); |
|
2277 |
|
2278 if (receiver != None) { |
|
2279 component = get_component_for_window(receiver); |
|
2280 } |
|
2281 } else { |
|
2282 receiver = event->window; |
|
2283 } |
|
2284 |
|
2285 /* Translate mouse position from root coordinates |
|
2286 to the target window coordinates. */ |
|
2287 if (receiver != None) { |
|
2288 Window child = None; |
|
2289 XTranslateCoordinates(event->display, |
|
2290 get_root_for_window(receiver), |
|
2291 get_outer_canvas_for_window(receiver), |
|
2292 x, y, &x, &y, &child); |
|
2293 } |
|
2294 |
|
2295 if (JNU_IsNull(env, component)) { |
|
2296 if (!JNU_IsNull(env, target_component)) { |
|
2297 /* Triggers dragExit */ |
|
2298 dt_postDropTargetEvent(env, target_component, x, y, |
|
2299 java_awt_dnd_DnDConstants_ACTION_NONE, |
|
2300 java_awt_event_MouseEvent_MOUSE_EXITED, |
|
2301 NULL); |
|
2302 } |
|
2303 } else { |
|
2304 dt_postDropTargetEvent(env, component, x, y, java_action, |
|
2305 java_awt_event_MouseEvent_MOUSE_RELEASED, |
|
2306 event); |
|
2307 } |
|
2308 |
|
2309 return EventSuccess; |
|
2310 } |
|
2311 |
|
2312 static void |
|
2313 send_enter_message_to_toplevel(Window toplevel, XClientMessageEvent* xclient) { |
|
2314 XClientMessageEvent enter; |
|
2315 |
|
2316 if (source_protocol == XDND_PROTOCOL) { |
|
2317 enter.display = xclient->display; |
|
2318 enter.type = ClientMessage; |
|
2319 enter.window = toplevel; |
|
2320 enter.format = 32; |
|
2321 enter.message_type = XA_XdndEnter; |
|
2322 enter.data.l[0] = xclient->data.l[0]; /* XID of the source window */ |
|
2323 enter.data.l[1] = source_protocol_version << XDND_PROTOCOL_SHIFT; |
|
2324 enter.data.l[1] |= source_data_types_count > 3 ? XDND_DATA_TYPES_BIT : 0; |
|
2325 enter.data.l[2] = |
|
2326 source_data_types_count > 0 ? source_data_types_native[0] : None; |
|
2327 enter.data.l[3] = |
|
2328 source_data_types_count > 1 ? source_data_types_native[1] : None; |
|
2329 enter.data.l[4] = |
|
2330 source_data_types_count > 2 ? source_data_types_native[2] : None; |
|
2331 } else if (source_protocol == MOTIF_DND_PROTOCOL) { |
|
2332 int reason = (int)(xclient->data.b[0] & MOTIF_MESSAGE_REASON_MASK); |
|
2333 unsigned char byte_order = xclient->data.b[1]; |
|
2334 |
|
2335 enter.display = xclient->display; |
|
2336 enter.type = ClientMessage; |
|
2337 enter.window = toplevel; |
|
2338 enter.format = 8; |
|
2339 enter.message_type = _XA_MOTIF_DRAG_AND_DROP_MESSAGE; |
|
2340 |
|
2341 { |
|
2342 void* p = &enter.data.b[0]; |
|
2343 int flags = 0; |
|
2344 |
|
2345 flags |= java_to_motif_actions(user_action) << MOTIF_DND_ACTION_SHIFT; |
|
2346 flags |= java_to_motif_actions(source_actions) << MOTIF_DND_ACTIONS_SHIFT; |
|
2347 |
|
2348 write_card8(&p, TOP_LEVEL_ENTER | MOTIF_MESSAGE_FROM_INITIATOR); |
|
2349 write_card8(&p, byte_order); |
|
2350 write_card16(&p, flags); |
|
2351 { |
|
2352 Time time_stamp = read_card32(xclient->data.b, 4, byte_order); |
|
2353 Window src_window = source_window; |
|
2354 Atom motif_atom = _XA_MOTIF_ATOM_0; |
|
2355 |
|
2356 if (byte_order != MOTIF_BYTE_ORDER) { |
|
2357 SWAP4BYTES(time_stamp); |
|
2358 SWAP4BYTES(src_window); |
|
2359 SWAP4BYTES(motif_atom); |
|
2360 } |
|
2361 write_card32(&p, time_stamp); |
|
2362 write_card32(&p, src_window); |
|
2363 write_card32(&p, motif_atom); |
|
2364 } |
|
2365 } |
|
2366 } else { |
|
2367 return; |
|
2368 } |
|
2369 |
|
2370 forward_client_message_to_toplevel(toplevel, &enter); |
|
2371 } |
|
2372 |
|
2373 static void |
|
2374 send_leave_message_to_toplevel(Window toplevel, XClientMessageEvent* xclient) { |
|
2375 XClientMessageEvent leave; |
|
2376 |
|
2377 if (source_protocol == XDND_PROTOCOL) { |
|
2378 leave.display = xclient->display; |
|
2379 leave.type = ClientMessage; |
|
2380 leave.window = toplevel; |
|
2381 leave.format = 32; |
|
2382 leave.message_type = XA_XdndLeave; |
|
2383 leave.data.l[0] = xclient->data.l[0]; /* XID of the source window */ |
|
2384 leave.data.l[1] = 0; /* flags */ |
|
2385 } else if (source_protocol == MOTIF_DND_PROTOCOL) { |
|
2386 int reason = (int)(xclient->data.b[0] & MOTIF_MESSAGE_REASON_MASK); |
|
2387 unsigned char byte_order = xclient->data.b[1]; |
|
2388 |
|
2389 leave.display = xclient->display; |
|
2390 leave.type = ClientMessage; |
|
2391 leave.window = toplevel; |
|
2392 leave.format = 8; |
|
2393 leave.message_type = _XA_MOTIF_DRAG_AND_DROP_MESSAGE; |
|
2394 |
|
2395 { |
|
2396 void* p = &leave.data.b[0]; |
|
2397 int flags = 0; |
|
2398 |
|
2399 write_card8(&p, TOP_LEVEL_LEAVE | MOTIF_MESSAGE_FROM_INITIATOR); |
|
2400 write_card8(&p, byte_order); |
|
2401 |
|
2402 { |
|
2403 Time time_stamp = read_card32(xclient->data.b, 4, byte_order); |
|
2404 Window src_window = source_window; |
|
2405 |
|
2406 if (byte_order != MOTIF_BYTE_ORDER) { |
|
2407 SWAP4BYTES(time_stamp); |
|
2408 SWAP4BYTES(src_window); |
|
2409 } |
|
2410 write_card32(&p, time_stamp); |
|
2411 write_card32(&p, src_window); |
|
2412 } |
|
2413 } |
|
2414 } else { |
|
2415 return; |
|
2416 } |
|
2417 |
|
2418 forward_client_message_to_toplevel(toplevel, &leave); |
|
2419 } |
|
2420 |
|
2421 static void |
|
2422 post_process_client_message(XClientMessageEvent* xclient, EventStatus status, |
|
2423 EventType type) { |
|
2424 Window win = xclient->window; |
|
2425 Boolean postponed_leave = motif_top_level_leave_postponed; |
|
2426 |
|
2427 motif_top_level_leave_postponed = False; |
|
2428 |
|
2429 if (is_embedding_toplevel(win)) { |
|
2430 Boolean server_grabbed = False; |
|
2431 |
|
2432 if (postponed_leave) { |
|
2433 XClientMessageEvent* leave = &motif_top_level_leave_postponed_event; |
|
2434 DASSERT(leave->type == ClientMessage && type == DropEvent); |
|
2435 /* Grab the server to ensure that no event is sent between |
|
2436 the TOP_LEVEL_LEAVE and the next message. */ |
|
2437 XGrabServer(awt_display); |
|
2438 forward_client_message_to_toplevel(leave->window, leave); |
|
2439 memset(&motif_top_level_leave_postponed_event, 0, |
|
2440 sizeof(XClientMessageEvent)); |
|
2441 } |
|
2442 |
|
2443 /* |
|
2444 * This code forwards drag notifications to the browser according to the |
|
2445 * following rules: |
|
2446 * - the messages that we failed to process are always forwarded to the |
|
2447 * browser; |
|
2448 * - MotionEvents and DropEvents are forwarded if and only if the drag |
|
2449 * is not over a plugin window; |
|
2450 * - XDnD: EnterEvents and LeaveEvents are never forwarded, instead, we |
|
2451 * send synthesized EnterEvents or LeaveEvents when the drag |
|
2452 * respectively exits or enters plugin windows; |
|
2453 * - Motif DnD: EnterEvents and LeaveEvents are always forwarded. |
|
2454 * Synthetic EnterEvents and LeaveEvents are needed, because the XDnD drop |
|
2455 * site implemented Netscape 6.2 has a nice feature: when it receives |
|
2456 * the first XdndPosition it continuously sends XdndStatus messages to |
|
2457 * the source (every 100ms) until the drag terminates or leaves the drop |
|
2458 * site. When the mouse is dragged over plugin window embedded in the |
|
2459 * browser frame, these XdndStatus messages are mixed with the XdndStatus |
|
2460 * messages sent from the plugin. |
|
2461 * For Motif DnD, synthetic events cause Motif warnings being displayed, |
|
2462 * so these events are always forwarded. However, Motif DnD drop site in |
|
2463 * Netscape 6.2 is implemented in the same way, so there could be similar |
|
2464 * problems if the drag source choose Motif DnD for communication. |
|
2465 */ |
|
2466 switch (status) { |
|
2467 case EventFailure: |
|
2468 forward_client_message_to_toplevel(win, xclient); |
|
2469 break; |
|
2470 case EventSuccess: |
|
2471 { |
|
2472 /* True iff the previous notification was MotionEvent and it was |
|
2473 forwarded to the browser. */ |
|
2474 static Boolean motion_passed_along = False; |
|
2475 |
|
2476 Boolean motif_protocol = |
|
2477 xclient->message_type == _XA_MOTIF_DRAG_AND_DROP_MESSAGE; |
|
2478 |
|
2479 switch (type) { |
|
2480 case MotionEvent: |
|
2481 if (JNU_IsNull(env, target_component)) { |
|
2482 if (!motion_passed_along && !motif_protocol) { |
|
2483 send_enter_message_to_toplevel(win, xclient); |
|
2484 } |
|
2485 forward_client_message_to_toplevel(win, xclient); |
|
2486 motion_passed_along = True; |
|
2487 } else { |
|
2488 if (motion_passed_along && !motif_protocol) { |
|
2489 send_leave_message_to_toplevel(win, xclient); |
|
2490 } |
|
2491 motion_passed_along = False; |
|
2492 } |
|
2493 break; |
|
2494 case DropEvent: |
|
2495 if (JNU_IsNull(env, target_component)) { |
|
2496 forward_client_message_to_toplevel(win, xclient); |
|
2497 /* The last chance to cleanup. */ |
|
2498 awt_dnd_cleanup(); |
|
2499 } |
|
2500 motion_passed_along = False; |
|
2501 break; |
|
2502 case EnterEvent: |
|
2503 case LeaveEvent: |
|
2504 if (motif_protocol) { |
|
2505 forward_client_message_to_toplevel(win, xclient); |
|
2506 } |
|
2507 motion_passed_along = False; |
|
2508 break; |
|
2509 } |
|
2510 } |
|
2511 } |
|
2512 |
|
2513 if (postponed_leave) { |
|
2514 XUngrabServer(awt_display); |
|
2515 } |
|
2516 } |
|
2517 } |
|
2518 |
|
2519 /* |
|
2520 * Returns True if the event is processed and shouldn't be passed along to Java. |
|
2521 * Otherwise, return False. |
|
2522 */ |
|
2523 Boolean |
|
2524 awt_dnd_dt_process_event(XEvent* event) { |
|
2525 Display* dpy = event->xany.display; |
|
2526 EventStatus status = EventFailure; |
|
2527 EventType type = UnknownEvent; |
|
2528 |
|
2529 if (event->type == DestroyNotify) { |
|
2530 if (event->xany.window == source_window) { |
|
2531 awt_dnd_cleanup(); |
|
2532 } |
|
2533 /* pass along */ |
|
2534 return False; |
|
2535 } |
|
2536 |
|
2537 if (event->type == PropertyNotify) { |
|
2538 if (is_embedding_toplevel(event->xany.window)) { |
|
2539 Atom atom = event->xproperty.atom; |
|
2540 /* |
|
2541 * If some other client replaced the XDnD or Motif DnD proxy with |
|
2542 * another window we set the proxy back to the awt_root_window |
|
2543 * and update the entry in the embedded_drop_site_list. |
|
2544 * This code is needed, as for example Netscape 4.7 resets the proxy |
|
2545 * when the browser shell is resized. |
|
2546 */ |
|
2547 if (atom == _XA_MOTIF_DRAG_RECEIVER_INFO) { |
|
2548 Window prev_motif_proxy; |
|
2549 ProxyRegistrationStatus status; |
|
2550 status = set_motif_proxy(event->xany.display, event->xany.window, |
|
2551 get_awt_root_window(), &prev_motif_proxy); |
|
2552 if (status != RegFailure && status != RegAlreadyRegistered) { |
|
2553 set_motif_proxy_for_toplevel(event->xany.window, |
|
2554 prev_motif_proxy, |
|
2555 status == RegOverride); |
|
2556 } |
|
2557 } |
|
2558 |
|
2559 if (atom == XA_XdndAware || atom == XA_XdndProxy) { |
|
2560 Window prev_xdnd_proxy; |
|
2561 unsigned int prev_protocol_version; |
|
2562 ProxyRegistrationStatus status; |
|
2563 status = set_xdnd_proxy(event->xany.display, event->xany.window, |
|
2564 get_awt_root_window(), &prev_xdnd_proxy, |
|
2565 &prev_protocol_version); |
|
2566 if (status != RegFailure && status != RegAlreadyRegistered) { |
|
2567 set_xdnd_proxy_for_toplevel(event->xany.window, |
|
2568 prev_xdnd_proxy, |
|
2569 prev_protocol_version, |
|
2570 status == RegOverride); |
|
2571 } |
|
2572 } |
|
2573 } |
|
2574 /* pass along */ |
|
2575 return False; |
|
2576 } |
|
2577 |
|
2578 if (event->type != ClientMessage) { |
|
2579 return False; |
|
2580 } |
|
2581 |
|
2582 if (get_component_for_window(event->xany.window) == NULL && |
|
2583 !is_embedding_toplevel(event->xany.window)) { |
|
2584 return False; |
|
2585 } |
|
2586 |
|
2587 if (motif_top_level_leave_postponed) { |
|
2588 /* Sanity check. */ |
|
2589 if (source_protocol != MOTIF_DND_PROTOCOL) { |
|
2590 DTRACE_PRINTLN2("%s:%d TOP_LEVEL_LEAVE rejected - invalid state.", |
|
2591 __FILE__, __LINE__); |
|
2592 awt_dnd_cleanup(); |
|
2593 } else if (event->xclient.message_type == |
|
2594 _XA_MOTIF_DRAG_AND_DROP_MESSAGE) { |
|
2595 unsigned char first_byte = event->xclient.data.b[0]; |
|
2596 unsigned char reason = first_byte & MOTIF_MESSAGE_REASON_MASK; |
|
2597 unsigned char origin = first_byte & MOTIF_MESSAGE_SENDER_MASK; |
|
2598 |
|
2599 if (origin == MOTIF_MESSAGE_FROM_INITIATOR && |
|
2600 reason != DROP_START) { |
|
2601 awt_dnd_cleanup(); |
|
2602 } |
|
2603 } else { |
|
2604 awt_dnd_cleanup(); |
|
2605 } |
|
2606 } |
|
2607 |
|
2608 if (event->xclient.message_type == XA_XdndEnter) { |
|
2609 status = handle_xdnd_enter(&event->xclient); |
|
2610 type = EnterEvent; |
|
2611 } else if (event->xclient.message_type == XA_XdndPosition) { |
|
2612 status = handle_xdnd_position(&event->xclient); |
|
2613 type = MotionEvent; |
|
2614 } else if (event->xclient.message_type == XA_XdndLeave) { |
|
2615 status = handle_xdnd_leave(&event->xclient); |
|
2616 type = LeaveEvent; |
|
2617 } else if (event->xclient.message_type == XA_XdndDrop) { |
|
2618 status = handle_xdnd_drop(&event->xclient); |
|
2619 type = DropEvent; |
|
2620 } else if (event->xclient.message_type == _XA_MOTIF_DRAG_AND_DROP_MESSAGE) { |
|
2621 unsigned char reason = event->xclient.data.b[0] & MOTIF_MESSAGE_REASON_MASK; |
|
2622 unsigned char origin = event->xclient.data.b[0] & MOTIF_MESSAGE_SENDER_MASK; |
|
2623 |
|
2624 /* Only initiator messages should be handled. */ |
|
2625 if (origin == MOTIF_MESSAGE_FROM_INITIATOR) { |
|
2626 switch (reason) { |
|
2627 case DRAG_MOTION: |
|
2628 case OPERATION_CHANGED: |
|
2629 status = handle_motif_drag_motion(&event->xclient); |
|
2630 type = MotionEvent; |
|
2631 break; |
|
2632 case TOP_LEVEL_ENTER: |
|
2633 status = handle_motif_top_level_enter(&event->xclient); |
|
2634 type = EnterEvent; |
|
2635 break; |
|
2636 case TOP_LEVEL_LEAVE: |
|
2637 status = handle_motif_top_level_leave(&event->xclient); |
|
2638 type = LeaveEvent; |
|
2639 break; |
|
2640 case DROP_START: |
|
2641 status = handle_motif_drop_start(&event->xclient); |
|
2642 type = DropEvent; |
|
2643 break; |
|
2644 } |
|
2645 } |
|
2646 } else { |
|
2647 /* Unknown message type. */ |
|
2648 return False; |
|
2649 } |
|
2650 |
|
2651 /* |
|
2652 * We need to handle a special case here: Motif DnD protocol prescribed that |
|
2653 * DROP_START message should always be preceeded with TOP_LEVEL_LEAVE |
|
2654 * message. We need to cleanup on TOP_LEVEL_LEAVE message, but DROP_START |
|
2655 * wouldn't be processed properly. Instead we postpone the cleanup and |
|
2656 * send a dummy client message to ourselves. If dummy arrives first we do a |
|
2657 * normal cleanup. If DROP_START arrives before the dummy we discard delayed |
|
2658 * cleanup. |
|
2659 * In case of forwarding events from an embedded Java app to an embedding |
|
2660 * Java app it could happen that the embedding app receives the dummy before |
|
2661 * the DROP_START message arrives from the embedding app. In this case the |
|
2662 * drop operation on the embedding app fails to complete. |
|
2663 * To resolve this problem we postpone forwarding of TOP_LEVEL_LEAVE message |
|
2664 * until the next client message is about to be forwarded. |
|
2665 */ |
|
2666 if (motif_top_level_leave_postponed && type == LeaveEvent) { |
|
2667 /* motif_top_level_leave_postponed can be set only if the latest client |
|
2668 message has been processed successfully. */ |
|
2669 DASSERT(status == EventSuccess); |
|
2670 memcpy(&motif_top_level_leave_postponed_event, &event->xclient, |
|
2671 sizeof(XClientMessageEvent)); |
|
2672 } else { |
|
2673 post_process_client_message(&event->xclient, status, type); |
|
2674 } |
|
2675 |
|
2676 return True; |
|
2677 } |
|
2678 |
|
2679 static Boolean |
|
2680 register_xdnd_drop_site(Display* dpy, Window toplevel, Window window) { |
|
2681 unsigned char ret; |
|
2682 Atom version_atom = XDND_PROTOCOL_VERSION; |
|
2683 |
|
2684 ret = checked_XChangeProperty(dpy, window, XA_XdndAware, XA_ATOM, 32, |
|
2685 PropModeReplace, |
|
2686 (unsigned char*)&version_atom, 1); |
|
2687 |
|
2688 return (ret == Success); |
|
2689 } |
|
2690 |
|
2691 static Boolean |
|
2692 register_motif_drop_site(Display* dpy, Window toplevel, Window window) { |
|
2693 unsigned char status; |
|
2694 size_t data_size = MOTIF_RECEIVER_INFO_SIZE; |
|
2695 char* data = malloc(data_size); |
|
2696 void* p = data; |
|
2697 |
|
2698 if (data == NULL) { |
|
2699 DTRACE_PRINTLN2("%s:%d malloc failed.", __FILE__, __LINE__); |
|
2700 return False; |
|
2701 } |
|
2702 |
|
2703 write_card8(&p, MOTIF_BYTE_ORDER); |
|
2704 write_card8(&p, MOTIF_DND_PROTOCOL_VERSION); /* protocol version */ |
|
2705 write_card8(&p, MOTIF_DYNAMIC_STYLE); /* protocol style */ |
|
2706 write_card8(&p, 0); /* pad */ |
|
2707 write_card32(&p, window); /* proxy window */ |
|
2708 write_card16(&p, 0); /* num_drop_sites */ |
|
2709 write_card16(&p, 0); /* pad */ |
|
2710 write_card32(&p, data_size); |
|
2711 |
|
2712 status = checked_XChangeProperty(dpy, window, _XA_MOTIF_DRAG_RECEIVER_INFO, |
|
2713 _XA_MOTIF_DRAG_RECEIVER_INFO, 8, PropModeReplace, |
|
2714 (unsigned char*)data, data_size); |
|
2715 |
|
2716 free(data); |
|
2717 |
|
2718 return (status == Success); |
|
2719 } |
|
2720 |
|
2721 static Window |
|
2722 find_toplevel_window(Display* dpy, Window window) { |
|
2723 Window ret = None; |
|
2724 Window root = None; |
|
2725 Window parent = None; |
|
2726 Window *children; |
|
2727 unsigned int nchildren; |
|
2728 |
|
2729 int status; |
|
2730 |
|
2731 Atom type; |
|
2732 int format; |
|
2733 unsigned long nitems; |
|
2734 unsigned long after; |
|
2735 unsigned char *data; |
|
2736 |
|
2737 /* Traverse the ancestor tree from window up to the root and find |
|
2738 the top-level client window nearest to the root. */ |
|
2739 do { |
|
2740 type = None; |
|
2741 |
|
2742 data = NULL; |
|
2743 status = XGetWindowProperty(dpy, window, XA_WM_STATE, 0, 0, False, |
|
2744 AnyPropertyType, &type, &format, &nitems, |
|
2745 &after, &data); |
|
2746 |
|
2747 if (status == Success) { |
|
2748 XFree(data); |
|
2749 } |
|
2750 |
|
2751 if (type != None) { |
|
2752 ret = window; |
|
2753 } |
|
2754 |
|
2755 if (!XQueryTree(dpy, window, &root, &parent, &children, &nchildren)) { |
|
2756 return None; |
|
2757 } |
|
2758 |
|
2759 XFree(children); |
|
2760 |
|
2761 window = parent; |
|
2762 } while (window != root); |
|
2763 |
|
2764 return ret; |
|
2765 } |
|
2766 |
|
2767 static Boolean |
|
2768 register_drop_site(Widget outer_canvas, XtPointer componentRef) { |
|
2769 Display* dpy = XtDisplay(outer_canvas); |
|
2770 Widget shell = NULL; |
|
2771 /* Shell window. */ |
|
2772 Window window = None; |
|
2773 Window root = None; |
|
2774 Window toplevel = None; |
|
2775 |
|
2776 for (shell = outer_canvas; shell != NULL && !XtIsShell(shell); |
|
2777 shell = XtParent(shell)); |
|
2778 |
|
2779 if (shell == NULL || !XtIsRealized(shell)) { |
|
2780 DTRACE_PRINTLN2("%s:%d Cannot find a realized shell for the widget.", |
|
2781 __FILE__, __LINE__); |
|
2782 return False; |
|
2783 } |
|
2784 |
|
2785 window = XtWindow(shell); |
|
2786 |
|
2787 if (!awt_dnd_init(dpy)) { |
|
2788 DTRACE_PRINTLN2("%s:%d Fail to initialize.", __FILE__, __LINE__); |
|
2789 return False; |
|
2790 } |
|
2791 |
|
2792 { |
|
2793 XWindowAttributes xwa; |
|
2794 |
|
2795 if (!XGetWindowAttributes(dpy, window, &xwa)) { |
|
2796 DTRACE_PRINTLN2("%s:%d XGetWindowAttributes failed.", __FILE__, __LINE__); |
|
2797 return False; |
|
2798 } |
|
2799 |
|
2800 root = xwa.root; |
|
2801 |
|
2802 if (root == None) { |
|
2803 DTRACE_PRINTLN2("%s:%d Bad root.", __FILE__, __LINE__); |
|
2804 return False; |
|
2805 } |
|
2806 } |
|
2807 |
|
2808 toplevel = find_toplevel_window(dpy, window); |
|
2809 |
|
2810 /* |
|
2811 * No window with WM_STATE property is found. |
|
2812 * Since the window can be a plugin window reparented to the browser |
|
2813 * toplevel, we cannot determine which window will eventually have WM_STATE |
|
2814 * property set. So we schedule a timer callback that will periodically |
|
2815 * attempt to find an ancestor with WM_STATE and register the drop site |
|
2816 * appropriately. |
|
2817 */ |
|
2818 if (toplevel == None) { |
|
2819 add_delayed_registration_entry(outer_canvas, componentRef); |
|
2820 return False; |
|
2821 } |
|
2822 |
|
2823 if (toplevel == window) { |
|
2824 Boolean xdnd_registered = False; |
|
2825 Boolean motif_registered = False; |
|
2826 |
|
2827 xdnd_registered = register_xdnd_drop_site(dpy, toplevel, window); |
|
2828 |
|
2829 motif_registered = register_motif_drop_site(dpy, toplevel, window); |
|
2830 |
|
2831 if (!xdnd_registered && !motif_registered) { |
|
2832 DTRACE_PRINTLN2("%s:%d Failed to register.", __FILE__, __LINE__); |
|
2833 return False; |
|
2834 } |
|
2835 } else { |
|
2836 if (!add_to_embedded_drop_site_list(dpy, root, toplevel, window)) { |
|
2837 DTRACE_PRINTLN2("%s:%d Failed to init proxy.", __FILE__, __LINE__); |
|
2838 return False; |
|
2839 } |
|
2840 } |
|
2841 |
|
2842 /* There is no need to update the window for the component later, since the |
|
2843 window is destroyed only when the component is disposed in which case the |
|
2844 drop site will be unregistered as well. */ |
|
2845 if (add_to_drop_site_list(window, root, toplevel, XtWindow(outer_canvas), |
|
2846 (jobject)componentRef)) { |
|
2847 DTRACE_PRINTLN2("%s:%d Drop site registered.", __FILE__, __LINE__); |
|
2848 return True; |
|
2849 } else { |
|
2850 DTRACE_PRINTLN2("%s:%d Failed to register.", __FILE__, __LINE__); |
|
2851 return False; |
|
2852 } |
|
2853 } |
|
2854 |
|
2855 static void |
|
2856 register_drop_site_when_realized(Widget outer_canvas, XtPointer client_data, |
|
2857 XEvent *event, Boolean *dontSwallow) { |
|
2858 if (XtIsRealized(outer_canvas)) { |
|
2859 XtRemoveEventHandler(outer_canvas, StructureNotifyMask, False, |
|
2860 register_drop_site_when_realized, client_data); |
|
2861 |
|
2862 register_drop_site(outer_canvas, client_data); |
|
2863 } |
|
2864 } |
|
2865 |
|
2866 /* |
|
2867 * Registers the top-level Window that contains the specified widget as a drop |
|
2868 * site that supports XDnD and Motif DnD protocols. |
|
2869 * If the registration fails for some reason, adds an event handler that will |
|
2870 * attempt to register the drop site later. |
|
2871 * |
|
2872 * Returns True if the drop site is registered successfully. |
|
2873 */ |
|
2874 static Boolean |
|
2875 awt_dnd_register_drop_site(Widget outer_canvas, XtPointer componentRef) { |
|
2876 if (XtIsRealized(outer_canvas)) { |
|
2877 return register_drop_site(outer_canvas, componentRef); |
|
2878 } else { |
|
2879 XtAddEventHandler(outer_canvas, StructureNotifyMask, False, |
|
2880 register_drop_site_when_realized, |
|
2881 componentRef); |
|
2882 |
|
2883 DTRACE_PRINTLN2("%s:%d Unrealized shell. Register later.", |
|
2884 __FILE__, __LINE__); |
|
2885 |
|
2886 return True; |
|
2887 } |
|
2888 } |
|
2889 |
|
2890 /* |
|
2891 * Unregisters the drop site associated with the top-level Window that contains |
|
2892 * the specified widget . |
|
2893 * |
|
2894 * Returns True if completes successfully, False otherwise. |
|
2895 */ |
|
2896 static Boolean |
|
2897 awt_dnd_unregister_drop_site(Widget outer_canvas, XtPointer componentRef) { |
|
2898 Widget shell = NULL; |
|
2899 |
|
2900 XtRemoveEventHandler(outer_canvas, StructureNotifyMask, False, |
|
2901 register_drop_site_when_realized, componentRef); |
|
2902 |
|
2903 remove_delayed_registration_entry(outer_canvas); |
|
2904 |
|
2905 for (shell = outer_canvas; shell != NULL && !XtIsShell(shell); |
|
2906 shell = XtParent(shell)); |
|
2907 |
|
2908 if (shell != NULL && XtIsShell(shell) && XtIsRealized(shell)) { |
|
2909 Window win = XtWindow(shell); |
|
2910 Window toplevel = get_toplevel_for_window(win); |
|
2911 /* |
|
2912 * Cleanup the global state if this drop site participate in the current |
|
2913 * drag operation. Particularly, this allows to delete global ref to the |
|
2914 * component safely. |
|
2915 */ |
|
2916 if (get_component_for_window(win) == target_component) { |
|
2917 awt_dnd_cleanup(); |
|
2918 } |
|
2919 if (toplevel != win) { |
|
2920 remove_from_embedded_drop_site_list(awt_display, toplevel, win); |
|
2921 } |
|
2922 return remove_from_drop_site_list(win); |
|
2923 } |
|
2924 |
|
2925 return True; |
|
2926 } |
|
2927 |
|
2928 /**************************** XEmbed server DnD support ***********************/ |
|
2929 |
|
2930 /* |
|
2931 * |
|
2932 * |
|
2933 */ |
|
2934 Boolean |
|
2935 register_xembed_drop_site(JNIEnv* env, Display* dpy, jobject server, |
|
2936 Window serverHandle, Window clientHandle) { |
|
2937 Atom type; |
|
2938 int format; |
|
2939 unsigned long nitems; |
|
2940 unsigned long after; |
|
2941 unsigned char* data; |
|
2942 unsigned char ret; |
|
2943 unsigned int protocol_version; |
|
2944 |
|
2945 Window xdnd_proxy = None; |
|
2946 unsigned int xdnd_protocol_version = 0; |
|
2947 Boolean xdnd_override = False; |
|
2948 |
|
2949 if (!awt_dnd_init(dpy)) { |
|
2950 DTRACE_PRINTLN2("%s:%d Fail to initialize.", __FILE__, __LINE__); |
|
2951 return False; |
|
2952 } |
|
2953 |
|
2954 /* Get the XDnD protocol version and XDnD proxy of the XEmbed client. */ |
|
2955 data = NULL; |
|
2956 ret = checked_XGetWindowProperty(dpy, clientHandle, XA_XdndAware, 0, 1, |
|
2957 False, AnyPropertyType, &type, &format, |
|
2958 &nitems, &after, &data); |
|
2959 |
|
2960 /* XEmbed client doesn't have an associated XDnD drop site - |
|
2961 do nothing and return True to indicate success. */ |
|
2962 if (ret != Success || data == NULL || nitems == 0 || type != XA_ATOM) { |
|
2963 XFree(data); |
|
2964 return False; |
|
2965 } |
|
2966 |
|
2967 protocol_version = *((unsigned int*)data); |
|
2968 |
|
2969 XFree(data); |
|
2970 |
|
2971 if (protocol_version < XDND_MIN_PROTOCOL_VERSION) { |
|
2972 return False; |
|
2973 } |
|
2974 |
|
2975 xdnd_protocol_version = protocol_version; |
|
2976 |
|
2977 /* XdndProxy is not supported prior to XDnD version 4 */ |
|
2978 if (protocol_version >= 4) { |
|
2979 int status; |
|
2980 |
|
2981 data = NULL; |
|
2982 status = XGetWindowProperty(dpy, clientHandle, XA_XdndProxy, 0, 1, |
|
2983 False, XA_WINDOW, &type, &format, |
|
2984 &nitems, &after, &data); |
|
2985 |
|
2986 if (status == Success && data != NULL && type == XA_WINDOW) { |
|
2987 xdnd_proxy = *((Window*)data); |
|
2988 |
|
2989 if (xdnd_proxy != None) { |
|
2990 XFree(data); |
|
2991 |
|
2992 data = NULL; |
|
2993 status = XGetWindowProperty(dpy, xdnd_proxy, XA_XdndProxy, |
|
2994 0, 1, False, XA_WINDOW, &type, |
|
2995 &format, &nitems, &after, |
|
2996 &data); |
|
2997 |
|
2998 if (status != Success || data == NULL || type != XA_WINDOW || |
|
2999 *((Window*)data) != xdnd_proxy) { |
|
3000 /* Ignore invalid proxy. */ |
|
3001 xdnd_proxy = None; |
|
3002 } |
|
3003 } |
|
3004 |
|
3005 if (xdnd_proxy != None) { |
|
3006 XFree(data); |
|
3007 |
|
3008 data = NULL; |
|
3009 status = XGetWindowProperty(dpy, xdnd_proxy, XA_XdndAware, 0, 1, |
|
3010 False, AnyPropertyType, &type, |
|
3011 &format, &nitems, &after, &data); |
|
3012 |
|
3013 if (status == Success && data != NULL && type == XA_ATOM) { |
|
3014 unsigned int proxy_version = *((unsigned int*)data); |
|
3015 |
|
3016 if (proxy_version != protocol_version) { |
|
3017 /* Ignore invalid proxy. */ |
|
3018 xdnd_proxy = None; |
|
3019 } |
|
3020 } else { |
|
3021 /* Ignore invalid proxy. */ |
|
3022 xdnd_proxy = None; |
|
3023 } |
|
3024 } |
|
3025 } |
|
3026 |
|
3027 XFree(data); |
|
3028 } |
|
3029 |
|
3030 set_xembed_drop_target(env, server); |
|
3031 |
|
3032 /* Add protocol specific entries for the embedded window. */ |
|
3033 /* Only XDnD protocol is supported for XEmbed clients. */ |
|
3034 { |
|
3035 EmbeddedDropSiteProtocolListEntry* xdnd_entry = NULL; |
|
3036 |
|
3037 xdnd_entry = malloc(sizeof(EmbeddedDropSiteProtocolListEntry)); |
|
3038 |
|
3039 if (xdnd_entry == NULL) { |
|
3040 return False; |
|
3041 } |
|
3042 |
|
3043 xdnd_entry->window = clientHandle; |
|
3044 xdnd_entry->proxy = xdnd_proxy; |
|
3045 xdnd_entry->protocol_version = xdnd_protocol_version; |
|
3046 xdnd_entry->overriden = True; |
|
3047 xdnd_entry->next = embedded_xdnd_protocol_list; |
|
3048 embedded_xdnd_protocol_list = xdnd_entry; |
|
3049 } |
|
3050 |
|
3051 { |
|
3052 EmbeddedDropSiteListEntry* entry = NULL; |
|
3053 Window* sites = NULL; |
|
3054 |
|
3055 entry = malloc(sizeof(EmbeddedDropSiteListEntry)); |
|
3056 |
|
3057 if (entry == NULL) { |
|
3058 return False; |
|
3059 } |
|
3060 |
|
3061 sites = malloc(sizeof(Window)); |
|
3062 |
|
3063 if (sites == NULL) { |
|
3064 free(entry); |
|
3065 return False; |
|
3066 } |
|
3067 |
|
3068 sites[0] = clientHandle; |
|
3069 |
|
3070 entry->toplevel = serverHandle; |
|
3071 entry->root = None; |
|
3072 entry->event_mask = 0; |
|
3073 entry->embedded_sites_count = 1; |
|
3074 entry->embedded_sites = sites; |
|
3075 entry->next = embedded_drop_site_list; |
|
3076 embedded_drop_site_list = entry; |
|
3077 } |
|
3078 |
|
3079 return True; |
|
3080 } |
|
3081 |
|
3082 Boolean |
|
3083 unregister_xembed_drop_site(JNIEnv* env, Display* dpy, jobject server, |
|
3084 Window serverHandle, Window clientHandle) { |
|
3085 remove_from_embedded_drop_site_list(dpy, serverHandle, clientHandle); |
|
3086 return True; |
|
3087 } |
|
3088 |
|
3089 void |
|
3090 forward_event_to_embedded(Window embedded, jlong ctxt, jint eventID) { |
|
3091 static XClientMessageEvent* prevMessage = NULL; |
|
3092 static Boolean overXEmbedClient = False; |
|
3093 |
|
3094 XClientMessageEvent* xclient = |
|
3095 (XClientMessageEvent*)jlong_to_ptr(ctxt); |
|
3096 |
|
3097 if (xclient == NULL && prevMessage == NULL) { |
|
3098 return; |
|
3099 } |
|
3100 |
|
3101 if (xclient != NULL) { |
|
3102 /* |
|
3103 * NOTE: this check guarantees that prevMessage will always be an XDnD |
|
3104 * drag message. |
|
3105 */ |
|
3106 if (!is_xdnd_drag_message_type(xclient->message_type)) { |
|
3107 return; |
|
3108 } |
|
3109 |
|
3110 if (!overXEmbedClient) { |
|
3111 long* appended_data = jlong_to_ptr(ctxt) + |
|
3112 sizeof(XClientMessageEvent); |
|
3113 |
|
3114 /* Copy XdndTypeList from source to proxy. */ |
|
3115 if ((appended_data[0] & XDND_DATA_TYPES_BIT) != 0) { |
|
3116 unsigned char ret; |
|
3117 Atom type; |
|
3118 int format; |
|
3119 unsigned long nitems; |
|
3120 unsigned long after; |
|
3121 unsigned char *data; |
|
3122 |
|
3123 data = NULL; |
|
3124 ret = checked_XGetWindowProperty(xclient->display, |
|
3125 xclient->data.l[0], |
|
3126 XA_XdndTypeList, 0, 0xFFFF, |
|
3127 False, XA_ATOM, &type, &format, |
|
3128 &nitems, &after, &data); |
|
3129 |
|
3130 /* Ignore the source if the window is destroyed. */ |
|
3131 if (ret == BadWindow) { |
|
3132 return; |
|
3133 } |
|
3134 |
|
3135 if (ret == Success) { |
|
3136 if (type == XA_ATOM && format == 32) { |
|
3137 ret = checked_XChangeProperty(xclient->display, |
|
3138 xclient->window, |
|
3139 XA_XdndTypeList, XA_ATOM, |
|
3140 32, PropModeReplace, data, |
|
3141 nitems); |
|
3142 } |
|
3143 |
|
3144 XFree(data); |
|
3145 } |
|
3146 } |
|
3147 |
|
3148 set_proxy_mode_source_window(xclient->data.l[0]); |
|
3149 |
|
3150 { |
|
3151 XClientMessageEvent enter; |
|
3152 enter.display = xclient->display; |
|
3153 enter.type = ClientMessage; |
|
3154 enter.window = embedded; |
|
3155 enter.format = 32; |
|
3156 enter.message_type = XA_XdndEnter; |
|
3157 |
|
3158 enter.data.l[0] = xclient->window; /* XID of the source window */ |
|
3159 enter.data.l[1] = appended_data[0]; |
|
3160 enter.data.l[2] = appended_data[1]; |
|
3161 enter.data.l[3] = appended_data[2]; |
|
3162 enter.data.l[4] = appended_data[3]; |
|
3163 |
|
3164 forward_client_message_to_toplevel(embedded, &enter); |
|
3165 } |
|
3166 |
|
3167 overXEmbedClient = True; |
|
3168 } |
|
3169 |
|
3170 /* Make a copy of the original event, since we are going to modify the |
|
3171 event while it still can be referenced from other Java events. */ |
|
3172 { |
|
3173 XClientMessageEvent copy; |
|
3174 memcpy(©, xclient, sizeof(XClientMessageEvent)); |
|
3175 copy.data.l[0] = xclient->window; |
|
3176 |
|
3177 forward_client_message_to_toplevel(embedded, ©); |
|
3178 } |
|
3179 } |
|
3180 |
|
3181 if (eventID == java_awt_event_MouseEvent_MOUSE_EXITED) { |
|
3182 if (overXEmbedClient) { |
|
3183 if (xclient != NULL || prevMessage != NULL) { |
|
3184 /* Last chance to send XdndLeave to the XEmbed client. */ |
|
3185 XClientMessageEvent leave; |
|
3186 |
|
3187 leave.display = xclient != NULL ? |
|
3188 xclient->display : prevMessage->display; |
|
3189 leave.type = ClientMessage; |
|
3190 leave.window = embedded; |
|
3191 leave.format = 32; |
|
3192 leave.message_type = XA_XdndLeave; |
|
3193 leave.data.l[0] = xclient != NULL ? |
|
3194 xclient->window : prevMessage->window; /* XID of the source window */ |
|
3195 leave.data.l[1] = 0; /* flags */ |
|
3196 |
|
3197 forward_client_message_to_toplevel(embedded, &leave); |
|
3198 } |
|
3199 overXEmbedClient = False; |
|
3200 } |
|
3201 } |
|
3202 |
|
3203 if (eventID == java_awt_event_MouseEvent_MOUSE_RELEASED) { |
|
3204 overXEmbedClient = False; |
|
3205 awt_dnd_cleanup(); |
|
3206 } |
|
3207 |
|
3208 if (prevMessage != 0) { |
|
3209 free(prevMessage); |
|
3210 prevMessage = 0; |
|
3211 } |
|
3212 |
|
3213 if (xclient != 0 && overXEmbedClient) { |
|
3214 prevMessage = malloc(sizeof(XClientMessageEvent)); |
|
3215 |
|
3216 memcpy(prevMessage, xclient, sizeof(XClientMessageEvent)); |
|
3217 } |
|
3218 } |
|
3219 |
|
3220 /******************************************************************************/ |
|
3221 |
|
3222 /* |
|
3223 * Class: sun_awt_motif_MWindowPeer |
|
3224 * Method: registerX11DropTarget |
|
3225 * Signature: (Ljava/awt/Component;)V |
|
3226 */ |
|
3227 |
|
3228 JNIEXPORT void JNICALL |
|
3229 Java_sun_awt_motif_MWindowPeer_registerX11DropTarget(JNIEnv *env, jobject this, |
|
3230 jobject target) { |
|
3231 struct FrameData* wdata = NULL; |
|
3232 DropSitePtr dsi = NULL; |
|
3233 |
|
3234 wdata = (struct FrameData *) |
|
3235 JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); |
|
3236 |
|
3237 if (wdata == NULL || wdata->winData.comp.widget == NULL) { |
|
3238 JNU_ThrowNullPointerException(env, "NULL component data"); |
|
3239 return; |
|
3240 } |
|
3241 |
|
3242 if (wdata->winData.shell == NULL) { |
|
3243 JNU_ThrowNullPointerException(env, "Null shell widget"); |
|
3244 return; |
|
3245 } |
|
3246 |
|
3247 DASSERT(wdata->winData.comp.dsi == NULL); |
|
3248 |
|
3249 dsi = (DropSitePtr)calloc(1, sizeof(struct DropSiteInfo)); |
|
3250 |
|
3251 if (dsi == NULL) { |
|
3252 JNU_ThrowOutOfMemoryError(env, ""); |
|
3253 return; |
|
3254 } |
|
3255 |
|
3256 dsi->component = (*env)->NewGlobalRef(env, target); |
|
3257 dsi->isComposite = False; |
|
3258 |
|
3259 wdata->winData.comp.dsi = dsi; |
|
3260 |
|
3261 AWT_LOCK(); |
|
3262 |
|
3263 awt_dnd_register_drop_site(wdata->winData.comp.widget, |
|
3264 dsi->component); |
|
3265 |
|
3266 AWT_UNLOCK(); |
|
3267 } |
|
3268 |
|
3269 /* |
|
3270 * Class: sun_awt_motif_MWindowPeer |
|
3271 * Method: unregisterX11DropTarget |
|
3272 * Signature: (Ljava/awt/Component;)V |
|
3273 */ |
|
3274 |
|
3275 JNIEXPORT void JNICALL |
|
3276 Java_sun_awt_motif_MWindowPeer_unregisterX11DropTarget(JNIEnv *env, |
|
3277 jobject this, |
|
3278 jobject target) { |
|
3279 struct FrameData* wdata = NULL; |
|
3280 DropSitePtr dsi = NULL; |
|
3281 |
|
3282 wdata = (struct FrameData *) |
|
3283 JNU_GetLongFieldAsPtr(env, this, mComponentPeerIDs.pData); |
|
3284 |
|
3285 if (wdata == NULL) { |
|
3286 JNU_ThrowNullPointerException(env, "Null component data"); |
|
3287 return; |
|
3288 } |
|
3289 |
|
3290 if (wdata->winData.shell == NULL) { |
|
3291 JNU_ThrowNullPointerException(env, "Null shell widget"); |
|
3292 return; |
|
3293 } |
|
3294 |
|
3295 dsi = wdata->winData.comp.dsi; |
|
3296 |
|
3297 if (dsi == NULL) { |
|
3298 JNU_ThrowNullPointerException(env, "Null DropSiteInfo"); |
|
3299 return; |
|
3300 } |
|
3301 |
|
3302 AWT_LOCK(); |
|
3303 |
|
3304 awt_dnd_unregister_drop_site(wdata->winData.comp.widget, dsi->component); |
|
3305 |
|
3306 AWT_UNLOCK(); |
|
3307 |
|
3308 wdata->winData.comp.dsi = NULL; |
|
3309 |
|
3310 (*env)->DeleteGlobalRef(env, dsi->component); |
|
3311 |
|
3312 free(dsi); |
|
3313 } |
|
3314 |
|
3315 static void |
|
3316 dt_send_event_to_source(XClientMessageEvent* xclient) { |
|
3317 /* Shortcut if the source is in the same JVM. */ |
|
3318 if (xclient->window == awt_dnd_ds_get_source_window()) { |
|
3319 awt_dnd_ds_process_event((XEvent*)xclient); |
|
3320 } else { |
|
3321 unsigned char ret; |
|
3322 |
|
3323 ret = checked_XSendEvent(xclient->display, xclient->window, False, |
|
3324 NoEventMask, (XEvent*)xclient); |
|
3325 |
|
3326 if (ret == BadWindow) { |
|
3327 DTRACE_PRINTLN2("%s:%d XSendEvent - invalid window.", |
|
3328 __FILE__, __LINE__); |
|
3329 |
|
3330 /* Cleanup if we are still communicating with this window. */ |
|
3331 if (source_window == xclient->window) { |
|
3332 awt_dnd_cleanup(); |
|
3333 } |
|
3334 } |
|
3335 } |
|
3336 } |
|
3337 |
|
3338 static void |
|
3339 dt_send_response(XClientMessageEvent* xclient, jint eventID, jint action) { |
|
3340 Display* dpy = xclient->display; |
|
3341 XClientMessageEvent response; |
|
3342 |
|
3343 if (xclient->message_type == XA_XdndPosition) { |
|
3344 long* event_data = xclient->data.l; |
|
3345 |
|
3346 if (eventID == java_awt_event_MouseEvent_MOUSE_EXITED) { |
|
3347 action = java_awt_dnd_DnDConstants_ACTION_NONE; |
|
3348 } |
|
3349 |
|
3350 response.display = dpy; |
|
3351 response.type = ClientMessage; |
|
3352 response.window = event_data[0]; |
|
3353 response.format = 32; |
|
3354 response.message_type = XA_XdndStatus; |
|
3355 /* target window */ |
|
3356 response.data.l[0] = xclient->window; |
|
3357 /* flags */ |
|
3358 response.data.l[1] = 0; |
|
3359 if (action != java_awt_dnd_DnDConstants_ACTION_NONE) { |
|
3360 response.data.l[1] |= XDND_ACCEPT_DROP_FLAG; |
|
3361 } |
|
3362 /* specify an empty rectangle */ |
|
3363 response.data.l[2] = 0; /* x, y */ |
|
3364 response.data.l[3] = 0; /* w, h */ |
|
3365 /* action accepted by the target */ |
|
3366 response.data.l[4] = java_to_xdnd_action(action); |
|
3367 } else if (xclient->message_type == _XA_MOTIF_DRAG_AND_DROP_MESSAGE) { |
|
3368 int reason = (int)(xclient->data.b[0] & MOTIF_MESSAGE_REASON_MASK); |
|
3369 int origin = (int)(xclient->data.b[0] & MOTIF_MESSAGE_SENDER_MASK); |
|
3370 unsigned char byte_order = xclient->data.b[1]; |
|
3371 CARD16 response_flags = 0; |
|
3372 CARD8 response_reason = 0; |
|
3373 void* p = &response.data.b; |
|
3374 |
|
3375 /* Only initiator messages should be handled. */ |
|
3376 if (origin != MOTIF_MESSAGE_FROM_INITIATOR) { |
|
3377 DTRACE_PRINTLN2("%s:%d Receiver message.", __FILE__, __LINE__); |
|
3378 return; |
|
3379 } |
|
3380 |
|
3381 switch (reason) { |
|
3382 case DRAG_MOTION: |
|
3383 switch (eventID) { |
|
3384 case java_awt_event_MouseEvent_MOUSE_ENTERED: |
|
3385 response_reason = DROP_SITE_ENTER; |
|
3386 break; |
|
3387 case java_awt_event_MouseEvent_MOUSE_DRAGGED: |
|
3388 response_reason = DRAG_MOTION; |
|
3389 break; |
|
3390 case java_awt_event_MouseEvent_MOUSE_EXITED: |
|
3391 response_reason = DROP_SITE_LEAVE; |
|
3392 break; |
|
3393 } |
|
3394 } |
|
3395 |
|
3396 response.display = dpy; |
|
3397 response.type = ClientMessage; |
|
3398 response.window = read_card32(xclient->data.b, 12, byte_order); |
|
3399 response.format = 8; |
|
3400 response.message_type = _XA_MOTIF_DRAG_AND_DROP_MESSAGE; |
|
3401 |
|
3402 write_card8(&p, response_reason | MOTIF_MESSAGE_FROM_RECEIVER); |
|
3403 write_card8(&p, MOTIF_BYTE_ORDER); |
|
3404 |
|
3405 if (response_reason != DROP_SITE_LEAVE) { |
|
3406 CARD16 flags = read_card16(xclient->data.b, 2, byte_order); |
|
3407 unsigned char drop_site_status = |
|
3408 (action == java_awt_dnd_DnDConstants_ACTION_NONE) ? |
|
3409 MOTIF_INVALID_DROP_SITE : MOTIF_VALID_DROP_SITE; |
|
3410 |
|
3411 /* Clear action and drop site status bits. */ |
|
3412 response_flags = |
|
3413 flags & ~MOTIF_DND_ACTION_MASK & ~MOTIF_DND_STATUS_MASK; |
|
3414 |
|
3415 /* Fill in new action and drop site status. */ |
|
3416 response_flags |= |
|
3417 java_to_motif_actions(action) << MOTIF_DND_ACTION_SHIFT; |
|
3418 response_flags |= |
|
3419 drop_site_status << MOTIF_DND_STATUS_SHIFT; |
|
3420 } else { |
|
3421 response_flags = 0; |
|
3422 } |
|
3423 |
|
3424 write_card16(&p, response_flags); |
|
3425 |
|
3426 /* Write time stamp. */ |
|
3427 write_card32(&p, read_card32(xclient->data.b, 4, byte_order)); |
|
3428 |
|
3429 /* Write coordinates. */ |
|
3430 if (response_reason != DROP_SITE_LEAVE) { |
|
3431 write_card16(&p, read_card16(xclient->data.b, 8, byte_order)); |
|
3432 write_card16(&p, read_card16(xclient->data.b, 10, byte_order)); |
|
3433 } else { |
|
3434 write_card16(&p, 0); |
|
3435 write_card16(&p, 0); |
|
3436 } |
|
3437 } else { |
|
3438 return; |
|
3439 } |
|
3440 |
|
3441 dt_send_event_to_source(&response); |
|
3442 } |
|
3443 |
|
3444 static void |
|
3445 dummy_selection_callback(Widget w, XtPointer client_data, Atom* selection, |
|
3446 Atom* type, XtPointer value, unsigned long *length, |
|
3447 int32_t *format) { |
|
3448 /* The selection callback is responsible for freeing the data. */ |
|
3449 if (value != NULL) { |
|
3450 XtFree(value); |
|
3451 value = NULL; |
|
3452 } |
|
3453 } |
|
3454 |
|
3455 static void |
|
3456 dt_notify_drop_done(JNIEnv* env, XClientMessageEvent* xclient, jboolean success, |
|
3457 jint action) { |
|
3458 if (xclient->message_type == XA_XdndDrop) { |
|
3459 Display* dpy = xclient->display; |
|
3460 XClientMessageEvent finished; |
|
3461 long* event_data = xclient->data.l; |
|
3462 |
|
3463 /* |
|
3464 * The XDnD protocol recommends that the target requests the special |
|
3465 * target DELETE in case if the drop action is XdndActionMove. |
|
3466 */ |
|
3467 if (action == java_awt_dnd_DnDConstants_ACTION_MOVE && |
|
3468 success == JNI_TRUE) { |
|
3469 |
|
3470 Time time_stamp = event_data[2]; |
|
3471 |
|
3472 XtGetSelectionValue(awt_root_shell, XA_XdndSelection, XA_DELETE, |
|
3473 dummy_selection_callback, NULL, time_stamp); |
|
3474 } |
|
3475 |
|
3476 finished.display = dpy; |
|
3477 finished.type = ClientMessage; |
|
3478 finished.window = event_data[0]; |
|
3479 finished.format = 32; |
|
3480 finished.message_type = XA_XdndFinished; |
|
3481 finished.data.l[0] = xclient->window; |
|
3482 finished.data.l[1] = 0; /* flags */ |
|
3483 finished.data.l[2] = None; |
|
3484 if (source_protocol_version >= 5) { |
|
3485 if (success == JNI_TRUE) { |
|
3486 finished.data.l[1] |= XDND_ACCEPT_DROP_FLAG; |
|
3487 } |
|
3488 finished.data.l[2] = java_to_xdnd_action(action); |
|
3489 } |
|
3490 |
|
3491 dt_send_event_to_source(&finished); |
|
3492 } else if (xclient->message_type == _XA_MOTIF_DRAG_AND_DROP_MESSAGE) { |
|
3493 char* event_data = xclient->data.b; |
|
3494 unsigned char event_byte_order = read_card8(event_data, 1); |
|
3495 unsigned char first_byte = read_card8(event_data, 0); |
|
3496 unsigned char reason = first_byte & MOTIF_MESSAGE_REASON_MASK; |
|
3497 unsigned char origin = first_byte & MOTIF_MESSAGE_SENDER_MASK; |
|
3498 Atom selection = None; |
|
3499 Time time_stamp = CurrentTime; |
|
3500 Atom status_atom = None; |
|
3501 |
|
3502 if (origin != MOTIF_MESSAGE_FROM_INITIATOR) { |
|
3503 DTRACE_PRINTLN2("%s:%d Invalid origin.", __FILE__, __LINE__); |
|
3504 return; |
|
3505 } |
|
3506 |
|
3507 if (reason != DROP_START) { |
|
3508 DTRACE_PRINTLN2("%s:%d Invalid reason.", __FILE__, __LINE__); |
|
3509 return; |
|
3510 } |
|
3511 |
|
3512 selection = read_card32(event_data, 12, event_byte_order); |
|
3513 time_stamp = read_card32(event_data, 4, event_byte_order); |
|
3514 |
|
3515 if (success == JNI_TRUE) { |
|
3516 status_atom = XA_XmTRANSFER_SUCCESS; |
|
3517 } else { |
|
3518 status_atom = XA_XmTRANSFER_FAILURE; |
|
3519 } |
|
3520 |
|
3521 /* |
|
3522 * This is just the way to communicate the drop completion status back |
|
3523 * to the initiator as prescribed by the Motif DnD protocol. |
|
3524 */ |
|
3525 XtGetSelectionValue(awt_root_shell, selection, status_atom, |
|
3526 dummy_selection_callback, NULL, time_stamp); |
|
3527 } |
|
3528 |
|
3529 /* |
|
3530 * Flush the buffer to guarantee that the drop completion event is sent |
|
3531 * to the source before the method returns. |
|
3532 */ |
|
3533 XFlush(awt_display); |
|
3534 |
|
3535 /* Trick to prevent awt_dnd_cleanup() from posting dragExit */ |
|
3536 target_component = NULL; |
|
3537 /* Cannot do cleanup before the drop finishes as we need source protocol |
|
3538 version to send XdndFinished message. */ |
|
3539 awt_dnd_cleanup(); |
|
3540 } |
|
3541 |
|
3542 /* |
|
3543 * Class: sun_awt_motif_X11DropTargetContextPeer |
|
3544 * Method: sendResponse |
|
3545 * Signature: (IIJZ)V |
|
3546 */ |
|
3547 |
|
3548 JNIEXPORT void JNICALL |
|
3549 Java_sun_awt_motif_X11DropTargetContextPeer_sendResponse(JNIEnv *env, |
|
3550 jobject this, |
|
3551 jint eventID, |
|
3552 jint action, |
|
3553 jlong nativeCtxt, |
|
3554 jboolean dispatcherDone, |
|
3555 jboolean consumed) { |
|
3556 XClientMessageEvent* xclient = |
|
3557 (XClientMessageEvent*)jlong_to_ptr(nativeCtxt); |
|
3558 |
|
3559 AWT_LOCK(); |
|
3560 |
|
3561 if (consumed == JNI_FALSE) { |
|
3562 dt_send_response(xclient, eventID, action); |
|
3563 } |
|
3564 |
|
3565 /* |
|
3566 * Free the native context only if all copies of the original event are |
|
3567 * processed. |
|
3568 */ |
|
3569 if (dispatcherDone == JNI_TRUE) { |
|
3570 XtFree((char*)xclient); |
|
3571 } |
|
3572 |
|
3573 AWT_UNLOCK(); |
|
3574 } |
|
3575 |
|
3576 /* |
|
3577 * Class: sun_awt_motif_X11DropTargetContextPeer |
|
3578 * Method: dropDone |
|
3579 * Signature: (JZI)V |
|
3580 */ |
|
3581 |
|
3582 JNIEXPORT void JNICALL |
|
3583 Java_sun_awt_motif_X11DropTargetContextPeer_dropDone(JNIEnv *env, |
|
3584 jobject this, |
|
3585 jlong nativeCtxt, |
|
3586 jboolean success, |
|
3587 jint action) { |
|
3588 XClientMessageEvent* xclient = |
|
3589 (XClientMessageEvent*)jlong_to_ptr(nativeCtxt); |
|
3590 |
|
3591 AWT_LOCK(); |
|
3592 |
|
3593 dt_notify_drop_done(env, xclient, success, action); |
|
3594 |
|
3595 XtFree((char*)xclient); |
|
3596 |
|
3597 AWT_UNLOCK(); |
|
3598 } |
|
3599 |
|
3600 /* |
|
3601 * Class: sun_awt_motif_X11DropTargetContextPeer |
|
3602 * Method: getData |
|
3603 * Signature: (IJ)Ljava/lang/Object; |
|
3604 */ |
|
3605 |
|
3606 JNIEXPORT jobject JNICALL |
|
3607 Java_sun_awt_motif_X11DropTargetContextPeer_getData(JNIEnv *env, |
|
3608 jobject this, |
|
3609 jlong nativeCtxt, |
|
3610 jlong formatAtom) { |
|
3611 XClientMessageEvent* xclient = |
|
3612 (XClientMessageEvent*)jlong_to_ptr(nativeCtxt); |
|
3613 |
|
3614 Atom selection = None; |
|
3615 Time time_stamp = CurrentTime; |
|
3616 Atom target = (Atom)formatAtom; |
|
3617 |
|
3618 if (xclient->message_type == XA_XdndDrop || |
|
3619 xclient->message_type == XA_XdndPosition) { |
|
3620 Display* dpy = xclient->display; |
|
3621 Window source_win = xclient->data.l[0]; |
|
3622 Atom protocol_version = 0; |
|
3623 |
|
3624 int status; |
|
3625 |
|
3626 Atom type; |
|
3627 int format; |
|
3628 unsigned long nitems; |
|
3629 unsigned long after; |
|
3630 unsigned char *data; |
|
3631 |
|
3632 AWT_LOCK(); |
|
3633 |
|
3634 data = NULL; |
|
3635 status = XGetWindowProperty(dpy, source_win, XA_XdndAware, 0, 0xFFFF, |
|
3636 False, XA_ATOM, &type, &format, &nitems, |
|
3637 &after, &data); |
|
3638 |
|
3639 if (status == Success && data != NULL && type == XA_ATOM && format == 32 |
|
3640 && nitems > 0) { |
|
3641 protocol_version = (protocol_version > XDND_PROTOCOL_VERSION) ? |
|
3642 XDND_PROTOCOL_VERSION : protocol_version; |
|
3643 |
|
3644 if (protocol_version > 0) { |
|
3645 if (xclient->message_type == XA_XdndDrop) { |
|
3646 time_stamp = xclient->data.l[2]; |
|
3647 } else if (xclient->message_type == XA_XdndPosition) { |
|
3648 time_stamp = xclient->data.l[3]; |
|
3649 } |
|
3650 } |
|
3651 } |
|
3652 |
|
3653 if (status == Success) { |
|
3654 XFree(data); |
|
3655 data = NULL; |
|
3656 } |
|
3657 |
|
3658 AWT_FLUSH_UNLOCK(); |
|
3659 |
|
3660 selection = XA_XdndSelection; |
|
3661 if (time_stamp == CurrentTime) { |
|
3662 time_stamp = awt_util_getCurrentServerTime(); |
|
3663 } |
|
3664 |
|
3665 } else if (xclient->message_type == _XA_MOTIF_DRAG_AND_DROP_MESSAGE) { |
|
3666 char* event_data = xclient->data.b; |
|
3667 unsigned char event_byte_order = read_card8(event_data, 1); |
|
3668 unsigned char first_byte = read_card8(event_data, 0); |
|
3669 unsigned char reason = first_byte & MOTIF_MESSAGE_REASON_MASK; |
|
3670 unsigned char origin = first_byte & MOTIF_MESSAGE_SENDER_MASK; |
|
3671 |
|
3672 if (origin != MOTIF_MESSAGE_FROM_INITIATOR) { |
|
3673 DTRACE_PRINTLN2("%s:%d Invalid origin.", __FILE__, __LINE__); |
|
3674 return NULL; |
|
3675 } |
|
3676 |
|
3677 switch (reason) { |
|
3678 case DROP_START: |
|
3679 selection = read_card32(event_data, 12, event_byte_order); |
|
3680 break; |
|
3681 case DRAG_MOTION: |
|
3682 case OPERATION_CHANGED: |
|
3683 selection = source_atom; |
|
3684 break; |
|
3685 default: |
|
3686 DTRACE_PRINTLN2("%s:%d Invalid reason.", __FILE__, __LINE__); |
|
3687 return NULL; |
|
3688 } |
|
3689 |
|
3690 if (selection == None) { |
|
3691 return NULL; |
|
3692 } |
|
3693 |
|
3694 time_stamp = read_card32(event_data, 4, event_byte_order); |
|
3695 } else { |
|
3696 return NULL; |
|
3697 } |
|
3698 |
|
3699 return get_selection_data(env, selection, target, time_stamp); |
|
3700 } |
|