Merged with mainline at revision 128810.
[official-gcc.git] / libjava / classpath / native / jni / gtk-peer / gnu_java_awt_peer_gtk_GtkToolkit.c
blob1186f659c1567e78340b4c254247258249118f6c
2 /* gtktoolkit.c -- Native portion of GtkToolkit
3 Copyright (C) 1998, 1999, 2005, 2007 Free Software Foundation, Inc.
5 This file is part of GNU Classpath.
7 GNU Classpath is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
12 GNU Classpath is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Classpath; see the file COPYING. If not, write to the
19 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 02110-1301 USA.
22 Linking this library statically or dynamically with other modules is
23 making a combined work based on this library. Thus, the terms and
24 conditions of the GNU General Public License cover the whole
25 combination.
27 As a special exception, the copyright holders of this library give you
28 permission to link this library with independent modules to produce an
29 executable, regardless of the license terms of these independent
30 modules, and to copy and distribute the resulting executable under
31 terms of your choice, provided that you also meet, for each linked
32 independent module, the terms and conditions of the license of that
33 module. An independent module is a module which is not derived from
34 or based on this library. If you modify this library, you may extend
35 this exception to your version of the library, but you are not
36 obligated to do so. If you do not wish to do so, delete this
37 exception statement from your version. */
40 #include "gtkpeer.h"
41 #include "gnu_java_awt_peer_gtk_GtkToolkit.h"
42 #include "jcl.h"
43 #include <gdk/gdkx.h>
45 #define RC_FILE ".classpath-gtkrc"
47 /* From java.awt.SystemColor */
48 #define AWT_DESKTOP 0
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
55 #define AWT_WINDOW 7
56 #define AWT_WINDOW_BORDER 8
57 #define AWT_WINDOW_TEXT 9
58 #define AWT_MENU 10
59 #define AWT_MENU_TEXT 11
60 #define AWT_TEXT 12
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
72 #define AWT_INFO 24
73 #define AWT_INFO_TEXT 25
74 #define AWT_NUM_COLORS 26
76 #define VK_SHIFT 16
77 #define VK_CONTROL 17
78 #define VK_ALT 18
79 #define VK_CAPS_LOCK 20
80 #define VK_META 157
82 static jclass gtkgenericpeer;
83 static jclass gtktoolkit;
84 static JavaVM *java_vm;
85 static jmethodID printCurrentThreadID;
86 static jmethodID setRunningID;
88 /**
89 * The global AWT lock object.
91 static jobject global_lock;
93 union env_union
95 void *void_env;
96 JNIEnv *jni_env;
99 JNIEnv *
100 cp_gtk_gdk_env()
102 union env_union tmp;
103 g_assert((*java_vm)->GetEnv(java_vm, &tmp.void_env, JNI_VERSION_1_2) == JNI_OK);
104 return tmp.jni_env;
108 GtkWindowGroup *cp_gtk_global_window_group;
109 double cp_gtk_dpi_conversion_factor;
111 static void jni_lock_cb();
112 static void jni_unlock_cb();
113 static void init_glib_threads(JNIEnv*, jint, jobject);
114 static gboolean post_set_running_flag (gpointer);
115 static gboolean set_running_flag (gpointer);
116 static gboolean clear_running_flag (gpointer);
117 static void init_dpi_conversion_factor (void);
118 static void dpi_changed_cb (GtkSettings *settings,
119 GParamSpec *pspec);
121 #if GTK_MINOR_VERSION > 4
122 static GLogFunc old_glog_func;
123 static void glog_func (const gchar *log_domain,
124 GLogLevelFlags log_level,
125 const gchar *message,
126 gpointer user_data);
127 #endif
129 JNIEXPORT void JNICALL
130 Java_gnu_java_awt_peer_gtk_GtkToolkit_initIDs
131 (JNIEnv *env, jclass cls __attribute__((unused)))
133 gtkpeer_init_pointer_IDs(env);
137 * Call gtk_init. It is very important that this happen before any other
138 * gtk calls.
140 * The portableNativeSync argument may have the values:
141 * 1 if the Java property gnu.classpath.awt.gtk.portable.native.sync
142 * is set to "true".
143 * 0 if it is set to "false"
144 * -1 if unset.
148 JNIEXPORT void JNICALL
149 Java_gnu_java_awt_peer_gtk_GtkToolkit_gtkInit (JNIEnv *env,
150 jclass clazz __attribute__((unused)),
151 jint portableNativeSync,
152 jobject lock)
154 int argc = 1;
155 char **argv;
156 char *homedir, *rcpath = NULL;
158 gtkgenericpeer = (*env)->FindClass(env, "gnu/java/awt/peer/gtk/GtkGenericPeer");
160 gtkgenericpeer = (*env)->NewGlobalRef(env, gtkgenericpeer);
162 printCurrentThreadID = (*env)->GetStaticMethodID (env, gtkgenericpeer,
163 "printCurrentThread", "()V");
165 g_assert((*env)->GetJavaVM(env, &java_vm) == 0);
167 /* GTK requires a program's argc and argv variables, and requires that they
168 be valid. Set it up. */
169 argv = (char **) g_malloc (sizeof (char *) * 2);
170 argv[0] = (char *) g_malloc(1);
171 argv[0][0] = '\0';
172 argv[1] = NULL;
174 init_glib_threads(env, portableNativeSync, lock);
176 /* From GDK 2.0 onwards we have to explicitly call gdk_threads_init */
177 gdk_threads_init();
179 gtk_init (&argc, &argv);
181 #if SYNCHRONIZE_GDK
182 XSynchronize (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()), True);
183 #endif
185 gtk_widget_set_default_colormap (gdk_rgb_get_colormap ());
187 /* Make sure queued calls don't get sent to GTK/GDK while
188 we're shutting down. */
189 atexit (gdk_threads_enter);
191 if ((homedir = getenv ("HOME")))
193 rcpath = (char *) g_malloc (strlen (homedir) + strlen (RC_FILE) + 2);
194 sprintf (rcpath, "%s/%s", homedir, RC_FILE);
197 gtk_rc_parse ((rcpath) ? rcpath : RC_FILE);
199 g_free (rcpath);
200 g_free (argv[0]);
201 g_free (argv);
203 /* On errors or warning print a whole stacktrace. */
204 #if GTK_MINOR_VERSION > 4
205 old_glog_func = g_log_set_default_handler (&glog_func, NULL);
206 #endif
208 cp_gtk_button_init_jni (env);
209 cp_gtk_checkbox_init_jni ();
210 cp_gtk_choice_init_jni ();
211 cp_gtk_component_init_jni ();
212 cp_gtk_filedialog_init_jni ();
213 cp_gtk_list_init_jni ();
214 cp_gtk_menuitem_init_jni ();
215 cp_gtk_scrollbar_init_jni ();
216 cp_gtk_textcomponent_init_jni ();
217 cp_gtk_window_init_jni ();
219 cp_gtk_global_window_group = gtk_window_group_new ();
221 init_dpi_conversion_factor ();
223 gtktoolkit = (*env)->FindClass(env, "gnu/java/awt/peer/gtk/GtkMainThread");
224 setRunningID = (*env)->GetStaticMethodID (env, gtktoolkit,
225 "setRunning", "(Z)V");
229 * A callback function that implements gdk_threads_enter(). This is
230 * implemented to wrap the JNI MonitorEnter() function.
232 static void jni_lock_cb()
234 JNIEnv * env = cp_gtk_gdk_env();
235 if ((*env)->MonitorEnter(env, global_lock) != JNI_OK)
237 printf("failure while entering GTK monitor\n");
242 * A callback function that implements gdk_threads_leave(). This is
243 * implemented to wrap the JNI MonitorExit() function.
245 static void jni_unlock_cb()
248 JNIEnv * env = cp_gtk_gdk_env();
249 if ((*env)->MonitorExit(env, global_lock))
251 printf("failure while exiting GTK monitor\n");
255 /** Initialize GLIB's threads properly, based on the value of the
256 gnu.classpath.awt.gtk.portable.native.sync Java system property. If
257 that's unset, use the PORTABLE_NATIVE_SYNC config.h macro. (TODO:
258 In some release following 0.10, that config.h macro will go away.)
260 static void
261 init_glib_threads(JNIEnv *env, jint portableNativeSync, jobject lock)
263 if (portableNativeSync < 0)
265 #ifdef PORTABLE_NATIVE_SYNC /* Default value, if not set by the Java system
266 property */
267 portableNativeSync = 1;
268 #else
269 portableNativeSync = 0;
270 #endif
273 if (!g_thread_supported ())
275 if (portableNativeSync)
277 global_lock = (*env)->NewGlobalRef(env, lock);
278 gdk_threads_set_lock_functions(&jni_lock_cb, &jni_unlock_cb);
280 g_thread_init(NULL);
282 else
284 /* Warn if portable native sync is desired but the threading
285 system is already initialized. In that case we can't
286 override the threading implementation with our portable
287 native sync functions. */
288 if (portableNativeSync)
289 g_printerr ("peer warning: portable native sync disabled.\n");
292 /* Debugging progress message; uncomment if needed: */
293 /* printf("called gthread init\n"); */
296 void
297 cp_gtk_print_current_thread (void)
299 (*cp_gtk_gdk_env())->CallStaticVoidMethod (cp_gtk_gdk_env(), gtkgenericpeer, printCurrentThreadID);
302 /* This is a big hack, needed until this pango bug is resolved:
303 http://bugzilla.gnome.org/show_bug.cgi?id=119081.
304 See: http://mail.gnome.org/archives/gtk-i18n-list/2003-August/msg00001.html
305 for details. */
306 static void
307 init_dpi_conversion_factor ()
309 GtkSettings *settings = gtk_settings_get_default ();
310 GObjectClass *klass;
312 klass = G_OBJECT_CLASS (GTK_SETTINGS_GET_CLASS (settings));
313 if (g_object_class_find_property (klass, "gtk-xft-dpi"))
315 int int_dpi;
316 g_object_get (settings, "gtk-xft-dpi", &int_dpi, NULL);
317 /* If int_dpi == -1 gtk-xft-dpi returns the default value. So we
318 have to do approximate calculation here. */
319 if (int_dpi < 0)
320 cp_gtk_dpi_conversion_factor = PANGO_SCALE * 72.0 / 96.;
321 else
322 cp_gtk_dpi_conversion_factor =
323 PANGO_SCALE * 72.0 / (int_dpi / PANGO_SCALE);
325 g_signal_connect (settings, "notify::gtk-xft-dpi",
326 G_CALLBACK (dpi_changed_cb), NULL);
328 else
329 /* Approximate. */
330 cp_gtk_dpi_conversion_factor = PANGO_SCALE * 72.0 / 96.;
333 static void
334 dpi_changed_cb (GtkSettings *settings,
335 GParamSpec *pspec __attribute__((unused)))
337 int int_dpi;
338 g_object_get (settings, "gtk-xft-dpi", &int_dpi, NULL);
339 if (int_dpi < 0)
340 cp_gtk_dpi_conversion_factor = PANGO_SCALE * 72.0 / 96.;
341 else
342 cp_gtk_dpi_conversion_factor =
343 PANGO_SCALE * 72.0 / (int_dpi / PANGO_SCALE);
346 #if GTK_MINOR_VERSION > 4
347 static void
348 glog_func (const gchar *log_domain,
349 GLogLevelFlags log_level,
350 const gchar *message,
351 gpointer user_data)
353 old_glog_func (log_domain, log_level, message, user_data);
354 if (log_level & (G_LOG_LEVEL_ERROR
355 | G_LOG_LEVEL_CRITICAL
356 | G_LOG_LEVEL_WARNING))
358 JNIEnv *env = cp_gtk_gdk_env ();
359 jthrowable *exc = (*env)->ExceptionOccurred(env);
360 gchar *detail = g_strconcat (log_domain, ": ", message, NULL);
361 JCL_ThrowException (env, "java/lang/InternalError", detail);
362 g_free (detail);
363 (*env)->ExceptionDescribe (env);
364 if (exc != NULL)
365 (*env)->Throw (env, exc);
366 else
367 (*env)->ExceptionClear (env);
370 #endif
372 JNIEXPORT void JNICALL
373 Java_gnu_java_awt_peer_gtk_GtkToolkit_gtkMain
374 (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)))
376 gdk_threads_enter();
378 gtk_init_add (post_set_running_flag, NULL);
379 gtk_quit_add (gtk_main_level (), clear_running_flag, NULL);
381 gtk_main ();
383 gdk_threads_leave();
386 JNIEXPORT void JNICALL
387 Java_gnu_java_awt_peer_gtk_GtkToolkit_gtkQuit
388 (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)))
390 gdk_threads_enter ();
392 gtk_main_quit ();
394 gdk_threads_leave ();
398 static jint gdk_color_to_java_color (GdkColor color);
401 JNIEXPORT void JNICALL
402 Java_gnu_java_awt_peer_gtk_GtkToolkit_beep
403 (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)))
405 gdk_threads_enter ();
407 gdk_beep ();
409 gdk_threads_leave ();
412 JNIEXPORT void JNICALL
413 Java_gnu_java_awt_peer_gtk_GtkToolkit_sync
414 (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)))
416 gdk_threads_enter ();
418 gdk_flush ();
420 gdk_threads_leave ();
423 JNIEXPORT void JNICALL
424 Java_gnu_java_awt_peer_gtk_GtkToolkit_getScreenSizeDimensions
425 (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)),
426 jintArray jdims)
428 jint *dims = (*env)->GetIntArrayElements (env, jdims, 0);
430 gdk_threads_enter ();
432 dims[0] = gdk_screen_width ();
433 dims[1] = gdk_screen_height ();
435 gdk_threads_leave ();
437 (*env)->ReleaseIntArrayElements(env, jdims, dims, 0);
440 JNIEXPORT jint JNICALL
441 Java_gnu_java_awt_peer_gtk_GtkToolkit_getScreenResolution
442 (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)))
444 jint res;
446 gdk_threads_enter ();
448 res = gdk_screen_width () / (gdk_screen_width_mm () / 25.4);
450 gdk_threads_leave ();
452 return res;
456 * Report the number of mouse buttons
457 * Returns the number of buttons of the first mouse found, or -1 if no mouse
458 * seems to be connected.
460 JNIEXPORT jint JNICALL
461 Java_gnu_java_awt_peer_gtk_GtkToolkit_getMouseNumberOfButtons
462 (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)))
464 jint res = -1;
465 GList *devices;
466 GdkDevice *d;
468 gdk_threads_enter ();
470 /* FIXME: Why doesn't this return the correct number? */
471 devices = gdk_devices_list();
473 while( res == -1 && devices != NULL )
475 d = GDK_DEVICE( devices->data );
476 if( d->source == GDK_SOURCE_MOUSE )
477 res = d->num_keys;
478 devices = devices->next;
481 gdk_threads_leave ();
483 return res;
486 #define CONVERT(type, state) \
487 gdk_color_to_java_color (style->type[GTK_STATE_ ## state])
489 JNIEXPORT void JNICALL
490 Java_gnu_java_awt_peer_gtk_GtkToolkit_loadSystemColors
491 (JNIEnv *env, jobject obj __attribute__((unused)),
492 jintArray jcolors)
494 jint *colors;
495 GtkStyle *style;
497 /* FIXME: this was deadlocking so assume it is thread-safe for now;
498 we need to replace this call with a .properties file anyway. */
499 #if 0
500 gdk_threads_enter ();
501 #endif
503 colors = (*env)->GetIntArrayElements (env, jcolors, 0);
505 style = gtk_widget_get_default_style ();
507 colors[AWT_DESKTOP] = CONVERT (bg, SELECTED);
508 colors[AWT_ACTIVE_CAPTION] = CONVERT (bg, SELECTED);
509 colors[AWT_ACTIVE_CAPTION_TEXT] = CONVERT (text, SELECTED);
510 colors[AWT_ACTIVE_CAPTION_BORDER] = CONVERT (fg, NORMAL);
511 colors[AWT_INACTIVE_CAPTION] = CONVERT (base, INSENSITIVE);
512 colors[AWT_INACTIVE_CAPTION_TEXT] = CONVERT (fg, INSENSITIVE);
513 colors[AWT_INACTIVE_CAPTION_BORDER] = CONVERT (fg, INSENSITIVE);
514 colors[AWT_WINDOW] = CONVERT (bg, NORMAL);
515 colors[AWT_WINDOW_BORDER] = CONVERT (fg, NORMAL);
516 colors[AWT_WINDOW_TEXT] = CONVERT (fg, NORMAL);
517 colors[AWT_MENU] = CONVERT (bg, NORMAL);
518 colors[AWT_MENU_TEXT] = CONVERT (fg, NORMAL);
519 colors[AWT_TEXT] = CONVERT (bg, NORMAL);
520 colors[AWT_TEXT_TEXT] = CONVERT (fg, NORMAL);
521 colors[AWT_TEXT_HIGHLIGHT] = CONVERT (bg, SELECTED);
522 colors[AWT_TEXT_HIGHLIGHT_TEXT] = CONVERT (fg, SELECTED);
523 colors[AWT_TEXT_INACTIVE_TEXT] = CONVERT (bg, INSENSITIVE);
524 colors[AWT_CONTROL] = CONVERT (bg, NORMAL);
525 colors[AWT_CONTROL_TEXT] = CONVERT (fg, NORMAL);
526 colors[AWT_CONTROL_HIGHLIGHT] = CONVERT (base, ACTIVE);
527 colors[AWT_CONTROL_LT_HIGHLIGHT] = CONVERT (bg, PRELIGHT);
528 colors[AWT_CONTROL_SHADOW] = CONVERT (bg, ACTIVE);
529 colors[AWT_CONTROL_DK_SHADOW] = CONVERT (fg, INSENSITIVE);
530 colors[AWT_SCROLLBAR] = CONVERT (base, INSENSITIVE);
531 colors[AWT_INFO] = CONVERT (bg, NORMAL);
532 colors[AWT_INFO_TEXT] = CONVERT (fg, NORMAL);
534 (*env)->ReleaseIntArrayElements(env, jcolors, colors, 0);
536 #if 0
537 gdk_threads_leave ();
538 #endif
541 #undef CONVERT
543 static jint
544 gdk_color_to_java_color (GdkColor gdk_color)
546 guchar red;
547 guchar green;
548 guchar blue;
549 float factor;
551 factor = 255.0 / 65535.0;
553 red = (float) gdk_color.red * factor;
554 green = (float) gdk_color.green * factor;
555 blue = (float) gdk_color.blue * factor;
557 return (jint) (0xff000000 | (red << 16) | (green << 8) | blue);
560 JNIEXPORT jint JNICALL
561 Java_gnu_java_awt_peer_gtk_GtkToolkit_getLockState
562 (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)),
563 jint key)
565 gint coord;
566 GdkModifierType state, mask;
567 GdkWindow *root_window;
569 gdk_threads_enter ();
571 root_window = gdk_get_default_root_window ();
572 gdk_window_get_pointer (root_window, &coord, &coord, &state);
574 switch (key)
576 case VK_SHIFT:
577 mask = GDK_SHIFT_MASK;
578 break;
579 case VK_CONTROL:
580 mask = GDK_CONTROL_MASK;
581 break;
582 case VK_ALT:
583 /* This is dubious, since MOD1 could have been mapped to something
584 other than ALT. */
585 mask = GDK_MOD1_MASK;
586 break;
587 #if GTK_CHECK_VERSION(2, 10, 0)
588 case VK_META:
589 mask = GDK_META_MASK;
590 break;
591 #endif
592 case VK_CAPS_LOCK:
593 mask = GDK_LOCK_MASK;
594 break;
595 default:
596 mask = 0;
599 gdk_threads_leave ();
601 if (mask == 0)
602 return -1;
604 return state & mask ? 1 : 0;
607 static gboolean
608 post_set_running_flag (gpointer data __attribute__((unused)))
610 g_idle_add (set_running_flag, NULL);
611 return FALSE;
614 static gboolean
615 set_running_flag (gpointer data __attribute__((unused)))
617 (*cp_gtk_gdk_env ())->CallStaticVoidMethod (cp_gtk_gdk_env (),
618 gtktoolkit,
619 setRunningID, TRUE);
620 return FALSE;
623 static gboolean
624 clear_running_flag (gpointer data __attribute__((unused)))
626 (*cp_gtk_gdk_env ())->CallStaticVoidMethod (cp_gtk_gdk_env (),
627 gtktoolkit,
628 setRunningID, FALSE);
629 return FALSE;