diff options
Diffstat (limited to 'libjava')
-rw-r--r-- | libjava/ChangeLog | 30 | ||||
-rw-r--r-- | libjava/gnu/java/awt/peer/gtk/GtkFileDialogPeer.java | 131 | ||||
-rw-r--r-- | libjava/java/awt/Dialog.java | 82 | ||||
-rw-r--r-- | libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkFileDialogPeer.c | 156 |
4 files changed, 386 insertions, 13 deletions
diff --git a/libjava/ChangeLog b/libjava/ChangeLog index 17c82cd..9434734 100644 --- a/libjava/ChangeLog +++ b/libjava/ChangeLog @@ -1,3 +1,33 @@ +2004-01-08 Fernando Nasser <fnasser@redhat.com> + + * gnu/java/awt/peer/gtk/GtkFileDialogPeer.java (nativeSetFile): + New name for the former setFile native method. + (setFile): New method. + (setDirectory): Implemented. + (connectSignals): New native method. + (setFilenameFilter): Improve comment. + (getGraphics): Comment. + (gtkHideFileDialog): New method. + (gtkDisposeFileDialog): New method. + (gtkSetFilename): New method. + * java/awt/Dialog.java (show): Block on modal dialogs, but only + for FileDialog for now. + (hide): New method. + (dispose): New method. + * jni/gtk-peer/gnu_java_awt_peer_gtk_GtkFileDialogPeer.c + (Java_gnu_java_awt_peer_gtk_GtkFileDialog_create): Replace + deprecated creation functions. Make dialog modal. Add it to the + window group. + (Java_gnu_java_awt_peer_gtk_GtkFileDialog_connectSignals): New + function. + (Java_gnu_java_awt_peer_gtk_GtkFileDialogPeer_gtkFileSelectionSetFilename): + Rename to... + (Java_gnu_java_awt_peer_gtk_GtkFileDialogPeer_nativeSetFile): New + name. + (window_closed): New function. + (ok_clicked): New function. + (cancel_clicked): New function. + 2004-01-08 Michael Koch <konqueror@gmx.de> * javax/swing/JLayeredPane.java: Revert changes to standard diff --git a/libjava/gnu/java/awt/peer/gtk/GtkFileDialogPeer.java b/libjava/gnu/java/awt/peer/gtk/GtkFileDialogPeer.java index 07422ac..dc2c8b0 100644 --- a/libjava/gnu/java/awt/peer/gtk/GtkFileDialogPeer.java +++ b/libjava/gnu/java/awt/peer/gtk/GtkFileDialogPeer.java @@ -38,13 +38,21 @@ exception statement from your version. */ package gnu.java.awt.peer.gtk; +import java.awt.AWTEvent; +import java.awt.Dialog; import java.awt.FileDialog; import java.awt.Graphics; +import java.awt.event.WindowEvent; import java.awt.peer.FileDialogPeer; import java.io.FilenameFilter; public class GtkFileDialogPeer extends GtkDialogPeer implements FileDialogPeer { + static final String FS = System.getProperty("file.separator"); + + private String currentFile = null; + private String currentDirectory = null; + native void create (); public GtkFileDialogPeer (FileDialog fd) @@ -52,21 +60,134 @@ public class GtkFileDialogPeer extends GtkDialogPeer implements FileDialogPeer super (fd); } - public void setDirectory (String directory) + native void connectJObject (); + native void connectSignals (); + native void nativeSetFile (String file); + + public void setFile (String fileName) { - setFile (directory); + /* If nothing changed do nothing. This usually happens because + the only way we have to set the file name in FileDialog is by + calling its SetFile which will call us back. */ + if ((fileName == null && currentFile == null) + || (fileName != null && fileName.equals (currentFile))) + return; + + if (fileName == null || fileName.equals ("")) + { + currentFile = ""; + nativeSetFile (""); + return; + } + + // Remove any directory path from the filename + int sepIndex = fileName.lastIndexOf (FS); + if (sepIndex < 0) + { + currentFile = fileName; + nativeSetFile (fileName); + } + else + { + if (fileName.length() > (sepIndex + 1)) + { + String fn = fileName.substring (sepIndex + 1); + currentFile = fn; + nativeSetFile (fn); + } + else + { + currentFile = ""; + nativeSetFile (""); + } + } } - public native void setFile (String file); - public native void connectJObject (); + public void setDirectory (String directory) + { + /* If nothing changed so nothing. This usually happens because + the only way we have to set the directory in FileDialog is by + calling its setDirectory which will call us back. */ + if ((directory == null && currentDirectory == null) + || (directory != null && directory.equals (currentDirectory))) + return; + + if (directory == null || directory.equals ("")) + { + currentDirectory = FS; + nativeSetFile (FS); + return; + } + + currentDirectory = directory; + + // Gtk expects the directory to end with a file separator + if (directory.substring (directory.length () - 1).equals (FS)) + nativeSetFile (directory); + else + nativeSetFile (directory + FS); + } public void setFilenameFilter (FilenameFilter filter) { - /* GTK has no filters. */ + /* GTK has no filter callbacks yet. It works by setting a pattern + * (see gtk_file_selection_complete), which we can't convert + * to the callback paradigm. With GTK-2.4 there will be a + * gtk_file_filter_add_custom function that we can use. */ } public Graphics getGraphics () { + // GtkFileDialog will repaint by itself return null; } + + void gtkHideFileDialog () + { + ((Dialog) awtComponent).hide(); + } + + void gtkDisposeFileDialog () + { + ((Dialog) awtComponent).dispose(); + } + + /* Callback to set the file and directory values when the user is finished + * with the dialog. + */ + void gtkSetFilename (String fileName) + { + FileDialog fd = (FileDialog) awtWidget; + if (fileName == null) + { + currentFile = null; + fd.setFile(null); + return; + } + + int sepIndex = fileName.lastIndexOf (FS); + if (sepIndex < 0) + { + /* This should never happen on Unix (all paths start with '/') */ + currentFile = fileName; + } + else + { + if (fileName.length() > (sepIndex + 1)) + { + String fn = fileName.substring (sepIndex + 1); + currentFile = fn; + } + else + { + currentFile = null; + } + + String dn = fileName.substring (0, sepIndex + 1); + currentDirectory = dn; + fd.setDirectory(dn); + } + + fd.setFile (currentFile); + } } diff --git a/libjava/java/awt/Dialog.java b/libjava/java/awt/Dialog.java index ac2e6ed..fd1eb4f 100644 --- a/libjava/java/awt/Dialog.java +++ b/libjava/java/awt/Dialog.java @@ -78,10 +78,15 @@ private boolean resizable = true; */ private String title; - /** - * This field indicates whether the dialog is undecorated or not. - */ - private boolean undecorated = false; +/** + * This field indicates whether the dialog is undecorated or not. + */ +private boolean undecorated = false; + +/** + * Indicates that we are blocked for modality in show + */ +private boolean blocked = false; /*************************************************************************/ @@ -380,11 +385,78 @@ addNotify() /** * Makes this dialog visible and brings it to the front. + * If the dialog is modal and is not already visible, this call will not + * return until the dialog is hidden by someone calling hide or dispose. + * If this is the event dispatching thread we must ensure that another event + * thread runs while the one which invoked this method is blocked. */ -public void +public synchronized void show() { super.show(); + if (isModal()) + { + // If already shown (and blocked) just return + if (blocked) + return; + + /* FIXME: Currently this thread may block forever if it called from + the event dispatch thread, so we only do this for FileDialog which + only depends on a signal which is delivered in the Gtk thread. + Remove this test when we add code to start another event + dispatch thread. */ + if ((Thread.currentThread () instanceof EventDispatchThread) && + !(this instanceof FileDialog)) + return; + + try + { + blocked = true; + wait (); + blocked = false; + } + catch (InterruptedException e) + { + blocked = false; + return; + } + } +} + +/*************************************************************************/ + +/** + * Hides the Dialog and then + * causes show() to return if it is currently blocked. + */ + +public synchronized void +hide () +{ + if (blocked) + { + notifyAll (); + } + + super.hide(); +} + +/*************************************************************************/ + +/** + * Disposes the Dialog and then causes show() to return + * if it is currently blocked. + */ + +public synchronized void +dispose () +{ + if (blocked) + { + notifyAll (); + } + + super.dispose(); } /*************************************************************************/ diff --git a/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkFileDialogPeer.c b/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkFileDialogPeer.c index 47a08ae..9e84dde 100644 --- a/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkFileDialogPeer.c +++ b/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkFileDialogPeer.c @@ -37,8 +37,17 @@ exception statement from your version. */ #include "gtkpeer.h" +#include "gnu_java_awt_peer_gtk_GtkComponentPeer.h" #include "gnu_java_awt_peer_gtk_GtkFileDialogPeer.h" +static void window_closed (GtkDialog *dialog, + gint responseId, + jobject peer_obj); +static void ok_clicked (GtkButton *button, + jobject peer_obj); +static void cancel_clicked (GtkButton *button, + jobject peer_obj); + /* * Make a new file selection dialog */ @@ -54,7 +63,13 @@ Java_gnu_java_awt_peer_gtk_GtkFileDialogPeer_create gdk_threads_enter (); - widget = gtk_type_new (gtk_file_selection_get_type ()); + widget = gtk_file_selection_new (""); + /* GtkFileSelect is not modal by default */ + gtk_window_set_modal (GTK_WINDOW (widget), TRUE); + + /* We must add this window to the group so input in the others are + disable while it is being shown */ + gtk_window_group_add_window (global_gtk_window_group, GTK_WINDOW (widget)); gdk_threads_leave (); @@ -76,12 +91,44 @@ Java_gnu_java_awt_peer_gtk_GtkFileDialogPeer_connectJObject gdk_threads_leave (); } +JNIEXPORT void JNICALL +Java_gnu_java_awt_peer_gtk_GtkFileDialogPeer_connectSignals + (JNIEnv *env, jobject obj) +{ + void *ptr = NSA_GET_PTR (env, obj); + jobject *gref = NSA_GET_GLOBAL_REF (env, obj); + g_assert (gref); + + gdk_threads_enter (); + + gtk_widget_realize (GTK_WIDGET (ptr)); + + /* connect buttons to handlers */ + + g_signal_connect (G_OBJECT (GTK_DIALOG (ptr)), + "response", + GTK_SIGNAL_FUNC (window_closed), *gref); + + g_signal_connect (G_OBJECT (GTK_FILE_SELECTION (ptr)->ok_button), + "clicked", + GTK_SIGNAL_FUNC (ok_clicked), *gref); + + g_signal_connect (G_OBJECT (GTK_FILE_SELECTION (ptr)->cancel_button), + "clicked", + GTK_SIGNAL_FUNC (cancel_clicked), *gref); + + gdk_threads_leave (); + + /* Connect the superclass signals. */ + Java_gnu_java_awt_peer_gtk_GtkComponentPeer_connectSignals (env, obj); +} + /* * Set the filename in the file selection dialog. */ JNIEXPORT void JNICALL -Java_gnu_java_awt_peer_gtk_GtkFileDialogPeer_gtkFileSelectionSetFilename +Java_gnu_java_awt_peer_gtk_GtkFileDialogPeer_nativeSetFile (JNIEnv *env, jobject obj, jstring filename) { void *ptr; @@ -89,9 +136,112 @@ Java_gnu_java_awt_peer_gtk_GtkFileDialogPeer_gtkFileSelectionSetFilename ptr = NSA_GET_PTR (env, obj); - str = (*env)->GetStringUTFChars (env, filename, 0); + str = (*env)->GetStringUTFChars (env, filename, 0); + gdk_threads_enter (); + gtk_file_selection_set_filename (GTK_FILE_SELECTION (ptr), str); + gdk_threads_leave (); + (*env)->ReleaseStringUTFChars (env, filename, str); } + +static void +window_closed (GtkDialog *dialog __attribute__((unused)), + gint responseId, + jobject peer_obj) +{ + static int isIDSet = 0; + static jmethodID disposeID; + void *ptr; + + // We only need this for the case when the user closed the window + if (responseId != GTK_RESPONSE_DELETE_EVENT) + return; + + ptr = NSA_GET_PTR (gdk_env, peer_obj); + + if (!isIDSet) + { + jclass cx = (*gdk_env)->GetObjectClass (gdk_env, peer_obj); + disposeID = (*gdk_env)->GetMethodID (gdk_env, cx, "gtkDisposeFileDialog", "()V"); + isIDSet = 1; + } + + gdk_threads_leave (); + + /* We can dispose of the dialog now (and unblock show) */ + (*gdk_env)->CallVoidMethod (gdk_env, peer_obj, disposeID); + + gdk_threads_enter (); +} + +static void +ok_clicked (GtkButton *button __attribute__((unused)), + jobject peer_obj) +{ + static int isIDSet = 0; + static jmethodID gtkSetFilenameID; + static jmethodID hideID; + void *ptr; + G_CONST_RETURN gchar *fileName; + + ptr = NSA_GET_PTR (gdk_env, peer_obj); + + fileName = gtk_file_selection_get_filename ( + GTK_FILE_SELECTION (GTK_WIDGET (ptr))); + + if (!isIDSet) + { + jclass cx = (*gdk_env)->GetObjectClass (gdk_env, peer_obj); + hideID = (*gdk_env)->GetMethodID (gdk_env, cx, "gtkHideFileDialog", "()V"); + gtkSetFilenameID = (*gdk_env)->GetMethodID (gdk_env, cx, + "gtkSetFilename", "(Ljava.lang.String;)V"); + isIDSet = 1; + } + + gdk_threads_leave (); + + /* Set the Java object field 'file' with this value. */ + jstring str_fileName = (*gdk_env)->NewStringUTF (gdk_env, fileName); + (*gdk_env)->CallVoidMethod (gdk_env, peer_obj, gtkSetFilenameID, str_fileName); + + /* We can hide the dialog now (and unblock show) */ + (*gdk_env)->CallVoidMethod (gdk_env, peer_obj, hideID); + + gdk_threads_enter (); +} + +static void +cancel_clicked (GtkButton *button __attribute__((unused)), + jobject peer_obj) +{ + static int isIDSet = 0; + static jmethodID gtkSetFilenameID; + static jmethodID hideID; + void *ptr; + + ptr = NSA_GET_PTR (gdk_env, peer_obj); + + if (!isIDSet) + { + jclass cx = (*gdk_env)->GetObjectClass (gdk_env, peer_obj); + hideID = (*gdk_env)->GetMethodID (gdk_env, cx, "gtkHideFileDialog", "()V"); + gtkSetFilenameID = (*gdk_env)->GetMethodID (gdk_env, cx, + "gtkSetFilename", "(Ljava.lang.String;)V"); + isIDSet = 1; + } + + gdk_threads_leave (); + + /* Set the Java object field 'file' with the null value. */ + (*gdk_env)->CallVoidMethod (gdk_env, peer_obj, gtkSetFilenameID, NULL); + + /* We can hide the dialog now (and unblock show) */ + (*gdk_env)->CallVoidMethod (gdk_env, peer_obj, hideID); + + gdk_threads_enter (); +} + + |