aboutsummaryrefslogtreecommitdiff
path: root/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkToolkit.c
diff options
context:
space:
mode:
Diffstat (limited to 'libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkToolkit.c')
-rw-r--r--libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkToolkit.c366
1 files changed, 366 insertions, 0 deletions
diff --git a/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkToolkit.c b/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkToolkit.c
index 6234b29c913..8cb9e2f5d68 100644
--- a/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkToolkit.c
+++ b/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkToolkit.c
@@ -38,9 +38,375 @@ exception statement from your version. */
#include "gtkpeer.h"
#include "gnu_java_awt_peer_gtk_GtkToolkit.h"
+#include "gthread-jni.h"
+
+#include <sys/time.h>
+
+#ifdef JVM_SUN
+ struct state_table *native_state_table;
+ struct state_table *native_global_ref_table;
+#endif
+
+jmethodID setBoundsCallbackID;
+
+jmethodID postActionEventID;
+jmethodID postMenuActionEventID;
+jmethodID postMouseEventID;
+jmethodID postConfigureEventID;
+jmethodID postExposeEventID;
+jmethodID postKeyEventID;
+jmethodID postFocusEventID;
+jmethodID postAdjustmentEventID;
+jmethodID postItemEventID;
+jmethodID choicePostItemEventID;
+jmethodID postListItemEventID;
+jmethodID postTextEventID;
+jmethodID postWindowEventID;
+jmethodID postInsetsChangedEventID;
+jmethodID windowGetWidthID;
+jmethodID windowGetHeightID;
+
+jmethodID beginNativeRepaintID;
+jmethodID endNativeRepaintID;
+
+jmethodID initComponentGraphicsID;
+jmethodID initComponentGraphics2DID;
+jmethodID setCursorID;
+
+JavaVM *java_vm;
+
+union env_union
+{
+ void *void_env;
+ JNIEnv *jni_env;
+};
+
+JNIEnv *
+gdk_env()
+{
+ union env_union tmp;
+ g_assert((*java_vm)->GetEnv(java_vm, &tmp.void_env, JNI_VERSION_1_2) == JNI_OK);
+ return tmp.jni_env;
+}
+
+
+GtkWindowGroup *global_gtk_window_group;
+
+static void init_glib_threads(JNIEnv *, jint);
+
+double dpi_conversion_factor;
+
+static void init_dpi_conversion_factor (void);
+static void dpi_changed_cb (GtkSettings *settings,
+ GParamSpec *pspec);
+
+/*
+ * Call gtk_init. It is very important that this happen before any other
+ * gtk calls.
+ *
+ * The portableNativeSync argument may have the values:
+ * 1 if the Java property gnu.classpath.awt.gtk.portable.native.sync
+ * is set to "true".
+ * 0 if it is set to "false"
+ * -1 if unset.
+ */
+
+
+JNIEXPORT void JNICALL
+Java_gnu_java_awt_peer_gtk_GtkToolkit_gtkInit (JNIEnv *env,
+ jclass clazz __attribute__((unused)),
+ jint portableNativeSync)
+{
+ int argc = 1;
+ char **argv;
+ char *homedir, *rcpath = NULL;
+
+ jclass gtkgenericpeer, gtkcomponentpeer, gtkchoicepeer, gtkwindowpeer, gtkscrollbarpeer, gtklistpeer,
+ gtkmenuitempeer, gtktextcomponentpeer, window, gdkgraphics, gdkgraphics2d;
+
+ gtkgenericpeer = (*env)->FindClass(env, "gnu/java/awt/peer/gtk/GtkGenericPeer");
+
+ NSA_INIT (env, gtkgenericpeer);
+
+ g_assert((*env)->GetJavaVM(env, &java_vm) == 0);
+
+ /* GTK requires a program's argc and argv variables, and requires that they
+ be valid. Set it up. */
+ argv = (char **) g_malloc (sizeof (char *) * 2);
+ argv[0] = (char *) g_malloc(1);
+#if 1
+ strcpy(argv[0], "");
+#else /* The following is a more efficient alternative, but less intuitively
+ * expresses what we are trying to do. This code is only run once, so
+ * I'm going for intuitive. */
+ argv[0][0] = '\0';
+#endif
+ argv[1] = NULL;
+
+ init_glib_threads(env, portableNativeSync);
+
+ /* From GDK 2.0 onwards we have to explicitly call gdk_threads_init */
+ gdk_threads_init();
+
+ gtk_init (&argc, &argv);
+
+ gdk_rgb_init ();
+ gtk_widget_set_default_colormap (gdk_rgb_get_cmap ());
+ gtk_widget_set_default_visual (gdk_rgb_get_visual ());
+
+ /* Make sure queued calls don't get sent to GTK/GDK while
+ we're shutting down. */
+ atexit (gdk_threads_enter);
+
+ gdk_event_handler_set ((GdkEventFunc)awt_event_handler, NULL, NULL);
+
+ if ((homedir = getenv ("HOME")))
+ {
+ rcpath = (char *) g_malloc (strlen (homedir) + strlen (RC_FILE) + 2);
+ sprintf (rcpath, "%s/%s", homedir, RC_FILE);
+ }
+
+ gtk_rc_parse ((rcpath) ? rcpath : RC_FILE);
+
+ g_free (rcpath);
+ g_free (argv[0]);
+ g_free (argv);
+
+ /* setup cached IDs for posting GTK events to Java */
+
+ window = (*env)->FindClass (env, "java/awt/Window");
+
+ gtkcomponentpeer = (*env)->FindClass (env,
+ "gnu/java/awt/peer/gtk/GtkComponentPeer");
+ gtkchoicepeer = (*env)->FindClass (env,
+ "gnu/java/awt/peer/gtk/GtkChoicePeer");
+ gtkwindowpeer = (*env)->FindClass (env,
+ "gnu/java/awt/peer/gtk/GtkWindowPeer");
+ gtkscrollbarpeer = (*env)->FindClass (env,
+ "gnu/java/awt/peer/gtk/GtkScrollbarPeer");
+ gtklistpeer = (*env)->FindClass (env, "gnu/java/awt/peer/gtk/GtkListPeer");
+ gtkmenuitempeer = (*env)->FindClass (env,
+ "gnu/java/awt/peer/gtk/GtkMenuItemPeer");
+ gtktextcomponentpeer = (*env)->FindClass (env,
+ "gnu/java/awt/peer/gtk/GtkTextComponentPeer");
+ gdkgraphics = (*env)->FindClass (env,
+ "gnu/java/awt/peer/gtk/GdkGraphics");
+ gdkgraphics2d = (*env)->FindClass (env,
+ "gnu/java/awt/peer/gtk/GdkGraphics2D");
+ setBoundsCallbackID = (*env)->GetMethodID (env, window,
+ "setBoundsCallback",
+ "(IIII)V");
+
+ postMenuActionEventID = (*env)->GetMethodID (env, gtkmenuitempeer,
+ "postMenuActionEvent",
+ "()V");
+ postMouseEventID = (*env)->GetMethodID (env, gtkcomponentpeer,
+ "postMouseEvent", "(IJIIIIZ)V");
+ setCursorID = (*env)->GetMethodID (env, gtkcomponentpeer,
+ "setCursor", "()V");
+ beginNativeRepaintID = (*env)->GetMethodID (env, gtkcomponentpeer,
+ "beginNativeRepaint", "()V");
+
+ endNativeRepaintID = (*env)->GetMethodID (env, gtkcomponentpeer,
+ "endNativeRepaint", "()V");
+
+ postConfigureEventID = (*env)->GetMethodID (env, gtkwindowpeer,
+ "postConfigureEvent", "(IIII)V");
+ postWindowEventID = (*env)->GetMethodID (env, gtkwindowpeer,
+ "postWindowEvent",
+ "(ILjava/awt/Window;I)V");
+ postInsetsChangedEventID = (*env)->GetMethodID (env, gtkwindowpeer,
+ "postInsetsChangedEvent",
+ "(IIII)V");
+ windowGetWidthID = (*env)->GetMethodID (env, gtkwindowpeer,
+ "getWidth", "()I");
+ windowGetHeightID = (*env)->GetMethodID (env, gtkwindowpeer,
+ "getHeight", "()I");
+
+ postExposeEventID = (*env)->GetMethodID (env, gtkcomponentpeer,
+ "postExposeEvent", "(IIII)V");
+ postKeyEventID = (*env)->GetMethodID (env, gtkcomponentpeer,
+ "postKeyEvent", "(IJIICI)V");
+ postFocusEventID = (*env)->GetMethodID (env, gtkcomponentpeer,
+ "postFocusEvent", "(IZ)V");
+ postAdjustmentEventID = (*env)->GetMethodID (env, gtkscrollbarpeer,
+ "postAdjustmentEvent",
+ "(II)V");
+ postItemEventID = (*env)->GetMethodID (env, gtkcomponentpeer,
+ "postItemEvent",
+ "(Ljava/lang/Object;I)V");
+ choicePostItemEventID = (*env)->GetMethodID (env, gtkchoicepeer,
+ "choicePostItemEvent",
+ "(Ljava/lang/String;I)V");
+ postListItemEventID = (*env)->GetMethodID (env, gtklistpeer,
+ "postItemEvent",
+ "(II)V");
+ postTextEventID = (*env)->GetMethodID (env, gtktextcomponentpeer,
+ "postTextEvent",
+ "()V");
+ initComponentGraphicsID = (*env)->GetMethodID (env, gdkgraphics,
+ "initComponentGraphics",
+ "()V");
+ initComponentGraphics2DID = (*env)->GetMethodID (env, gdkgraphics2d,
+ "initComponentGraphics2D",
+ "()V");
+ global_gtk_window_group = gtk_window_group_new ();
+
+ init_dpi_conversion_factor ();
+}
+
+
+/** Initialize GLIB's threads properly, based on the value of the
+ gnu.classpath.awt.gtk.portable.native.sync Java system property. If
+ that's unset, use the PORTABLE_NATIVE_SYNC config.h macro. (TODO:
+ In some release following 0.10, that config.h macro will go away.)
+ */
+static void
+init_glib_threads(JNIEnv *env, jint portableNativeSync)
+{
+ if (portableNativeSync < 0)
+ {
+#ifdef PORTABLE_NATIVE_SYNC /* Default value, if not set by the Java system
+ property */
+ portableNativeSync = 1;
+#else
+ portableNativeSync = 0;
+#endif
+ }
+
+ (*env)->GetJavaVM( env, &the_vm );
+ if (portableNativeSync)
+ g_thread_init ( &portable_native_sync_jni_functions );
+ else
+ g_thread_init ( NULL );
+
+ /* Debugging progress message; uncomment if needed: */
+ /* printf("called gthread init\n"); */
+}
+
+
+/* This is a big hack, needed until this pango bug is resolved:
+ http://bugzilla.gnome.org/show_bug.cgi?id=119081.
+ See: http://mail.gnome.org/archives/gtk-i18n-list/2003-August/msg00001.html
+ for details. */
+static void
+init_dpi_conversion_factor ()
+{
+ GtkSettings *settings = gtk_settings_get_default ();
+ GObjectClass *klass;
+
+ klass = G_OBJECT_CLASS (GTK_SETTINGS_GET_CLASS (settings));
+ if (g_object_class_find_property (klass, "gtk-xft-dpi"))
+ {
+ int int_dpi;
+ g_object_get (settings, "gtk-xft-dpi", &int_dpi, NULL);
+ /* If int_dpi == -1 gtk-xft-dpi returns the default value. So we
+ have to do approximate calculation here. */
+ if (int_dpi < 0)
+ dpi_conversion_factor = PANGO_SCALE * 72.0 / 96.;
+ else
+ dpi_conversion_factor = PANGO_SCALE * 72.0 / (int_dpi / PANGO_SCALE);
+
+ g_signal_connect (settings, "notify::gtk-xft-dpi",
+ G_CALLBACK (dpi_changed_cb), NULL);
+ }
+ else
+ /* Approximate. */
+ dpi_conversion_factor = PANGO_SCALE * 72.0 / 96.;
+}
+
+static void
+dpi_changed_cb (GtkSettings *settings,
+ GParamSpec *pspec __attribute__((unused)))
+{
+ int int_dpi;
+ g_object_get (settings, "gtk-xft-dpi", &int_dpi, NULL);
+ if (int_dpi < 0)
+ dpi_conversion_factor = PANGO_SCALE * 72.0 / 96.;
+ else
+ dpi_conversion_factor = PANGO_SCALE * 72.0 / (int_dpi / PANGO_SCALE);
+}
+
+static int
+within_human_latency_tolerance(struct timeval *init)
+{
+ struct timeval curr;
+ unsigned long milliseconds_elapsed;
+
+ gettimeofday(&curr, NULL);
+
+ milliseconds_elapsed = (((curr.tv_sec * 1000) + (curr.tv_usec / 1000))
+ - ((init->tv_sec * 1000) + (init->tv_usec / 1000)));
+
+ return milliseconds_elapsed < 100;
+}
+
+
+JNIEXPORT void JNICALL
+Java_gnu_java_awt_peer_gtk_GtkToolkit_iterateNativeQueue
+(JNIEnv *env,
+ jobject self __attribute__((unused)),
+ jobject lockedQueue,
+ jboolean block)
+{
+ /* We're holding an EventQueue lock, and we're about to acquire the GDK
+ * lock before dropping the EventQueue lock. This can deadlock if someone
+ * holds the GDK lock and wants to acquire the EventQueue lock; however
+ * all callbacks from GTK happen with the GDK lock released, so this
+ * would only happen in an odd case such as some JNI helper code
+ * acquiring the GDK lock and calling back into
+ * EventQueue.getNextEvent().
+ */
+
+ struct timeval init;
+ gettimeofday(&init, NULL);
+
+ gdk_threads_enter ();
+ (*env)->MonitorExit (env, lockedQueue);
+
+ if (block)
+ {
+
+ /* If we're blocking-when-empty, we want a do .. while loop. */
+ do
+ gtk_main_iteration ();
+ while (within_human_latency_tolerance (&init)
+ && gtk_events_pending ());
+ }
+ else
+ {
+ /* If we're not blocking-when-empty, we want a while loop. */
+ while (within_human_latency_tolerance (&init)
+ && gtk_events_pending ())
+ gtk_main_iteration ();
+ }
+
+ (*env)->MonitorEnter (env, lockedQueue);
+ gdk_threads_leave ();
+}
+
+JNIEXPORT void JNICALL
+Java_gnu_java_awt_peer_gtk_GtkToolkit_wakeNativeQueue
+ (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)))
+{
+ g_main_context_wakeup (NULL);
+}
+
+JNIEXPORT jboolean JNICALL
+Java_gnu_java_awt_peer_gtk_GtkToolkit_nativeQueueEmpty
+ (JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)))
+{
+ jboolean empty = FALSE;
+ gdk_threads_enter ();
+ empty = ! gtk_events_pending();
+ gdk_threads_leave ();
+ return empty;
+}
+
static jint gdk_color_to_java_color (GdkColor color);
+
JNIEXPORT void JNICALL
Java_gnu_java_awt_peer_gtk_GtkToolkit_beep
(JNIEnv *env __attribute__((unused)), jobject obj __attribute__((unused)))