1 /* gtktoolkit.c -- Native portion of GtkToolkit
2 Copyright (C) 1998, 1999, 2005 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)
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., 51 Franklin Street, Fifth Floor, Boston, MA
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
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. */
40 #include "gnu_java_awt_peer_gtk_GtkToolkit.h"
41 #include "gthread-jni.h"
45 #define RC_FILE ".classpath-gtkrc"
47 /* From java.awt.SystemColor */
49 #define AWT_ACTIVE_CAPTION 1
50 #define AWT_ACTIVE_CAPTION_TEXT 2
51 #define AWT_ACTIVE_CAPTION_BORDER 3
52 #define AWT_INACTIVE_CAPTION 4
53 #define AWT_INACTIVE_CAPTION_TEXT 5
54 #define AWT_INACTIVE_CAPTION_BORDER 6
56 #define AWT_WINDOW_BORDER 8
57 #define AWT_WINDOW_TEXT 9
59 #define AWT_MENU_TEXT 11
61 #define AWT_TEXT_TEXT 13
62 #define AWT_TEXT_HIGHLIGHT 14
63 #define AWT_TEXT_HIGHLIGHT_TEXT 15
64 #define AWT_TEXT_INACTIVE_TEXT 16
65 #define AWT_CONTROL 17
66 #define AWT_CONTROL_TEXT 18
67 #define AWT_CONTROL_HIGHLIGHT 19
68 #define AWT_CONTROL_LT_HIGHLIGHT 20
69 #define AWT_CONTROL_SHADOW 21
70 #define AWT_CONTROL_DK_SHADOW 22
71 #define AWT_SCROLLBAR 23
73 #define AWT_INFO_TEXT 25
74 #define AWT_NUM_COLORS 26
76 struct state_table *cp_gtk_native_state_table;
77 struct state_table *cp_gtk_native_global_ref_table;
79 static jclass gtkgenericpeer;
80 static JavaVM *java_vm;
81 static jmethodID printCurrentThreadID;
93 g_assert((*java_vm)->GetEnv(java_vm, &tmp.void_env, JNI_VERSION_1_2) == JNI_OK);
98 GtkWindowGroup *cp_gtk_global_window_group;
99 double cp_gtk_dpi_conversion_factor;
101 static void init_glib_threads(JNIEnv *, jint);
103 static void init_dpi_conversion_factor (void);
104 static void dpi_changed_cb (GtkSettings *settings,
107 #if GTK_MINOR_VERSION > 4
108 static GLogFunc old_glog_func;
109 static void glog_func (const gchar *log_domain,
110 GLogLevelFlags log_level,
111 const gchar *message,
116 * Call gtk_init. It is very important that this happen before any other
119 * The portableNativeSync argument may have the values:
120 * 1 if the Java property gnu.classpath.awt.gtk.portable.native.sync
122 * 0 if it is set to "false"
127 JNIEXPORT void JNICALL
128 Java_gnu_java_awt_peer_gtk_GtkToolkit_gtkInit (JNIEnv *env,
129 jclass clazz __attribute__((unused)),
130 jint portableNativeSync)
134 char *homedir, *rcpath = NULL;
136 gtkgenericpeer = (*env)->FindClass(env, "gnu/java/awt/peer/gtk/GtkGenericPeer");
138 gtkgenericpeer = (*env)->NewGlobalRef(env, gtkgenericpeer);
140 printCurrentThreadID = (*env)->GetStaticMethodID (env, gtkgenericpeer,
141 "printCurrentThread", "()V");
143 NSA_INIT (env, gtkgenericpeer);
145 g_assert((*env)->GetJavaVM(env, &java_vm) == 0);
147 /* GTK requires a program's argc and argv variables, and requires that they
148 be valid. Set it up. */
149 argv = (char **) g_malloc (sizeof (char *) * 2);
150 argv[0] = (char *) g_malloc(1);
154 init_glib_threads(env, portableNativeSync);
156 /* From GDK 2.0 onwards we have to explicitly call gdk_threads_init */
159 gtk_init (&argc, &argv);
162 XSynchronize (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), True);
165 gtk_widget_set_default_colormap (gdk_rgb_get_colormap ());
167 /* Make sure queued calls don't get sent to GTK/GDK while
168 we're shutting down. */
169 atexit (gdk_threads_enter);
171 if ((homedir = getenv ("HOME")))
173 rcpath = (char *) g_malloc (strlen (homedir) + strlen (RC_FILE) + 2);
174 sprintf (rcpath, "%s/%s", homedir, RC_FILE);
177 gtk_rc_parse ((rcpath) ? rcpath : RC_FILE);
183 /* On errors or warning print a whole stacktrace. */
184 #if GTK_MINOR_VERSION > 4
185 old_glog_func = g_log_set_default_handler (&glog_func, NULL);
188 cp_gtk_button_init_jni ();
189 cp_gtk_checkbox_init_jni ();
190 cp_gtk_choice_init_jni ();
191 cp_gtk_component_init_jni ();
192 cp_gtk_filedialog_init_jni ();
193 cp_gtk_list_init_jni ();
194 cp_gtk_menuitem_init_jni ();
195 cp_gtk_scrollbar_init_jni ();
196 cp_gtk_textcomponent_init_jni ();
197 cp_gtk_window_init_jni ();
199 cp_gtk_global_window_group = gtk_window_group_new ();
201 init_dpi_conversion_factor ();
205 /** Initialize GLIB's threads properly, based on the value of the
206 gnu.classpath.awt.gtk.portable.native.sync Java system property. If
207 that's unset, use the PORTABLE_NATIVE_SYNC config.h macro. (TODO:
208 In some release following 0.10, that config.h macro will go away.)
211 init_glib_threads(JNIEnv *env, jint portableNativeSync)
213 if (portableNativeSync < 0)
215 #ifdef PORTABLE_NATIVE_SYNC /* Default value, if not set by the Java system
217 portableNativeSync = 1;
219 portableNativeSync = 0;
223 (*env)->GetJavaVM( env, &cp_gtk_the_vm );
224 if (!g_thread_supported ())
226 if (portableNativeSync)
227 g_thread_init ( &cp_gtk_portable_native_sync_jni_functions );
229 g_thread_init ( NULL );
233 /* Warn if portable native sync is desired but the threading
234 system is already initialized. In that case we can't
235 override the threading implementation with our portable
236 native sync functions. */
237 if (portableNativeSync)
238 g_printerr ("peer warning: portable native sync disabled.\n");
241 /* Debugging progress message; uncomment if needed: */
242 /* printf("called gthread init\n"); */
246 cp_gtk_print_current_thread (void)
248 (*cp_gtk_gdk_env())->CallStaticVoidMethod (cp_gtk_gdk_env(), gtkgenericpeer, printCurrentThreadID);
251 /* This is a big hack, needed until this pango bug is resolved:
252 http://bugzilla.gnome.org/show_bug.cgi?id=119081.
253 See: http://mail.gnome.org/archives/gtk-i18n-list/2003-August/msg00001.html
256 init_dpi_conversion_factor ()
258 GtkSettings *settings = gtk_settings_get_default ();
261 klass = G_OBJECT_CLASS (GTK_SETTINGS_GET_CLASS (settings));
262 if (g_object_class_find_property (klass, "gtk-xft-dpi"))
265 g_object_get (settings, "gtk-xft-dpi", &int_dpi, NULL);
266 /* If int_dpi == -1 gtk-xft-dpi returns the default value. So we
267 have to do approximate calculation here. */
269 cp_gtk_dpi_conversion_factor = PANGO_SCALE * 72.0 / 96.;
271 cp_gtk_dpi_conversion_factor =
272 PANGO_SCALE * 72.0 / (int_dpi / PANGO_SCALE);
274 g_signal_connect (settings, "notify::gtk-xft-dpi",
275 G_CALLBACK (dpi_changed_cb), NULL);
279 cp_gtk_dpi_conversion_factor = PANGO_SCALE * 72.0 / 96.;
283 dpi_changed_cb (GtkSettings *settings,
284 GParamSpec *pspec __attribute__((unused)))
287 g_object_get (settings, "gtk-xft-dpi", &int_dpi, NULL);
289 cp_gtk_dpi_conversion_factor = PANGO_SCALE * 72.0 / 96.;
291 cp_gtk_dpi_conversion_factor =
292 PANGO_SCALE * 72.0 / (int_dpi / PANGO_SCALE);
295 #if GTK_MINOR_VERSION > 4
297 glog_func (const gchar *log_domain,
298 GLogLevelFlags log_level,
299 const gchar *message,
302 old_glog_func (log_domain, log_level, message, user_data);
303 if (log_level & (G_LOG_LEVEL_ERROR
304 | G_LOG_LEVEL_CRITICAL
305 | G_LOG_LEVEL_WARNING))
307 JNIEnv *env = cp_gtk_gdk_env ();
308 jthrowable *exc = (*env)->ExceptionOccurred(env);
309 gchar *detail = g_strconcat (log_domain, ": ", message, NULL);
310 JCL_ThrowException (env, "java/lang/InternalError", detail);
312 (*env)->ExceptionDescribe (env);
314 (*env)->Throw (env, exc);
316 (*env)->ExceptionClear (env);
321 JNIEXPORT void JNICALL
322 Java_gnu_java_awt_peer_gtk_GtkToolkit_gtkMain
323 (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)))
325 gdk_threads_enter ();
329 gdk_threads_leave ();
333 static jint gdk_color_to_java_color (GdkColor color);
336 JNIEXPORT void JNICALL
337 Java_gnu_java_awt_peer_gtk_GtkToolkit_beep
338 (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)))
340 gdk_threads_enter ();
344 gdk_threads_leave ();
347 JNIEXPORT void JNICALL
348 Java_gnu_java_awt_peer_gtk_GtkToolkit_sync
349 (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)))
351 gdk_threads_enter ();
355 gdk_threads_leave ();
358 JNIEXPORT void JNICALL
359 Java_gnu_java_awt_peer_gtk_GtkToolkit_getScreenSizeDimensions
360 (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)),
363 jint *dims = (*env)->GetIntArrayElements (env, jdims, 0);
365 gdk_threads_enter ();
367 dims[0] = gdk_screen_width ();
368 dims[1] = gdk_screen_height ();
370 gdk_threads_leave ();
372 (*env)->ReleaseIntArrayElements(env, jdims, dims, 0);
375 JNIEXPORT jint JNICALL
376 Java_gnu_java_awt_peer_gtk_GtkToolkit_getScreenResolution
377 (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)))
381 gdk_threads_enter ();
383 res = gdk_screen_width () / (gdk_screen_width_mm () / 25.4);
385 gdk_threads_leave ();
391 * Report the number of mouse buttons
392 * Returns the number of buttons of the first mouse found, or -1 if no mouse
393 * seems to be connected.
395 JNIEXPORT jint JNICALL
396 Java_gnu_java_awt_peer_gtk_GtkToolkit_getMouseNumberOfButtons
397 (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)))
403 gdk_threads_enter ();
405 /* FIXME: Why doesn't this return the correct number? */
406 devices = gdk_devices_list();
408 while( res == -1 && devices != NULL )
410 d = GDK_DEVICE( devices->data );
411 if( d->source == GDK_SOURCE_MOUSE )
413 devices = devices->next;
416 gdk_threads_leave ();
421 #define CONVERT(type, state) \
422 gdk_color_to_java_color (style->type[GTK_STATE_ ## state])
424 JNIEXPORT void JNICALL
425 Java_gnu_java_awt_peer_gtk_GtkToolkit_loadSystemColors
426 (JNIEnv *env, jobject obj __attribute__((unused)),
432 /* FIXME: this was deadlocking so assume it is thread-safe for now;
433 we need to replace this call with a .properties file anyway. */
435 gdk_threads_enter ();
438 colors = (*env)->GetIntArrayElements (env, jcolors, 0);
440 style = gtk_widget_get_default_style ();
442 colors[AWT_DESKTOP] = CONVERT (bg, SELECTED);
443 colors[AWT_ACTIVE_CAPTION] = CONVERT (bg, SELECTED);
444 colors[AWT_ACTIVE_CAPTION_TEXT] = CONVERT (text, SELECTED);
445 colors[AWT_ACTIVE_CAPTION_BORDER] = CONVERT (fg, NORMAL);
446 colors[AWT_INACTIVE_CAPTION] = CONVERT (base, INSENSITIVE);
447 colors[AWT_INACTIVE_CAPTION_TEXT] = CONVERT (fg, INSENSITIVE);
448 colors[AWT_INACTIVE_CAPTION_BORDER] = CONVERT (fg, INSENSITIVE);
449 colors[AWT_WINDOW] = CONVERT (bg, NORMAL);
450 colors[AWT_WINDOW_BORDER] = CONVERT (fg, NORMAL);
451 colors[AWT_WINDOW_TEXT] = CONVERT (fg, NORMAL);
452 colors[AWT_MENU] = CONVERT (bg, NORMAL);
453 colors[AWT_MENU_TEXT] = CONVERT (fg, NORMAL);
454 colors[AWT_TEXT] = CONVERT (bg, NORMAL);
455 colors[AWT_TEXT_TEXT] = CONVERT (fg, NORMAL);
456 colors[AWT_TEXT_HIGHLIGHT] = CONVERT (bg, SELECTED);
457 colors[AWT_TEXT_HIGHLIGHT_TEXT] = CONVERT (fg, SELECTED);
458 colors[AWT_TEXT_INACTIVE_TEXT] = CONVERT (bg, INSENSITIVE);
459 colors[AWT_CONTROL] = CONVERT (bg, NORMAL);
460 colors[AWT_CONTROL_TEXT] = CONVERT (fg, NORMAL);
461 colors[AWT_CONTROL_HIGHLIGHT] = CONVERT (base, ACTIVE);
462 colors[AWT_CONTROL_LT_HIGHLIGHT] = CONVERT (bg, PRELIGHT);
463 colors[AWT_CONTROL_SHADOW] = CONVERT (bg, ACTIVE);
464 colors[AWT_CONTROL_DK_SHADOW] = CONVERT (fg, INSENSITIVE);
465 colors[AWT_SCROLLBAR] = CONVERT (base, INSENSITIVE);
466 colors[AWT_INFO] = CONVERT (bg, NORMAL);
467 colors[AWT_INFO_TEXT] = CONVERT (fg, NORMAL);
469 (*env)->ReleaseIntArrayElements(env, jcolors, colors, 0);
472 gdk_threads_leave ();
479 gdk_color_to_java_color (GdkColor gdk_color)
486 factor = 255.0 / 65535.0;
488 red = (float) gdk_color.red * factor;
489 green = (float) gdk_color.green * factor;
490 blue = (float) gdk_color.blue * factor;
492 return (jint) (0xff000000 | (red << 16) | (green << 8) | blue);