OSDN Git Service

Merged gcj-eclipse branch to trunk.
[pf3gnuchains/gcc-fork.git] / libjava / classpath / native / jni / gtk-peer / gnu_java_awt_peer_gtk_GtkComponentPeer.c
1 /* gtkcomponentpeer.c -- Native implementation of GtkComponentPeer
2    Copyright (C) 1998, 1999, 2002, 2004, 2006 Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath.
5
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.
10
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.
15
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., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20
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.
25
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. */
37
38
39 #include "gtkpeer.h"
40 #include "gnu_java_awt_peer_gtk_GtkComponentPeer.h"
41
42 #include <gtk/gtkprivate.h>
43
44 #define AWT_DEFAULT_CURSOR 0
45 #define AWT_CROSSHAIR_CURSOR 1
46 #define AWT_TEXT_CURSOR 2
47 #define AWT_WAIT_CURSOR 3
48 #define AWT_SW_RESIZE_CURSOR 4
49 #define AWT_SE_RESIZE_CURSOR 5
50 #define AWT_NW_RESIZE_CURSOR 6
51 #define AWT_NE_RESIZE_CURSOR 7
52 #define AWT_N_RESIZE_CURSOR 8
53 #define AWT_S_RESIZE_CURSOR 9
54 #define AWT_W_RESIZE_CURSOR 10
55 #define AWT_E_RESIZE_CURSOR 11
56 #define AWT_HAND_CURSOR 12
57 #define AWT_MOVE_CURSOR 13
58
59 /* FIXME: use gtk-double-click-time, gtk-double-click-distance */
60 #define MULTI_CLICK_TIME   250
61 /* as opposed to a MULTI_PASS_TIME :) */
62
63 #define AWT_MOUSE_CLICKED  500
64 #define AWT_MOUSE_PRESSED  501
65 #define AWT_MOUSE_RELEASED 502
66 #define AWT_MOUSE_MOVED    503
67 #define AWT_MOUSE_ENTERED  504
68 #define AWT_MOUSE_EXITED   505
69 #define AWT_MOUSE_DRAGGED  506
70 #define AWT_MOUSE_WHEEL    507
71
72 #define AWT_WHEEL_UNIT_SCROLL 0
73
74 #define AWT_FOCUS_GAINED 1004
75 #define AWT_FOCUS_LOST 1005
76
77 static GtkWidget *find_fg_color_widget (GtkWidget *widget);
78 static GtkWidget *find_bg_color_widget (GtkWidget *widget);
79 static GtkWidget *get_widget (GtkWidget *widget);
80
81 static jmethodID postMouseEventID;
82 static jmethodID postMouseWheelEventID;
83 static jmethodID postExposeEventID;
84 static jmethodID postFocusEventID;
85
86 void
87 cp_gtk_component_init_jni (void)
88  {
89   jclass gtkcomponentpeer;
90
91   gtkcomponentpeer = (*cp_gtk_gdk_env())->FindClass (cp_gtk_gdk_env(),
92                                      "gnu/java/awt/peer/gtk/GtkComponentPeer");
93
94   postMouseEventID = (*cp_gtk_gdk_env())->GetMethodID (cp_gtk_gdk_env(), gtkcomponentpeer,
95                                                "postMouseEvent", "(IJIIIIZ)V");
96
97   postMouseWheelEventID = (*cp_gtk_gdk_env())->GetMethodID (cp_gtk_gdk_env(),
98                                                         gtkcomponentpeer,
99                                                         "postMouseWheelEvent",
100                                                         "(IJIIIIZIII)V");
101
102   postExposeEventID = (*cp_gtk_gdk_env())->GetMethodID (cp_gtk_gdk_env(), gtkcomponentpeer,
103                                                  "postExposeEvent", "(IIII)V");
104
105   postFocusEventID = (*cp_gtk_gdk_env())->GetMethodID (cp_gtk_gdk_env(), gtkcomponentpeer,
106                                                 "postFocusEvent", "(IZ)V");
107 }
108
109 static gboolean component_button_press_cb (GtkWidget *widget,
110                                            GdkEventButton *event,
111                                            jobject peer);
112 static gboolean component_button_release_cb (GtkWidget *widget,
113                                              GdkEventButton *event,
114                                              jobject peer);
115 static gboolean component_motion_notify_cb (GtkWidget *widget,
116                                             GdkEventMotion *event,
117                                             jobject peer);
118 static gboolean component_scroll_cb (GtkWidget *widget,
119                                      GdkEventScroll *event,
120                                      jobject peer);
121 static gboolean component_enter_notify_cb (GtkWidget *widget,
122                                            GdkEventCrossing *event,
123                                            jobject peer);
124 static gboolean component_leave_notify_cb (GtkWidget *widget,
125                                            GdkEventCrossing *event,
126                                            jobject peer);
127 static gboolean component_expose_cb (GtkWidget *widget,
128                                      GdkEventExpose *event,
129                                      jobject peer);
130 static gboolean component_focus_in_cb (GtkWidget *widget,
131                                        GdkEventFocus *event,
132                                        jobject peer);
133 static gboolean component_focus_out_cb (GtkWidget *widget,
134                                         GdkEventFocus *event,
135                                         jobject peer);
136
137 static jint
138 button_to_awt_mods (int button)
139 {
140   switch (button)
141     {
142     case 1:
143       return AWT_BUTTON1_DOWN_MASK | AWT_BUTTON1_MASK;
144     case 2:
145       return AWT_BUTTON2_DOWN_MASK | AWT_BUTTON2_MASK;
146     case 3:
147       return AWT_BUTTON3_DOWN_MASK | AWT_BUTTON3_MASK;
148     }
149
150   return 0;
151 }
152
153 jint
154 cp_gtk_state_to_awt_mods (guint state)
155 {
156   jint result = 0;
157
158   if (state & GDK_SHIFT_MASK)
159     result |= (AWT_SHIFT_DOWN_MASK | AWT_SHIFT_MASK);
160   if (state & GDK_CONTROL_MASK)
161     result |= (AWT_CTRL_DOWN_MASK | AWT_CTRL_MASK);
162   if (state & GDK_MOD1_MASK)
163     result |= (AWT_ALT_DOWN_MASK | AWT_ALT_MASK);
164
165   return result;
166 }
167
168 static jint
169 state_to_awt_mods_with_button_states (guint state)
170 {
171   jint result = 0;
172
173   if (state & GDK_SHIFT_MASK)
174     result |= AWT_SHIFT_DOWN_MASK | AWT_SHIFT_MASK;
175   if (state & GDK_CONTROL_MASK)
176     result |= AWT_CTRL_DOWN_MASK | AWT_CTRL_MASK;
177   if (state & GDK_MOD1_MASK)
178     result |= AWT_ALT_DOWN_MASK | AWT_ALT_MASK;
179   if (state & GDK_BUTTON1_MASK)
180     result |= AWT_BUTTON1_DOWN_MASK | AWT_BUTTON1_MASK;
181   if (state & GDK_BUTTON2_MASK)
182     result |= AWT_BUTTON2_DOWN_MASK;
183   if (state & GDK_BUTTON3_MASK)
184     result |= AWT_BUTTON3_DOWN_MASK;
185
186   return result;
187 }
188
189 JNIEXPORT void JNICALL 
190 Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetSetCursor 
191   (JNIEnv *env, jobject obj, jint type, jobject image, jint x, jint y) 
192 {
193   gdk_threads_enter ();
194
195   Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetSetCursorUnlocked
196     (env, obj, type, image, x, y);
197
198   gdk_threads_leave ();
199 }
200
201 JNIEXPORT void JNICALL 
202 Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetSetCursorUnlocked
203   (JNIEnv *env, jobject obj, jint type, jobject image, jint x, jint y) 
204 {
205   void *ptr;
206   GtkWidget *widget;
207   GdkWindow *win;
208   GdkCursorType gdk_cursor_type;
209   GdkCursor *gdk_cursor;
210
211   ptr = NSA_GET_PTR (env, obj);
212
213   switch (type)
214     {
215     case AWT_CROSSHAIR_CURSOR:
216       gdk_cursor_type = GDK_CROSSHAIR;
217       break;
218     case AWT_TEXT_CURSOR:
219       gdk_cursor_type = GDK_XTERM;
220       break;
221     case AWT_WAIT_CURSOR:
222       gdk_cursor_type = GDK_WATCH;
223       break;
224     case AWT_SW_RESIZE_CURSOR:
225       gdk_cursor_type = GDK_BOTTOM_LEFT_CORNER;
226       break;
227     case AWT_SE_RESIZE_CURSOR:
228       gdk_cursor_type = GDK_BOTTOM_RIGHT_CORNER;
229       break;
230     case AWT_NW_RESIZE_CURSOR:
231       gdk_cursor_type = GDK_TOP_LEFT_CORNER;
232       break;
233     case AWT_NE_RESIZE_CURSOR:
234       gdk_cursor_type = GDK_TOP_RIGHT_CORNER;
235       break;
236     case AWT_N_RESIZE_CURSOR:
237       gdk_cursor_type = GDK_TOP_SIDE;
238       break;
239     case AWT_S_RESIZE_CURSOR:
240       gdk_cursor_type = GDK_BOTTOM_SIDE;
241       break;
242     case AWT_W_RESIZE_CURSOR:
243       gdk_cursor_type = GDK_LEFT_SIDE;
244       break;
245     case AWT_E_RESIZE_CURSOR:
246       gdk_cursor_type = GDK_RIGHT_SIDE;
247       break;
248     case AWT_HAND_CURSOR:
249       gdk_cursor_type = GDK_HAND2;
250       break;
251     case AWT_MOVE_CURSOR:
252       gdk_cursor_type = GDK_FLEUR;
253       break;
254     default:
255       gdk_cursor_type = GDK_LEFT_PTR;
256     }
257       
258   widget = get_widget(GTK_WIDGET(ptr));
259   
260   win = widget->window;
261   if ((widget->window) == NULL)
262     win = GTK_WIDGET(ptr)->window;
263     
264   if (image == NULL)
265     gdk_cursor = gdk_cursor_new (gdk_cursor_type);
266   else
267     gdk_cursor
268       = gdk_cursor_new_from_pixbuf (gdk_drawable_get_display (win),
269                                     cp_gtk_image_get_pixbuf (env, image),
270                                     x, y);
271
272   gdk_window_set_cursor (win, gdk_cursor);
273   gdk_cursor_unref (gdk_cursor);
274
275   /* Make sure the cursor is replaced on screen. */
276   gdk_flush();
277 }
278
279 JNIEXPORT void JNICALL
280 Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetSetParent
281   (JNIEnv *env, jobject obj, jobject parent)
282 {
283   void *ptr;
284   void *parent_ptr;
285   GtkWidget *widget;
286   GtkWidget *parent_widget;
287
288   gdk_threads_enter ();
289
290   ptr = NSA_GET_PTR (env, obj);
291   parent_ptr = NSA_GET_PTR (env, parent);
292   
293   widget = GTK_WIDGET (ptr);
294   parent_widget = get_widget(GTK_WIDGET (parent_ptr));
295
296   if (widget->parent == NULL)
297     {
298       if (GTK_IS_WINDOW (parent_widget))
299         {
300           GList *children = gtk_container_get_children
301             (GTK_CONTAINER (parent_widget));
302
303           if (GTK_IS_MENU_BAR (children->data))
304             gtk_fixed_put (GTK_FIXED (children->next->data), widget, 0, 0);
305           else
306             gtk_fixed_put (GTK_FIXED (children->data), widget, 0, 0);
307         }
308       else
309         if (GTK_IS_SCROLLED_WINDOW (parent_widget))
310           {
311             gtk_scrolled_window_add_with_viewport 
312               (GTK_SCROLLED_WINDOW (parent_widget), widget);
313             gtk_viewport_set_shadow_type (GTK_VIEWPORT (widget->parent), 
314                                           GTK_SHADOW_NONE);
315
316           }
317         else
318           {
319             if (widget->parent == NULL)
320               gtk_fixed_put (GTK_FIXED (parent_widget), widget, 0, 0);
321           }
322     }
323
324   gdk_threads_leave ();
325 }
326
327 JNIEXPORT void JNICALL
328 Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetSetSensitive
329   (JNIEnv *env, jobject obj, jboolean sensitive)
330 {
331   void *ptr;
332
333   gdk_threads_enter ();
334
335   ptr = NSA_GET_PTR (env, obj);
336
337   gtk_widget_set_sensitive (get_widget(GTK_WIDGET (ptr)), sensitive);
338
339   gdk_threads_leave ();
340 }
341
342 JNIEXPORT jboolean JNICALL
343 Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetHasFocus
344 (JNIEnv *env, jobject obj)
345 {
346   void *ptr;
347   jboolean retval;
348
349   gdk_threads_enter ();
350
351   ptr = NSA_GET_PTR (env, obj);
352   
353   retval = GTK_WIDGET_HAS_FOCUS((GTK_WIDGET (ptr)));
354
355   gdk_threads_leave ();
356
357   return retval;
358 }
359
360 JNIEXPORT jboolean JNICALL
361 Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetCanFocus
362 (JNIEnv *env, jobject obj)
363 {
364   void *ptr;
365   jboolean retval;
366
367   gdk_threads_enter ();
368
369   ptr = NSA_GET_PTR (env, obj);
370   
371   retval = GTK_WIDGET_CAN_FOCUS((GTK_WIDGET (ptr)));
372
373   gdk_threads_leave ();
374
375   return retval;
376 }
377
378 JNIEXPORT void JNICALL
379 Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetRequestFocus
380   (JNIEnv *env, jobject obj)
381 {
382   void *ptr;
383
384   gdk_threads_enter ();
385
386   ptr = NSA_GET_PTR (env, obj);
387   
388   gtk_widget_grab_focus (get_widget(GTK_WIDGET (ptr)));
389
390   gdk_threads_leave ();
391 }
392
393 /*
394  * Translate a Java KeyEvent object into a GdkEventKey event, then
395  * pass it to the GTK main loop for processing.
396  */
397 JNIEXPORT void JNICALL
398 Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetDispatchKeyEvent
399   (JNIEnv *env, jobject obj, jint id, jlong when, jint mods,
400    jint keyCode, jint keyLocation)
401 {
402   void *ptr;
403   GdkEvent *event = NULL;
404   GdkKeymapKey *keymap_keys = NULL;
405   gint n_keys = 0;
406   guint lookup_keyval = 0;
407
408   gdk_threads_enter ();
409
410   ptr = NSA_GET_PTR (env, obj);
411
412   if (id == AWT_KEY_PRESSED)
413     event = gdk_event_new (GDK_KEY_PRESS);
414   else if (id == AWT_KEY_RELEASED)
415     event = gdk_event_new (GDK_KEY_RELEASE);
416   else
417     {
418       gdk_threads_leave ();
419       /* Don't send AWT KEY_TYPED events to GTK. */
420       return;
421     }
422
423   if (GTK_IS_BUTTON (ptr))
424     event->key.window = GTK_BUTTON (get_widget(GTK_WIDGET (ptr)))->event_window;
425   else if (GTK_IS_SCROLLED_WINDOW (get_widget(GTK_WIDGET (ptr))))
426     event->key.window = GTK_WIDGET (GTK_SCROLLED_WINDOW (get_widget(GTK_WIDGET (ptr)))->container.child)->window;
427   else
428     event->key.window = get_widget(GTK_WIDGET (ptr))->window;
429
430   event->key.send_event = 0;
431   event->key.time = (guint32) when;
432
433   if (mods & AWT_SHIFT_DOWN_MASK)
434     event->key.state |= GDK_SHIFT_MASK;
435   if (mods & AWT_CTRL_DOWN_MASK)
436     event->key.state |= GDK_CONTROL_MASK;
437   if (mods & AWT_ALT_DOWN_MASK)
438     event->key.state |= GDK_MOD1_MASK;
439
440   /* This hack is needed because the AWT has no notion of num lock.
441      It infers numlock state from the only Java virtual keys that are
442      affected by it. */
443   if (keyCode == VK_NUMPAD9
444       || keyCode == VK_NUMPAD8
445       || keyCode == VK_NUMPAD7
446       || keyCode == VK_NUMPAD6
447       || keyCode == VK_NUMPAD5
448       || keyCode == VK_NUMPAD4
449       || keyCode == VK_NUMPAD3
450       || keyCode == VK_NUMPAD2
451       || keyCode == VK_NUMPAD1
452       || keyCode == VK_NUMPAD0
453       || keyCode == VK_DECIMAL)
454     event->key.state |= GDK_MOD2_MASK;
455
456   /* These values don't need to be filled in since GTK doesn't use
457      them. */
458   event->key.length = 0;
459   event->key.string = NULL;
460
461   lookup_keyval = cp_gtk_awt_keycode_to_keysym (keyCode, keyLocation);
462
463   if (!gdk_keymap_get_entries_for_keyval (gdk_keymap_get_default (),
464                                           lookup_keyval,
465                                           &keymap_keys,
466                                           &n_keys))
467     {
468       /* No matching keymap entry was found. */
469       g_printerr ("No matching keymap entries were found\n");
470       gdk_threads_leave ();
471       return;
472     }
473
474   /* Note: if n_keys > 1 then there are multiple hardware keycodes
475      that translate to lookup_keyval.  We arbitrarily choose the first
476      hardware keycode from the list returned by
477      gdk_keymap_get_entries_for_keyval. */
478
479   event->key.hardware_keycode = keymap_keys[0].keycode;
480   event->key.group =  keymap_keys[0].group;
481
482   g_free (keymap_keys);
483
484   if (!gdk_keymap_translate_keyboard_state (gdk_keymap_get_default (),
485                                             event->key.hardware_keycode,
486                                             event->key.state,
487                                             event->key.group,
488                                             &event->key.keyval,
489                                             NULL, NULL, NULL))
490     {
491       /* No matching keyval was found. */
492       g_printerr ("No matching keyval was found\n");
493       gdk_threads_leave ();
494       return;
495     }
496
497   /*  keyevent = (GdkEventKey *) event; */
498   /*  g_printerr ("generated event: sent: %d  time: %d  state: %d  keyval: %d  length: %d  string: %s  hardware_keycode: %d  group: %d\n", keyevent->send_event, keyevent->time, keyevent->state, keyevent->keyval, keyevent->length, keyevent->string, keyevent->hardware_keycode, keyevent->group); */
499
500   /* We already received the original key event on the window itself,
501      so we don't want to resend it. */
502   if (!GTK_IS_WINDOW (ptr))
503     {
504       if (GTK_IS_SCROLLED_WINDOW (get_widget(GTK_WIDGET (ptr))))
505         gtk_widget_event (GTK_WIDGET (GTK_SCROLLED_WINDOW (get_widget(GTK_WIDGET (ptr)))->container.child), event);
506       else
507         gtk_widget_event (get_widget(GTK_WIDGET (ptr)), event);
508     }
509
510   gdk_threads_leave ();
511 }
512
513 /*
514  * Find the origin of a widget's window.
515  */
516 JNIEXPORT void JNICALL 
517 Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWindowGetLocationOnScreen
518   (JNIEnv * env, jobject obj, jintArray jpoint)
519 {
520   void *ptr;
521   jint *point;
522
523   gdk_threads_enter ();
524
525   ptr = NSA_GET_PTR (env, obj);
526   point = (*env)->GetIntArrayElements (env, jpoint, 0);
527
528   gdk_window_get_root_origin (get_widget(GTK_WIDGET (ptr))->window, point, point+1);
529
530   (*env)->ReleaseIntArrayElements(env, jpoint, point, 0);
531
532   gdk_threads_leave ();
533 }
534
535 /*
536  * Find the origin of a widget
537  */
538 JNIEXPORT void JNICALL 
539 Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetGetLocationOnScreen
540   (JNIEnv * env, jobject obj, jintArray jpoint)
541 {
542   void *ptr;
543   jint *point;
544   GtkWidget *widget;
545
546   gdk_threads_enter ();
547
548   ptr = NSA_GET_PTR (env, obj);
549   point = (*env)->GetIntArrayElements (env, jpoint, 0);
550
551   widget = get_widget(GTK_WIDGET (ptr));
552   while(gtk_widget_get_parent(widget) != NULL)
553     widget = gtk_widget_get_parent(widget);
554   gdk_window_get_position (GTK_WIDGET(widget)->window, point, point+1);
555
556   *point += GTK_WIDGET(ptr)->allocation.x;
557   *(point+1) += GTK_WIDGET(ptr)->allocation.y;
558
559   (*env)->ReleaseIntArrayElements(env, jpoint, point, 0);
560
561   gdk_threads_leave ();
562 }
563
564 /*
565  * Find this widget's current size.
566  */
567 JNIEXPORT void JNICALL 
568 Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetGetDimensions
569   (JNIEnv *env, jobject obj, jintArray jdims)
570 {
571   void *ptr;
572   jint *dims;
573   GtkRequisition requisition;
574
575   gdk_threads_enter ();
576
577   ptr = NSA_GET_PTR (env, obj);
578
579   dims = (*env)->GetIntArrayElements (env, jdims, 0);  
580   dims[0] = dims[1] = 0;
581
582   gtk_widget_size_request (get_widget(GTK_WIDGET (ptr)), &requisition);
583
584   dims[0] = requisition.width;
585   dims[1] = requisition.height;
586
587   (*env)->ReleaseIntArrayElements (env, jdims, dims, 0);
588
589   gdk_threads_leave ();
590 }
591
592 /*
593  * Find this widget's preferred size.
594  */
595 JNIEXPORT void JNICALL 
596 Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetGetPreferredDimensions
597   (JNIEnv *env, jobject obj, jintArray jdims)
598 {
599   void *ptr;
600   jint *dims;
601   GtkRequisition current_req;
602   GtkRequisition natural_req;
603
604   gdk_threads_enter ();
605
606   ptr = NSA_GET_PTR (env, obj);
607
608   dims = (*env)->GetIntArrayElements (env, jdims, 0);  
609   dims[0] = dims[1] = 0;
610
611   /* Widgets that extend GtkWindow such as GtkFileChooserDialog may have
612      a default size.  These values seem more useful then the natural
613      requisition values, particularly for GtkFileChooserDialog. */
614   if (GTK_IS_WINDOW (get_widget(GTK_WIDGET (ptr))))
615     {
616       gint width, height;
617       gtk_window_get_default_size (GTK_WINDOW (get_widget(GTK_WIDGET (ptr))), &width, &height);
618
619       dims[0] = width;
620       dims[1] = height;
621     }
622   else
623     {
624       /* Save the widget's current size request. */
625       gtk_widget_size_request (get_widget(GTK_WIDGET (ptr)), &current_req);
626
627       /* Get the widget's "natural" size request. */
628       gtk_widget_set_size_request (get_widget(GTK_WIDGET (ptr)), -1, -1);
629       gtk_widget_size_request (get_widget(GTK_WIDGET (ptr)), &natural_req);
630
631       /* Reset the widget's size request. */
632       gtk_widget_set_size_request (get_widget(GTK_WIDGET (ptr)),
633                                    current_req.width, current_req.height);
634
635       dims[0] = natural_req.width;
636       dims[1] = natural_req.height;
637     }
638
639   (*env)->ReleaseIntArrayElements (env, jdims, dims, 0);
640
641   gdk_threads_leave ();
642 }
643
644 JNIEXPORT void JNICALL
645 Java_gnu_java_awt_peer_gtk_GtkComponentPeer_setNativeBounds
646   (JNIEnv *env, jobject obj, jint x, jint y, jint width, jint height)
647 {
648   GtkWidget *widget;
649   void *ptr;
650
651   gdk_threads_enter ();
652
653   ptr = NSA_GET_PTR (env, obj);
654
655   widget = GTK_WIDGET (ptr);
656
657   /* We assume that -1 is a width or height and not a request for the
658      widget's natural size. */
659   width = width < 0 ? 0 : width;
660   height = height < 0 ? 0 : height;
661
662   if (!(width == 0 && height == 0))
663     {
664       gtk_widget_set_size_request (widget, width, height);
665       /* The GTK_IS_FIXED check here prevents gtk_fixed_move being
666          called when our parent is a GtkScrolledWindow.  In that
667          case though, moving the child widget is invalid since a
668          ScrollPane only has one child and that child is always
669          located at (0, 0) in viewport coordinates. */
670       if (widget->parent != NULL && GTK_IS_FIXED (widget->parent))
671         gtk_fixed_move (GTK_FIXED (widget->parent), widget, x, y);
672     }
673
674   gdk_threads_leave ();
675 }
676
677 JNIEXPORT jintArray JNICALL 
678 Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetGetBackground
679   (JNIEnv *env, jobject obj)
680 {
681   void *ptr;
682   jintArray array;
683   int *rgb;
684   GdkColor bg;
685
686   gdk_threads_enter ();
687
688   ptr = NSA_GET_PTR (env, obj);
689
690   bg = GTK_WIDGET (ptr)->style->bg[GTK_STATE_NORMAL];
691
692   array = (*env)->NewIntArray (env, 3);
693
694   rgb = (*env)->GetIntArrayElements (env, array, NULL);
695   /* convert color data from 16 bit values down to 8 bit values */
696   rgb[0] = bg.red   >> 8;
697   rgb[1] = bg.green >> 8;
698   rgb[2] = bg.blue  >> 8;
699   (*env)->ReleaseIntArrayElements (env, array, rgb, 0);
700
701   gdk_threads_leave ();
702
703   return array;
704 }
705
706 JNIEXPORT jintArray JNICALL 
707 Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetGetForeground
708   (JNIEnv *env, jobject obj)
709 {
710   void *ptr;
711   jintArray array;
712   jint *rgb;
713   GdkColor fg;
714
715   gdk_threads_enter ();
716
717   ptr = NSA_GET_PTR (env, obj);
718
719   fg = get_widget(GTK_WIDGET (ptr))->style->fg[GTK_STATE_NORMAL];
720
721   array = (*env)->NewIntArray (env, 3);
722
723   rgb = (*env)->GetIntArrayElements (env, array, NULL);
724   /* convert color data from 16 bit values down to 8 bit values */
725   rgb[0] = fg.red   >> 8;
726   rgb[1] = fg.green >> 8;
727   rgb[2] = fg.blue  >> 8;
728   (*env)->ReleaseIntArrayElements (env, array, rgb, 0);
729
730   gdk_threads_leave ();
731
732   return array;
733 }
734
735 JNIEXPORT void JNICALL 
736 Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetSetBackground
737   (JNIEnv *env, jobject obj, jint red, jint green, jint blue)
738 {
739   GdkColor normal_color;
740   GdkColor active_color;
741   GtkWidget *widget;
742   void *ptr;
743
744   gdk_threads_enter ();
745
746   ptr = NSA_GET_PTR (env, obj);
747
748   normal_color.red = (red / 255.0) * 65535;
749   normal_color.green = (green / 255.0) * 65535;
750   normal_color.blue = (blue / 255.0) * 65535;
751
752   /* This calculation only approximates the active colors produced by
753      Sun's AWT. */
754   active_color.red = 0.85 * (red / 255.0) * 65535;
755   active_color.green = 0.85 * (green / 255.0) * 65535;
756   active_color.blue = 0.85 * (blue / 255.0) * 65535;
757
758   widget = find_bg_color_widget (GTK_WIDGET (ptr));
759
760   gtk_widget_modify_bg (widget, GTK_STATE_NORMAL, &normal_color);
761   gtk_widget_modify_bg (widget, GTK_STATE_ACTIVE, &active_color);
762   gtk_widget_modify_bg (widget, GTK_STATE_PRELIGHT, &normal_color);
763
764   gdk_threads_leave ();
765 }
766
767 JNIEXPORT void JNICALL 
768 Java_gnu_java_awt_peer_gtk_GtkComponentPeer_gtkWidgetSetForeground
769   (JNIEnv *env, jobject obj, jint red, jint green, jint blue)
770 {
771   GdkColor color;
772   GtkWidget *widget;
773   void *ptr;
774
775   gdk_threads_enter ();
776
777   ptr = NSA_GET_PTR (env, obj);
778
779   color.red = (red / 255.0) * 65535;
780   color.green = (green / 255.0) * 65535;
781   color.blue = (blue / 255.0) * 65535;
782
783   widget = find_fg_color_widget (GTK_WIDGET (ptr));
784
785   gtk_widget_modify_fg (widget, GTK_STATE_NORMAL, &color);
786   gtk_widget_modify_fg (widget, GTK_STATE_ACTIVE, &color);
787   gtk_widget_modify_fg (widget, GTK_STATE_PRELIGHT, &color);
788
789   gdk_threads_leave ();
790 }
791
792 JNIEXPORT void JNICALL
793 Java_gnu_java_awt_peer_gtk_GtkComponentPeer_realize (JNIEnv *env, jobject obj)
794 {
795   void *ptr;
796
797   gdk_threads_enter ();
798
799   ptr = NSA_GET_PTR (env, obj);
800
801   gtk_widget_realize (GTK_WIDGET (ptr));
802
803   gdk_threads_leave ();
804 }
805
806 JNIEXPORT void JNICALL
807 Java_gnu_java_awt_peer_gtk_GtkComponentPeer_setVisibleNative
808   (JNIEnv *env, jobject obj, jboolean visible)
809 {
810   gdk_threads_enter();
811
812   Java_gnu_java_awt_peer_gtk_GtkComponentPeer_setVisibleNativeUnlocked
813     (env, obj, visible);
814
815   gdk_threads_leave();
816 }
817
818 JNIEXPORT void JNICALL
819 Java_gnu_java_awt_peer_gtk_GtkComponentPeer_setVisibleNativeUnlocked
820   (JNIEnv *env, jobject obj, jboolean visible)
821 {
822   void *ptr;
823
824   ptr = NSA_GET_PTR (env, obj);
825
826   if (visible)
827     gtk_widget_show (GTK_WIDGET (ptr));
828   else
829     gtk_widget_hide (GTK_WIDGET (ptr));
830 }
831
832 JNIEXPORT jboolean JNICALL 
833 Java_gnu_java_awt_peer_gtk_GtkComponentPeer_isEnabled 
834   (JNIEnv *env, jobject obj)
835 {
836   void *ptr;
837   jboolean ret_val;
838   
839   gdk_threads_enter ();
840
841   ptr = NSA_GET_PTR (env, obj);
842
843   ret_val = GTK_WIDGET_IS_SENSITIVE (get_widget(GTK_WIDGET (ptr)));
844
845   gdk_threads_leave ();
846
847   return ret_val;
848 }
849
850 JNIEXPORT jboolean JNICALL 
851 Java_gnu_java_awt_peer_gtk_GtkComponentPeer_modalHasGrab
852   (JNIEnv *env __attribute__((unused)), jclass clazz __attribute__((unused)))
853 {
854   GtkWidget *widget;
855   jboolean retval;
856
857   gdk_threads_enter ();
858
859   widget = gtk_grab_get_current ();
860   retval = (widget && GTK_IS_WINDOW (widget) && GTK_WINDOW (widget)->modal);
861
862   gdk_threads_leave ();
863
864   return retval;
865 }
866
867 JNIEXPORT void JNICALL
868 Java_gnu_java_awt_peer_gtk_GtkComponentPeer_connectSignals
869   (JNIEnv *env, jobject obj)
870 {
871   void *ptr;
872   jobject *gref;
873
874   gdk_threads_enter ();
875
876   ptr = NSA_GET_PTR (env, obj);
877   gref = NSA_GET_GLOBAL_REF (env, obj);
878
879   cp_gtk_component_connect_signals (ptr, gref);
880
881   gdk_threads_leave ();
882 }
883
884 JNIEXPORT void JNICALL
885 Java_gnu_java_awt_peer_gtk_GtkComponentPeer_setNativeEventMask
886   (JNIEnv *env, jobject obj)
887 {
888   void *ptr;
889
890   gdk_threads_enter ();
891
892   ptr = NSA_GET_PTR (env, obj);
893
894   gtk_widget_add_events (get_widget(GTK_WIDGET (ptr)),
895                          GDK_POINTER_MOTION_MASK
896                          | GDK_BUTTON_MOTION_MASK
897                          | GDK_BUTTON_PRESS_MASK
898                          | GDK_BUTTON_RELEASE_MASK
899                          | GDK_KEY_PRESS_MASK
900                          | GDK_KEY_RELEASE_MASK
901                          | GDK_ENTER_NOTIFY_MASK
902                          | GDK_LEAVE_NOTIFY_MASK
903                          | GDK_STRUCTURE_MASK
904                          | GDK_KEY_PRESS_MASK
905                          | GDK_FOCUS_CHANGE_MASK);
906
907   gdk_threads_leave ();
908 }
909
910 static GtkWidget *
911 get_widget (GtkWidget *widget)
912 {
913   GtkWidget *w;
914
915   if (GTK_IS_EVENT_BOX (widget))
916     w = gtk_bin_get_child (GTK_BIN(widget));
917   else
918     w = widget;
919
920   return w;
921 }
922
923 /* FIXME: these functions should be implemented by overridding the
924    appropriate GtkComponentPeer methods. */
925 static GtkWidget *
926 find_fg_color_widget (GtkWidget *widget)
927 {
928   GtkWidget *fg_color_widget;
929
930   if (GTK_IS_EVENT_BOX (widget)
931       || (GTK_IS_BUTTON (widget)
932           && !GTK_IS_COMBO_BOX (widget)))
933     fg_color_widget = gtk_bin_get_child (GTK_BIN(widget));
934   else
935     fg_color_widget = widget;
936
937   return fg_color_widget;
938 }
939
940 static GtkWidget *
941 find_bg_color_widget (GtkWidget *widget)
942 {
943   GtkWidget *bg_color_widget;
944
945   bg_color_widget = widget;
946
947   return bg_color_widget;
948 }
949
950 void
951 cp_gtk_component_connect_expose_signals (GObject *ptr, jobject *gref)
952 {
953   g_signal_connect (G_OBJECT (ptr), "expose-event",
954                     G_CALLBACK (component_expose_cb), *gref);
955 }
956
957 void
958 cp_gtk_component_connect_focus_signals (GObject *ptr, jobject *gref)
959 {
960   g_signal_connect (G_OBJECT (ptr), "focus-in-event",
961                     G_CALLBACK (component_focus_in_cb), *gref);
962  
963   g_signal_connect (G_OBJECT (ptr), "focus-out-event",
964                     G_CALLBACK (component_focus_out_cb), *gref);
965 }
966
967 void
968 cp_gtk_component_connect_mouse_signals (GObject *ptr, jobject *gref)
969 {
970   g_signal_connect (G_OBJECT (ptr), "button-press-event",
971                     G_CALLBACK (component_button_press_cb), *gref);
972  
973   g_signal_connect (G_OBJECT (ptr), "button-release-event",
974                     G_CALLBACK (component_button_release_cb), *gref);
975  
976   g_signal_connect (G_OBJECT (ptr), "enter-notify-event",
977                     G_CALLBACK (component_enter_notify_cb), *gref);
978  
979   g_signal_connect (G_OBJECT (ptr), "leave-notify-event",
980                     G_CALLBACK (component_leave_notify_cb), *gref);
981
982   g_signal_connect (G_OBJECT (ptr), "motion-notify-event",
983                     G_CALLBACK (component_motion_notify_cb), *gref);
984
985   g_signal_connect (G_OBJECT (ptr), "scroll-event",
986                     G_CALLBACK (component_scroll_cb), *gref);
987 }
988
989 void
990 cp_gtk_component_connect_signals (GObject *ptr, jobject *gref)
991 {
992   cp_gtk_component_connect_expose_signals (ptr, gref);
993   cp_gtk_component_connect_focus_signals (ptr, gref);
994   cp_gtk_component_connect_mouse_signals (ptr, gref);
995 }
996
997 /* These variables are used to keep track of click counts.  The AWT
998    allows more than a triple click to occur but GTK doesn't report
999    more-than-triple clicks.  Also used for keeping track of scroll events.*/
1000 static jint click_count = 1;
1001 static guint32 button_click_time = 0;
1002 static GdkWindow *button_window = NULL;
1003 static guint button_number_direction = -1;
1004 static int hasBeenDragged;
1005
1006 static gboolean
1007 component_button_press_cb (GtkWidget *widget __attribute__((unused)),
1008                            GdkEventButton *event,
1009                            jobject peer)
1010 {
1011   /* Ignore double and triple click events. */
1012   if (event->type == GDK_2BUTTON_PRESS
1013       || event->type == GDK_3BUTTON_PRESS)
1014     return FALSE;
1015
1016   if ((event->time < (button_click_time + MULTI_CLICK_TIME))
1017       && (event->window == button_window)
1018       && (event->button == button_number_direction))
1019     click_count++;
1020   else
1021     click_count = 1;
1022       
1023   button_click_time = event->time;
1024   button_window = event->window;
1025   button_number_direction = event->button;
1026
1027   (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer,
1028                                 postMouseEventID,
1029                                 AWT_MOUSE_PRESSED, 
1030                                 (jlong)event->time,
1031                                 cp_gtk_state_to_awt_mods (event->state)
1032                                 | button_to_awt_mods (event->button),
1033                                 (jint)event->x,
1034                                 (jint)event->y, 
1035                                 click_count, 
1036                                 (event->button == 3) ? JNI_TRUE :
1037                                 JNI_FALSE);
1038
1039   hasBeenDragged = FALSE;
1040
1041   return FALSE;
1042 }
1043
1044 static gboolean
1045 component_button_release_cb (GtkWidget *widget __attribute__((unused)),
1046                              GdkEventButton *event,
1047                              jobject peer)
1048 {
1049   int width, height;
1050
1051   (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer,
1052                                 postMouseEventID,
1053                                 AWT_MOUSE_RELEASED, 
1054                                 (jlong)event->time,
1055                                 cp_gtk_state_to_awt_mods (event->state)
1056                                 | button_to_awt_mods (event->button),
1057                                 (jint)event->x,
1058                                 (jint)event->y, 
1059                                 click_count,
1060                                 JNI_FALSE);
1061
1062   /* Generate an AWT click event only if the release occured in the
1063      window it was pressed in, and the mouse has not been dragged since
1064      the last time it was pressed. */
1065   gdk_drawable_get_size (event->window, &width, &height);
1066   if (! hasBeenDragged
1067       && event->x >= 0
1068       && event->y >= 0
1069       && event->x <= width 
1070       && event->y <= height)
1071     {
1072       (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer,
1073                                     postMouseEventID,
1074                                     AWT_MOUSE_CLICKED, 
1075                                     (jlong)event->time,
1076                                     cp_gtk_state_to_awt_mods (event->state)
1077                                     | button_to_awt_mods (event->button),
1078                                     (jint)event->x,
1079                                     (jint)event->y, 
1080                                     click_count,
1081                                     JNI_FALSE);
1082     }
1083   return FALSE;
1084 }
1085  
1086 static gboolean
1087 component_motion_notify_cb (GtkWidget *widget __attribute__((unused)),
1088                             GdkEventMotion *event,
1089                             jobject peer)
1090 {
1091   if (event->state & (GDK_BUTTON1_MASK
1092                       | GDK_BUTTON2_MASK
1093                       | GDK_BUTTON3_MASK
1094                       | GDK_BUTTON4_MASK
1095                       | GDK_BUTTON5_MASK))
1096     {
1097       (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer,
1098                                     postMouseEventID,
1099                                     AWT_MOUSE_DRAGGED,
1100                                     (jlong)event->time,
1101                                     state_to_awt_mods_with_button_states (event->state),
1102                                     (jint)event->x,
1103                                     (jint)event->y,
1104                                     0,
1105                                     JNI_FALSE);
1106
1107       hasBeenDragged = TRUE;
1108     }
1109   else
1110     {
1111       (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, postMouseEventID,
1112                                     AWT_MOUSE_MOVED,
1113                                     (jlong)event->time,
1114                                     cp_gtk_state_to_awt_mods (event->state),
1115                                     (jint)event->x,
1116                                     (jint)event->y,
1117                                     0,
1118                                     JNI_FALSE);
1119     }
1120   return FALSE;
1121 }
1122
1123 static gboolean
1124 component_scroll_cb (GtkWidget *widget __attribute__((unused)),
1125                      GdkEventScroll *event,
1126                      jobject peer)
1127 {
1128   int rotation;
1129   /** Record click count for specific direction. */
1130   if ((event->time < (button_click_time + MULTI_CLICK_TIME))
1131       && (event->window == button_window)
1132       && (event->direction == button_number_direction))
1133     click_count++;
1134   else
1135     click_count = 1;
1136       
1137   button_click_time = event->time;
1138   button_window = event->window;
1139   button_number_direction = event->direction;
1140
1141   if (event->direction == GDK_SCROLL_UP
1142       || event->direction == GDK_SCROLL_LEFT)
1143     rotation = -1;
1144   else
1145     rotation = 1;
1146
1147   (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer,
1148                                        postMouseWheelEventID,
1149                                        AWT_MOUSE_WHEEL, 
1150                                        (jlong)event->time,
1151                                        cp_gtk_state_to_awt_mods (event->state),
1152                                        (jint)event->x,
1153                                        (jint)event->y, 
1154                                        click_count, 
1155                                        JNI_FALSE,
1156                                        AWT_WHEEL_UNIT_SCROLL,
1157                                        1 /* amount */,
1158                                        rotation);
1159   return FALSE;
1160 }
1161
1162 static gboolean
1163 component_enter_notify_cb (GtkWidget *widget __attribute__((unused)),
1164                            GdkEventCrossing *event,
1165                            jobject peer)
1166 {
1167   /* We are not interested in enter events that are due to
1168      grab/ungrab and not to actually crossing boundaries */
1169   if (event->mode == GDK_CROSSING_NORMAL)
1170     {
1171       (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer, postMouseEventID,
1172                                     AWT_MOUSE_ENTERED, 
1173                                     (jlong)event->time,
1174                                     state_to_awt_mods_with_button_states (event->state), 
1175                                     (jint)event->x,
1176                                     (jint)event->y, 
1177                                     0,
1178                                     JNI_FALSE);
1179     }
1180   return FALSE;
1181 }
1182
1183 static gboolean
1184 component_leave_notify_cb (GtkWidget *widget __attribute__((unused)),
1185                            GdkEventCrossing *event,
1186                            jobject peer)
1187 {
1188   /* We are not interested in leave events that are due to
1189      grab/ungrab and not to actually crossing boundaries */
1190   if (event->mode == GDK_CROSSING_NORMAL)
1191     {
1192       (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer,
1193                                     postMouseEventID,
1194                                     AWT_MOUSE_EXITED, 
1195                                     (jlong)event->time,
1196                                     state_to_awt_mods_with_button_states (event->state),
1197                                     (jint)event->x,
1198                                     (jint)event->y, 
1199                                     0,
1200                                     JNI_FALSE);
1201     }
1202   return FALSE;
1203 }
1204
1205 static gboolean
1206 component_expose_cb (GtkWidget *widget __attribute__((unused)),
1207                      GdkEventExpose *event,
1208                      jobject peer)
1209 {
1210   (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer,
1211                                 postExposeEventID,
1212                                 (jint)event->area.x,
1213                                 (jint)event->area.y,
1214                                 (jint)event->area.width,
1215                                 (jint)event->area.height);
1216
1217   return FALSE;
1218 }
1219
1220 static gboolean
1221 component_focus_in_cb (GtkWidget *widget __attribute((unused)),
1222                        GdkEventFocus *event __attribute((unused)),
1223                        jobject peer)
1224 {
1225   (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer,
1226                                 postFocusEventID,
1227                                 AWT_FOCUS_GAINED,
1228                                 JNI_FALSE);
1229
1230   return FALSE;
1231 }
1232
1233 static gboolean
1234 component_focus_out_cb (GtkWidget *widget __attribute((unused)),
1235                         GdkEventFocus *event __attribute((unused)),
1236                         jobject peer)
1237 {
1238   (*cp_gtk_gdk_env())->CallVoidMethod (cp_gtk_gdk_env(), peer,
1239                                 postFocusEventID,
1240                                 AWT_FOCUS_LOST,
1241                                 JNI_FALSE);
1242
1243   return FALSE;
1244 }