FSF GCC merge 02/23/03
[official-gcc.git] / libjava / jni / gtk-peer / gnu_java_awt_peer_gtk_GtkEvents.c
blob99ca0934c3dd67658ccb7821d39f62edec4c6139
1 /* gtkevents.c -- GDK/GTK event handlers
2 Copyright (C) 1998, 1999, 2002 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 #include "gtkpeer.h"
40 #include <X11/Xlib.h>
41 #include <gdk/gdkkeysyms.h>
42 #include <stdarg.h>
43 #include <assert.h>
45 /* A widget can be composed of multipled windows, so we need to hook
46 events on all of them. */
47 struct event_hook_info
49 jobject *peer_obj;
50 int nwindows;
51 GdkWindow ***windows; /* array of pointers to (GdkWindow *) */
54 static jint
55 button_to_awt_mods (int button)
57 switch (button)
59 case 1:
60 return AWT_BUTTON1_MASK;
61 case 2:
62 return AWT_BUTTON2_MASK;
63 case 3:
64 return AWT_BUTTON3_MASK;
67 return 0;
70 static jint
71 state_to_awt_mods (int mods)
73 jint result = 0;
75 if (mods & (GDK_SHIFT_MASK | GDK_LOCK_MASK))
76 result |= AWT_SHIFT_MASK;
77 if (mods & GDK_CONTROL_MASK)
78 result |= AWT_CTRL_MASK;
80 return result;
83 #ifdef __GNUC__
84 __inline
85 #endif
86 static jint
87 keysym_to_awt_keycode (guint keyval)
89 guint vk;
91 vk = gdk_keyval_to_upper (keyval);
93 if (vk <= 0x41 && vk <= 0x5A) /* VK_A through VK_Z */
94 return vk;
96 if (vk <= 0x30 && vk <= 39) /* VK_0 through VK_9 */
97 return vk;
99 switch (vk)
101 case GDK_Alt_L:
102 case GDK_Alt_R:
103 return VK_ALT;
104 case GDK_BackSpace:
105 return VK_BACK_SPACE;
106 case GDK_Cancel:
107 return VK_CANCEL;
108 case GDK_Caps_Lock:
109 return VK_CAPS_LOCK;
110 case GDK_Clear:
111 return VK_CLEAR;
112 case GDK_bracketright:
113 return VK_CLOSE_BRACKET;
114 case GDK_comma:
115 return VK_COMMA;
116 case GDK_Control_L:
117 case GDK_Control_R:
118 return VK_CONTROL;
119 case GDK_KP_Decimal:
120 return VK_DECIMAL;
121 case GDK_Delete:
122 return VK_DELETE;
123 case GDK_KP_Divide:
124 return VK_DIVIDE;
125 case GDK_Down:
126 return VK_DOWN;
127 case GDK_End:
128 return VK_END;
129 case GDK_Return:
130 return VK_ENTER;
131 case GDK_Escape:
132 return VK_ESCAPE;
133 case GDK_F1:
134 return VK_F1;
135 case GDK_F2:
136 return VK_F2;
137 case GDK_F3:
138 return VK_F3;
139 case GDK_F4:
140 return VK_F4;
141 case GDK_F5:
142 return VK_F5;
143 case GDK_F6:
144 return VK_F6;
145 case GDK_F7:
146 return VK_F7;
147 case GDK_F8:
148 return VK_F8;
149 case GDK_F9:
150 return VK_F9;
151 case GDK_F10:
152 return VK_F10;
153 case GDK_F11:
154 return VK_F11;
155 case GDK_F12:
156 return VK_F12;
157 case GDK_Help:
158 return VK_HELP;
159 case GDK_Home:
160 return VK_HOME;
161 case GDK_Insert:
162 return VK_INSERT;
163 case GDK_Kanji:
164 return VK_KANJI;
165 case GDK_Left:
166 return VK_LEFT;
167 case GDK_Meta_L:
168 case GDK_Meta_R:
169 return VK_META;
170 case GDK_KP_Multiply:
171 return VK_MULTIPLY;
172 case GDK_Num_Lock:
173 return VK_NUM_LOCK;
174 case GDK_KP_0:
175 return VK_NUMPAD0;
176 case GDK_KP_1:
177 return VK_NUMPAD1;
178 case GDK_KP_2:
179 return VK_NUMPAD2;
180 case GDK_KP_3:
181 return VK_NUMPAD3;
182 case GDK_KP_4:
183 return VK_NUMPAD4;
184 case GDK_KP_5:
185 return VK_NUMPAD5;
186 case GDK_KP_6:
187 return VK_NUMPAD6;
188 case GDK_KP_7:
189 return VK_NUMPAD7;
190 case GDK_KP_8:
191 return VK_NUMPAD8;
192 case GDK_KP_9:
193 return VK_NUMPAD9;
194 case GDK_bracketleft:
195 return VK_OPEN_BRACKET;
196 case GDK_Page_Down:
197 return VK_PAGE_DOWN;
198 case GDK_Page_Up:
199 return VK_PAGE_UP;
200 case GDK_Pause:
201 return VK_PAUSE;
202 case GDK_period:
203 return VK_PERIOD;
204 case GDK_Print:
205 return VK_PRINTSCREEN;
206 case GDK_quoteright:
207 return VK_QUOTE;
208 case GDK_Right:
209 return VK_RIGHT;
210 case GDK_Scroll_Lock:
211 return VK_SCROLL_LOCK;
212 case GDK_semicolon:
213 return VK_SEMICOLON;
214 case GDK_KP_Separator:
215 return VK_SEPARATOR;
216 case GDK_Shift_L:
217 case GDK_Shift_R:
218 return VK_SHIFT;
219 case GDK_slash:
220 return VK_SLASH;
221 case GDK_space:
222 return VK_SPACE;
223 case GDK_KP_Subtract:
224 return VK_SUBTRACT;
225 case GDK_Tab:
226 return VK_TAB;
227 case GDK_Up:
228 return VK_UP;
230 default:
231 return VK_UNDEFINED;
235 void
236 awt_event_handler (GdkEvent *event)
238 jobject *obj_ptr;
239 static guint32 button_click_time = 0;
240 static GdkWindow *button_window = NULL;
241 static guint button_number = -1;
242 static jint click_count = 1;
244 /* keep synthetic AWT events from being processed recursively */
245 if (event->type & SYNTHETIC_EVENT_MASK && event->type != GDK_NOTHING)
247 event->type ^= SYNTHETIC_EVENT_MASK;
248 gtk_main_do_event (event);
249 return;
252 /* keep track of clickCount ourselves, since the AWT allows more
253 than a triple click to occur */
254 if (event->type == GDK_BUTTON_PRESS)
256 if ((event->button.time < (button_click_time + MULTI_CLICK_TIME))
257 && (event->button.window == button_window)
258 && (event->button.button == button_number))
259 click_count++;
260 else
261 click_count = 1;
263 button_click_time = event->button.time;
264 button_window = event->button.window;
265 button_number = event->button.button;
268 /* for all input events, which have a window with a jobject attached,
269 send the input event off to Java before GTK has a chance to process
270 the event */
271 if ((event->type == GDK_BUTTON_PRESS
272 || event->type == GDK_BUTTON_RELEASE
273 || event->type == GDK_ENTER_NOTIFY
274 || event->type == GDK_LEAVE_NOTIFY
275 || event->type == GDK_CONFIGURE
276 || event->type == GDK_EXPOSE
277 || event->type == GDK_KEY_PRESS
278 || event->type == GDK_FOCUS_CHANGE
279 || event->type == GDK_MOTION_NOTIFY)
280 && gdk_property_get (event->any.window,
281 gdk_atom_intern ("_GNU_GTKAWT_ADDR", FALSE),
282 gdk_atom_intern ("CARDINAL", FALSE),
284 sizeof (jobject),
285 FALSE,
286 NULL,
287 NULL,
288 NULL,
289 (guchar **)&obj_ptr))
291 switch (event->type)
293 case GDK_BUTTON_PRESS:
294 (*gdk_env)->CallVoidMethod (gdk_env, *obj_ptr, postMouseEventID,
295 AWT_MOUSE_PRESSED,
296 (jlong)event->button.time,
297 state_to_awt_mods (event->button.state) |
298 button_to_awt_mods (event->button.button),
299 (jint)event->button.x,
300 (jint)event->button.y,
301 click_count,
302 (event->button.button == 3) ? JNI_TRUE :
303 JNI_FALSE);
305 /* grab_counter++;
306 gdk_pointer_grab (event->any.window,
307 FALSE,
308 GDK_POINTER_MOTION_MASK |
309 GDK_BUTTON_MOTION_MASK |
310 GDK_BUTTON_PRESS_MASK |
311 GDK_BUTTON_RELEASE_MASK |
312 GDK_ENTER_NOTIFY_MASK |
313 GDK_LEAVE_NOTIFY_MASK,
314 NULL,
315 NULL,
316 event->button.time);*/
317 break;
318 case GDK_BUTTON_RELEASE:
320 int width, height;
322 /* only ungrab if no other buttons are pressed down */
323 /* if (--grab_counter == 0)
324 gdk_pointer_ungrab (event->button.time);
326 (*gdk_env)->CallVoidMethod (gdk_env, *obj_ptr, postMouseEventID,
327 AWT_MOUSE_RELEASED,
328 (jlong)event->button.time,
329 state_to_awt_mods (event->button.state) |
330 button_to_awt_mods (event->button.button),
331 (jint)event->button.x,
332 (jint)event->button.y,
333 click_count, JNI_FALSE);
335 /* check to see if the release occured in the window it was pressed
336 in, and if so, generate an AWT click event */
337 gdk_window_get_size (event->any.window, &width, &height);
338 if (event->button.x >= 0
339 && event->button.y >= 0
340 && event->button.x <= width
341 && event->button.y <= height)
342 (*gdk_env)->CallVoidMethod (gdk_env, *obj_ptr, postMouseEventID,
343 AWT_MOUSE_CLICKED,
344 (jlong)event->button.time,
345 state_to_awt_mods (event->button.state) |
346 button_to_awt_mods (event->button.button),
347 (jint)event->button.x,
348 (jint)event->button.y,
349 click_count, JNI_FALSE);
352 break;
353 case GDK_MOTION_NOTIFY:
354 (*gdk_env)->CallVoidMethod (gdk_env, *obj_ptr, postMouseEventID,
355 AWT_MOUSE_MOVED,
356 (jlong)event->motion.time,
357 state_to_awt_mods (event->motion.state),
358 (jint)event->motion.x,
359 (jint)event->motion.y,
360 0, JNI_FALSE);
362 if (event->motion.state & (GDK_BUTTON1_MASK
363 | GDK_BUTTON2_MASK
364 | GDK_BUTTON3_MASK
365 | GDK_BUTTON4_MASK
366 | GDK_BUTTON5_MASK))
368 (*gdk_env)->CallVoidMethod (gdk_env, *obj_ptr, postMouseEventID,
369 AWT_MOUSE_DRAGGED,
370 (jlong)event->motion.time,
371 state_to_awt_mods (event->motion.state),
372 (jint)event->motion.x,
373 (jint)event->motion.y,
374 0, JNI_FALSE);
376 break;
377 case GDK_ENTER_NOTIFY:
378 (*gdk_env)->CallVoidMethod (gdk_env, *obj_ptr, postMouseEventID,
379 AWT_MOUSE_ENTERED,
380 (jlong)event->crossing.time,
381 state_to_awt_mods (event->crossing.state),
382 (jint)event->crossing.x,
383 (jint)event->crossing.y,
384 0, JNI_FALSE);
385 break;
386 case GDK_LEAVE_NOTIFY:
387 if (event->crossing.mode == GDK_CROSSING_NORMAL)
388 (*gdk_env)->CallVoidMethod (gdk_env, *obj_ptr, postMouseEventID,
389 AWT_MOUSE_EXITED,
390 (jlong)event->crossing.time,
391 state_to_awt_mods (event->crossing.state),
392 (jint)event->crossing.x,
393 (jint)event->crossing.y,
394 0, JNI_FALSE);
395 break;
396 case GDK_CONFIGURE:
398 GtkWidget *widget;
400 gdk_window_get_user_data (event->any.window, (void **) &widget);
402 if (widget && GTK_WIDGET_TOPLEVEL (widget))
404 gint top, left, right, bottom;
405 gint x, y, w, h, wb, d;
407 /* calculate our insets */
408 gdk_window_get_root_geometry (event->any.window,
409 &x, &y, &w, &h, &wb, &d);
411 /* We used to compute these based on the configure
412 event's fields. However, that gives strange and
413 apparently incorrect results. */
414 top = left = bottom = right = 0;
416 /* configure events are not posted to the AWT event queue,
417 and as such, gdk/gtk will be called back before
418 postConfigureEvent returns */
419 gdk_threads_leave ();
420 (*gdk_env)->CallVoidMethod (gdk_env, *obj_ptr,
421 postConfigureEventID,
422 (jint)event->configure.x,
423 (jint)event->configure.y,
424 (jint)event->configure.width,
425 (jint)event->configure.height,
426 (jint)top,
427 (jint)left,
428 (jint)bottom,
429 (jint)right);
430 gdk_threads_enter ();
433 break;
434 case GDK_EXPOSE:
436 (*gdk_env)->CallVoidMethod (gdk_env, *obj_ptr,
437 postExposeEventID,
438 (jint)event->expose.area.x,
439 (jint)event->expose.area.y,
440 (jint)event->expose.area.width,
441 (jint)event->expose.area.height);
443 break;
445 case GDK_KEY_PRESS:
447 GtkWidget *widget;
448 GtkWindow *window;
450 gdk_window_get_user_data (event->any.window, (void **) &widget);
452 window = GTK_WINDOW (gtk_widget_get_ancestor (widget,
453 GTK_TYPE_WINDOW));
454 if (window
455 && GTK_WIDGET_IS_SENSITIVE (window)
456 && window->focus_widget
457 && GTK_WIDGET_IS_SENSITIVE (window->focus_widget)
458 && window->focus_widget->window)
460 gtk_widget_activate (window->focus_widget);
461 gdk_property_get (window->focus_widget->window,
462 gdk_atom_intern ("_GNU_GTKAWT_ADDR", FALSE),
463 gdk_atom_intern ("CARDINAL", FALSE),
465 sizeof (jobject),
466 FALSE,
467 NULL,
468 NULL,
469 NULL,
470 (guchar **)&obj_ptr);
472 /* if (grab && GTK_WIDGET_HAS_DEFAULT (widget) ) */
473 /* { */
474 (*gdk_env)->CallVoidMethod (gdk_env, *obj_ptr,
475 postKeyEventID,
476 (jint) AWT_KEY_PRESSED,
477 (jlong) event->key.time,
478 state_to_awt_mods (event->key.state),
479 keysym_to_awt_keycode (event->key.keyval),
480 (jchar) (event->key.length) ?
481 event->key.string[0] :
482 AWT_KEY_CHAR_UNDEFINED);
483 if (event->key.length)
484 (*gdk_env)->CallVoidMethod (gdk_env, *obj_ptr,
485 postKeyEventID,
486 (jint) AWT_KEY_TYPED,
487 (jlong) event->key.time,
488 state_to_awt_mods (event->key.state),
489 VK_UNDEFINED,
490 (jchar) event->key.string[0]);
493 break;
494 case GDK_FOCUS_CHANGE:
495 (*gdk_env)->CallVoidMethod (gdk_env, *obj_ptr,
496 postFocusEventID,
497 (jint) (event->focus_change.in) ?
498 AWT_FOCUS_GAINED : AWT_FOCUS_LOST,
499 JNI_FALSE);
500 break;
501 default:
503 g_free (obj_ptr);
506 gtk_main_do_event (event);
509 static void
510 attach_jobject (GdkWindow *window, jobject *obj)
512 GdkAtom addr_atom = gdk_atom_intern ("_GNU_GTKAWT_ADDR", FALSE);
513 GdkAtom type_atom = gdk_atom_intern ("CARDINAL", FALSE);
515 gdk_window_set_events (window,
516 gdk_window_get_events (window)
517 | GDK_POINTER_MOTION_MASK
518 | GDK_BUTTON_MOTION_MASK
519 | GDK_BUTTON_PRESS_MASK
520 | GDK_BUTTON_RELEASE_MASK
521 | GDK_KEY_PRESS_MASK
522 | GDK_KEY_RELEASE_MASK
523 | GDK_ENTER_NOTIFY_MASK
524 | GDK_LEAVE_NOTIFY_MASK
525 | GDK_STRUCTURE_MASK
526 | GDK_KEY_PRESS_MASK
527 | GDK_FOCUS_CHANGE_MASK);
529 gdk_property_change (window,
530 addr_atom,
531 type_atom,
533 GDK_PROP_MODE_REPLACE,
534 (guchar *)obj,
535 sizeof (jobject));
538 void
539 connect_awt_hook (JNIEnv *env, jobject peer_obj, int nwindows, ...)
541 int i;
542 va_list ap;
543 jobject *obj;
545 obj = (jobject *) malloc (sizeof (jobject));
546 *obj = (*env)->NewGlobalRef (env, peer_obj);
548 va_start (ap, nwindows);
549 for (i = 0; i < nwindows; i++)
550 attach_jobject (va_arg (ap, GdkWindow *), obj);
551 va_end (ap);