<AWT Dev> Bug 6913179, FileDialog uses native GTK under Linux: first patch

Damjan Jovanovic damjan.jov at gmail.com
Fri Feb 12 00:36:14 PST 2010


On Thu, Feb 11, 2010 at 1:24 PM, Costantino Cerbo <c.cerbo at gmail.com> wrote:
> Hi Peter, Hi Damjan
>
> 2010/2/11 Damjan Jovanovic <damjan.jov at gmail.com>:
>> Hi Peter
>>
>> Your patch causes a native assertion error upon clicking "Save":
>>
>> $ java sun.awt.X11.FileDialogTest
>> java: ../../src/xcb_io.c:242: process_responses: Assertion `(((long)
>> (dpy->last_request_read) - (long) (dpy->request)) <= 0)' failed.
>> Aborted
>>
>> Clicking "Open" either silently exits or indefinitely hangs (no
>> redraw) both the file dialog and the Java window.
>
> Yes, using a new Thread with the GTK L&F causes the same problem also
> on my system (Fedora 12).
> Without a new Thread it seems to work, but the EDT is of course blocked.
>
> I think we should investigate how we initialise the GTK multithreaded system.

While testing without Peter's change I got a JVM crash from
FileDialogTest in "C  [libmC  [libmawt.so+0x3e992]
Java_com_sun_java_swing_plaf_gtk_GTKStyle_nativeGetColorForState+0x32".
This error is reproducible by opening and closing a file dialog twice.

Now with Peter's change, reproducing the hung GUI situation and
sending Java signal 3 gives an all threads stack trace that doesn't
seem particularly useful, since it doesn't trace into native code.

Tracing with gdb is equally doomed, since setting a breakpoint on
"assert" causes the entire X11 server to hang until Java is killed
;-).

But since the assertion error happens in xcb, and Java doesn't link to
libxcb while ldd shows that libgtk-x11 definitely does, it's safe to
conclude the assertion is caused by GTK itself.

strace shows 2 X11 sockets are opened during Java's execution, so
hopefully Java and GTK use different X11 sockets and don't interfere
with each other this way.

That only leaves Java's usage of GTK as a suspect.

The multithreading rule for GTK is "simply" gdk_threads_enter() before
and gdk_threads_leave() after every call to GTK. You've added those
for some (probably not enough) of the file dialog code, but the rest
of Java's GTK code doesn't do it, so when Peter's patch starts calling
into GTK from 2 threads and 1 of them isn't locking, things go very
bad, rapidly. See
http://www.cairographics.org/threaded_animation_with_cairo/ and
http://blogs.operationaldynamics.com/andrew/software/gnome-desktop/gtk-thread-awareness.html
for details. There was another example I found earlier that does
exactly what Java does (gtk_init and gtk_main in different threads),
but I can't find it now.

Anyway what happens when gdk_threads_init() and gdk_threads_leave()
are added everywhere?

Firstly Java hangs on startup. Luckily this time gdb's "thread apply
all bt" does work, and shows that the problem is caused by
gdk_threads_enter()/leave() not being reentrant, so
gtk2_init_painting() takes the lock and calls init_containers() which
also tries to take the lock -> deadlock. Unluckily there's a lot of
functions in gtk2_interface.c that call each other; setting up locking
to avoid reentrance would be a pain.

On http://blogs.operationaldynamics.com/andrew/software/gnome-desktop/gtk-thread-awareness.html
we read that while GDK locks are not reentrant, they can be safely
replaced by locks that are reentrant, and the java-gnome library
successfully does just that. Unfortunately for us
gdk_threads_set_lock_functions() only exists since GDK 2.4 -> no go.

So, after much hacking, when finally GTK calls are made thread-safe
and avoid gdk lock reentrance AFAICT, the dialog displays, the Java
GUI remains redrawable, and there's no crash. Unfortunately the dialog
won't close (it keeps coming back when you click Cancel) but that's a
different bug ;-).

My patch for all these changes is based on your latest one and include
Peter's (hackish?) patch. It's attached.

Otherwise, your patch lacks error checking (eg. in calls to
GetJavaVM() and NewStringUTF()), has typos in comments, and relies on
C99 features like C++ style comments and variable declarations in the
middle of a code block (do we allow those in Java?). In
sun_awt_X11_GtkFileDialogPeer.c you name the function "quit" and
document it as "hide"; similarly for "show" and "run". I am not
convinced I got all the GTK calls to be thread safe, so please audit
the code very carefully, and my locking could be a bit too fine
grained and impact the GTK LAF drawing performance.

> Regards,
> Costantino
>

Regards
Damjan
-------------- next part --------------
diff -r 66c193082586 make/sun/xawt/FILES_c_unix.gmk
--- a/make/sun/xawt/FILES_c_unix.gmk	Mon Feb 08 17:02:43 2010 +0300
+++ b/make/sun/xawt/FILES_c_unix.gmk	Fri Feb 12 10:30:40 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 66c193082586 make/sun/xawt/FILES_export_unix.gmk
--- a/make/sun/xawt/FILES_export_unix.gmk	Mon Feb 08 17:02:43 2010 +0300
+++ b/make/sun/xawt/FILES_export_unix.gmk	Fri Feb 12 10:30:40 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 66c193082586 make/sun/xawt/mapfile-vers
--- a/make/sun/xawt/mapfile-vers	Mon Feb 08 17:02:43 2010 +0300
+++ b/make/sun/xawt/mapfile-vers	Fri Feb 12 10:30:40 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 66c193082586 src/solaris/classes/sun/awt/UNIXToolkit.java
--- a/src/solaris/classes/sun/awt/UNIXToolkit.java	Mon Feb 08 17:02:43 2010 +0300
+++ b/src/solaris/classes/sun/awt/UNIXToolkit.java	Fri Feb 12 10:30:40 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 66c193082586 src/solaris/classes/sun/awt/X11/XToolkit.java
--- a/src/solaris/classes/sun/awt/X11/XToolkit.java	Mon Feb 08 17:02:43 2010 +0300
+++ b/src/solaris/classes/sun/awt/X11/XToolkit.java	Fri Feb 12 10:30:40 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 66c193082586 src/solaris/native/sun/awt/awt_UNIXToolkit.c
--- a/src/solaris/native/sun/awt/awt_UNIXToolkit.c	Mon Feb 08 17:02:43 2010 +0300
+++ b/src/solaris/native/sun/awt/awt_UNIXToolkit.c	Fri Feb 12 10:30:40 2010 +0200
@@ -154,7 +154,9 @@
         return JNI_FALSE;
     }
     (*env)->GetStringUTFRegion(env, filename, 0, len, filename_str);
+    fp_gdk_threads_enter();
     pixbuf = (*fp_gdk_pixbuf_new_from_file)(filename_str, error);
+    fp_gdk_threads_leave();
 
     /* Release the strings we've allocated. */
     free(filename_str);
@@ -208,8 +210,10 @@
         (*env)->GetStringUTFRegion(env, detail, 0, len, detail_str);
     }
 
+    fp_gdk_threads_enter();
     pixbuf = gtk2_get_stock_icon(widget_type, stock_id_str, icon_size,
                                  text_direction, detail_str);
+    fp_gdk_threads_leave();
 
     /* Release the strings we've allocated. */
     free(stock_id_str);
@@ -260,3 +264,21 @@
     }
     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 = fp_gtk_check_version(major, minor, micro);
+	if (ret == NULL) {
+		return TRUE;
+	}
+
+	free(ret);
+	return FALSE;
+}
diff -r 66c193082586 src/solaris/native/sun/awt/gtk2_interface.c
--- a/src/solaris/native/sun/awt/gtk2_interface.c	Mon Feb 08 17:02:43 2010 +0300
+++ b/src/solaris/native/sun/awt/gtk2_interface.c	Fri Feb 12 10:30:40 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"
 
 #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,26 @@
     }
 }
 
+/**
+ * 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");
+}
+
 gboolean gtk2_load()
 {
     gboolean result;
@@ -423,7 +449,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 +625,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 +677,10 @@
     {
         dlclose(gtk2_libhandle);
         gtk2_libhandle = NULL;
+
+        dlclose(gthread_libhandle);
+        gthread_libhandle = NULL;
+        
         return FALSE;
     }
 
@@ -678,6 +733,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 +790,7 @@
 
     dlerror();
     dlclose(gtk2_libhandle);
+    dlclose(gthread_libhandle);
     if ((gtk2_error = dlerror()) != NULL)
     {
         return FALSE;
diff -r 66c193082586 src/solaris/native/sun/awt/gtk2_interface.h
--- a/src/solaris/native/sun/awt/gtk2_interface.h	Mon Feb 08 17:02:43 2010 +0300
+++ b/src/solaris/native/sun/awt/gtk2_interface.h	Fri Feb 12 10:30:40 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 */
@@ -556,6 +571,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 +644,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 +733,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 +743,41 @@
 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);
+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);
+
+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 66c193082586 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	Fri Feb 12 10:30:40 2010 +0200
@@ -0,0 +1,138 @@
+#include <jni.h>
+#include <stdio.h>
+#include "gtk2_interface.h"
+#include "sun_awt_X11_GtkFileDialogPeer.h"
+
+static JavaVM *jvm;
+static GtkWidget *dialog = NULL;
+
+// In order to Cache some method IDs
+static jmethodID filenameFilterCallbackMethodID = NULL;
+static jmethodID setFileInternalMethodID = NULL;
+
+static gboolean filenameFilterCallback(const GtkFileFilterInfo * filter_info,
+		gpointer obj)
+{
+	JNIEnv *env = (JNIEnv *) JNU_GetEnv(jvm, JNI_VERSION_1_2);
+
+	if (filenameFilterCallbackMethodID == NULL) {
+		jclass cx = (*env)->GetObjectClass(env, (jobject) obj);
+		filenameFilterCallbackMethodID = (*env)->GetMethodID(env, cx,
+				"filenameFilterCallback", "(Ljava/lang/String;)Z");
+	}
+
+	jstring filename = (*env)->NewStringUTF(env, filter_info->filename);
+
+	return (*env)->CallBooleanMethod(env, obj, filenameFilterCallbackMethodID,
+			filename);
+}
+
+/*
+ * Class:     sun_awt_X11_GtkFileDialogPeer
+ * Method:    hide
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_sun_awt_X11_GtkFileDialogPeer_quit
+(JNIEnv * env, jobject jpeer)
+{
+	if (dialog != NULL)
+	{
+		fp_gtk_widget_hide (dialog);
+		fp_gtk_widget_destroy (dialog);
+
+		fp_gtk_main_quit ();
+		dialog = NULL;
+	}
+}
+
+static void handle_response(GtkWidget * aDialog, gint responseId, gpointer obj)
+{
+	JNIEnv *env = (JNIEnv *) JNU_GetEnv(jvm, JNI_VERSION_1_2);
+
+	char *filename = NULL;
+
+	if (responseId == GTK_RESPONSE_ACCEPT) {
+		filename = fp_gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(aDialog));
+	}
+
+	if (setFileInternalMethodID == NULL) {
+		jclass cx = (*env)->GetObjectClass(env, (jobject) obj);
+		setFileInternalMethodID = (*env)->GetMethodID(env, cx,
+				"setFileInternal", "(Ljava/lang/String;)V");
+	}
+
+	jstring jfilename = (*env)->NewStringUTF(env, filename);
+
+	(*env)->CallVoidMethod(env, obj, setFileInternalMethodID, jfilename);
+	fp_g_free(filename);
+
+	Java_sun_awt_X11_GtkFileDialogPeer_quit(NULL, NULL);
+}
+
+/*
+ * Class:     sun_awt_X11_GtkFileDialogPeer
+ * Method:    show
+ * Signature: (Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/io/FilenameFilter;)V
+ */
+JNIEXPORT void JNICALL
+Java_sun_awt_X11_GtkFileDialogPeer_run(JNIEnv * env, jobject jpeer,
+		jstring jtitle, jint mode, jstring jdir, jstring jfile, jobject jfilter)
+{
+	if (jvm == NULL) {
+		(*env)->GetJavaVM(env, &jvm);
+	}
+
+	const char *title = (*env)->GetStringUTFChars(env, jtitle, 0);
+
+	fp_gdk_threads_enter();
+
+	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);
+	}
+
+	(*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) {
+		GtkFileFilter *filter;
+		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 66c193082586 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	Fri Feb 12 10:30:40 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;)V
+ */
+JNIEXPORT void JNICALL Java_sun_awt_X11_GtkFileDialogPeer_run
+  (JNIEnv *, jobject, jstring, jint, jstring, jstring, jobject);
+
+/*
+ * 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 66c193082586 src/solaris/native/sun/awt/swing_GTKEngine.c
--- a/src/solaris/native/sun/awt/swing_GTKEngine.c	Mon Feb 08 17:02:43 2010 +0300
+++ b/src/solaris/native/sun/awt/swing_GTKEngine.c	Fri Feb 12 10:30:40 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 66c193082586 src/solaris/native/sun/awt/swing_GTKStyle.c
--- a/src/solaris/native/sun/awt/swing_GTKStyle.c	Mon Feb 08 17:02:43 2010 +0300
+++ b/src/solaris/native/sun/awt/swing_GTKStyle.c	Fri Feb 12 10:30:40 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