<AWT Dev> Review request: 6913179 (The java.awt.FileDialog should use native GTK file chooser on linux distros)

Damjan Jovanovic damjan.jov at gmail.com
Thu Mar 11 02:09:27 PST 2010


On Wed, Mar 10, 2010 at 11:35 PM, Costantino Cerbo <c.cerbo at gmail.com> wrote:
> Hallo,

Hi

> the only change in this new patch is the include of <string.h> and and
> <jni_util.h>.
>
> The answers for Damjan:
> 1) Using gdk_threads_enter() and gdk_threads_leave() in
> Java_sun_awt_X11_GtkFileDialogPeer_quit(..) freezes the dialog on
> close.

Sun, your latest awt tree still doesn't compile for me, I had to hack
it to not call a method that doesn't exist so it does compile:

diff -r d6d2de6ee2d1
src/share/classes/javax/swing/plaf/nimbus/NimbusLookAndFeel.java
--- a/src/share/classes/javax/swing/plaf/nimbus/NimbusLookAndFeel.java
 Fri Feb 19 15:13:37 2010 -0800
+++ b/src/share/classes/javax/swing/plaf/nimbus/NimbusLookAndFeel.java
 Thu Mar 11 11:33:29 2010 +0200
@@ -288,7 +288,7 @@
             "JComponent.sizeVariant" == eName) {

             JComponent c = (JComponent) ev.getSource();
-            defaults.clearOverridesCache(c);
+            //defaults.clearOverridesCache(c);
             return true;
         }

Now onto your patch.

You probably didn't listen to my warning about not calling
gdk_threads_enter when Java_sun_awt_X11_GtkFileDialogPeer_quit is
called from handle_response (because GTK itself holds that GDK lock
during the entire handle_response invocation, and that lock is not
reentrant). Hence you got the freeze.

My tests show the way I described does work, and the patch that uses
it correctly and doesn't freeze is attached.

> 2) This patch is tested with the last code in the OpenJDK repository
> and compiles correctly.
>
> I think, we all have done a good job and now it's time to put the
> patch in the OpenJDK.

With my patch and some heavier testing, I managed to get an assertion failure:

java: ../../src/xcb_io.c:176: process_responses: Assertion `!(req &&
current_request && !(((long) (req->sequence) - (long)
(current_request)) <= 0))' failed.
Aborted

I couldn't reproduce it but I'll keep trying.

There's probably still some place where we're not locking properly.

> Best Regards,
> Costantino

Regards
Damjan

> 2010/3/10 Costantino Cerbo <c.cerbo at gmail.com>:
>> Hello Damjan,
>>
>> 2010/3/10 Damjan Jovanovic <damjan.jov at gmail.com>:
>>> You should probably include the real header files here, like string.h
>>> and jni_util.h, instead of declaring those functions yourself.
>>
>> You're right. I will do so.
>>
>>
>>> Should we put the GDK lock statements around those 3 functions? But if
>>> we should, make sure they aren't taken recursively: when called from
>>> Java the GDK lock isn't taken and we must, but when called from the
>>> handle_response callback function, GTK already holds that lock and we
>>> must not.
>>
>> I don't know. I'll try later and let you know.
>>
>>
>>> You've still got some C++ comments:
>>> $ grep '//' b6913179.patch
>>
>> They are comments in Java classes ;-)
>>
>>
>>> Also the patch doesn't even compile from me, fpulling the awt forest
>>> to the latest and trying again...
>>
>> Yesterday I could compile without problems.
>> When I go home later, I check out the last code in the repository and try again.
>>
>>
>> Thanks for your comments and best regards,
>> Costantino
>>
>
-------------- next part --------------
diff -r d6d2de6ee2d1 make/sun/xawt/FILES_c_unix.gmk
--- a/make/sun/xawt/FILES_c_unix.gmk	Fri Feb 19 15:13:37 2010 -0800
+++ b/make/sun/xawt/FILES_c_unix.gmk	Thu Mar 11 11:49:23 2010 +0200
@@ -79,4 +79,5 @@
 	gtk2_interface.c \
         swing_GTKEngine.c \
         swing_GTKStyle.c \
-        rect.c
+        rect.c \
+	sun_awt_X11_GtkFileDialogPeer.c
diff -r d6d2de6ee2d1 make/sun/xawt/FILES_export_unix.gmk
--- a/make/sun/xawt/FILES_export_unix.gmk	Fri Feb 19 15:13:37 2010 -0800
+++ b/make/sun/xawt/FILES_export_unix.gmk	Thu Mar 11 11:49:23 2010 +0200
@@ -33,4 +33,5 @@
       sun/awt/X11/XDesktopPeer.java \
       sun/awt/X11/XToolkit.java \
       sun/awt/X11/XComponentPeer.java \
-      sun/awt/X11/XInputMethod.java
+      sun/awt/X11/XInputMethod.java \
+      sun/awt/X11/GtkFileDialogPeer.java
diff -r d6d2de6ee2d1 make/sun/xawt/mapfile-vers
--- a/make/sun/xawt/mapfile-vers	Fri Feb 19 15:13:37 2010 -0800
+++ b/make/sun/xawt/mapfile-vers	Thu Mar 11 11:49:23 2010 +0200
@@ -172,6 +172,7 @@
         Java_sun_awt_UNIXToolkit_load_1stock_1icon;
         Java_sun_awt_UNIXToolkit_load_1gtk_1icon;
         Java_sun_awt_UNIXToolkit_nativeSync;
+        Java_sun_awt_UNIXToolkit_gtkCheckVersionImpl;
         Java_java_awt_AWTEvent_initIDs;
         Java_java_awt_event_InputEvent_initIDs;
         Java_java_awt_event_KeyEvent_initIDs;
@@ -396,6 +397,9 @@
         Java_com_sun_java_swing_plaf_gtk_GTKStyle_nativeGetClassValue;
         Java_com_sun_java_swing_plaf_gtk_GTKStyle_nativeGetPangoFontName;
 
+	Java_sun_awt_X11_GtkFileDialogPeer_run;
+	Java_sun_awt_X11_GtkFileDialogPeer_quit;
+
 	Java_sun_print_CUPSPrinter_initIDs;
 	Java_sun_print_CUPSPrinter_getCupsServer;
 	Java_sun_print_CUPSPrinter_getCupsPort;
diff -r d6d2de6ee2d1 src/solaris/classes/sun/awt/UNIXToolkit.java
--- a/src/solaris/classes/sun/awt/UNIXToolkit.java	Fri Feb 19 15:13:37 2010 -0800
+++ b/src/solaris/classes/sun/awt/UNIXToolkit.java	Thu Mar 11 11:49:23 2010 +0200
@@ -314,4 +314,27 @@
         }
         return new RenderingHints(KEY_TEXT_ANTIALIASING, aaHint);
     }
+    
+    private native boolean gtkCheckVersionImpl(int major, int minor, 
+    		int micro);
+    
+	/**
+	 * Returns {@code true} if the GTK+ library is compatible with the given
+	 * version.
+	 * 
+	 * @param major
+	 *            The required major version.
+	 * @param minor
+	 *            The required minor version.
+	 * @param micro
+	 *            The required micro version.
+	 * @return {@code true} if the GTK+ library is compatible with the given
+	 *         version.
+	 */
+	public boolean checkGtkVersion(int major, int minor, int micro) {
+		if(loadGTK()) {
+			return gtkCheckVersionImpl(major, minor, micro);
+		}
+		return false;
+	}
 }
diff -r d6d2de6ee2d1 src/solaris/classes/sun/awt/X11/GtkFileDialogPeer.java
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/solaris/classes/sun/awt/X11/GtkFileDialogPeer.java	Thu Mar 11 11:49:23 2010 +0200
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2010 Sun Microsystems, Inc.  All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+package sun.awt.X11;
+
+import java.awt.Dialog;
+import java.awt.FileDialog;
+import java.awt.peer.FileDialogPeer;
+import java.io.File;
+import java.io.FilenameFilter;
+import javax.swing.SwingUtilities;
+import javax.swing.SwingWorker;
+import sun.awt.AWTAccessor;
+
+/**
+ * FileDialogPeer for the GtkFileChooser.
+ * 
+ * @author Costantino Cerbo (c.cerbo at gmail.com)
+ */
+class GtkFileDialogPeer extends XDialogPeer implements FileDialogPeer {
+
+    private FileDialog fd;
+
+    public GtkFileDialogPeer(FileDialog fd) {
+        super((Dialog) fd);
+        this.fd = fd;
+    }
+
+    private native void run(String title, int mode, String dir, String file,
+            FilenameFilter filter, boolean isMultipleMode);
+
+    private native void quit();
+
+    /**
+     * Called exclusively by the native C code.
+     */
+    private void setFileInternal(String directory, String[] filenames) {
+        AWTAccessor.FileDialogAccessor accessor = AWTAccessor.getFileDialogAccessor();
+  
+        if (filenames == null) {
+            accessor.setDirectory(fd, null);
+            accessor.setFile(fd, null);
+            accessor.setFiles(fd, null, null);
+        } else {
+            accessor.setDirectory(fd, directory);
+            accessor.setFile(fd, filenames[0]);
+            accessor.setFiles(fd, directory, filenames);
+        }
+    }
+
+    /**
+     * Called exclusively by the native C code.
+     */
+    private boolean filenameFilterCallback(String fullname) {
+        if (fd.getFilenameFilter() == null) {
+            // no filter, accept all.
+            return true;
+        }
+
+        File filen = new File(fullname);
+        return fd.getFilenameFilter().accept(new File(filen.getParent()),
+                filen.getName());
+    }
+
+    @Override
+    public void setVisible(boolean b) {
+        XToolkit.awtLock();
+        try {
+            if (b) {
+                Thread t = new Thread() {
+                    public void run() {
+                        GtkFileDialogPeer.this.run(fd.getTitle(), fd.getMode(), 
+                                fd.getDirectory(), fd.getFile(), 
+                                fd.getFilenameFilter(), fd.isMultipleMode());
+                        fd.setVisible(false);
+                    }
+                };
+                t.start();
+            } else {
+                quit();
+                fd.setVisible(false);
+            }
+        } finally {
+            XToolkit.awtUnlock();
+        }
+    }
+
+    @Override
+    public void dispose() {
+        quit();
+        super.dispose();
+    }
+
+    @Override
+    public void setDirectory(String dir) {
+        // We do not implement this method because we
+        // have delegated to FileDialog#setDirectory
+    }
+
+    @Override
+    public void setFile(String file) {
+        // We do not implement this method because we
+        // have delegated to FileDialog#setFile
+    }
+
+    @Override
+    public void setFilenameFilter(FilenameFilter filter) {
+        // We do not implement this method because we
+        // have delegated to FileDialog#setFilenameFilter
+    }
+}
diff -r d6d2de6ee2d1 src/solaris/classes/sun/awt/X11/XToolkit.java
--- a/src/solaris/classes/sun/awt/X11/XToolkit.java	Fri Feb 19 15:13:37 2010 -0800
+++ b/src/solaris/classes/sun/awt/X11/XToolkit.java	Thu Mar 11 11:49:23 2010 +0200
@@ -1041,7 +1041,9 @@
     }
 
     public FileDialogPeer createFileDialog(FileDialog target) {
-        FileDialogPeer peer = new XFileDialogPeer(target);
+        // The current GtkFileChooser is available from GTK+ 2.4
+        FileDialogPeer peer = checkGtkVersion(2, 4, 0) ? new GtkFileDialogPeer(
+                target) : new XFileDialogPeer(target);
         targetCreatedPeer(target, peer);
         return peer;
     }
diff -r d6d2de6ee2d1 src/solaris/native/sun/awt/awt_UNIXToolkit.c
--- a/src/solaris/native/sun/awt/awt_UNIXToolkit.c	Fri Feb 19 15:13:37 2010 -0800
+++ b/src/solaris/native/sun/awt/awt_UNIXToolkit.c	Thu Mar 11 11:49:23 2010 +0200
@@ -260,3 +260,24 @@
     }
     dlclose(hSplashLib);
 }
+
+/*
+ * Class:     sun_awt_UNIXToolkit
+ * Method:    gtkCheckVersionImpl
+ * Signature: (III)Ljava/lang/String;
+ */
+JNIEXPORT jboolean JNICALL
+Java_sun_awt_UNIXToolkit_gtkCheckVersionImpl
+  (JNIEnv *env, jobject this, jint major, jint minor, jint micro)
+{
+	char *ret;
+
+	ret = fp_gtk_check_version(major, minor, micro);
+	if (ret == NULL)
+	{
+		return TRUE;
+	}
+
+	free(ret);
+	return FALSE;
+}
diff -r d6d2de6ee2d1 src/solaris/native/sun/awt/gtk2_interface.c
--- a/src/solaris/native/sun/awt/gtk2_interface.c	Fri Feb 19 15:13:37 2010 -0800
+++ b/src/solaris/native/sun/awt/gtk2_interface.c	Thu Mar 11 11:49:23 2010 +0200
@@ -32,6 +32,7 @@
 #include "java_awt_Transparency.h"
 
 #define GTK2_LIB "libgtk-x11-2.0.so.0"
+#define GTHREAD_LIB "libgthread-2.0.so.0"
 
 #define G_TYPE_INVALID                  G_TYPE_MAKE_FUNDAMENTAL (0)
 #define G_TYPE_NONE                     G_TYPE_MAKE_FUNDAMENTAL (1)
@@ -75,6 +76,7 @@
 const gint DEFAULT    = 1 << 10;
 
 static void *gtk2_libhandle = NULL;
+static void *gthread_libhandle = NULL;
 static jmp_buf j;
 
 /* Widgets */
@@ -150,7 +152,6 @@
 /*************************
  * Glib function pointers
  *************************/
-static void     (*fp_g_free)(gpointer mem);
 
 static gboolean (*fp_g_main_context_iteration)(GMainContext *context,
                                              gboolean may_block);
@@ -204,9 +205,6 @@
 /************************
  * Gtk function pointers
  ************************/
-static gchar*   (*fp_gtk_check_version)(guint required_major,
-                                        guint required_minor,
-                                        guint required_micro);
 static gboolean (*fp_gtk_init_check)(int* argc, char** argv);
 
 /* Painting */
@@ -330,7 +328,6 @@
 static void (*fp_gtk_menu_item_set_submenu)(GtkMenuItem *menu_item,
         GtkWidget *submenu);
 static void (*fp_gtk_widget_realize)(GtkWidget *widget);
-static void (*fp_gtk_widget_destroy)(GtkWidget *widget);
 static GdkPixbuf* (*fp_gtk_widget_render_icon)(GtkWidget *widget,
         const gchar *stock_id, GtkIconSize size, const gchar *detail);
 static void (*fp_gtk_widget_set_name)(GtkWidget *widget, const gchar *name);
@@ -388,6 +385,15 @@
     return result;
 }
 
+static void* dl_symbol_gthread(const char* name)
+{
+    void* result = dlsym(gthread_libhandle, name);
+    if (!result)
+        longjmp(j, NO_SYMBOL_EXCEPTION);
+
+    return result;
+}
+
 gboolean gtk2_check_version()
 {
     if (gtk2_libhandle != NULL) {
@@ -414,6 +420,33 @@
     }
 }
 
+/**
+ * Functions for sun_awt_X11_GtkFileDialogPeer.c
+ */
+void gtk2_file_chooser_load()
+{
+	fp_gtk_file_chooser_get_filename = dl_symbol(
+			"gtk_file_chooser_get_filename");
+	fp_gtk_file_chooser_dialog_new = dl_symbol("gtk_file_chooser_dialog_new");
+	fp_gtk_file_chooser_set_current_folder = dl_symbol(
+			"gtk_file_chooser_set_current_folder");
+	fp_gtk_file_chooser_set_filename = dl_symbol(
+			"gtk_file_chooser_set_filename");
+	fp_gtk_file_filter_add_custom = dl_symbol("gtk_file_filter_add_custom");
+	fp_gtk_file_chooser_set_filter = dl_symbol("gtk_file_chooser_set_filter");
+	fp_gtk_file_chooser_get_type = dl_symbol("gtk_file_chooser_get_type");
+	fp_gtk_file_filter_new = dl_symbol("gtk_file_filter_new");
+	fp_gtk_file_chooser_set_do_overwrite_confirmation = dl_symbol(
+			"gtk_file_chooser_set_do_overwrite_confirmation");
+	fp_gtk_file_chooser_set_select_multiple = dl_symbol(
+			"gtk_file_chooser_set_select_multiple");
+	fp_gtk_file_chooser_get_current_folder = dl_symbol(
+			"gtk_file_chooser_get_current_folder");
+	fp_gtk_file_chooser_get_filenames = dl_symbol(
+			"gtk_file_chooser_get_filenames");
+	fp_gtk_g_slist_length = dl_symbol("g_slist_length");
+}
+
 gboolean gtk2_load()
 {
     gboolean result;
@@ -423,7 +456,9 @@
     char *gtk_modules_env;
 
     gtk2_libhandle = dlopen(GTK2_LIB, RTLD_LAZY | RTLD_LOCAL);
-    if (gtk2_libhandle == NULL)
+    gthread_libhandle = dlopen(GTHREAD_LIB, RTLD_LAZY | RTLD_LOCAL);
+
+    if (gtk2_libhandle == NULL || gthread_libhandle == NULL)
         return FALSE;
 
     if (setjmp(j) == 0)
@@ -597,6 +632,29 @@
         fp_gtk_range_get_adjustment =
             dl_symbol("gtk_range_get_adjustment");
 
+    	fp_gtk_widget_hide = dl_symbol("gtk_widget_hide");
+    	fp_gtk_main_quit = dl_symbol("gtk_main_quit");
+    	fp_g_signal_connect_data = dl_symbol("g_signal_connect_data");
+    	fp_gtk_widget_show = dl_symbol("gtk_widget_show");
+    	fp_gtk_main = dl_symbol("gtk_main");
+
+    	/**
+    	 * GLib thread system
+    	 */
+    	fp_g_thread_get_initialized = dl_symbol_gthread("g_thread_get_initialized");
+    	fp_g_thread_init = dl_symbol_gthread("g_thread_init");
+    	fp_gdk_threads_init = dl_symbol("gdk_threads_init");
+    	fp_gdk_threads_enter = dl_symbol("gdk_threads_enter");
+    	fp_gdk_threads_leave = dl_symbol("gdk_threads_leave");
+
+        /**
+         * Functions for sun_awt_X11_GtkFileDialogPeer.c
+         */
+    	if (fp_gtk_check_version(2, 4, 0) == NULL) {
+    		// The current GtkFileChooser is available from GTK+ 2.4
+    		gtk2_file_chooser_load();
+    	}
+
         /* Some functions may be missing in pre-2.4 GTK.
            We handle them specially here.
          */
@@ -626,6 +684,10 @@
     {
         dlclose(gtk2_libhandle);
         gtk2_libhandle = NULL;
+
+        dlclose(gthread_libhandle);
+        gthread_libhandle = NULL;
+        
         return FALSE;
     }
 
@@ -678,6 +740,19 @@
     */
     handler = XSetErrorHandler(NULL);
     io_handler = XSetIOErrorHandler(NULL);
+
+    if (fp_gtk_check_version(2, 2, 0) == NULL)
+    {
+    	// Init the thread system to use GLib in a thread-safe mode
+    	if (!fp_g_thread_get_initialized())
+    	{
+    		fp_g_thread_init(NULL);
+
+    		//According the GTK documentation, gdk_threads_init() should be
+    		//called before gtk_init() or gtk_init_check()
+    		fp_gdk_threads_init();
+    	}
+    }
     result = (*fp_gtk_init_check)(NULL, NULL);
 
     XSetErrorHandler(handler);
@@ -722,6 +797,7 @@
 
     dlerror();
     dlclose(gtk2_libhandle);
+    dlclose(gthread_libhandle);
     if ((gtk2_error = dlerror()) != NULL)
     {
         return FALSE;
diff -r d6d2de6ee2d1 src/solaris/native/sun/awt/gtk2_interface.h
--- a/src/solaris/native/sun/awt/gtk2_interface.h	Fri Feb 19 15:13:37 2010 -0800
+++ b/src/solaris/native/sun/awt/gtk2_interface.h	Thu Mar 11 11:49:23 2010 +0200
@@ -28,6 +28,21 @@
 #include <stdlib.h>
 #include <jni.h>
 
+#define _G_TYPE_CIC(ip, gt, ct)       ((ct*) ip)
+#define G_TYPE_CHECK_INSTANCE_CAST(instance, g_type, c_type)    (_G_TYPE_CIC ((instance), (g_type), c_type))
+#define GTK_TYPE_FILE_CHOOSER             (fp_gtk_file_chooser_get_type ())
+#define GTK_FILE_CHOOSER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_FILE_CHOOSER, GtkFileChooser))
+#define fp_g_signal_connect(instance, detailed_signal, c_handler, data) \
+    fp_g_signal_connect_data ((instance), (detailed_signal), (c_handler), (data), NULL, (GConnectFlags) 0)
+#define	G_CALLBACK(f) ((GCallback) (f))
+#define	G_TYPE_FUNDAMENTAL_SHIFT	(2)
+#define	G_TYPE_MAKE_FUNDAMENTAL(x)	((GType) ((x) << G_TYPE_FUNDAMENTAL_SHIFT))
+#define G_TYPE_OBJECT G_TYPE_MAKE_FUNDAMENTAL (20)
+#define G_OBJECT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), G_TYPE_OBJECT, GObject))
+#define GTK_STOCK_CANCEL           "gtk-cancel"
+#define GTK_STOCK_SAVE             "gtk-save"
+#define GTK_STOCK_OPEN             "gtk-open"
+
 typedef enum _WidgetType
 {
     BUTTON,                     /* GtkButton */
@@ -254,7 +269,13 @@
 /* We define all structure pointers to be void* */
 typedef void GError;
 typedef void GMainContext;
-typedef void GSList;
+
+typedef struct _GSList GSList;
+struct _GSList
+{
+  gpointer data;
+  GSList *next;
+};
 
 typedef void GdkColormap;
 typedef void GdkDrawable;
@@ -556,6 +577,66 @@
   guint ellipsize : 3;
 };
 
+typedef enum {
+	GTK_RESPONSE_NONE = -1,
+	GTK_RESPONSE_REJECT = -2,
+	GTK_RESPONSE_ACCEPT = -3,
+	GTK_RESPONSE_DELETE_EVENT = -4,
+	GTK_RESPONSE_OK = -5,
+	GTK_RESPONSE_CANCEL = -6,
+	GTK_RESPONSE_CLOSE = -7,
+	GTK_RESPONSE_YES = -8,
+	GTK_RESPONSE_NO = -9,
+	GTK_RESPONSE_APPLY = -10,
+	GTK_RESPONSE_HELP = -11
+} GtkResponseType;
+
+typedef struct _GtkWindow GtkWindow;
+
+typedef struct _GtkFileChooser GtkFileChooser;
+
+typedef enum {
+	GTK_FILE_CHOOSER_ACTION_OPEN,
+	GTK_FILE_CHOOSER_ACTION_SAVE,
+	GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
+	GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER
+} GtkFileChooserAction;
+
+typedef struct _GtkFileFilter GtkFileFilter;
+
+typedef enum {
+	GTK_FILE_FILTER_FILENAME = 1 << 0,
+	GTK_FILE_FILTER_URI = 1 << 1,
+	GTK_FILE_FILTER_DISPLAY_NAME = 1 << 2,
+	GTK_FILE_FILTER_MIME_TYPE = 1 << 3
+} GtkFileFilterFlags;
+
+typedef struct {
+	GtkFileFilterFlags contains;
+
+	const gchar *filename;
+	const gchar *uri;
+	const gchar *display_name;
+	const gchar *mime_type;
+} GtkFileFilterInfo;
+
+typedef gboolean (*GtkFileFilterFunc)(const GtkFileFilterInfo *filter_info,
+		gpointer data);
+
+typedef void (*GDestroyNotify)(gpointer data);
+
+typedef void (*GCallback)(void);
+
+typedef struct _GClosure GClosure;
+
+typedef void (*GClosureNotify)(gpointer data, GClosure *closure);
+
+typedef enum {
+	G_CONNECT_AFTER = 1 << 0, G_CONNECT_SWAPPED = 1 << 1
+} GConnectFlags;
+
+typedef struct _GThreadFunctions GThreadFunctions;
+
 /*
  * Converts java.lang.String object to UTF-8 character string.
  */
@@ -569,6 +650,13 @@
  */
 gboolean gtk2_check_version();
 
+/**
+ * Returns :
+ *	NULL if the GTK+ library is compatible with the given version, or a string
+ *	describing the version mismatch.
+ */
+gchar* (*fp_gtk_check_version)(guint required_major, guint required_minor,
+		                       guint required_micro);
 /*
  * Load the gtk2 library.  If the library is already loaded this method has no
  * effect and returns success.
@@ -651,6 +739,7 @@
 void gtk2_set_range_value(WidgetType widget_type, jdouble value,
                           jdouble min, jdouble max, jdouble visible);
 
+void (*fp_g_free)(gpointer mem);
 void (*fp_g_object_unref)(gpointer object);
 int (*fp_gdk_pixbuf_get_bits_per_sample)(const GdkPixbuf *pixbuf);
 guchar *(*fp_gdk_pixbuf_get_pixels)(const GdkPixbuf *pixbuf);
@@ -660,5 +749,48 @@
 int (*fp_gdk_pixbuf_get_rowstride)(const GdkPixbuf *pixbuf);
 int (*fp_gdk_pixbuf_get_width)(const GdkPixbuf *pixbuf);
 GdkPixbuf *(*fp_gdk_pixbuf_new_from_file)(const char *filename, GError **error);
+void (*fp_gtk_widget_destroy)(GtkWidget *widget);
+
+
+/**
+ * Function Pointers for GtkFileChooser
+ */
+gchar* (*fp_gtk_file_chooser_get_filename)(GtkFileChooser *chooser);
+void (*fp_gtk_widget_hide)(GtkWidget *widget);
+void (*fp_gtk_main_quit)(void);
+GtkWidget* (*fp_gtk_file_chooser_dialog_new)(const gchar *title,
+		GtkWindow *parent, GtkFileChooserAction action,
+		const gchar *first_button_text, ...);
+gboolean (*fp_gtk_file_chooser_set_current_folder)(GtkFileChooser *chooser,
+		const gchar *filename);
+gboolean (*fp_gtk_file_chooser_set_filename)(GtkFileChooser *chooser,
+		const char *filename);
+void (*fp_gtk_file_filter_add_custom)(GtkFileFilter *filter,
+		GtkFileFilterFlags needed, GtkFileFilterFunc func, gpointer data,
+		GDestroyNotify notify);
+void (*fp_gtk_file_chooser_set_filter)(GtkFileChooser *chooser,
+		GtkFileFilter *filter);
+GType (*fp_gtk_file_chooser_get_type)(void);
+GtkFileFilter* (*fp_gtk_file_filter_new)(void);
+void (*fp_gtk_file_chooser_set_do_overwrite_confirmation)(
+		GtkFileChooser *chooser, gboolean do_overwrite_confirmation);
+void (*fp_gtk_file_chooser_set_select_multiple)(
+		GtkFileChooser *chooser, gboolean select_multiple);
+gchar* (*fp_gtk_file_chooser_get_current_folder)(GtkFileChooser *chooser);
+GSList* (*fp_gtk_file_chooser_get_filenames)(GtkFileChooser *chooser);
+guint (*fp_gtk_g_slist_length)(GSList *list);
+gulong (*fp_g_signal_connect_data)(gpointer instance,
+		const gchar *detailed_signal, GCallback c_handler, gpointer data,
+		GClosureNotify destroy_data, GConnectFlags connect_flags);
+void (*fp_gtk_widget_show)(GtkWidget *widget);
+void (*fp_gtk_main)(void);
+guint (*fp_gtk_main_level)(void);
+
+
+gboolean (*fp_g_thread_get_initialized)(void);
+void (*fp_g_thread_init)(GThreadFunctions *vtable);
+void (*fp_gdk_threads_init)(void);
+void (*fp_gdk_threads_enter)(void);
+void (*fp_gdk_threads_leave)(void);
 
 #endif /* !_GTK2_INTERFACE_H */
diff -r d6d2de6ee2d1 src/solaris/native/sun/awt/sun_awt_X11_GtkFileDialogPeer.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/solaris/native/sun/awt/sun_awt_X11_GtkFileDialogPeer.c	Thu Mar 11 11:49:23 2010 +0200
@@ -0,0 +1,252 @@
+#include <jni.h>
+#include <stdio.h>
+#include <jni_util.h>
+#include <string.h>
+#include "gtk2_interface.h"
+#include "sun_awt_X11_GtkFileDialogPeer.h"
+
+static JavaVM *jvm;
+static GtkWidget *dialog = NULL;
+
+/* To cache some method IDs */
+static jmethodID filenameFilterCallbackMethodID = NULL;
+static jmethodID setFileInternalMethodID = NULL;
+
+static gboolean filenameFilterCallback(const GtkFileFilterInfo * filter_info,
+		gpointer obj)
+{
+	JNIEnv *env;
+	jclass cx;
+	jstring filename;
+
+	env = (JNIEnv *) JNU_GetEnv(jvm, JNI_VERSION_1_2);
+
+	if (filenameFilterCallbackMethodID == NULL)
+	{
+		cx = (*env)->GetObjectClass(env, (jobject) obj);
+		if (cx == NULL)
+		{
+			JNU_ThrowInternalError(env, "Could not get file filter class");
+			return 0;
+		}
+
+		filenameFilterCallbackMethodID = (*env)->GetMethodID(env, cx,
+				"filenameFilterCallback", "(Ljava/lang/String;)Z");
+		if (filenameFilterCallbackMethodID == NULL)
+		{
+			JNU_ThrowInternalError(env,
+					"Could not get filenameFilterCallback method id");
+			return 0;
+		}
+	}
+
+	filename = (*env)->NewStringUTF(env, filter_info->filename);
+
+	return (*env)->CallBooleanMethod(env, obj, filenameFilterCallbackMethodID,
+			filename);
+}
+
+static void unlocked_quit(void)
+{
+	if (dialog != NULL)
+	{
+		fp_gtk_widget_hide (dialog);
+		fp_gtk_widget_destroy (dialog);
+
+		fp_gtk_main_quit ();
+		dialog = NULL;
+	}
+}
+
+/*
+ * Class:     sun_awt_X11_GtkFileDialogPeer
+ * Method:    quit
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_sun_awt_X11_GtkFileDialogPeer_quit
+(JNIEnv * env, jobject jpeer)
+{
+	fp_gdk_threads_enter();
+	unlocked_quit();
+	fp_gdk_threads_leave();
+}
+
+/**
+ * Convert a GSList to an array of filenames (without the parent folder)
+ */
+static jobjectArray toFilenamesArray(JNIEnv *env, GSList* list)
+{
+	jstring str;
+	jclass stringCls;
+	GSList *iterator;
+	jobjectArray array;
+	int i;
+	char* entry;
+
+	if (NULL == list)
+	{
+		return NULL;
+	}
+
+	stringCls = (*env)->FindClass(env, "java/lang/String");
+	if (stringCls == NULL)
+	{
+		JNU_ThrowInternalError(env, "Could not get java.lang.String class");
+		return NULL;
+	}
+
+	array = (*env)->NewObjectArray(env, fp_gtk_g_slist_length(list), stringCls,
+			NULL);
+	if (array == NULL)
+	{
+		JNU_ThrowInternalError(env, "Could not instantiate array files array");
+		return NULL;
+	}
+
+	i = 0;
+	for (iterator = list; iterator; iterator = iterator->next)
+	{
+		entry = (char*) iterator->data;
+		entry = strrchr(entry, '/') + 1;
+		str = (*env)->NewStringUTF(env, entry);
+		(*env)->SetObjectArrayElement(env, array, i, str);
+		i++;
+	}
+
+	return array;
+}
+
+static void handle_response(GtkWidget* aDialog, gint responseId, gpointer obj)
+{
+	JNIEnv *env;
+	char *current_folder;
+	GSList *filenames;
+	jclass cx;
+	jstring jcurrent_folder;
+	jobjectArray jfilenames;
+
+	env = (JNIEnv *) JNU_GetEnv(jvm, JNI_VERSION_1_2);
+	current_folder = NULL;
+	filenames = NULL;
+
+	if (responseId == GTK_RESPONSE_ACCEPT)
+	{
+		current_folder = fp_gtk_file_chooser_get_current_folder(
+				GTK_FILE_CHOOSER(dialog));
+		filenames = fp_gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog));
+	}
+
+	if (setFileInternalMethodID == NULL)
+	{
+		cx = (*env)->GetObjectClass(env, (jobject) obj);
+		if (cx == NULL)
+		{
+			JNU_ThrowInternalError(env, "Could not get GTK peer class");
+			return;
+		}
+
+		setFileInternalMethodID = (*env)->GetMethodID(env, cx,
+				"setFileInternal", "(Ljava/lang/String;[Ljava/lang/String;)V");
+		if (setFileInternalMethodID == NULL)
+		{
+			JNU_ThrowInternalError(env,
+					"Could not get setFileInternalMethodID method id");
+			return;
+		}
+	}
+
+	jcurrent_folder = (*env)->NewStringUTF(env, current_folder);
+	jfilenames = toFilenamesArray(env, filenames);
+
+	(*env)->CallVoidMethod(env, obj, setFileInternalMethodID, jcurrent_folder,
+			jfilenames);
+	fp_g_free(current_folder);
+
+	unlocked_quit();
+}
+
+/*
+ * Class:     sun_awt_X11_GtkFileDialogPeer
+ * Method:    run
+ * Signature: (Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/io/FilenameFilter;Z;)V
+ */
+JNIEXPORT void JNICALL
+Java_sun_awt_X11_GtkFileDialogPeer_run(JNIEnv * env, jobject jpeer,
+		jstring jtitle, jint mode, jstring jdir, jstring jfile,
+		jobject jfilter, jboolean multiple)
+{
+	GtkFileFilter *filter;
+
+	if (jvm == NULL)
+	{
+		(*env)->GetJavaVM(env, &jvm);
+	}
+
+	fp_gdk_threads_init();
+	fp_gdk_threads_enter();
+
+	const char *title = (*env)->GetStringUTFChars(env, jtitle, 0);
+
+	if (mode == 1)
+	{
+		/* Save action */
+		dialog = fp_gtk_file_chooser_dialog_new(title, NULL,
+				GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL,
+				GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL);
+	}
+	else
+	{
+		/* Default action OPEN */
+		dialog = fp_gtk_file_chooser_dialog_new(title, NULL,
+				GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL,
+				GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);
+
+		/* Set multiple selection mode, that is allowed only in OPEN action */
+		if (multiple)
+		{
+			fp_gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog),
+					multiple);
+		}
+	}
+
+	(*env)->ReleaseStringUTFChars(env, jtitle, title);
+
+	/* Set the directory */
+	if (jdir != NULL)
+	{
+		const char *dir = (*env)->GetStringUTFChars(env, jdir, 0);
+		fp_gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), dir);
+		(*env)->ReleaseStringUTFChars(env, jdir, dir);
+	}
+
+	/* Set the filename */
+	if (jfile != NULL)
+	{
+		const char *filename = (*env)->GetStringUTFChars(env, jfile, 0);
+		fp_gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), filename);
+		(*env)->ReleaseStringUTFChars(env, jfile, filename);
+	}
+
+	/* Set the file filter */
+	if (jfilter != NULL)
+	{
+		filter = fp_gtk_file_filter_new();
+		fp_gtk_file_filter_add_custom(filter, GTK_FILE_FILTER_FILENAME,
+				filenameFilterCallback, jpeer, NULL);
+		fp_gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter);
+	}
+
+	/* Other Properties */
+	if (fp_gtk_check_version(2, 8, 0) == NULL)
+	{
+		fp_gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(
+				dialog), TRUE);
+	}
+
+	fp_g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(
+			handle_response), jpeer);
+	fp_gtk_widget_show(dialog);
+
+	fp_gtk_main();
+	fp_gdk_threads_leave();
+}
diff -r d6d2de6ee2d1 src/solaris/native/sun/awt/sun_awt_X11_GtkFileDialogPeer.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/solaris/native/sun/awt/sun_awt_X11_GtkFileDialogPeer.h	Thu Mar 11 11:49:23 2010 +0200
@@ -0,0 +1,31 @@
+/* DO NOT EDIT THIS FILE - it is machine generated */
+#include <jni.h>
+/* Header for class sun_awt_X11_GtkFileDialogPeer */
+
+#ifndef _Included_sun_awt_X11_GtkFileDialogPeer
+#define _Included_sun_awt_X11_GtkFileDialogPeer
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ * Class:     sun_awt_X11_GtkFileDialogPeer
+ * Method:    run
+ * Signature: (Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/io/FilenameFilter;Z;)V
+ */
+JNIEXPORT void JNICALL Java_sun_awt_X11_GtkFileDialogPeer_run
+  (JNIEnv *, jobject, jstring, jint, jstring, jstring, jobject, jboolean);
+
+/*
+ * Class:     sun_awt_X11_GtkFileDialogPeer
+ * Method:    quit
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_sun_awt_X11_GtkFileDialogPeer_quit
+  (JNIEnv *, jobject);
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff -r d6d2de6ee2d1 src/solaris/native/sun/awt/swing_GTKEngine.c
--- a/src/solaris/native/sun/awt/swing_GTKEngine.c	Fri Feb 19 15:13:37 2010 -0800
+++ b/src/solaris/native/sun/awt/swing_GTKEngine.c	Thu Mar 11 11:49:23 2010 +0200
@@ -38,8 +38,10 @@
         jint widget_type, jint state, jint shadow_type, jstring detail,
         jint x, jint y, jint w, jint h, jint arrow_type)
 {
+    fp_gdk_threads_enter();
     gtk2_paint_arrow(widget_type, state, shadow_type, getStrFor(env, detail),
             x, y, w, h, arrow_type, TRUE);
+    fp_gdk_threads_leave();
 }
 
 /*
@@ -54,8 +56,10 @@
         jint x, jint y, jint w, jint h,
         jint synth_state, jint dir)
 {
+    fp_gdk_threads_enter();
     gtk2_paint_box(widget_type, state, shadow_type, getStrFor(env, detail),
                    x, y, w, h, synth_state, dir);
+    fp_gdk_threads_leave();
 }
 
 /*
@@ -70,8 +74,10 @@
         jint x, jint y, jint w, jint h,
         jint gap_side, jint gap_x, jint gap_w)
 {
+    fp_gdk_threads_enter();
     gtk2_paint_box_gap(widget_type, state, shadow_type, getStrFor(env, detail),
             x, y, w, h, gap_side, gap_x, gap_w);
+    fp_gdk_threads_leave();
 }
 
 /*
@@ -85,8 +91,10 @@
         jint widget_type, jint synth_state, jstring detail,
         jint x, jint y, jint w, jint h)
 {
+    fp_gdk_threads_enter();
     gtk2_paint_check(widget_type, synth_state, getStrFor(env, detail),
                      x, y, w, h);
+    fp_gdk_threads_leave();
 }
 
 /*
@@ -100,8 +108,10 @@
         jint widget_type, jint state, jstring detail,
         jint x, jint y, jint w, jint h, jint expander_style)
 {
+    fp_gdk_threads_enter();
     gtk2_paint_expander(widget_type, state, getStrFor(env, detail),
             x, y, w, h, expander_style);
+    fp_gdk_threads_leave();
 }
 
 /*
@@ -115,8 +125,10 @@
         jint widget_type, jint state, jint shadow_type, jstring detail,
         jint x, jint y, jint w, jint h, jint placement)
 {
+    fp_gdk_threads_enter();
     gtk2_paint_extension(widget_type, state, shadow_type,
             getStrFor(env, detail), x, y, w, h, placement);
+    fp_gdk_threads_leave();
 }
 
 /*
@@ -130,8 +142,10 @@
         jint widget_type, jint state, jint shadow_type, jstring detail,
         jint x, jint y, jint w, jint h, jboolean has_focus)
 {
+    fp_gdk_threads_enter();
     gtk2_paint_flat_box(widget_type, state, shadow_type,
             getStrFor(env, detail), x, y, w, h, has_focus);
+    fp_gdk_threads_leave();
 }
 
 /*
@@ -145,8 +159,10 @@
         jint widget_type, jint state, jstring detail,
         jint x, jint y, jint w, jint h)
 {
+    fp_gdk_threads_enter();
     gtk2_paint_focus(widget_type, state, getStrFor(env, detail),
             x, y, w, h);
+    fp_gdk_threads_leave();
 }
 
 /*
@@ -160,8 +176,10 @@
         jint widget_type, jint state, jint shadow_type, jstring detail,
         jint x, jint y, jint w, jint h, jint orientation)
 {
+    fp_gdk_threads_enter();
     gtk2_paint_handle(widget_type, state, shadow_type, getStrFor(env, detail),
             x, y, w, h, orientation);
+    fp_gdk_threads_leave();
 }
 
 /*
@@ -175,8 +193,10 @@
         jint widget_type, jint state, jstring detail,
         jint x, jint y, jint w, jint h)
 {
+    fp_gdk_threads_enter();
     gtk2_paint_hline(widget_type, state, getStrFor(env, detail),
             x, y, w, h);
+    fp_gdk_threads_leave();
 }
 
 /*
@@ -190,8 +210,10 @@
         jint widget_type, jint synth_state, jstring detail,
         jint x, jint y, jint w, jint h)
 {
+    fp_gdk_threads_enter();
     gtk2_paint_option(widget_type, synth_state, getStrFor(env, detail),
                       x, y, w, h);
+    fp_gdk_threads_leave();
 }
 
 /*
@@ -206,8 +228,10 @@
         jint x, jint y, jint w, jint h,
         jint synth_state, jint dir)
 {
+    fp_gdk_threads_enter();
     gtk2_paint_shadow(widget_type, state, shadow_type, getStrFor(env, detail),
                       x, y, w, h, synth_state, dir);
+    fp_gdk_threads_leave();
 }
 
 /*
@@ -221,8 +245,10 @@
         jint widget_type, jint state, jint shadow_type, jstring detail,
         jint x, jint y, jint w, jint h, jint orientation)
 {
+    fp_gdk_threads_enter();
     gtk2_paint_slider(widget_type, state, shadow_type, getStrFor(env, detail),
             x, y, w, h, orientation);
+    fp_gdk_threads_leave();
 }
 
 /*
@@ -236,8 +262,10 @@
         jint widget_type, jint state, jstring detail,
         jint x, jint y, jint w, jint h)
 {
+    fp_gdk_threads_enter();
     gtk2_paint_vline(widget_type, state, getStrFor(env, detail),
             x, y, w, h);
+    fp_gdk_threads_leave();
 }
 
 /*
@@ -250,7 +278,9 @@
         JNIEnv *env, jobject this, jint widget_type, jint state,
         jint x, jint y, jint w, jint h)
 {
+    fp_gdk_threads_enter();
     gtk_paint_background(widget_type, state, x, y, w, h);
+    fp_gdk_threads_leave();
 }
 
 /*
@@ -262,7 +292,9 @@
 Java_com_sun_java_swing_plaf_gtk_GTKEngine_nativeStartPainting(
         JNIEnv *env, jobject this, jint w, jint h)
 {
+    fp_gdk_threads_enter();
     gtk2_init_painting(w, h);
+    fp_gdk_threads_leave();
 }
 
 /*
@@ -276,7 +308,9 @@
 {
     jint transparency;
     gint *buffer = (gint*) (*env)->GetPrimitiveArrayCritical(env, dest, 0);
+    fp_gdk_threads_enter();
     transparency = gtk2_copy_image(buffer, width, height);
+    fp_gdk_threads_leave();
     (*env)->ReleasePrimitiveArrayCritical(env, dest, buffer, 0);
     return transparency;
 }
@@ -289,7 +323,9 @@
 JNIEXPORT void JNICALL Java_com_sun_java_swing_plaf_gtk_GTKEngine_native_1switch_1theme(
         JNIEnv *env, jobject this)
 {
+    fp_gdk_threads_enter();
     flush_gtk_event_loop();
+    fp_gdk_threads_leave();
 }
 
 /*
@@ -300,7 +336,11 @@
 JNIEXPORT jobject JNICALL Java_com_sun_java_swing_plaf_gtk_GTKEngine_native_1get_1gtk_1setting(
         JNIEnv *env, jobject this, jint property)
 {
-    return gtk2_get_setting(env, property);
+    jobject obj;
+    fp_gdk_threads_enter();
+    obj = gtk2_get_setting(env, property);
+    fp_gdk_threads_leave();
+    return obj;
 }
 
 /*
@@ -313,5 +353,7 @@
         JNIEnv *env, jobject this, jint widget_type,
         jdouble value, jdouble min, jdouble max, jdouble visible)
 {
+    fp_gdk_threads_enter();
     gtk2_set_range_value(widget_type, value, min, max, visible);
+    fp_gdk_threads_leave();
 }
diff -r d6d2de6ee2d1 src/solaris/native/sun/awt/swing_GTKStyle.c
--- a/src/solaris/native/sun/awt/swing_GTKStyle.c	Fri Feb 19 15:13:37 2010 -0800
+++ b/src/solaris/native/sun/awt/swing_GTKStyle.c	Thu Mar 11 11:49:23 2010 +0200
@@ -36,7 +36,11 @@
 Java_com_sun_java_swing_plaf_gtk_GTKStyle_nativeGetXThickness(
     JNIEnv *env, jclass klass, jint widget_type)
 {
-    return gtk2_get_xthickness(env, widget_type);
+    jint ret;
+    fp_gdk_threads_enter();
+    ret = gtk2_get_xthickness(env, widget_type);
+    fp_gdk_threads_leave();
+    return ret;
 }
 
 /*
@@ -48,7 +52,11 @@
 Java_com_sun_java_swing_plaf_gtk_GTKStyle_nativeGetYThickness(
     JNIEnv *env, jclass klass, jint widget_type)
 {
-    return gtk2_get_ythickness(env, widget_type);
+    jint ret;
+    fp_gdk_threads_enter();
+    ret = gtk2_get_ythickness(env, widget_type);
+    fp_gdk_threads_leave();
+    return ret;
 }
 
 /*
@@ -61,7 +69,11 @@
     JNIEnv *env, jclass klass, jint widget_type,
     jint state_type, jint type_id)
 {
-    return gtk2_get_color_for_state(env, widget_type, state_type, type_id);
+    jint ret;
+    fp_gdk_threads_enter();
+    ret = gtk2_get_color_for_state(env, widget_type, state_type, type_id);
+    fp_gdk_threads_leave();
+    return ret;
 }
 
 /*
@@ -73,7 +85,11 @@
 Java_com_sun_java_swing_plaf_gtk_GTKStyle_nativeGetClassValue(
     JNIEnv *env, jclass klass, jint widget_type, jstring key)
 {
-    return gtk2_get_class_value(env, widget_type, key);
+    jobject ret;
+    fp_gdk_threads_enter();
+    ret = gtk2_get_class_value(env, widget_type, key);
+    fp_gdk_threads_leave();
+    return ret;
 }
 
 /*
@@ -85,5 +101,9 @@
 Java_com_sun_java_swing_plaf_gtk_GTKStyle_nativeGetPangoFontName(
     JNIEnv *env, jclass klass, jint widget_type)
 {
-    return gtk2_get_pango_font_name(env, widget_type);
+    jstring ret;
+    fp_gdk_threads_enter();
+    ret = gtk2_get_pango_font_name(env, widget_type);
+    fp_gdk_threads_leave();
+    return ret;
 }


More information about the awt-dev mailing list