2328N/A#include <jni.h>
2328N/A#include <stdio.h>
2328N/A#include <jni_util.h>
2328N/A#include <string.h>
2328N/A#include "gtk2_interface.h"
2328N/A#include "sun_awt_X11_GtkFileDialogPeer.h"
3940N/A#include "java_awt_FileDialog.h"
3021N/A#include "debug_assert.h"
2328N/A
2328N/Astatic JavaVM *jvm;
2328N/A
2328N/A/* To cache some method IDs */
2328N/Astatic jmethodID filenameFilterCallbackMethodID = NULL;
2328N/Astatic jmethodID setFileInternalMethodID = NULL;
3021N/Astatic jfieldID widgetFieldID = NULL;
3021N/A
3021N/AJNIEXPORT void JNICALL Java_sun_awt_X11_GtkFileDialogPeer_initIDs
3021N/A(JNIEnv *env, jclass cx)
3021N/A{
3021N/A filenameFilterCallbackMethodID = (*env)->GetMethodID(env, cx,
3021N/A "filenameFilterCallback", "(Ljava/lang/String;)Z");
3021N/A DASSERT(filenameFilterCallbackMethodID != NULL);
3021N/A
3021N/A setFileInternalMethodID = (*env)->GetMethodID(env, cx,
3021N/A "setFileInternal", "(Ljava/lang/String;[Ljava/lang/String;)V");
3021N/A DASSERT(setFileInternalMethodID != NULL);
3021N/A
3021N/A widgetFieldID = (*env)->GetFieldID(env, cx, "widget", "J");
3021N/A DASSERT(widgetFieldID != NULL);
3021N/A}
2328N/A
2328N/Astatic gboolean filenameFilterCallback(const GtkFileFilterInfo * filter_info, gpointer obj)
2328N/A{
2328N/A JNIEnv *env;
2328N/A jclass cx;
2328N/A jstring filename;
2328N/A
2328N/A env = (JNIEnv *) JNU_GetEnv(jvm, JNI_VERSION_1_2);
2328N/A
2328N/A filename = (*env)->NewStringUTF(env, filter_info->filename);
2328N/A
2328N/A return (*env)->CallBooleanMethod(env, obj, filenameFilterCallbackMethodID,
2328N/A filename);
2328N/A}
2328N/A
3021N/Astatic void quit(JNIEnv * env, jobject jpeer, gboolean isSignalHandler)
2519N/A{
3021N/A GtkWidget * dialog = (GtkWidget*)jlong_to_ptr(
3021N/A (*env)->GetLongField(env, jpeer, widgetFieldID));
3021N/A
2519N/A if (dialog != NULL)
2519N/A {
2519N/A // Callbacks from GTK signals are made within the GTK lock
2519N/A // So, within a signal handler there is no need to call
2519N/A // gdk_threads_enter() / fp_gdk_threads_leave()
2519N/A if (!isSignalHandler) {
2519N/A fp_gdk_threads_enter();
2519N/A }
2519N/A
2519N/A fp_gtk_widget_hide (dialog);
2519N/A fp_gtk_widget_destroy (dialog);
2519N/A
2519N/A fp_gtk_main_quit ();
3021N/A
3021N/A (*env)->SetLongField(env, jpeer, widgetFieldID, 0);
2519N/A
2519N/A if (!isSignalHandler) {
2519N/A fp_gdk_threads_leave();
2519N/A }
2519N/A }
2519N/A}
2519N/A
2328N/A/*
2328N/A * Class: sun_awt_X11_GtkFileDialogPeer
2328N/A * Method: quit
2328N/A * Signature: ()V
2328N/A */
2328N/AJNIEXPORT void JNICALL Java_sun_awt_X11_GtkFileDialogPeer_quit
2328N/A(JNIEnv * env, jobject jpeer)
2328N/A{
3021N/A quit(env, jpeer, FALSE);
2328N/A}
2328N/A
3077N/A/*
3077N/A * Class: sun_awt_X11_GtkFileDialogPeer
3077N/A * Method: toFront
3077N/A * Signature: ()V
3077N/A */
3077N/AJNIEXPORT void JNICALL Java_sun_awt_X11_GtkFileDialogPeer_toFront
3077N/A(JNIEnv * env, jobject jpeer)
3077N/A{
3077N/A GtkWidget * dialog;
3077N/A
3077N/A fp_gdk_threads_enter();
3077N/A
3077N/A dialog = (GtkWidget*)jlong_to_ptr(
3077N/A (*env)->GetLongField(env, jpeer, widgetFieldID));
3077N/A
3077N/A if (dialog != NULL) {
3077N/A fp_gtk_window_present((GtkWindow*)dialog);
3077N/A }
3077N/A
3077N/A fp_gdk_threads_leave();
3077N/A}
3077N/A
3616N/A/*
3616N/A * Class: sun_awt_X11_GtkFileDialogPeer
3616N/A * Method: setBounds
3616N/A * Signature: (IIIII)V
3616N/A */
3616N/AJNIEXPORT void JNICALL Java_sun_awt_X11_GtkFileDialogPeer_setBounds
3616N/A(JNIEnv * env, jobject jpeer, jint x, jint y, jint width, jint height, jint op)
3616N/A{
3616N/A GtkWindow* dialog;
3616N/A
3616N/A fp_gdk_threads_enter();
3616N/A
3616N/A dialog = (GtkWindow*)jlong_to_ptr(
3616N/A (*env)->GetLongField(env, jpeer, widgetFieldID));
3616N/A
3616N/A if (dialog != NULL) {
3616N/A if (x >= 0 && y >= 0) {
3616N/A fp_gtk_window_move(dialog, (gint)x, (gint)y);
3616N/A }
3616N/A if (width > 0 && height > 0) {
3616N/A fp_gtk_window_resize(dialog, (gint)width, (gint)height);
3616N/A }
3616N/A }
3616N/A
3616N/A fp_gdk_threads_leave();
3616N/A}
3616N/A
2328N/A/**
2328N/A * Convert a GSList to an array of filenames (without the parent folder)
2328N/A */
2328N/Astatic jobjectArray toFilenamesArray(JNIEnv *env, GSList* list)
2328N/A{
2328N/A jstring str;
2328N/A jclass stringCls;
2328N/A GSList *iterator;
2328N/A jobjectArray array;
2328N/A int i;
2328N/A char* entry;
2328N/A
2328N/A if (NULL == list) {
2328N/A return NULL;
2328N/A }
2328N/A
2328N/A stringCls = (*env)->FindClass(env, "java/lang/String");
2328N/A if (stringCls == NULL) {
2328N/A JNU_ThrowInternalError(env, "Could not get java.lang.String class");
2328N/A return NULL;
2328N/A }
2328N/A
2328N/A array = (*env)->NewObjectArray(env, fp_gtk_g_slist_length(list), stringCls,
2328N/A NULL);
2328N/A if (array == NULL) {
2328N/A JNU_ThrowInternalError(env, "Could not instantiate array files array");
2328N/A return NULL;
2328N/A }
2328N/A
2328N/A i = 0;
2328N/A for (iterator = list; iterator; iterator = iterator->next) {
2328N/A entry = (char*) iterator->data;
2328N/A entry = strrchr(entry, '/') + 1;
2328N/A str = (*env)->NewStringUTF(env, entry);
2328N/A (*env)->SetObjectArrayElement(env, array, i, str);
2328N/A i++;
2328N/A }
2328N/A
2328N/A return array;
2328N/A}
2328N/A
2328N/Astatic void handle_response(GtkWidget* aDialog, gint responseId, gpointer obj)
2328N/A{
2328N/A JNIEnv *env;
2328N/A char *current_folder;
2328N/A GSList *filenames;
2328N/A jclass cx;
2328N/A jstring jcurrent_folder;
2328N/A jobjectArray jfilenames;
2328N/A
2328N/A env = (JNIEnv *) JNU_GetEnv(jvm, JNI_VERSION_1_2);
2328N/A current_folder = NULL;
2328N/A filenames = NULL;
2328N/A
2328N/A if (responseId == GTK_RESPONSE_ACCEPT) {
2328N/A current_folder = fp_gtk_file_chooser_get_current_folder(
3021N/A GTK_FILE_CHOOSER(aDialog));
3021N/A filenames = fp_gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(aDialog));
2328N/A }
2328N/A
2328N/A jcurrent_folder = (*env)->NewStringUTF(env, current_folder);
2328N/A jfilenames = toFilenamesArray(env, filenames);
2328N/A
2328N/A (*env)->CallVoidMethod(env, obj, setFileInternalMethodID, jcurrent_folder,
2328N/A jfilenames);
2328N/A fp_g_free(current_folder);
2328N/A
3021N/A quit(env, (jobject)obj, TRUE);
2328N/A}
2328N/A
2328N/A/*
2328N/A * Class: sun_awt_X11_GtkFileDialogPeer
2328N/A * Method: run
3616N/A * Signature: (Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/io/FilenameFilter;ZII)V
2328N/A */
2328N/AJNIEXPORT void JNICALL
2328N/AJava_sun_awt_X11_GtkFileDialogPeer_run(JNIEnv * env, jobject jpeer,
2328N/A jstring jtitle, jint mode, jstring jdir, jstring jfile,
3616N/A jobject jfilter, jboolean multiple, int x, int y)
2328N/A{
3021N/A GtkWidget *dialog = NULL;
2328N/A GtkFileFilter *filter;
2328N/A
2328N/A if (jvm == NULL) {
2328N/A (*env)->GetJavaVM(env, &jvm);
2328N/A }
2328N/A
2328N/A fp_gdk_threads_enter();
2328N/A
3294N/A const char *title = jtitle == NULL? "": (*env)->GetStringUTFChars(env, jtitle, 0);
2328N/A
3940N/A if (mode == java_awt_FileDialog_SAVE) {
2328N/A /* Save action */
2328N/A dialog = fp_gtk_file_chooser_dialog_new(title, NULL,
2328N/A GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL,
2328N/A GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL);
2328N/A }
2328N/A else {
2328N/A /* Default action OPEN */
2328N/A dialog = fp_gtk_file_chooser_dialog_new(title, NULL,
2328N/A GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL,
2328N/A GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);
2328N/A
2328N/A /* Set multiple selection mode, that is allowed only in OPEN action */
2328N/A if (multiple) {
2328N/A fp_gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog),
2328N/A multiple);
2328N/A }
2328N/A }
2328N/A
3294N/A if (jtitle != NULL) {
3294N/A (*env)->ReleaseStringUTFChars(env, jtitle, title);
3294N/A }
2328N/A
2328N/A /* Set the directory */
2328N/A if (jdir != NULL) {
2328N/A const char *dir = (*env)->GetStringUTFChars(env, jdir, 0);
2328N/A fp_gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(dialog), dir);
2328N/A (*env)->ReleaseStringUTFChars(env, jdir, dir);
2328N/A }
2328N/A
2328N/A /* Set the filename */
2328N/A if (jfile != NULL) {
2328N/A const char *filename = (*env)->GetStringUTFChars(env, jfile, 0);
3940N/A if (mode == java_awt_FileDialog_SAVE) {
3940N/A fp_gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog), filename);
3940N/A } else {
3940N/A fp_gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), filename);
3940N/A }
2328N/A (*env)->ReleaseStringUTFChars(env, jfile, filename);
2328N/A }
2328N/A
2328N/A /* Set the file filter */
2328N/A if (jfilter != NULL) {
2328N/A filter = fp_gtk_file_filter_new();
2328N/A fp_gtk_file_filter_add_custom(filter, GTK_FILE_FILTER_FILENAME,
2328N/A filenameFilterCallback, jpeer, NULL);
2328N/A fp_gtk_file_chooser_set_filter(GTK_FILE_CHOOSER(dialog), filter);
2328N/A }
2328N/A
2328N/A /* Other Properties */
2328N/A if (fp_gtk_check_version(2, 8, 0) == NULL) {
2328N/A fp_gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(
2328N/A dialog), TRUE);
2328N/A }
2328N/A
3616N/A /* Set the initial location */
3616N/A if (x >= 0 && y >= 0) {
3616N/A fp_gtk_window_move((GtkWindow*)dialog, (gint)x, (gint)y);
3616N/A
3616N/A // NOTE: it doesn't set the initial size for the file chooser
3616N/A // as it seems like the file chooser overrides the size internally
3616N/A }
3616N/A
2328N/A fp_g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(
2328N/A handle_response), jpeer);
3021N/A
3021N/A (*env)->SetLongField(env, jpeer, widgetFieldID, ptr_to_jlong(dialog));
3021N/A
2328N/A fp_gtk_widget_show(dialog);
2328N/A
2328N/A fp_gtk_main();
2328N/A fp_gdk_threads_leave();
2328N/A}
3021N/A