This is the mail archive of the
java-patches@gcc.gnu.org
mailing list for the Java project.
Re: [PATCH] Modal FileDialog implementation.
- From: Fernando Nasser <fnasser at redhat dot com>
- Cc: GCJ Patches <java-patches at gcc dot gnu dot org>
- Date: Thu, 08 Jan 2004 16:11:59 -0500
- Subject: Re: [PATCH] Modal FileDialog implementation.
- Organization: Red Hat Canada
- References: <3FFCD34C.4060101@redhat.com> <87lloifcu2.fsf@fleche.redhat.com>
For the record, this was the patch checked in with Tom Tromey's and Tom
Fitzsimmon's suggestions/requests.
--
Fernando Nasser
Red Hat Canada Ltd. E-Mail: fnasser@redhat.com
2323 Yonge Street, Suite #300
Toronto, Ontario M4P 2C9
? .snprj
? DIFF
? DIFF2
? libjava.proj
? gnu/java/awt/peer/gtk/TestAWT
Index: ChangeLog
===================================================================
RCS file: /cvs/gcc/gcc/libjava/ChangeLog,v
retrieving revision 1.2532
diff -c -p -r1.2532 ChangeLog
*** ChangeLog 8 Jan 2004 09:46:49 -0000 1.2532
--- ChangeLog 8 Jan 2004 21:11:46 -0000
***************
*** 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
Index: gnu/java/awt/peer/gtk/GtkFileDialogPeer.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/gnu/java/awt/peer/gtk/GtkFileDialogPeer.java,v
retrieving revision 1.3
diff -c -p -r1.3 GtkFileDialogPeer.java
*** gnu/java/awt/peer/gtk/GtkFileDialogPeer.java 11 Dec 2003 13:50:50 -0000 1.3
--- gnu/java/awt/peer/gtk/GtkFileDialogPeer.java 8 Jan 2004 21:11:46 -0000
*************** exception statement from your version. *
*** 38,50 ****
--- 38,58 ----
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)
*************** public class GtkFileDialogPeer extends G
*** 52,72 ****
super (fd);
}
! public void setDirectory (String directory)
{
! setFile (directory);
}
! public native void setFile (String file);
! public native void connectJObject ();
public void setFilenameFilter (FilenameFilter filter)
{
! /* GTK has no filters. */
}
public Graphics getGraphics ()
{
return null;
}
}
--- 60,193 ----
super (fd);
}
! native void connectJObject ();
! native void connectSignals ();
! native void nativeSetFile (String file);
!
! public void setFile (String fileName)
{
! /* 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 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 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);
}
}
Index: java/awt/Dialog.java
===================================================================
RCS file: /cvs/gcc/gcc/libjava/java/awt/Dialog.java,v
retrieving revision 1.11
diff -c -p -r1.11 Dialog.java
*** java/awt/Dialog.java 5 Jan 2004 21:23:12 -0000 1.11
--- java/awt/Dialog.java 8 Jan 2004 21:11:46 -0000
*************** private boolean resizable = true;
*** 78,87 ****
*/
private String title;
! /**
! * This field indicates whether the dialog is undecorated or not.
! */
! private boolean undecorated = false;
/*************************************************************************/
--- 78,92 ----
*/
private String title;
! /**
! * 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;
/*************************************************************************/
*************** addNotify()
*** 380,390 ****
/**
* Makes this dialog visible and brings it to the front.
*/
! public void
show()
{
super.show();
}
/*************************************************************************/
--- 385,462 ----
/**
* 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 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();
}
/*************************************************************************/
Index: jni/gtk-peer/gnu_java_awt_peer_gtk_GtkFileDialogPeer.c
===================================================================
RCS file: /cvs/gcc/gcc/libjava/jni/gtk-peer/gnu_java_awt_peer_gtk_GtkFileDialogPeer.c,v
retrieving revision 1.3
diff -c -p -r1.3 gnu_java_awt_peer_gtk_GtkFileDialogPeer.c
*** jni/gtk-peer/gnu_java_awt_peer_gtk_GtkFileDialogPeer.c 13 Dec 2003 01:15:47 -0000 1.3
--- jni/gtk-peer/gnu_java_awt_peer_gtk_GtkFileDialogPeer.c 8 Jan 2004 21:11:47 -0000
*************** exception statement from your version. *
*** 37,44 ****
--- 37,53 ----
#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
*/
*************** Java_gnu_java_awt_peer_gtk_GtkFileDialog
*** 54,60 ****
gdk_threads_enter ();
! widget = gtk_type_new (gtk_file_selection_get_type ());
gdk_threads_leave ();
--- 63,75 ----
gdk_threads_enter ();
! 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 ();
*************** Java_gnu_java_awt_peer_gtk_GtkFileDialog
*** 76,87 ****
gdk_threads_leave ();
}
/*
* Set the filename in the file selection dialog.
*/
JNIEXPORT void JNICALL
! Java_gnu_java_awt_peer_gtk_GtkFileDialogPeer_gtkFileSelectionSetFilename
(JNIEnv *env, jobject obj, jstring filename)
{
void *ptr;
--- 91,134 ----
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_nativeSetFile
(JNIEnv *env, jobject obj, jstring filename)
{
void *ptr;
*************** Java_gnu_java_awt_peer_gtk_GtkFileDialog
*** 89,97 ****
ptr = NSA_GET_PTR (env, obj);
! 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);
}
--- 136,247 ----
ptr = NSA_GET_PTR (env, obj);
! 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 ();
+ }
+
+