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 /* Declares getCursor(JNIEnv, jobject) */ |
|
33 #include "awt_Cursor.h" |
|
34 |
|
35 /* Define java constants */ |
|
36 #include "java_awt_dnd_DnDConstants.h" |
|
37 #include "sun_awt_dnd_SunDragSourceContextPeer.h" |
|
38 |
|
39 /* Define DECLARE_* macros */ |
|
40 #include "awt_DataTransferer.h" |
|
41 |
|
42 #define GRAB_EVENT_MASK \ |
|
43 (ButtonPressMask | ButtonMotionMask | ButtonReleaseMask) |
|
44 |
|
45 /* Events selected on the root window during drag. */ |
|
46 #define ROOT_EVENT_MASK \ |
|
47 (ButtonMotionMask | KeyPressMask | KeyReleaseMask) |
|
48 |
|
49 /* Events selected on registered receiver windows during drag. */ |
|
50 #define RECEIVER_EVENT_MASK \ |
|
51 (StructureNotifyMask) |
|
52 |
|
53 |
|
54 /* in canvas.c */ |
|
55 extern jint getModifiers(uint32_t state, jint button, jint keyCode); |
|
56 |
|
57 typedef struct { |
|
58 CARD8 byte_order; |
|
59 CARD8 protocol_version; |
|
60 CARD16 index; |
|
61 CARD32 selection_atom; |
|
62 } InitiatorInfo; |
|
63 |
|
64 typedef enum { |
|
65 /* |
|
66 * Communicate with receivers of both protocols. |
|
67 * If the receiver supports both protocols, |
|
68 * choose Motif DnD for communication. |
|
69 */ |
|
70 DS_POLICY_PREFER_MOTIF, |
|
71 /* |
|
72 * Communicate with receivers of both protocols. |
|
73 * If the receiver supports both protocols, |
|
74 * choose XDnD for communication. [default] |
|
75 */ |
|
76 DS_POLICY_PREFER_XDND, |
|
77 /* Communicate only with Motif DnD receivers. */ |
|
78 DS_POLICY_ONLY_MOTIF, |
|
79 /* Communicate only with XDnD receivers. */ |
|
80 DS_POLICY_ONLY_XDND |
|
81 } DragSourcePolicy; |
|
82 |
|
83 |
|
84 /* The drag source policy. */ |
|
85 static DragSourcePolicy drag_source_policy = DS_POLICY_PREFER_XDND; |
|
86 |
|
87 static Boolean dnd_in_progress = False; |
|
88 static Boolean drag_in_progress = False; |
|
89 static jobject source_peer = NULL; |
|
90 static Atom* data_types = NULL; |
|
91 static unsigned int data_types_count = 0; |
|
92 static Window drag_root_window = None; |
|
93 static EventMask your_root_event_mask = NoEventMask; |
|
94 static Time latest_time_stamp = CurrentTime; |
|
95 |
|
96 /* The child of the root which is currently under the mouse. */ |
|
97 static Window target_root_subwindow = None; |
|
98 |
|
99 static Window target_window = None; |
|
100 static long target_window_mask = 0; |
|
101 static Window target_proxy_window = None; |
|
102 static Protocol target_protocol = NO_PROTOCOL; |
|
103 static unsigned int target_protocol_version = 0; |
|
104 /* |
|
105 * The server time when the pointer entered the current target - |
|
106 * needed on Motif DnD to filter out messages from the previous |
|
107 * target. |
|
108 * It is updated whenever the target_window is updated. |
|
109 * If the target_window is set to non-None, it is set to the time stamp |
|
110 * of the X event that trigger the update. Otherwise, it is set to CurrentTime. |
|
111 */ |
|
112 static Time target_enter_server_time = CurrentTime; |
|
113 |
|
114 static int x_root = 0; |
|
115 static int y_root = 0; |
|
116 static unsigned int event_state = 0; |
|
117 |
|
118 static jint source_action = java_awt_dnd_DnDConstants_ACTION_NONE; |
|
119 static jint source_actions = java_awt_dnd_DnDConstants_ACTION_NONE; |
|
120 static jint target_action = java_awt_dnd_DnDConstants_ACTION_NONE; |
|
121 |
|
122 /* Forward declarations */ |
|
123 static void cleanup_drag(Display* dpy, Time time); |
|
124 static Boolean process_proxy_mode_event(XEvent* xev); |
|
125 |
|
126 /**************************** XEmbed server DnD support ***********************/ |
|
127 static Window proxy_mode_source_window = None; |
|
128 /******************************************************************************/ |
|
129 |
|
130 /**************************** JNI stuff ***************************************/ |
|
131 |
|
132 DECLARE_JAVA_CLASS(dscp_clazz, "sun/awt/dnd/SunDragSourceContextPeer") |
|
133 |
|
134 static void |
|
135 ds_postDragSourceDragEvent(JNIEnv* env, jint targetAction, unsigned int state, |
|
136 int x, int y, jint dispatch_type) { |
|
137 DECLARE_VOID_JAVA_METHOD(dscp_postDragSourceDragEvent, dscp_clazz, |
|
138 "postDragSourceDragEvent", "(IIIII)V"); |
|
139 |
|
140 DASSERT(!JNU_IsNull(env, source_peer)); |
|
141 if (JNU_IsNull(env, source_peer)) { |
|
142 return; |
|
143 } |
|
144 |
|
145 (*env)->CallVoidMethod(env, source_peer, dscp_postDragSourceDragEvent, |
|
146 targetAction, getModifiers(state, 0, 0), x, y, |
|
147 dispatch_type); |
|
148 } |
|
149 |
|
150 static jint |
|
151 ds_convertModifiersToDropAction(JNIEnv* env, unsigned int state) { |
|
152 jint action; |
|
153 DECLARE_STATIC_JINT_JAVA_METHOD(dscp_convertModifiersToDropAction, dscp_clazz, |
|
154 "convertModifiersToDropAction", "(II)I"); |
|
155 action = (*env)->CallStaticIntMethod(env, clazz, dscp_convertModifiersToDropAction, |
|
156 getModifiers(state, 0, 0), source_actions); |
|
157 if ((*env)->ExceptionCheck(env) == JNI_TRUE) { |
|
158 (*env)->ExceptionDescribe(env); |
|
159 (*env)->ExceptionClear(env); |
|
160 return java_awt_dnd_DnDConstants_ACTION_NONE; |
|
161 } |
|
162 return action; |
|
163 } |
|
164 |
|
165 static void |
|
166 ds_postDragSourceEvent(JNIEnv* env, int x, int y) { |
|
167 DECLARE_VOID_JAVA_METHOD(dscp_dragExit, dscp_clazz, |
|
168 "dragExit", "(II)V"); |
|
169 |
|
170 DASSERT(!JNU_IsNull(env, source_peer)); |
|
171 if (JNU_IsNull(env, source_peer)) { |
|
172 return; |
|
173 } |
|
174 |
|
175 (*env)->CallVoidMethod(env, source_peer, dscp_dragExit, x, y); |
|
176 } |
|
177 |
|
178 static void |
|
179 ds_postDragSourceDropEvent(JNIEnv* env, jboolean success, jint targetAction, |
|
180 int x, int y) { |
|
181 DECLARE_VOID_JAVA_METHOD(dscp_dragDropFinished, dscp_clazz, |
|
182 "dragDropFinished", "(ZIII)V"); |
|
183 |
|
184 DASSERT(!JNU_IsNull(env, source_peer)); |
|
185 if (JNU_IsNull(env, source_peer)) { |
|
186 return; |
|
187 } |
|
188 |
|
189 (*env)->CallVoidMethod(env, source_peer, dscp_dragDropFinished, |
|
190 success, targetAction, x, y); |
|
191 } |
|
192 |
|
193 /******************************************************************************/ |
|
194 |
|
195 static void |
|
196 cancel_drag(XtPointer client_data, XtIntervalId* id) { |
|
197 Time time_stamp = awt_util_getCurrentServerTime(); |
|
198 |
|
199 cleanup_drag(awt_display, time_stamp); |
|
200 } |
|
201 |
|
202 #define DONT_CARE -1 |
|
203 |
|
204 static void |
|
205 awt_popupCallback(Widget shell, XtPointer closure, XtPointer call_data) { |
|
206 XtGrabKind grab_kind = XtGrabNone; |
|
207 |
|
208 if (call_data != NULL) { |
|
209 grab_kind = *((XtGrabKind*)call_data); |
|
210 } |
|
211 |
|
212 if (XmIsVendorShell(shell)) { |
|
213 int input_mode; |
|
214 XtVaGetValues(shell, XmNmwmInputMode, &input_mode, NULL); |
|
215 switch (input_mode) { |
|
216 case DONT_CARE: |
|
217 case MWM_INPUT_MODELESS: |
|
218 grab_kind = XtGrabNonexclusive; break; |
|
219 case MWM_INPUT_PRIMARY_APPLICATION_MODAL: |
|
220 case MWM_INPUT_SYSTEM_MODAL: |
|
221 case MWM_INPUT_FULL_APPLICATION_MODAL: |
|
222 grab_kind = XtGrabExclusive; break; |
|
223 } |
|
224 } |
|
225 |
|
226 if (grab_kind == XtGrabExclusive) { |
|
227 /* |
|
228 * We should cancel the drag on the toolkit thread. Otherwise, it can be |
|
229 * called while the toolkit thread is waiting inside some drag callback. |
|
230 * In this case Motif will crash when the drag callback returns. |
|
231 */ |
|
232 XtAppAddTimeOut(awt_appContext, 0L, cancel_drag, NULL); |
|
233 } |
|
234 } |
|
235 |
|
236 static XtInitProc xt_shell_initialize = NULL; |
|
237 |
|
238 static void |
|
239 awt_ShellInitialize(Widget req, Widget new, ArgList args, Cardinal *num_args) { |
|
240 XtAddCallback(new, XtNpopupCallback, awt_popupCallback, NULL); |
|
241 (*xt_shell_initialize)(req, new, args, num_args); |
|
242 } |
|
243 |
|
244 /* |
|
245 * Fix for 4484572 (copied from awt_XmDnD.c). |
|
246 * Modify the 'initialize' routine for all ShellWidget instances, so that it |
|
247 * will install an XtNpopupCallback that cancels the current drag operation. |
|
248 * It is needed, since AWT doesn't have full control over all ShellWidget |
|
249 * instances (e.g. XmPopupMenu internally creates and popups an XmMenuShell). |
|
250 */ |
|
251 static void |
|
252 awt_set_ShellInitialize() { |
|
253 static Boolean inited = False; |
|
254 |
|
255 DASSERT(!inited); |
|
256 if (inited) { |
|
257 return; |
|
258 } |
|
259 |
|
260 xt_shell_initialize = shellWidgetClass->core_class.initialize; |
|
261 shellWidgetClass->core_class.initialize = (XtInitProc)awt_ShellInitialize; |
|
262 inited = True; |
|
263 } |
|
264 |
|
265 /* |
|
266 * Returns True if initialization completes successfully. |
|
267 */ |
|
268 Boolean |
|
269 awt_dnd_ds_init(Display* display) { |
|
270 if (XSaveContext(display, XA_XdndSelection, awt_convertDataContext, |
|
271 (XPointer)NULL) == XCNOMEM) { |
|
272 return False; |
|
273 } |
|
274 |
|
275 if (XSaveContext(display, _XA_MOTIF_ATOM_0, awt_convertDataContext, |
|
276 (XPointer)NULL) == XCNOMEM) { |
|
277 return False; |
|
278 } |
|
279 |
|
280 { |
|
281 char *ev = getenv("_JAVA_DRAG_SOURCE_POLICY"); |
|
282 |
|
283 /* By default XDnD protocol is preferred. */ |
|
284 drag_source_policy = DS_POLICY_PREFER_XDND; |
|
285 |
|
286 if (ev != NULL) { |
|
287 if (strcmp(ev, "PREFER_XDND") == 0) { |
|
288 drag_source_policy = DS_POLICY_PREFER_XDND; |
|
289 } else if (strcmp(ev, "PREFER_MOTIF") == 0) { |
|
290 drag_source_policy = DS_POLICY_PREFER_MOTIF; |
|
291 } else if (strcmp(ev, "ONLY_MOTIF") == 0) { |
|
292 drag_source_policy = DS_POLICY_ONLY_MOTIF; |
|
293 } else if (strcmp(ev, "ONLY_XDND") == 0) { |
|
294 drag_source_policy = DS_POLICY_ONLY_XDND; |
|
295 } |
|
296 } |
|
297 } |
|
298 |
|
299 awt_set_ShellInitialize(); |
|
300 |
|
301 return True; |
|
302 } |
|
303 |
|
304 /* |
|
305 * Returns a handle of the window used as a drag source. |
|
306 */ |
|
307 Window |
|
308 awt_dnd_ds_get_source_window() { |
|
309 return get_awt_root_window(); |
|
310 } |
|
311 |
|
312 /* |
|
313 * Returns True if a drag operation initiated by this client |
|
314 * is still in progress. |
|
315 */ |
|
316 Boolean |
|
317 awt_dnd_ds_in_progress() { |
|
318 return dnd_in_progress; |
|
319 } |
|
320 |
|
321 static void |
|
322 ds_send_event_to_target(XClientMessageEvent* xclient) { |
|
323 /* Shortcut if the source is in the same JVM. */ |
|
324 if (XtWindowToWidget(xclient->display, target_proxy_window) != NULL) { |
|
325 awt_dnd_dt_process_event((XEvent*)xclient); |
|
326 } else { |
|
327 XSendEvent(xclient->display, target_proxy_window, False, NoEventMask, |
|
328 (XEvent*)xclient); |
|
329 } |
|
330 } |
|
331 |
|
332 static void |
|
333 xdnd_send_enter(Display* dpy, Time time) { |
|
334 XClientMessageEvent enter; |
|
335 |
|
336 enter.display = dpy; |
|
337 enter.type = ClientMessage; |
|
338 enter.window = target_window; |
|
339 enter.format = 32; |
|
340 enter.message_type = XA_XdndEnter; |
|
341 enter.data.l[0] = awt_dnd_ds_get_source_window(); |
|
342 enter.data.l[1] = target_protocol_version << XDND_PROTOCOL_SHIFT; |
|
343 enter.data.l[1] |= data_types_count > 3 ? XDND_DATA_TYPES_BIT : 0; |
|
344 enter.data.l[2] = data_types_count > 0 ? data_types[0] : None; |
|
345 enter.data.l[3] = data_types_count > 1 ? data_types[1] : None; |
|
346 enter.data.l[4] = data_types_count > 2 ? data_types[2] : None; |
|
347 |
|
348 ds_send_event_to_target(&enter); |
|
349 } |
|
350 |
|
351 static void |
|
352 motif_send_enter(Display* dpy, Time time) { |
|
353 XClientMessageEvent enter; |
|
354 |
|
355 enter.display = dpy; |
|
356 enter.type = ClientMessage; |
|
357 enter.window = target_window; |
|
358 enter.format = 8; |
|
359 enter.message_type = _XA_MOTIF_DRAG_AND_DROP_MESSAGE; |
|
360 |
|
361 { |
|
362 void* p = &enter.data.b[0]; |
|
363 int flags = 0; |
|
364 |
|
365 flags |= java_to_motif_actions(source_action) << MOTIF_DND_ACTION_SHIFT; |
|
366 flags |= java_to_motif_actions(source_actions) << MOTIF_DND_ACTIONS_SHIFT; |
|
367 |
|
368 write_card8(&p, TOP_LEVEL_ENTER | MOTIF_MESSAGE_FROM_INITIATOR); |
|
369 write_card8(&p, MOTIF_BYTE_ORDER); |
|
370 write_card16(&p, flags); |
|
371 write_card32(&p, time); |
|
372 write_card32(&p, awt_dnd_ds_get_source_window()); |
|
373 write_card32(&p, _XA_MOTIF_ATOM_0); |
|
374 } |
|
375 |
|
376 ds_send_event_to_target(&enter); |
|
377 } |
|
378 |
|
379 static void |
|
380 send_enter(Display* dpy, Time time) { |
|
381 switch (target_protocol) { |
|
382 case XDND_PROTOCOL: |
|
383 xdnd_send_enter(dpy, time); |
|
384 break; |
|
385 case MOTIF_DND_PROTOCOL: |
|
386 motif_send_enter(dpy, time); |
|
387 break; |
|
388 case NO_PROTOCOL: |
|
389 default: |
|
390 DTRACE_PRINTLN2("%s:%d send_enter: unknown DnD protocol.", __FILE__, __LINE__); |
|
391 break; |
|
392 } |
|
393 } |
|
394 |
|
395 static void |
|
396 xdnd_send_move(XMotionEvent* event) { |
|
397 XClientMessageEvent move; |
|
398 |
|
399 move.display = event->display; |
|
400 move.type = ClientMessage; |
|
401 move.window = target_window; |
|
402 move.format = 32; |
|
403 move.message_type = XA_XdndPosition; |
|
404 move.data.l[0] = awt_dnd_ds_get_source_window(); |
|
405 move.data.l[1] = 0; /* flags */ |
|
406 move.data.l[2] = event->x_root << 16 | event->y_root; |
|
407 move.data.l[3] = event->time; |
|
408 move.data.l[4] = java_to_xdnd_action(source_action); |
|
409 |
|
410 ds_send_event_to_target(&move); |
|
411 } |
|
412 |
|
413 static void |
|
414 motif_send_move(XMotionEvent* event) { |
|
415 XClientMessageEvent move; |
|
416 |
|
417 move.display = event->display; |
|
418 move.type = ClientMessage; |
|
419 move.window = target_window; |
|
420 move.format = 8; |
|
421 move.message_type = _XA_MOTIF_DRAG_AND_DROP_MESSAGE; |
|
422 |
|
423 { |
|
424 void* p = move.data.b; |
|
425 int flags = 0; |
|
426 |
|
427 flags |= java_to_motif_actions(source_action) << MOTIF_DND_ACTION_SHIFT; |
|
428 flags |= java_to_motif_actions(source_actions) << MOTIF_DND_ACTIONS_SHIFT; |
|
429 |
|
430 write_card8(&p, DRAG_MOTION | MOTIF_MESSAGE_FROM_INITIATOR); |
|
431 write_card8(&p, MOTIF_BYTE_ORDER); |
|
432 write_card16(&p, flags); |
|
433 write_card32(&p, event->time); |
|
434 write_card16(&p, event->x_root); |
|
435 write_card16(&p, event->y_root); |
|
436 } |
|
437 |
|
438 ds_send_event_to_target(&move); |
|
439 } |
|
440 |
|
441 static void |
|
442 send_move(XMotionEvent* event) { |
|
443 switch (target_protocol) { |
|
444 case XDND_PROTOCOL: |
|
445 xdnd_send_move(event); |
|
446 break; |
|
447 case MOTIF_DND_PROTOCOL: |
|
448 motif_send_move(event); |
|
449 break; |
|
450 case NO_PROTOCOL: |
|
451 default: |
|
452 DTRACE_PRINTLN2("%s:%d send_move: unknown DnD protocol.", __FILE__, __LINE__); |
|
453 break; |
|
454 } |
|
455 } |
|
456 |
|
457 static void |
|
458 xdnd_send_leave(Display* dpy, Time time) { |
|
459 XClientMessageEvent leave; |
|
460 |
|
461 leave.display = dpy; |
|
462 leave.type = ClientMessage; |
|
463 leave.window = target_window; |
|
464 leave.format = 32; |
|
465 leave.message_type = XA_XdndLeave; |
|
466 leave.data.l[0] = awt_dnd_ds_get_source_window(); |
|
467 leave.data.l[1] = 0; |
|
468 leave.data.l[2] = 0; |
|
469 leave.data.l[3] = 0; |
|
470 leave.data.l[4] = 0; |
|
471 |
|
472 ds_send_event_to_target(&leave); |
|
473 } |
|
474 |
|
475 static void |
|
476 motif_send_leave(Display* dpy, Time time) { |
|
477 XClientMessageEvent leave; |
|
478 |
|
479 leave.display = dpy; |
|
480 leave.type = ClientMessage; |
|
481 leave.window = target_window; |
|
482 leave.format = 8; |
|
483 leave.message_type = _XA_MOTIF_DRAG_AND_DROP_MESSAGE; |
|
484 |
|
485 { |
|
486 void* p = &leave.data.b[0]; |
|
487 |
|
488 write_card8(&p, TOP_LEVEL_LEAVE | MOTIF_MESSAGE_FROM_INITIATOR); |
|
489 write_card8(&p, MOTIF_BYTE_ORDER); |
|
490 write_card16(&p, 0); |
|
491 write_card32(&p, time); |
|
492 write_card32(&p, awt_dnd_ds_get_source_window()); |
|
493 } |
|
494 |
|
495 ds_send_event_to_target(&leave); |
|
496 } |
|
497 |
|
498 static void |
|
499 send_leave(Display* dpy, Time time) { |
|
500 switch (target_protocol) { |
|
501 case XDND_PROTOCOL: |
|
502 xdnd_send_leave(dpy, time); |
|
503 break; |
|
504 case MOTIF_DND_PROTOCOL: |
|
505 motif_send_leave(dpy, time); |
|
506 break; |
|
507 case NO_PROTOCOL: |
|
508 default: |
|
509 DTRACE_PRINTLN2("%s:%d send_leave: unknown DnD protocol.", __FILE__, __LINE__); |
|
510 break; |
|
511 } |
|
512 } |
|
513 |
|
514 |
|
515 static void |
|
516 xdnd_send_drop(XButtonEvent* event) { |
|
517 XClientMessageEvent drop; |
|
518 |
|
519 drop.display = event->display; |
|
520 drop.type = ClientMessage; |
|
521 drop.window = target_window; |
|
522 drop.format = 32; |
|
523 drop.message_type = XA_XdndDrop; |
|
524 drop.data.l[0] = awt_dnd_ds_get_source_window(); |
|
525 drop.data.l[1] = 0; /* flags */ |
|
526 drop.data.l[2] = event->time; /* ### */ |
|
527 drop.data.l[3] = 0; |
|
528 drop.data.l[4] = 0; |
|
529 |
|
530 ds_send_event_to_target(&drop); |
|
531 } |
|
532 |
|
533 static void |
|
534 motif_send_drop(XButtonEvent* event) { |
|
535 XClientMessageEvent drop; |
|
536 |
|
537 /* |
|
538 * Motif drop sites expect TOP_LEVEL_LEAVE before DROP_START. |
|
539 */ |
|
540 motif_send_leave(event->display, event->time); |
|
541 |
|
542 drop.display = event->display; |
|
543 drop.type = ClientMessage; |
|
544 drop.window = target_window; |
|
545 drop.format = 8; |
|
546 drop.message_type = _XA_MOTIF_DRAG_AND_DROP_MESSAGE; |
|
547 |
|
548 { |
|
549 void* p = &drop.data.b[0]; |
|
550 int flags = 0; |
|
551 |
|
552 flags |= java_to_motif_actions(source_action) << MOTIF_DND_ACTION_SHIFT; |
|
553 flags |= java_to_motif_actions(source_actions) << MOTIF_DND_ACTIONS_SHIFT; |
|
554 |
|
555 write_card8(&p, DROP_START | MOTIF_MESSAGE_FROM_INITIATOR); |
|
556 write_card8(&p, MOTIF_BYTE_ORDER); |
|
557 write_card16(&p, flags); |
|
558 write_card32(&p, event->time); |
|
559 write_card16(&p, event->x_root); |
|
560 write_card16(&p, event->y_root); |
|
561 write_card32(&p, _XA_MOTIF_ATOM_0); |
|
562 write_card32(&p, awt_dnd_ds_get_source_window()); |
|
563 } |
|
564 |
|
565 ds_send_event_to_target(&drop); |
|
566 } |
|
567 |
|
568 static void |
|
569 send_drop(XButtonEvent* event) { |
|
570 switch (target_protocol) { |
|
571 case XDND_PROTOCOL: |
|
572 xdnd_send_drop(event); |
|
573 break; |
|
574 case MOTIF_DND_PROTOCOL: |
|
575 motif_send_drop(event); |
|
576 break; |
|
577 case NO_PROTOCOL: |
|
578 default: |
|
579 DTRACE_PRINTLN2("%s:%d send_drop: unknown DnD protocol.", __FILE__, __LINE__); |
|
580 break; |
|
581 } |
|
582 } |
|
583 |
|
584 static void |
|
585 remove_dnd_grab(Display* dpy, Time time) { |
|
586 XUngrabPointer(dpy, time); |
|
587 XUngrabKeyboard(dpy, time); |
|
588 |
|
589 /* Restore the root event mask if it was changed. */ |
|
590 if ((your_root_event_mask | ROOT_EVENT_MASK) != your_root_event_mask && |
|
591 drag_root_window != None) { |
|
592 |
|
593 XSelectInput(dpy, drag_root_window, your_root_event_mask); |
|
594 |
|
595 drag_root_window = None; |
|
596 your_root_event_mask = NoEventMask; |
|
597 } |
|
598 } |
|
599 |
|
600 static void |
|
601 cleanup_target_info(Display* dpy) { |
|
602 target_root_subwindow = None; |
|
603 |
|
604 target_window = None; |
|
605 target_proxy_window = None; |
|
606 target_protocol = NO_PROTOCOL; |
|
607 target_protocol_version = 0; |
|
608 target_enter_server_time = CurrentTime; |
|
609 target_action = java_awt_dnd_DnDConstants_ACTION_NONE; |
|
610 } |
|
611 |
|
612 static void |
|
613 cleanup_drag(Display* dpy, Time time) { |
|
614 JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4); |
|
615 |
|
616 if (dnd_in_progress) { |
|
617 if (target_window != None) { |
|
618 send_leave(dpy, time); |
|
619 } |
|
620 |
|
621 if (target_action != java_awt_dnd_DnDConstants_ACTION_NONE) { |
|
622 JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4); |
|
623 ds_postDragSourceEvent(env, x_root, y_root); |
|
624 } |
|
625 |
|
626 ds_postDragSourceDropEvent(env, JNI_FALSE, |
|
627 java_awt_dnd_DnDConstants_ACTION_NONE, |
|
628 x_root, y_root); |
|
629 } |
|
630 |
|
631 /* Cleanup the global state */ |
|
632 dnd_in_progress = False; |
|
633 drag_in_progress = False; |
|
634 data_types_count = 0; |
|
635 if (data_types != NULL) { |
|
636 free(data_types); |
|
637 data_types = NULL; |
|
638 } |
|
639 if (!JNU_IsNull(env, source_peer)) { |
|
640 (*env)->DeleteGlobalRef(env, source_peer); |
|
641 source_peer = NULL; |
|
642 } |
|
643 |
|
644 cleanup_target_info(dpy); |
|
645 |
|
646 remove_dnd_grab(dpy, time); |
|
647 |
|
648 XDeleteProperty(awt_display, awt_dnd_ds_get_source_window(), _XA_MOTIF_ATOM_0); |
|
649 XDeleteProperty(awt_display, awt_dnd_ds_get_source_window(), XA_XdndTypeList); |
|
650 XDeleteProperty(awt_display, awt_dnd_ds_get_source_window(), XA_XdndActionList); |
|
651 XtDisownSelection(awt_root_shell, _XA_MOTIF_ATOM_0, time); |
|
652 XtDisownSelection(awt_root_shell, XA_XdndSelection, time); |
|
653 |
|
654 awt_cleanupConvertDataContext(env, _XA_MOTIF_ATOM_0); |
|
655 awt_cleanupConvertDataContext(env, XA_XdndSelection); |
|
656 } |
|
657 |
|
658 static void |
|
659 process_drop(XButtonEvent* event) { |
|
660 unsigned char ret; |
|
661 XWindowAttributes xwa; |
|
662 |
|
663 DASSERT(target_window != None); |
|
664 |
|
665 XGetWindowAttributes(event->display, target_window, &xwa); |
|
666 |
|
667 target_window_mask = xwa.your_event_mask; |
|
668 |
|
669 /* Select for DestoyNotify to cleanup if the target crashes. */ |
|
670 ret = checked_XSelectInput(event->display, target_window, |
|
671 (target_window_mask | StructureNotifyMask)); |
|
672 |
|
673 if (ret == Success) { |
|
674 send_drop(event); |
|
675 } else { |
|
676 DTRACE_PRINTLN2("%s:%d drop rejected - invalid window.", |
|
677 __FILE__, __LINE__); |
|
678 cleanup_drag(event->display, event->time); |
|
679 } |
|
680 } |
|
681 |
|
682 static Window |
|
683 find_client_window(Display* dpy, Window window) { |
|
684 Window root, parent, *children; |
|
685 unsigned int nchildren, idx; |
|
686 |
|
687 Atom type; |
|
688 int format; |
|
689 unsigned long nitems; |
|
690 unsigned long after; |
|
691 unsigned char *data; |
|
692 Status ret; |
|
693 |
|
694 if (XGetWindowProperty(dpy, window, XA_WM_STATE, 0, 0, False, |
|
695 AnyPropertyType, &type, &format, &nitems, |
|
696 &after, &data) == Success) { |
|
697 XFree(data); |
|
698 } |
|
699 |
|
700 if (type != None) { |
|
701 return window; |
|
702 } |
|
703 |
|
704 if (!XQueryTree(dpy, window, &root, &parent, &children, &nchildren)) { |
|
705 return None; |
|
706 } |
|
707 |
|
708 if (children == NULL) { |
|
709 return None; |
|
710 } |
|
711 |
|
712 for (idx = 0; idx < nchildren; idx++) { |
|
713 Window win = find_client_window(dpy, children[idx]); |
|
714 if (win != None) { |
|
715 XFree(children); |
|
716 return win; |
|
717 } |
|
718 } |
|
719 |
|
720 XFree(children); |
|
721 return None; |
|
722 } |
|
723 |
|
724 static void |
|
725 do_update_target_window(Display* dpy, Window subwindow, Time time) { |
|
726 Window client_window = None; |
|
727 Window proxy_window = None; |
|
728 Protocol protocol = NO_PROTOCOL; |
|
729 unsigned int protocol_version = 0; |
|
730 Boolean is_receiver = False; |
|
731 |
|
732 client_window = find_client_window(dpy, subwindow); |
|
733 |
|
734 if (client_window != None) { |
|
735 /* Request status */ |
|
736 int status; |
|
737 |
|
738 /* Returns of XGetWindowProperty */ |
|
739 Atom type; |
|
740 int format; |
|
741 unsigned long nitems; |
|
742 unsigned long after; |
|
743 unsigned char *data; |
|
744 |
|
745 /* |
|
746 * No need for checked_XGetWindowProperty, since we check the returned |
|
747 * property type anyway. |
|
748 */ |
|
749 if (drag_source_policy != DS_POLICY_ONLY_XDND) { |
|
750 |
|
751 data = NULL; |
|
752 status = XGetWindowProperty(dpy, client_window, |
|
753 _XA_MOTIF_DRAG_RECEIVER_INFO, |
|
754 0, 0xFFFF, False, AnyPropertyType, |
|
755 &type, &format, &nitems, &after, &data); |
|
756 |
|
757 if (status == Success && data != NULL && type != None && format == 8 |
|
758 && nitems >= MOTIF_RECEIVER_INFO_SIZE) { |
|
759 unsigned char byte_order = read_card8((char*)data, 0); |
|
760 unsigned char drag_protocol_style = read_card8((char*)data, 2); |
|
761 |
|
762 switch (drag_protocol_style) { |
|
763 case MOTIF_PREFER_PREREGISTER_STYLE : |
|
764 case MOTIF_PREFER_DYNAMIC_STYLE : |
|
765 case MOTIF_DYNAMIC_STYLE : |
|
766 case MOTIF_PREFER_RECEIVER_STYLE : |
|
767 proxy_window = read_card32((char*)data, 4, byte_order); |
|
768 protocol = MOTIF_DND_PROTOCOL; |
|
769 protocol_version = read_card8((char*)data, 1); |
|
770 is_receiver = True; |
|
771 break; |
|
772 default: |
|
773 DTRACE_PRINTLN3("%s:%d unsupported protocol style (%d).", |
|
774 __FILE__, __LINE__, (int)drag_protocol_style); |
|
775 } |
|
776 } |
|
777 |
|
778 if (status == Success) { |
|
779 XFree(data); |
|
780 data = NULL; |
|
781 } |
|
782 } |
|
783 |
|
784 if (drag_source_policy != DS_POLICY_ONLY_MOTIF && |
|
785 (drag_source_policy != DS_POLICY_PREFER_MOTIF || !is_receiver)) { |
|
786 |
|
787 data = NULL; |
|
788 status = XGetWindowProperty(dpy, client_window, XA_XdndAware, 0, 1, |
|
789 False, AnyPropertyType, &type, &format, |
|
790 &nitems, &after, &data); |
|
791 |
|
792 if (status == Success && data != NULL && type == XA_ATOM) { |
|
793 unsigned int target_version = *((unsigned int*)data); |
|
794 |
|
795 if (target_version >= XDND_MIN_PROTOCOL_VERSION) { |
|
796 proxy_window = None; |
|
797 protocol = XDND_PROTOCOL; |
|
798 protocol_version = target_version < XDND_PROTOCOL_VERSION ? |
|
799 target_version : XDND_PROTOCOL_VERSION; |
|
800 is_receiver = True; |
|
801 } |
|
802 } |
|
803 |
|
804 /* Retrieve the proxy window handle and check if it is valid. */ |
|
805 if (protocol == XDND_PROTOCOL) { |
|
806 if (status == Success) { |
|
807 XFree(data); |
|
808 } |
|
809 |
|
810 data = NULL; |
|
811 status = XGetWindowProperty(dpy, client_window, XA_XdndProxy, 0, |
|
812 1, False, XA_WINDOW, &type, &format, |
|
813 &nitems, &after, &data); |
|
814 |
|
815 if (status == Success && data != NULL && type == XA_WINDOW) { |
|
816 proxy_window = *((Window*)data); |
|
817 } |
|
818 |
|
819 if (proxy_window != None) { |
|
820 if (status == Success) { |
|
821 XFree(data); |
|
822 } |
|
823 |
|
824 data = NULL; |
|
825 status = XGetWindowProperty(dpy, proxy_window, XA_XdndProxy, |
|
826 0, 1, False, XA_WINDOW, &type, |
|
827 &format, &nitems, &after, &data); |
|
828 |
|
829 if (status != Success || data == NULL || type != XA_WINDOW || |
|
830 *((Window*)data) != proxy_window) { |
|
831 proxy_window = None; |
|
832 } else { |
|
833 if (status == Success) { |
|
834 XFree(data); |
|
835 } |
|
836 |
|
837 data = NULL; |
|
838 status = XGetWindowProperty(dpy, proxy_window, |
|
839 XA_XdndAware, 0, 1, False, |
|
840 AnyPropertyType, &type, |
|
841 &format, &nitems, &after, |
|
842 &data); |
|
843 |
|
844 if (status != Success || data == NULL || type != XA_ATOM) { |
|
845 proxy_window = None; |
|
846 } |
|
847 } |
|
848 } |
|
849 } |
|
850 |
|
851 XFree(data); |
|
852 } |
|
853 |
|
854 if (proxy_window == None) { |
|
855 proxy_window = client_window; |
|
856 } |
|
857 } |
|
858 |
|
859 if (is_receiver) { |
|
860 target_window = client_window; |
|
861 target_proxy_window = proxy_window; |
|
862 target_protocol = protocol; |
|
863 target_protocol_version = protocol_version; |
|
864 } else { |
|
865 target_window = None; |
|
866 target_proxy_window = None; |
|
867 target_protocol = NO_PROTOCOL; |
|
868 target_protocol_version = 0; |
|
869 } |
|
870 |
|
871 target_action = java_awt_dnd_DnDConstants_ACTION_NONE; |
|
872 |
|
873 if (target_window != None) { |
|
874 target_enter_server_time = time; |
|
875 } else { |
|
876 target_enter_server_time = CurrentTime; |
|
877 } |
|
878 |
|
879 target_root_subwindow = subwindow; |
|
880 } |
|
881 |
|
882 static void |
|
883 update_target_window(XMotionEvent* event) { |
|
884 Display* dpy = event->display; |
|
885 int x = event->x_root; |
|
886 int y = event->x_root; |
|
887 Time time = event->time; |
|
888 Window subwindow = event->subwindow; |
|
889 |
|
890 /* |
|
891 * If this event had occurred before the pointer was grabbed, |
|
892 * query the server for the current root subwindow. |
|
893 */ |
|
894 if (event->window != event->root) { |
|
895 int xw, yw, xr, yr; |
|
896 unsigned int modifiers; |
|
897 XQueryPointer(dpy, event->root, &event->root, &subwindow, |
|
898 &xr, &yr, &xw, &yw, &modifiers); |
|
899 } |
|
900 |
|
901 if (target_root_subwindow != subwindow) { |
|
902 if (target_window != None) { |
|
903 send_leave(dpy, time); |
|
904 |
|
905 /* |
|
906 * Neither Motif DnD nor XDnD provide a mean for the target |
|
907 * to notify the source that the pointer exits the drop site |
|
908 * that occupies the whole top level. |
|
909 * We detect this situation and post dragExit. |
|
910 */ |
|
911 if (target_action != java_awt_dnd_DnDConstants_ACTION_NONE) { |
|
912 JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4); |
|
913 ds_postDragSourceEvent(env, x, y); |
|
914 } |
|
915 } |
|
916 |
|
917 /* Update the global state. */ |
|
918 do_update_target_window(dpy, subwindow, time); |
|
919 |
|
920 if (target_window != None) { |
|
921 send_enter(dpy, time); |
|
922 } |
|
923 } |
|
924 } |
|
925 |
|
926 /* |
|
927 * Updates the source action based on the specified event state. |
|
928 * Returns True if source action changed, False otherwise. |
|
929 */ |
|
930 static Boolean |
|
931 update_source_action(unsigned int state) { |
|
932 JNIEnv* env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4); |
|
933 jint action = ds_convertModifiersToDropAction(env, state); |
|
934 if (source_action == action) { |
|
935 return False; |
|
936 } |
|
937 source_action = action; |
|
938 return True; |
|
939 } |
|
940 |
|
941 static void |
|
942 handle_mouse_move(XMotionEvent* event) { |
|
943 if (!drag_in_progress) { |
|
944 return; |
|
945 } |
|
946 |
|
947 if (x_root != event->x_root || y_root != event->y_root) { |
|
948 JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4); |
|
949 ds_postDragSourceDragEvent(env, target_action, event->state, |
|
950 event->x_root, event->y_root, |
|
951 sun_awt_dnd_SunDragSourceContextPeer_DISPATCH_MOUSE_MOVED); |
|
952 |
|
953 x_root = event->x_root; |
|
954 y_root = event->y_root; |
|
955 } |
|
956 |
|
957 if (event_state != event->state) { |
|
958 if (update_source_action(event->state) && target_window != None) { |
|
959 JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4); |
|
960 ds_postDragSourceDragEvent(env, target_action, event->state, |
|
961 event->x_root, event->y_root, |
|
962 sun_awt_dnd_SunDragSourceContextPeer_DISPATCH_CHANGED); |
|
963 } |
|
964 event_state = event->state; |
|
965 } |
|
966 |
|
967 update_target_window(event); |
|
968 |
|
969 if (target_window != None) { |
|
970 send_move(event); |
|
971 } |
|
972 } |
|
973 |
|
974 static Boolean |
|
975 handle_xdnd_status(XClientMessageEvent* event) { |
|
976 JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4); |
|
977 long* event_data = event->data.l; |
|
978 Window target_win = None; |
|
979 jint action = java_awt_dnd_DnDConstants_ACTION_NONE; |
|
980 |
|
981 DTRACE_PRINTLN4("%s:%d XdndStatus target_window=%ld target_protocol=%d.", |
|
982 __FILE__, __LINE__, target_window, target_protocol); |
|
983 |
|
984 if (target_protocol != XDND_PROTOCOL) { |
|
985 DTRACE_PRINTLN2("%s:%d XdndStatus rejected - invalid state.", |
|
986 __FILE__, __LINE__); |
|
987 return True; |
|
988 } |
|
989 |
|
990 target_win = event_data[0]; |
|
991 |
|
992 /* Ignore XDnD messages from all other windows. */ |
|
993 if (target_window != target_win) { |
|
994 DTRACE_PRINTLN4("%s:%d XdndStatus rejected - invalid target window cur=%ld this=%ld.", |
|
995 __FILE__, __LINE__, target_window, target_win); |
|
996 return True; |
|
997 } |
|
998 |
|
999 if (event_data[1] & XDND_ACCEPT_DROP_FLAG) { |
|
1000 /* This feature is new in XDnD version 2, but we can use it as XDnD |
|
1001 compliance only requires supporting version 3 and up. */ |
|
1002 action = xdnd_to_java_action(event_data[4]); |
|
1003 } |
|
1004 |
|
1005 if (action == java_awt_dnd_DnDConstants_ACTION_NONE && |
|
1006 target_action != java_awt_dnd_DnDConstants_ACTION_NONE) { |
|
1007 ds_postDragSourceEvent(env, x_root, y_root); |
|
1008 } else if (action != java_awt_dnd_DnDConstants_ACTION_NONE) { |
|
1009 jint type = 0; |
|
1010 |
|
1011 if (target_action == java_awt_dnd_DnDConstants_ACTION_NONE) { |
|
1012 type = sun_awt_dnd_SunDragSourceContextPeer_DISPATCH_ENTER; |
|
1013 } else { |
|
1014 type = sun_awt_dnd_SunDragSourceContextPeer_DISPATCH_MOTION; |
|
1015 } |
|
1016 |
|
1017 ds_postDragSourceDragEvent(env, action, event_state, |
|
1018 x_root, y_root, type); |
|
1019 } |
|
1020 |
|
1021 target_action = action; |
|
1022 |
|
1023 return True; |
|
1024 } |
|
1025 |
|
1026 static Boolean |
|
1027 handle_xdnd_finished(XClientMessageEvent* event) { |
|
1028 JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4); |
|
1029 long* event_data = event->data.l; |
|
1030 Window target_win = None; |
|
1031 jboolean success = JNI_TRUE; |
|
1032 jint action = java_awt_dnd_DnDConstants_ACTION_NONE; |
|
1033 |
|
1034 if (target_protocol != XDND_PROTOCOL) { |
|
1035 DTRACE_PRINTLN2("%s:%d XdndStatus rejected - invalid state.", |
|
1036 __FILE__, __LINE__); |
|
1037 return True; |
|
1038 } |
|
1039 |
|
1040 target_win = event_data[0]; |
|
1041 |
|
1042 /* Ignore XDnD messages from all other windows. */ |
|
1043 if (target_window != target_win) { |
|
1044 DTRACE_PRINTLN4("%s:%d XdndStatus rejected - invalid target window cur=%ld this=%ld.", |
|
1045 __FILE__, __LINE__, target_window, target_win); |
|
1046 return True; |
|
1047 } |
|
1048 |
|
1049 if (target_protocol_version >= 5) { |
|
1050 success = (event_data[1] & XDND_ACCEPT_DROP_FLAG) != 0 ? |
|
1051 JNI_TRUE : JNI_FALSE; |
|
1052 action = xdnd_to_java_action(event_data[2]); |
|
1053 } else { |
|
1054 /* Assume that the drop was successful and the performed drop action is |
|
1055 the drop action accepted with the latest XdndStatus message. */ |
|
1056 success = JNI_TRUE; |
|
1057 action = target_action; |
|
1058 } |
|
1059 |
|
1060 ds_postDragSourceDropEvent(env, success, action, x_root, y_root); |
|
1061 |
|
1062 dnd_in_progress = False; |
|
1063 |
|
1064 XSelectInput(event->display, target_win, target_window_mask); |
|
1065 |
|
1066 cleanup_drag(event->display, CurrentTime); |
|
1067 |
|
1068 return True; |
|
1069 } |
|
1070 |
|
1071 static Boolean |
|
1072 handle_motif_client_message(XClientMessageEvent* event) { |
|
1073 JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4); |
|
1074 int reason = (int)(event->data.b[0] & MOTIF_MESSAGE_REASON_MASK); |
|
1075 int origin = (int)(event->data.b[0] & MOTIF_MESSAGE_SENDER_MASK); |
|
1076 unsigned char byte_order = event->data.b[1]; |
|
1077 jint action = java_awt_dnd_DnDConstants_ACTION_NONE; |
|
1078 Time time = CurrentTime; |
|
1079 int x = 0, y = 0; |
|
1080 |
|
1081 /* Only receiver messages should be handled. */ |
|
1082 if (origin != MOTIF_MESSAGE_FROM_RECEIVER) { |
|
1083 return False; |
|
1084 } |
|
1085 |
|
1086 if (target_protocol != MOTIF_DND_PROTOCOL) { |
|
1087 DTRACE_PRINTLN2("%s:%d _MOTIF_DRAG_AND_DROP_MESSAGE rejected - invalid state.", |
|
1088 __FILE__, __LINE__); |
|
1089 return True; |
|
1090 } |
|
1091 |
|
1092 switch (reason) { |
|
1093 case DROP_SITE_ENTER: |
|
1094 case DROP_SITE_LEAVE: |
|
1095 case DRAG_MOTION: |
|
1096 case OPERATION_CHANGED: |
|
1097 break; |
|
1098 default: |
|
1099 return False; |
|
1100 } |
|
1101 |
|
1102 time = read_card32(event->data.b, 4, byte_order); |
|
1103 |
|
1104 /* Discard events from the previous receiver. */ |
|
1105 if (target_enter_server_time == CurrentTime || |
|
1106 time < target_enter_server_time) { |
|
1107 DTRACE_PRINTLN2("%s:%d _MOTIF_DRAG_AND_DROP_MESSAGE rejected - invalid time.", |
|
1108 __FILE__, __LINE__); |
|
1109 return True; |
|
1110 } |
|
1111 |
|
1112 if (reason != DROP_SITE_LEAVE) { |
|
1113 CARD16 flags = read_card16(event->data.b, 2, byte_order); |
|
1114 unsigned char status = (flags & MOTIF_DND_STATUS_MASK) >> |
|
1115 MOTIF_DND_STATUS_SHIFT; |
|
1116 unsigned char motif_action = (flags & MOTIF_DND_ACTION_MASK) >> |
|
1117 MOTIF_DND_ACTION_SHIFT; |
|
1118 |
|
1119 if (status == MOTIF_VALID_DROP_SITE) { |
|
1120 action = motif_to_java_actions(motif_action); |
|
1121 } else { |
|
1122 action = java_awt_dnd_DnDConstants_ACTION_NONE; |
|
1123 } |
|
1124 |
|
1125 x = read_card16(event->data.b, 8, byte_order); |
|
1126 y = read_card16(event->data.b, 10, byte_order); |
|
1127 } |
|
1128 |
|
1129 /* |
|
1130 * We should derive the type of java event to post not from the message |
|
1131 * reason, but from the combination of the current and previous target |
|
1132 * actions: |
|
1133 * Even if the reason is DROP_SITE_LEAVE we shouldn't post dragExit |
|
1134 * if the drag was rejected earlier. |
|
1135 * Even if the reason is DROP_SITE_ENTER we shouldn't post dragEnter |
|
1136 * if the drag is not accepted. |
|
1137 */ |
|
1138 if (target_action != java_awt_dnd_DnDConstants_ACTION_NONE && |
|
1139 action == java_awt_dnd_DnDConstants_ACTION_NONE) { |
|
1140 |
|
1141 ds_postDragSourceEvent(env, x, y); |
|
1142 } else if (action != java_awt_dnd_DnDConstants_ACTION_NONE) { |
|
1143 jint type = 0; |
|
1144 |
|
1145 if (target_action == java_awt_dnd_DnDConstants_ACTION_NONE) { |
|
1146 type = sun_awt_dnd_SunDragSourceContextPeer_DISPATCH_ENTER; |
|
1147 } else { |
|
1148 type = sun_awt_dnd_SunDragSourceContextPeer_DISPATCH_MOTION; |
|
1149 } |
|
1150 |
|
1151 ds_postDragSourceDragEvent(env, action, event_state, x, y, type); |
|
1152 } |
|
1153 |
|
1154 target_action = action; |
|
1155 |
|
1156 return True; |
|
1157 } |
|
1158 |
|
1159 /* |
|
1160 * Handles client messages. |
|
1161 * Returns True if the event is processed, False otherwise. |
|
1162 */ |
|
1163 static Boolean |
|
1164 handle_client_message(XClientMessageEvent* event) { |
|
1165 if (event->message_type == XA_XdndStatus) { |
|
1166 return handle_xdnd_status(event); |
|
1167 } else if (event->message_type == XA_XdndFinished) { |
|
1168 return handle_xdnd_finished(event); |
|
1169 } else if (event->message_type == _XA_MOTIF_DRAG_AND_DROP_MESSAGE) { |
|
1170 return handle_motif_client_message(event); |
|
1171 } |
|
1172 return False; |
|
1173 } |
|
1174 |
|
1175 /* |
|
1176 * Similar to XtLastTimestampProcessed(). We cannot use Xt time stamp, as it is |
|
1177 * updated in XtDispatchEvent that may not be called if a java event is |
|
1178 * consumed. This can make Xt time stamp out-of-date and cause XGrab* failures |
|
1179 * with GrabInvalidTime reason. |
|
1180 */ |
|
1181 static Time |
|
1182 get_latest_time_stamp() { |
|
1183 return latest_time_stamp; |
|
1184 } |
|
1185 |
|
1186 static void |
|
1187 update_latest_time_stamp(XEvent* event) { |
|
1188 Time time = latest_time_stamp; |
|
1189 |
|
1190 switch (event->type) { |
|
1191 case KeyPress: |
|
1192 case KeyRelease: time = event->xkey.time; break; |
|
1193 case ButtonPress: |
|
1194 case ButtonRelease: time = event->xbutton.time; break; |
|
1195 case MotionNotify: time = event->xmotion.time; break; |
|
1196 case EnterNotify: |
|
1197 case LeaveNotify: time = event->xcrossing.time; break; |
|
1198 case PropertyNotify: time = event->xproperty.time; break; |
|
1199 case SelectionClear: time = event->xselectionclear.time; break; |
|
1200 } |
|
1201 |
|
1202 latest_time_stamp = time; |
|
1203 } |
|
1204 |
|
1205 Boolean |
|
1206 awt_dnd_ds_process_event(XEvent* event) { |
|
1207 Display* dpy = event->xany.display; |
|
1208 |
|
1209 update_latest_time_stamp(event); |
|
1210 |
|
1211 if (process_proxy_mode_event(event)) { |
|
1212 return True; |
|
1213 } |
|
1214 |
|
1215 if (!dnd_in_progress) { |
|
1216 return False; |
|
1217 } |
|
1218 |
|
1219 /* Process drag and drop messages. */ |
|
1220 switch (event->type) { |
|
1221 case ClientMessage: |
|
1222 return handle_client_message(&event->xclient); |
|
1223 case DestroyNotify: |
|
1224 /* Target crashed during drop processing - cleanup. */ |
|
1225 if (!drag_in_progress && |
|
1226 event->xdestroywindow.window == target_window) { |
|
1227 cleanup_drag(dpy, CurrentTime); |
|
1228 return True; |
|
1229 } |
|
1230 /* Pass along */ |
|
1231 return False; |
|
1232 } |
|
1233 |
|
1234 if (!drag_in_progress) { |
|
1235 return False; |
|
1236 } |
|
1237 |
|
1238 /* Process drag-only messages. */ |
|
1239 switch (event->type) { |
|
1240 case KeyRelease: |
|
1241 case KeyPress: { |
|
1242 KeySym keysym = XKeycodeToKeysym(dpy, event->xkey.keycode, 0); |
|
1243 switch (keysym) { |
|
1244 case XK_Escape: { |
|
1245 if (keysym == XK_Escape) { |
|
1246 remove_dnd_grab(dpy, event->xkey.time); |
|
1247 cleanup_drag(dpy, event->xkey.time); |
|
1248 } |
|
1249 break; |
|
1250 } |
|
1251 case XK_Control_R: |
|
1252 case XK_Control_L: |
|
1253 case XK_Shift_R: |
|
1254 case XK_Shift_L: { |
|
1255 Window subwindow; |
|
1256 int xw, yw, xr, yr; |
|
1257 unsigned int modifiers; |
|
1258 XQueryPointer(event->xkey.display, event->xkey.root, &event->xkey.root, &subwindow, |
|
1259 &xr, &yr, &xw, &yw, &modifiers); |
|
1260 event->xkey.state = modifiers; |
|
1261 //It's safe to use key event as motion event since we use only their common fields. |
|
1262 handle_mouse_move(&event->xmotion); |
|
1263 break; |
|
1264 } |
|
1265 } |
|
1266 return True; |
|
1267 } |
|
1268 case ButtonPress: |
|
1269 return True; |
|
1270 case MotionNotify: |
|
1271 handle_mouse_move(&event->xmotion); |
|
1272 return True; |
|
1273 case ButtonRelease: |
|
1274 /* |
|
1275 * On some X servers it could happen that ButtonRelease coordinates |
|
1276 * differ from the latest MotionNotify coordinates, so we need to |
|
1277 * process it as a mouse motion. |
|
1278 * MotionNotify differs from ButtonRelease only in is_hint member, but |
|
1279 * we never use it, so it is safe to cast to MotionNotify. |
|
1280 */ |
|
1281 handle_mouse_move(&event->xmotion); |
|
1282 if (event->xbutton.button == Button1 || event->xbutton.button == Button2) { |
|
1283 // drag is initiated with Button1 or Button2 pressed and |
|
1284 // ended on release of either of these buttons (as the same |
|
1285 // behavior was with our old Motif DnD-based implementation) |
|
1286 remove_dnd_grab(dpy, event->xbutton.time); |
|
1287 drag_in_progress = False; |
|
1288 if (target_window != None && target_action != java_awt_dnd_DnDConstants_ACTION_NONE) { |
|
1289 /* |
|
1290 * ACTION_NONE indicates that either the drop target rejects the |
|
1291 * drop or it haven't responded yet. The latter could happen in |
|
1292 * case of fast drag, slow target-server connection or slow |
|
1293 * drag notifications processing on the target side. |
|
1294 */ |
|
1295 process_drop(&event->xbutton); |
|
1296 } else { |
|
1297 cleanup_drag(dpy, event->xbutton.time); |
|
1298 } |
|
1299 } |
|
1300 return True; |
|
1301 default: |
|
1302 return False; |
|
1303 } |
|
1304 } |
|
1305 |
|
1306 static Boolean |
|
1307 motif_convert_proc(Widget w, Atom* selection, Atom* target, Atom* type, |
|
1308 XtPointer* value, unsigned long* length, int32_t* format) { |
|
1309 |
|
1310 if (*target == XA_XmTRANSFER_SUCCESS || |
|
1311 *target == XA_XmTRANSFER_FAILURE) { |
|
1312 |
|
1313 JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4); |
|
1314 jboolean success = |
|
1315 (*target == XA_XmTRANSFER_SUCCESS) ? JNI_TRUE : JNI_FALSE; |
|
1316 |
|
1317 ds_postDragSourceDropEvent(env, success, target_action, |
|
1318 x_root, y_root); |
|
1319 |
|
1320 dnd_in_progress = False; |
|
1321 |
|
1322 XSelectInput(XtDisplay(w), target_window, target_window_mask); |
|
1323 |
|
1324 cleanup_drag(XtDisplay(w), CurrentTime); |
|
1325 |
|
1326 *type = *target; |
|
1327 *length = 0; |
|
1328 *format = 32; |
|
1329 *value = NULL; |
|
1330 |
|
1331 return True; |
|
1332 } else { |
|
1333 return awt_convertData(w, selection, target, type, value, length, |
|
1334 format); |
|
1335 } |
|
1336 } |
|
1337 |
|
1338 static Boolean |
|
1339 set_convert_data_context(JNIEnv* env, Display* dpy, XID xid, jobject component, |
|
1340 jobject transferable, jobject formatMap, |
|
1341 jlongArray formats) { |
|
1342 awt_convertDataCallbackStruct* structPtr = NULL; |
|
1343 |
|
1344 if (XFindContext(awt_display, xid, awt_convertDataContext, |
|
1345 (XPointer*)&structPtr) == XCNOMEM || structPtr != NULL) { |
|
1346 return False; |
|
1347 } |
|
1348 |
|
1349 structPtr = calloc(1, sizeof(awt_convertDataCallbackStruct)); |
|
1350 if (structPtr == NULL) { |
|
1351 return False; |
|
1352 } |
|
1353 |
|
1354 structPtr->source = (*env)->NewGlobalRef(env, component); |
|
1355 structPtr->transferable = (*env)->NewGlobalRef(env, transferable); |
|
1356 structPtr->formatMap = (*env)->NewGlobalRef(env, formatMap); |
|
1357 structPtr->formats = (*env)->NewGlobalRef(env, formats); |
|
1358 |
|
1359 if (JNU_IsNull(env, structPtr->source) || |
|
1360 JNU_IsNull(env, structPtr->transferable) || |
|
1361 JNU_IsNull(env, structPtr->formatMap) || |
|
1362 JNU_IsNull(env, structPtr->formats)) { |
|
1363 |
|
1364 if (!JNU_IsNull(env, structPtr->source)) { |
|
1365 (*env)->DeleteGlobalRef(env, structPtr->source); |
|
1366 } |
|
1367 if (!JNU_IsNull(env, structPtr->transferable)) { |
|
1368 (*env)->DeleteGlobalRef(env, structPtr->transferable); |
|
1369 } |
|
1370 if (!JNU_IsNull(env, structPtr->formatMap)) { |
|
1371 (*env)->DeleteGlobalRef(env, structPtr->formatMap); |
|
1372 } |
|
1373 if (!JNU_IsNull(env, structPtr->formats)) { |
|
1374 (*env)->DeleteGlobalRef(env, structPtr->formats); |
|
1375 } |
|
1376 free(structPtr); |
|
1377 return False; |
|
1378 } |
|
1379 |
|
1380 if (XSaveContext(dpy, xid, awt_convertDataContext, |
|
1381 (XPointer)structPtr) == XCNOMEM) { |
|
1382 free(structPtr); |
|
1383 return False; |
|
1384 } |
|
1385 |
|
1386 return True; |
|
1387 } |
|
1388 |
|
1389 /* |
|
1390 * Convenience routine. Constructs an appropriate exception message based on the |
|
1391 * specified prefix and the return code of XGrab* function and throws an |
|
1392 * InvalidDnDOperationException with the constructed message. |
|
1393 */ |
|
1394 static void |
|
1395 throw_grab_failure_exception(JNIEnv* env, int ret_code, char* msg_prefix) { |
|
1396 char msg[200]; |
|
1397 char* msg_cause = ""; |
|
1398 |
|
1399 switch (ret_code) { |
|
1400 case GrabNotViewable: msg_cause = "not viewable"; break; |
|
1401 case AlreadyGrabbed: msg_cause = "already grabbed"; break; |
|
1402 case GrabInvalidTime: msg_cause = "invalid time"; break; |
|
1403 case GrabFrozen: msg_cause = "grab frozen"; break; |
|
1404 default: msg_cause = "unknown failure"; break; |
|
1405 } |
|
1406 |
|
1407 sprintf(msg, "%s: %s.", msg_prefix, msg_cause); |
|
1408 JNU_ThrowByName(env, "java/awt/dnd/InvalidDnDOperationException", |
|
1409 msg); |
|
1410 } |
|
1411 |
|
1412 /* |
|
1413 * Sets the proxy mode source window - the source window which the drag |
|
1414 * notifications from an XEmbed client should be forwarded to. |
|
1415 * If the window is not None and there is a drag operation in progress, |
|
1416 * throws InvalidDnDOperationException and doesn't change |
|
1417 * proxy_mode_source_window. |
|
1418 * The caller mush hold AWT_LOCK. |
|
1419 */ |
|
1420 void |
|
1421 set_proxy_mode_source_window(Window window) { |
|
1422 if (window != None && dnd_in_progress) { |
|
1423 JNIEnv *env = (JNIEnv*)JNU_GetEnv(jvm, JNI_VERSION_1_4); |
|
1424 JNU_ThrowByName(env, "java/awt/dnd/InvalidDnDOperationException", |
|
1425 "Drag and drop is already in progress."); |
|
1426 return; |
|
1427 } |
|
1428 |
|
1429 proxy_mode_source_window = window; |
|
1430 } |
|
1431 |
|
1432 /* |
|
1433 * Checks if the event is a drag notification from an XEmbed client. |
|
1434 * If it is, forwards this event back to the current source and returns True. |
|
1435 * Otherwise, returns False. |
|
1436 * Currently only XDnD protocol notifications are recognized. |
|
1437 * The caller must hold AWT_LOCK. |
|
1438 */ |
|
1439 static Boolean |
|
1440 process_proxy_mode_event(XEvent* event) { |
|
1441 if (proxy_mode_source_window == None) { |
|
1442 return False; |
|
1443 } |
|
1444 |
|
1445 if (event->type == ClientMessage) { |
|
1446 XClientMessageEvent* xclient = &event->xclient; |
|
1447 if (xclient->message_type == XA_XdndStatus || |
|
1448 xclient->message_type == XA_XdndFinished) { |
|
1449 Window source = proxy_mode_source_window; |
|
1450 |
|
1451 xclient->data.l[0] = xclient->window; |
|
1452 xclient->window = source; |
|
1453 |
|
1454 XSendEvent(xclient->display, source, False, NoEventMask, |
|
1455 (XEvent*)xclient); |
|
1456 |
|
1457 if (xclient->message_type == XA_XdndFinished) { |
|
1458 proxy_mode_source_window = None; |
|
1459 } |
|
1460 |
|
1461 return True; |
|
1462 } |
|
1463 } |
|
1464 |
|
1465 return False; |
|
1466 } |
|
1467 |
|
1468 /* |
|
1469 * Class: sun_awt_motif_X11DragSourceContextPeer |
|
1470 * Method: startDrag |
|
1471 * Signature: ()V |
|
1472 */ |
|
1473 JNIEXPORT void JNICALL |
|
1474 Java_sun_awt_motif_X11DragSourceContextPeer_startDrag(JNIEnv *env, |
|
1475 jobject this, |
|
1476 jobject component, |
|
1477 jobject wpeer, |
|
1478 jobject transferable, |
|
1479 jobject trigger, |
|
1480 jobject cursor, |
|
1481 jint ctype, |
|
1482 jint actions, |
|
1483 jlongArray formats, |
|
1484 jobject formatMap) { |
|
1485 Time time_stamp = CurrentTime; |
|
1486 Cursor xcursor = None; |
|
1487 Window root_window = None; |
|
1488 Atom* targets = NULL; |
|
1489 jsize num_targets = 0; |
|
1490 |
|
1491 AWT_LOCK(); |
|
1492 |
|
1493 if (dnd_in_progress) { |
|
1494 JNU_ThrowByName(env, "java/awt/dnd/InvalidDnDOperationException", |
|
1495 "Drag and drop is already in progress."); |
|
1496 AWT_UNLOCK(); |
|
1497 return; |
|
1498 } |
|
1499 |
|
1500 if (proxy_mode_source_window != None) { |
|
1501 JNU_ThrowByName(env, "java/awt/dnd/InvalidDnDOperationException", |
|
1502 "Proxy drag is in progress."); |
|
1503 AWT_UNLOCK(); |
|
1504 return; |
|
1505 } |
|
1506 |
|
1507 if (!awt_dnd_init(awt_display)) { |
|
1508 JNU_ThrowByName(env, "java/awt/dnd/InvalidDnDOperationException", |
|
1509 "DnD subsystem initialization failed."); |
|
1510 AWT_UNLOCK(); |
|
1511 return; |
|
1512 } |
|
1513 |
|
1514 if (!JNU_IsNull(env, cursor)) { |
|
1515 xcursor = getCursor(env, cursor); |
|
1516 |
|
1517 if (xcursor == None) { |
|
1518 JNU_ThrowByName(env, "java/awt/dnd/InvalidDnDOperationException", |
|
1519 "Invalid drag cursor"); |
|
1520 AWT_UNLOCK(); |
|
1521 } |
|
1522 } |
|
1523 |
|
1524 /* Determine the root window for the drag operation. */ |
|
1525 { |
|
1526 struct FrameData* wdata = (struct FrameData*) |
|
1527 JNU_GetLongFieldAsPtr(env, wpeer, mComponentPeerIDs.pData); |
|
1528 |
|
1529 if (wdata == NULL) { |
|
1530 JNU_ThrowNullPointerException(env, "Null component data"); |
|
1531 AWT_UNLOCK(); |
|
1532 return; |
|
1533 } |
|
1534 |
|
1535 if (wdata->winData.shell == NULL) { |
|
1536 JNU_ThrowNullPointerException(env, "Null shell widget"); |
|
1537 AWT_UNLOCK(); |
|
1538 return; |
|
1539 } |
|
1540 |
|
1541 root_window = RootWindowOfScreen(XtScreen(wdata->winData.shell)); |
|
1542 |
|
1543 if (root_window == None) { |
|
1544 JNU_ThrowByName(env, "java/awt/dnd/InvalidDnDOperationException", |
|
1545 "Cannot get the root window for the drag operation."); |
|
1546 AWT_UNLOCK(); |
|
1547 return; |
|
1548 } |
|
1549 } |
|
1550 |
|
1551 time_stamp = get_latest_time_stamp(); |
|
1552 |
|
1553 /* Extract the targets from java array. */ |
|
1554 { |
|
1555 targets = NULL; |
|
1556 num_targets = (*env)->GetArrayLength(env, formats); |
|
1557 |
|
1558 /* |
|
1559 * In debug build GetLongArrayElements aborts with assertion on an empty |
|
1560 * array. |
|
1561 */ |
|
1562 if (num_targets > 0) { |
|
1563 jboolean isCopy = JNI_TRUE; |
|
1564 jlong* java_targets = (*env)->GetLongArrayElements(env, formats, |
|
1565 &isCopy); |
|
1566 |
|
1567 if ((*env)->ExceptionCheck(env) == JNI_TRUE) { |
|
1568 AWT_UNLOCK(); |
|
1569 return; |
|
1570 } |
|
1571 |
|
1572 if (java_targets != NULL) { |
|
1573 targets = (Atom*)malloc(num_targets * sizeof(Atom)); |
|
1574 if (targets != NULL) { |
|
1575 #ifdef _LP64 |
|
1576 memcpy(targets, java_targets, num_targets * sizeof(Atom)); |
|
1577 #else |
|
1578 jsize i; |
|
1579 |
|
1580 for (i = 0; i < num_targets; i++) { |
|
1581 targets[i] = (Atom)java_targets[i]; |
|
1582 } |
|
1583 #endif |
|
1584 } |
|
1585 (*env)->ReleaseLongArrayElements(env, formats, java_targets, |
|
1586 JNI_ABORT); |
|
1587 } |
|
1588 } |
|
1589 if (targets == NULL) { |
|
1590 num_targets = 0; |
|
1591 } |
|
1592 } |
|
1593 |
|
1594 /* Write the XDnD initiator info on the awt_root_shell. */ |
|
1595 { |
|
1596 unsigned char ret; |
|
1597 Atom action_atoms[3]; |
|
1598 unsigned int action_count = 0; |
|
1599 |
|
1600 if (actions & java_awt_dnd_DnDConstants_ACTION_COPY) { |
|
1601 action_atoms[action_count] = XA_XdndActionCopy; |
|
1602 action_count++; |
|
1603 } |
|
1604 if (actions & java_awt_dnd_DnDConstants_ACTION_MOVE) { |
|
1605 action_atoms[action_count] = XA_XdndActionMove; |
|
1606 action_count++; |
|
1607 } |
|
1608 if (actions & java_awt_dnd_DnDConstants_ACTION_LINK) { |
|
1609 action_atoms[action_count] = XA_XdndActionLink; |
|
1610 action_count++; |
|
1611 } |
|
1612 |
|
1613 ret = checked_XChangeProperty(awt_display, awt_dnd_ds_get_source_window(), |
|
1614 XA_XdndActionList, XA_ATOM, 32, |
|
1615 PropModeReplace, (unsigned char*)action_atoms, |
|
1616 action_count * sizeof(Atom)); |
|
1617 |
|
1618 if (ret != Success) { |
|
1619 cleanup_drag(awt_display, time_stamp); |
|
1620 JNU_ThrowByName(env, "java/awt/dnd/InvalidDnDOperationException", |
|
1621 "Cannot write XdndActionList property"); |
|
1622 AWT_UNLOCK(); |
|
1623 return; |
|
1624 } |
|
1625 |
|
1626 ret = checked_XChangeProperty(awt_display, awt_dnd_ds_get_source_window(), |
|
1627 XA_XdndTypeList, XA_ATOM, 32, |
|
1628 PropModeReplace, (unsigned char*)targets, |
|
1629 num_targets); |
|
1630 |
|
1631 if (ret != Success) { |
|
1632 cleanup_drag(awt_display, time_stamp); |
|
1633 JNU_ThrowByName(env, "java/awt/dnd/InvalidDnDOperationException", |
|
1634 "Cannot write XdndTypeList property"); |
|
1635 AWT_UNLOCK(); |
|
1636 return; |
|
1637 } |
|
1638 } |
|
1639 |
|
1640 /* Write the Motif DnD initiator info on the awt_root_shell. */ |
|
1641 { |
|
1642 InitiatorInfo info; |
|
1643 unsigned char ret; |
|
1644 int target_list_index = |
|
1645 get_index_for_target_list(awt_display, targets, num_targets); |
|
1646 |
|
1647 if (target_list_index == -1) { |
|
1648 cleanup_drag(awt_display, time_stamp); |
|
1649 JNU_ThrowByName(env, "java/awt/dnd/InvalidDnDOperationException", |
|
1650 "Cannot determine the target list index."); |
|
1651 AWT_UNLOCK(); |
|
1652 return; |
|
1653 } |
|
1654 |
|
1655 info.byte_order = MOTIF_BYTE_ORDER; |
|
1656 info.protocol_version = MOTIF_DND_PROTOCOL_VERSION; |
|
1657 info.index = target_list_index; |
|
1658 info.selection_atom = _XA_MOTIF_ATOM_0; |
|
1659 |
|
1660 ret = checked_XChangeProperty(awt_display, awt_dnd_ds_get_source_window(), |
|
1661 _XA_MOTIF_ATOM_0, |
|
1662 _XA_MOTIF_DRAG_INITIATOR_INFO, 8, |
|
1663 PropModeReplace, (unsigned char*)&info, |
|
1664 sizeof(InitiatorInfo)); |
|
1665 |
|
1666 if (ret != Success) { |
|
1667 cleanup_drag(awt_display, time_stamp); |
|
1668 JNU_ThrowByName(env, "java/awt/dnd/InvalidDnDOperationException", |
|
1669 "Cannot write the Motif DnD initiator info"); |
|
1670 AWT_UNLOCK(); |
|
1671 return; |
|
1672 } |
|
1673 } |
|
1674 |
|
1675 /* Acquire XDnD selection ownership. */ |
|
1676 if (XtOwnSelection(awt_root_shell, XA_XdndSelection, time_stamp, |
|
1677 awt_convertData, NULL, NULL) != True) { |
|
1678 cleanup_drag(awt_display, time_stamp); |
|
1679 JNU_ThrowByName(env, "java/awt/dnd/InvalidDnDOperationException", |
|
1680 "Cannot acquire XdndSelection ownership."); |
|
1681 AWT_UNLOCK(); |
|
1682 return; |
|
1683 } |
|
1684 |
|
1685 /* Acquire Motif DnD selection ownership. */ |
|
1686 if (XtOwnSelection(awt_root_shell, _XA_MOTIF_ATOM_0, time_stamp, |
|
1687 motif_convert_proc, NULL, NULL) != True) { |
|
1688 cleanup_drag(awt_display, time_stamp); |
|
1689 JNU_ThrowByName(env, "java/awt/dnd/InvalidDnDOperationException", |
|
1690 "Cannot acquire Motif DnD selection ownership."); |
|
1691 AWT_UNLOCK(); |
|
1692 return; |
|
1693 } |
|
1694 |
|
1695 /* |
|
1696 * Store the information needed to convert data for both selections |
|
1697 * in awt_convertDataContext. |
|
1698 */ |
|
1699 { |
|
1700 if (!set_convert_data_context(env, awt_display, XA_XdndSelection, |
|
1701 component, transferable, formatMap, |
|
1702 formats)) { |
|
1703 cleanup_drag(awt_display, time_stamp); |
|
1704 JNU_ThrowByName(env, "java/awt/dnd/InvalidDnDOperationException", |
|
1705 "Cannot save context for XDnD selection data conversion."); |
|
1706 AWT_UNLOCK(); |
|
1707 return; |
|
1708 } |
|
1709 |
|
1710 if (!set_convert_data_context(env, awt_display, _XA_MOTIF_ATOM_0, |
|
1711 component, transferable, formatMap, |
|
1712 formats)) { |
|
1713 cleanup_drag(awt_display, time_stamp); |
|
1714 JNU_ThrowByName(env, "java/awt/dnd/InvalidDnDOperationException", |
|
1715 "Cannot save context for Motif DnD selection data conversion."); |
|
1716 AWT_UNLOCK(); |
|
1717 return; |
|
1718 } |
|
1719 } |
|
1720 |
|
1721 /* Install X grabs. */ |
|
1722 { |
|
1723 XWindowAttributes xwa; |
|
1724 int ret; |
|
1725 |
|
1726 XGetWindowAttributes(awt_display, root_window, &xwa); |
|
1727 |
|
1728 your_root_event_mask = xwa.your_event_mask; |
|
1729 |
|
1730 XSelectInput(awt_display, root_window, |
|
1731 your_root_event_mask | ROOT_EVENT_MASK); |
|
1732 |
|
1733 ret = XGrabPointer(awt_display, |
|
1734 root_window, |
|
1735 False, |
|
1736 GRAB_EVENT_MASK, |
|
1737 GrabModeAsync, |
|
1738 GrabModeAsync, |
|
1739 None, |
|
1740 xcursor, |
|
1741 time_stamp); |
|
1742 |
|
1743 if (ret != GrabSuccess) { |
|
1744 cleanup_drag(awt_display, time_stamp); |
|
1745 throw_grab_failure_exception(env, ret, "Cannot grab pointer"); |
|
1746 AWT_UNLOCK(); |
|
1747 return; |
|
1748 } |
|
1749 |
|
1750 ret = XGrabKeyboard(awt_display, |
|
1751 root_window, |
|
1752 False, |
|
1753 GrabModeAsync, |
|
1754 GrabModeAsync, |
|
1755 time_stamp); |
|
1756 |
|
1757 if (ret != GrabSuccess) { |
|
1758 cleanup_drag(awt_display, time_stamp); |
|
1759 throw_grab_failure_exception(env, ret, "Cannot grab keyboard"); |
|
1760 AWT_UNLOCK(); |
|
1761 return; |
|
1762 } |
|
1763 } |
|
1764 |
|
1765 /* Update the global state. */ |
|
1766 source_peer = (*env)->NewGlobalRef(env, this); |
|
1767 dnd_in_progress = True; |
|
1768 drag_in_progress = True; |
|
1769 data_types = targets; |
|
1770 data_types_count = num_targets; |
|
1771 source_actions = actions; |
|
1772 drag_root_window = root_window; |
|
1773 |
|
1774 AWT_UNLOCK(); |
|
1775 } |
|
1776 |
|
1777 /* |
|
1778 * Class: sun_awt_motif_X11DragSourceContextPeer |
|
1779 * Method: setNativeCursor |
|
1780 * Signature: ()V |
|
1781 */ |
|
1782 JNIEXPORT void JNICALL |
|
1783 Java_sun_awt_motif_X11DragSourceContextPeer_setNativeCursor(JNIEnv *env, |
|
1784 jobject this, |
|
1785 jlong nativeCtxt, |
|
1786 jobject cursor, |
|
1787 jint type) { |
|
1788 if (JNU_IsNull(env, cursor)) { |
|
1789 return; |
|
1790 } |
|
1791 |
|
1792 XChangeActivePointerGrab(awt_display, |
|
1793 GRAB_EVENT_MASK, |
|
1794 getCursor(env, cursor), |
|
1795 CurrentTime); |
|
1796 } |
|