Merge from the pain train
[official-gcc.git] / libjava / jni / gtk-peer / gnu_java_awt_peer_gtk_GtkToolkit.c
blob8cb9e2f5d68c31cb2ed53b92e6775f9ab409fad3
1 /* gtktoolkit.c -- Native portion of GtkToolkit
2 Copyright (C) 1998, 1999 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 "gnu_java_awt_peer_gtk_GtkToolkit.h"
41 #include "gthread-jni.h"
43 #include <sys/time.h>
45 #ifdef JVM_SUN
46 struct state_table *native_state_table;
47 struct state_table *native_global_ref_table;
48 #endif
50 jmethodID setBoundsCallbackID;
52 jmethodID postActionEventID;
53 jmethodID postMenuActionEventID;
54 jmethodID postMouseEventID;
55 jmethodID postConfigureEventID;
56 jmethodID postExposeEventID;
57 jmethodID postKeyEventID;
58 jmethodID postFocusEventID;
59 jmethodID postAdjustmentEventID;
60 jmethodID postItemEventID;
61 jmethodID choicePostItemEventID;
62 jmethodID postListItemEventID;
63 jmethodID postTextEventID;
64 jmethodID postWindowEventID;
65 jmethodID postInsetsChangedEventID;
66 jmethodID windowGetWidthID;
67 jmethodID windowGetHeightID;
69 jmethodID beginNativeRepaintID;
70 jmethodID endNativeRepaintID;
72 jmethodID initComponentGraphicsID;
73 jmethodID initComponentGraphics2DID;
74 jmethodID setCursorID;
76 JavaVM *java_vm;
78 union env_union
80 void *void_env;
81 JNIEnv *jni_env;
84 JNIEnv *
85 gdk_env()
87 union env_union tmp;
88 g_assert((*java_vm)->GetEnv(java_vm, &tmp.void_env, JNI_VERSION_1_2) == JNI_OK);
89 return tmp.jni_env;
93 GtkWindowGroup *global_gtk_window_group;
95 static void init_glib_threads(JNIEnv *, jint);
97 double dpi_conversion_factor;
99 static void init_dpi_conversion_factor (void);
100 static void dpi_changed_cb (GtkSettings *settings,
101 GParamSpec *pspec);
104 * Call gtk_init. It is very important that this happen before any other
105 * gtk calls.
107 * The portableNativeSync argument may have the values:
108 * 1 if the Java property gnu.classpath.awt.gtk.portable.native.sync
109 * is set to "true".
110 * 0 if it is set to "false"
111 * -1 if unset.
115 JNIEXPORT void JNICALL
116 Java_gnu_java_awt_peer_gtk_GtkToolkit_gtkInit (JNIEnv *env,
117 jclass clazz __attribute__((unused)),
118 jint portableNativeSync)
120 int argc = 1;
121 char **argv;
122 char *homedir, *rcpath = NULL;
124 jclass gtkgenericpeer, gtkcomponentpeer, gtkchoicepeer, gtkwindowpeer, gtkscrollbarpeer, gtklistpeer,
125 gtkmenuitempeer, gtktextcomponentpeer, window, gdkgraphics, gdkgraphics2d;
127 gtkgenericpeer = (*env)->FindClass(env, "gnu/java/awt/peer/gtk/GtkGenericPeer");
129 NSA_INIT (env, gtkgenericpeer);
131 g_assert((*env)->GetJavaVM(env, &java_vm) == 0);
133 /* GTK requires a program's argc and argv variables, and requires that they
134 be valid. Set it up. */
135 argv = (char **) g_malloc (sizeof (char *) * 2);
136 argv[0] = (char *) g_malloc(1);
137 #if 1
138 strcpy(argv[0], "");
139 #else /* The following is a more efficient alternative, but less intuitively
140 * expresses what we are trying to do. This code is only run once, so
141 * I'm going for intuitive. */
142 argv[0][0] = '\0';
143 #endif
144 argv[1] = NULL;
146 init_glib_threads(env, portableNativeSync);
148 /* From GDK 2.0 onwards we have to explicitly call gdk_threads_init */
149 gdk_threads_init();
151 gtk_init (&argc, &argv);
153 gdk_rgb_init ();
154 gtk_widget_set_default_colormap (gdk_rgb_get_cmap ());
155 gtk_widget_set_default_visual (gdk_rgb_get_visual ());
157 /* Make sure queued calls don't get sent to GTK/GDK while
158 we're shutting down. */
159 atexit (gdk_threads_enter);
161 gdk_event_handler_set ((GdkEventFunc)awt_event_handler, NULL, NULL);
163 if ((homedir = getenv ("HOME")))
165 rcpath = (char *) g_malloc (strlen (homedir) + strlen (RC_FILE) + 2);
166 sprintf (rcpath, "%s/%s", homedir, RC_FILE);
169 gtk_rc_parse ((rcpath) ? rcpath : RC_FILE);
171 g_free (rcpath);
172 g_free (argv[0]);
173 g_free (argv);
175 /* setup cached IDs for posting GTK events to Java */
177 window = (*env)->FindClass (env, "java/awt/Window");
179 gtkcomponentpeer = (*env)->FindClass (env,
180 "gnu/java/awt/peer/gtk/GtkComponentPeer");
181 gtkchoicepeer = (*env)->FindClass (env,
182 "gnu/java/awt/peer/gtk/GtkChoicePeer");
183 gtkwindowpeer = (*env)->FindClass (env,
184 "gnu/java/awt/peer/gtk/GtkWindowPeer");
185 gtkscrollbarpeer = (*env)->FindClass (env,
186 "gnu/java/awt/peer/gtk/GtkScrollbarPeer");
187 gtklistpeer = (*env)->FindClass (env, "gnu/java/awt/peer/gtk/GtkListPeer");
188 gtkmenuitempeer = (*env)->FindClass (env,
189 "gnu/java/awt/peer/gtk/GtkMenuItemPeer");
190 gtktextcomponentpeer = (*env)->FindClass (env,
191 "gnu/java/awt/peer/gtk/GtkTextComponentPeer");
192 gdkgraphics = (*env)->FindClass (env,
193 "gnu/java/awt/peer/gtk/GdkGraphics");
194 gdkgraphics2d = (*env)->FindClass (env,
195 "gnu/java/awt/peer/gtk/GdkGraphics2D");
196 setBoundsCallbackID = (*env)->GetMethodID (env, window,
197 "setBoundsCallback",
198 "(IIII)V");
200 postMenuActionEventID = (*env)->GetMethodID (env, gtkmenuitempeer,
201 "postMenuActionEvent",
202 "()V");
203 postMouseEventID = (*env)->GetMethodID (env, gtkcomponentpeer,
204 "postMouseEvent", "(IJIIIIZ)V");
205 setCursorID = (*env)->GetMethodID (env, gtkcomponentpeer,
206 "setCursor", "()V");
207 beginNativeRepaintID = (*env)->GetMethodID (env, gtkcomponentpeer,
208 "beginNativeRepaint", "()V");
210 endNativeRepaintID = (*env)->GetMethodID (env, gtkcomponentpeer,
211 "endNativeRepaint", "()V");
213 postConfigureEventID = (*env)->GetMethodID (env, gtkwindowpeer,
214 "postConfigureEvent", "(IIII)V");
215 postWindowEventID = (*env)->GetMethodID (env, gtkwindowpeer,
216 "postWindowEvent",
217 "(ILjava/awt/Window;I)V");
218 postInsetsChangedEventID = (*env)->GetMethodID (env, gtkwindowpeer,
219 "postInsetsChangedEvent",
220 "(IIII)V");
221 windowGetWidthID = (*env)->GetMethodID (env, gtkwindowpeer,
222 "getWidth", "()I");
223 windowGetHeightID = (*env)->GetMethodID (env, gtkwindowpeer,
224 "getHeight", "()I");
226 postExposeEventID = (*env)->GetMethodID (env, gtkcomponentpeer,
227 "postExposeEvent", "(IIII)V");
228 postKeyEventID = (*env)->GetMethodID (env, gtkcomponentpeer,
229 "postKeyEvent", "(IJIICI)V");
230 postFocusEventID = (*env)->GetMethodID (env, gtkcomponentpeer,
231 "postFocusEvent", "(IZ)V");
232 postAdjustmentEventID = (*env)->GetMethodID (env, gtkscrollbarpeer,
233 "postAdjustmentEvent",
234 "(II)V");
235 postItemEventID = (*env)->GetMethodID (env, gtkcomponentpeer,
236 "postItemEvent",
237 "(Ljava/lang/Object;I)V");
238 choicePostItemEventID = (*env)->GetMethodID (env, gtkchoicepeer,
239 "choicePostItemEvent",
240 "(Ljava/lang/String;I)V");
241 postListItemEventID = (*env)->GetMethodID (env, gtklistpeer,
242 "postItemEvent",
243 "(II)V");
244 postTextEventID = (*env)->GetMethodID (env, gtktextcomponentpeer,
245 "postTextEvent",
246 "()V");
247 initComponentGraphicsID = (*env)->GetMethodID (env, gdkgraphics,
248 "initComponentGraphics",
249 "()V");
250 initComponentGraphics2DID = (*env)->GetMethodID (env, gdkgraphics2d,
251 "initComponentGraphics2D",
252 "()V");
253 global_gtk_window_group = gtk_window_group_new ();
255 init_dpi_conversion_factor ();
259 /** Initialize GLIB's threads properly, based on the value of the
260 gnu.classpath.awt.gtk.portable.native.sync Java system property. If
261 that's unset, use the PORTABLE_NATIVE_SYNC config.h macro. (TODO:
262 In some release following 0.10, that config.h macro will go away.)
264 static void
265 init_glib_threads(JNIEnv *env, jint portableNativeSync)
267 if (portableNativeSync < 0)
269 #ifdef PORTABLE_NATIVE_SYNC /* Default value, if not set by the Java system
270 property */
271 portableNativeSync = 1;
272 #else
273 portableNativeSync = 0;
274 #endif
277 (*env)->GetJavaVM( env, &the_vm );
278 if (portableNativeSync)
279 g_thread_init ( &portable_native_sync_jni_functions );
280 else
281 g_thread_init ( NULL );
283 /* Debugging progress message; uncomment if needed: */
284 /* printf("called gthread init\n"); */
288 /* This is a big hack, needed until this pango bug is resolved:
289 http://bugzilla.gnome.org/show_bug.cgi?id=119081.
290 See: http://mail.gnome.org/archives/gtk-i18n-list/2003-August/msg00001.html
291 for details. */
292 static void
293 init_dpi_conversion_factor ()
295 GtkSettings *settings = gtk_settings_get_default ();
296 GObjectClass *klass;
298 klass = G_OBJECT_CLASS (GTK_SETTINGS_GET_CLASS (settings));
299 if (g_object_class_find_property (klass, "gtk-xft-dpi"))
301 int int_dpi;
302 g_object_get (settings, "gtk-xft-dpi", &int_dpi, NULL);
303 /* If int_dpi == -1 gtk-xft-dpi returns the default value. So we
304 have to do approximate calculation here. */
305 if (int_dpi < 0)
306 dpi_conversion_factor = PANGO_SCALE * 72.0 / 96.;
307 else
308 dpi_conversion_factor = PANGO_SCALE * 72.0 / (int_dpi / PANGO_SCALE);
310 g_signal_connect (settings, "notify::gtk-xft-dpi",
311 G_CALLBACK (dpi_changed_cb), NULL);
313 else
314 /* Approximate. */
315 dpi_conversion_factor = PANGO_SCALE * 72.0 / 96.;
318 static void
319 dpi_changed_cb (GtkSettings *settings,
320 GParamSpec *pspec __attribute__((unused)))
322 int int_dpi;
323 g_object_get (settings, "gtk-xft-dpi", &int_dpi, NULL);
324 if (int_dpi < 0)
325 dpi_conversion_factor = PANGO_SCALE * 72.0 / 96.;
326 else
327 dpi_conversion_factor = PANGO_SCALE * 72.0 / (int_dpi / PANGO_SCALE);
330 static int
331 within_human_latency_tolerance(struct timeval *init)
333 struct timeval curr;
334 unsigned long milliseconds_elapsed;
336 gettimeofday(&curr, NULL);
338 milliseconds_elapsed = (((curr.tv_sec * 1000) + (curr.tv_usec / 1000))
339 - ((init->tv_sec * 1000) + (init->tv_usec / 1000)));
341 return milliseconds_elapsed < 100;
345 JNIEXPORT void JNICALL
346 Java_gnu_java_awt_peer_gtk_GtkToolkit_iterateNativeQueue
347 (JNIEnv *env,
348 jobject self __attribute__((unused)),
349 jobject lockedQueue,
350 jboolean block)
352 /* We're holding an EventQueue lock, and we're about to acquire the GDK
353 * lock before dropping the EventQueue lock. This can deadlock if someone
354 * holds the GDK lock and wants to acquire the EventQueue lock; however
355 * all callbacks from GTK happen with the GDK lock released, so this
356 * would only happen in an odd case such as some JNI helper code
357 * acquiring the GDK lock and calling back into
358 * EventQueue.getNextEvent().
361 struct timeval init;
362 gettimeofday(&init, NULL);
364 gdk_threads_enter ();
365 (*env)->MonitorExit (env, lockedQueue);
367 if (block)
370 /* If we're blocking-when-empty, we want a do .. while loop. */
372 gtk_main_iteration ();
373 while (within_human_latency_tolerance (&init)
374 && gtk_events_pending ());
376 else
378 /* If we're not blocking-when-empty, we want a while loop. */
379 while (within_human_latency_tolerance (&init)
380 && gtk_events_pending ())
381 gtk_main_iteration ();
384 (*env)->MonitorEnter (env, lockedQueue);
385 gdk_threads_leave ();
388 JNIEXPORT void JNICALL
389 Java_gnu_java_awt_peer_gtk_GtkToolkit_wakeNativeQueue
390 (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)))
392 g_main_context_wakeup (NULL);
395 JNIEXPORT jboolean JNICALL
396 Java_gnu_java_awt_peer_gtk_GtkToolkit_nativeQueueEmpty
397 (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)))
399 jboolean empty = FALSE;
400 gdk_threads_enter ();
401 empty = ! gtk_events_pending();
402 gdk_threads_leave ();
403 return empty;
407 static jint gdk_color_to_java_color (GdkColor color);
410 JNIEXPORT void JNICALL
411 Java_gnu_java_awt_peer_gtk_GtkToolkit_beep
412 (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)))
414 gdk_threads_enter ();
415 gdk_beep ();
416 gdk_threads_leave ();
419 JNIEXPORT void JNICALL
420 Java_gnu_java_awt_peer_gtk_GtkToolkit_sync
421 (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)))
423 gdk_threads_enter ();
424 gdk_flush ();
425 gdk_threads_leave ();
428 JNIEXPORT void JNICALL
429 Java_gnu_java_awt_peer_gtk_GtkToolkit_getScreenSizeDimensions
430 (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)),
431 jintArray jdims)
433 jint *dims = (*env)->GetIntArrayElements (env, jdims, 0);
435 gdk_threads_enter ();
437 dims[0] = gdk_screen_width ();
438 dims[1] = gdk_screen_height ();
440 gdk_threads_leave ();
442 (*env)->ReleaseIntArrayElements(env, jdims, dims, 0);
445 JNIEXPORT jint JNICALL
446 Java_gnu_java_awt_peer_gtk_GtkToolkit_getScreenResolution
447 (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)))
449 jint res;
451 gdk_threads_enter ();
453 res = gdk_screen_width () / (gdk_screen_width_mm () / 25.4);
455 gdk_threads_leave ();
456 return res;
459 #define CONVERT(type, state) \
460 gdk_color_to_java_color (style->type[GTK_STATE_ ## state])
462 JNIEXPORT void JNICALL
463 Java_gnu_java_awt_peer_gtk_GtkToolkit_loadSystemColors
464 (JNIEnv *env, jobject obj __attribute__((unused)),
465 jintArray jcolors)
467 jint *colors;
468 GtkStyle *style;
470 colors = (*env)->GetIntArrayElements (env, jcolors, 0);
472 gdk_threads_enter ();
474 style = gtk_widget_get_default_style ();
476 colors[AWT_DESKTOP] = CONVERT (bg, SELECTED);
477 colors[AWT_ACTIVE_CAPTION] = CONVERT (bg, SELECTED);
478 colors[AWT_ACTIVE_CAPTION_TEXT] = CONVERT (text, SELECTED);
479 colors[AWT_ACTIVE_CAPTION_BORDER] = CONVERT (fg, NORMAL);
480 colors[AWT_INACTIVE_CAPTION] = CONVERT (base, INSENSITIVE);
481 colors[AWT_INACTIVE_CAPTION_TEXT] = CONVERT (fg, INSENSITIVE);
482 colors[AWT_INACTIVE_CAPTION_BORDER] = CONVERT (fg, INSENSITIVE);
483 colors[AWT_WINDOW] = CONVERT (bg, NORMAL);
484 colors[AWT_WINDOW_BORDER] = CONVERT (fg, NORMAL);
485 colors[AWT_WINDOW_TEXT] = CONVERT (fg, NORMAL);
486 colors[AWT_MENU] = CONVERT (bg, NORMAL);
487 colors[AWT_MENU_TEXT] = CONVERT (fg, NORMAL);
488 colors[AWT_TEXT] = CONVERT (bg, NORMAL);
489 colors[AWT_TEXT_TEXT] = CONVERT (fg, NORMAL);
490 colors[AWT_TEXT_HIGHLIGHT] = CONVERT (bg, SELECTED);
491 colors[AWT_TEXT_HIGHLIGHT_TEXT] = CONVERT (fg, SELECTED);
492 colors[AWT_TEXT_INACTIVE_TEXT] = CONVERT (bg, INSENSITIVE);
493 colors[AWT_CONTROL] = CONVERT (bg, NORMAL);
494 colors[AWT_CONTROL_TEXT] = CONVERT (fg, NORMAL);
495 colors[AWT_CONTROL_HIGHLIGHT] = CONVERT (base, ACTIVE);
496 colors[AWT_CONTROL_LT_HIGHLIGHT] = CONVERT (bg, PRELIGHT);
497 colors[AWT_CONTROL_SHADOW] = CONVERT (bg, ACTIVE);
498 colors[AWT_CONTROL_DK_SHADOW] = CONVERT (fg, INSENSITIVE);
499 colors[AWT_SCROLLBAR] = CONVERT (base, INSENSITIVE);
500 colors[AWT_INFO] = CONVERT (bg, NORMAL);
501 colors[AWT_INFO_TEXT] = CONVERT (fg, NORMAL);
503 gdk_threads_leave ();
505 (*env)->ReleaseIntArrayElements(env, jcolors, colors, 0);
508 #undef CONVERT
510 static jint
511 gdk_color_to_java_color (GdkColor gdk_color)
513 guchar red;
514 guchar green;
515 guchar blue;
516 float factor;
518 factor = 255.0 / 65535.0;
520 red = (float) gdk_color.red * factor;
521 green = (float) gdk_color.green * factor;
522 blue = (float) gdk_color.blue * factor;
524 return (jint) (0xff000000 | (red << 16) | (green << 8) | blue);