changeset 5295:eff4787e6884

RT-24133 Gtk: URL is recognised both as FILE and as URL, linux only, DnD and Clipboard
author Alexander Zvegintsev
date Tue, 08 Oct 2013 14:31:21 +0400
parents 94d55039bc0d
children f2d3f04c1632
files modules/graphics/src/main/native-glass/gtk/GlassSystemClipboard.cpp modules/graphics/src/main/native-glass/gtk/glass_dnd.cpp modules/graphics/src/main/native-glass/gtk/glass_general.cpp modules/graphics/src/main/native-glass/gtk/glass_general.h
diffstat 4 files changed, 258 insertions(+), 184 deletions(-) [+]
line wrap: on
line diff
--- a/modules/graphics/src/main/native-glass/gtk/GlassSystemClipboard.cpp	Mon Oct 07 16:25:34 2013 -0700
+++ b/modules/graphics/src/main/native-glass/gtk/GlassSystemClipboard.cpp	Tue Oct 08 14:31:21 2013 +0400
@@ -36,7 +36,6 @@
 
 static GdkAtom MIME_JAVA_IMAGE;
 
-static GdkAtom FILES_TARGET;
 static GdkAtom MIME_FILES_TARGET;
 
 static void init_atoms()
@@ -50,7 +49,6 @@
 
         MIME_JAVA_IMAGE = gdk_atom_intern_static_string("application/x-java-rawimage");
 
-        FILES_TARGET = gdk_atom_intern_static_string("FILE_NAME");
         MIME_FILES_TARGET = gdk_atom_intern_static_string("application/x-java-file-list");
         initialized = 1;
     }
@@ -58,6 +56,8 @@
 
 
 static GtkClipboard* clipboard = NULL;
+static gboolean is_clipboard_owner = FALSE;
+static gboolean is_clipboard_updated_by_glass = FALSE;
 
 static GtkClipboard *get_clipboard() {
     if (clipboard == NULL) {
@@ -73,15 +73,13 @@
         gtk_target_list_add_text_targets(list, 0);
     } else if (g_strcmp0(gstring, "application/x-java-rawimage") == 0) {
         gtk_target_list_add_image_targets(list, 0, TRUE);
-        return;
     } else if (g_strcmp0(gstring, "application/x-java-file-list") == 0) {
         gtk_target_list_add(list, MIME_TEXT_URI_LIST_TARGET, 0, 0);
-        return; // do not add application/x-java-file-list
+    } else {
+        gtk_target_list_add(list, gdk_atom_intern(gstring, FALSE), 0, 0);
     }
 
-    gtk_target_list_add(list, gdk_atom_intern(gstring, FALSE), 0, 0);
     env->ReleaseStringUTFChars(string, gstring);
-
 }
 
 static void data_to_targets(JNIEnv *env, jobject data, GtkTargetEntry **targets, gint *ntargets)
@@ -138,47 +136,74 @@
     mainEnv->ReleaseByteArrayElements(byteArray, raw, JNI_ABORT);
 }
 
-#define FILE_PREFIX "file://"
-#define FILE_PREFIX_N 7
+static void set_uri_data(GtkSelectionData *selection_data, jobject data) {
+    const gchar* url = NULL;
+    jstring jurl = NULL;
 
-static void set_file_uri_data(GtkSelectionData *selection_data, jobjectArray data)
-{
-    jsize ndata = mainEnv->GetArrayLength(data);
-    jsize i;
-    jsize string_size;
-    jstring string;
+    jobjectArray files_array = NULL;
+    gsize files_cnt = 0;
+    
+    jstring typeString;
 
-    gchar **uris = (gchar**) glass_try_malloc0_n(ndata + 1, sizeof(gchar*));
+    typeString = mainEnv->NewStringUTF("text/uri-list");
+    if (mainEnv->CallBooleanMethod(data, jMapContainsKey, typeString, NULL)) {
+        jurl = (jstring) mainEnv->CallObjectMethod(data, jMapGet, typeString, NULL);
+        CHECK_JNI_EXCEPTION(mainEnv);
+        url = mainEnv->GetStringUTFChars(jurl, NULL);
+    }
+    
+    typeString = mainEnv->NewStringUTF("application/x-java-file-list");
+    if (mainEnv->CallBooleanMethod(data, jMapContainsKey, typeString, NULL)) {
+        files_array = (jobjectArray) mainEnv->CallObjectMethod(data, jMapGet, typeString, NULL);
+        CHECK_JNI_EXCEPTION(mainEnv);
+        if (files_array) {
+            files_cnt = mainEnv->GetArrayLength(files_array);
+        }
+    }
+
+    if (!url && !files_cnt) {
+        return;
+    }
+
+    gsize uri_cnt = files_cnt + (url ? 1 : 0);
+
+    gchar **uris = 
+            (gchar**) glass_try_malloc0_n(uri_cnt + 1, // uris must be a NULL-terminated array of strings
+                                            sizeof(gchar*));
     if (!uris) {
+        if (url) {
+            mainEnv->ReleaseStringUTFChars(jurl, url);
+        }
         glass_throw_oom(mainEnv, "Failed to allocate uri data");
         return;
     }
-    
-    for (i = 0; i < ndata; ++i) {
-        string = (jstring) mainEnv->GetObjectArrayElement(data, i);
-        string_size = mainEnv->GetStringUTFLength(string);
 
-        uris[i] = (gchar*) g_try_malloc0(string_size + FILE_PREFIX_N + 1);
-        if (!uris[i]) {
-            glass_throw_oom(mainEnv, "Failed to allocate uri data");
-            for (int k = 0; k < i; k++) {
-                g_free(uris[k]);
-            }
-            g_free(uris);
-            return;
+    gsize i = 0;
+    if (files_cnt > 0) {
+        for (; i < files_cnt; ++i) {
+            jstring string = (jstring) mainEnv->GetObjectArrayElement(files_array, i);
+            const gchar* file = mainEnv->GetStringUTFChars(string, NULL);
+            uris[i] = g_filename_to_uri(file, NULL, NULL);
+            mainEnv->ReleaseStringUTFChars(string, file);
         }
-
-        g_strlcpy(uris[i], FILE_PREFIX, FILE_PREFIX_N + 1);
-        mainEnv->GetStringUTFRegion(string, 0, string_size, (char*) uris[i] + FILE_PREFIX_N);
     }
 
+    if (url) {
+        uris[i] = (gchar*) url;
+    }
+    //http://www.ietf.org/rfc/rfc2483.txt
     gtk_selection_data_set_uris(selection_data, uris);
 
-    for (i = 0; i < ndata; ++i) {
-        g_free(uris[i]);
+    for (i = 0; i < uri_cnt; ++i) {
+        if (uris[i] != url) {
+            g_free(uris[i]);
+        }
+    }
+
+    if (url) {
+        mainEnv->ReleaseStringUTFChars(jurl, url);
     }
     g_free(uris);
-
 }
 
 static void set_image_data(GtkSelectionData *selection_data, jobject pixels)
@@ -212,19 +237,7 @@
             set_image_data(selection_data, result);
         }
     } else if (target == MIME_TEXT_URI_LIST_TARGET) {
-        typeString = mainEnv->NewStringUTF(name);
-        if (mainEnv->CallBooleanMethod(data, jMapContainsKey, typeString, NULL)) {
-            result = mainEnv->CallObjectMethod(data, jMapGet, typeString, NULL);
-            if (!EXCEPTION_OCCURED(mainEnv) && result != NULL) {
-                set_jstring_data(selection_data, target, (jstring)result);
-            }
-        } else {
-            typeString = mainEnv->NewStringUTF("application/x-java-file-list");
-            result = mainEnv->CallObjectMethod(data, jMapGet, typeString, NULL);
-            if (!EXCEPTION_OCCURED(mainEnv) && result != NULL) {
-                set_file_uri_data(selection_data, (jobjectArray) result);
-            }
-        }
+        set_uri_data(selection_data, data);
     } else {
         typeString = mainEnv->NewStringUTF(name);
         result = mainEnv->CallObjectMethod(data, jMapGet, typeString, NULL);
@@ -268,32 +281,9 @@
     return jdata;
 }
 
-static jobject get_data_file_list(JNIEnv *env)
+static jobject get_data_uri_list(JNIEnv *env, gboolean files)
 {
-    jobjectArray result = NULL;
-    guint i,size;
-    jstring str;
-    gchar *path;
-    gchar **uris;
-
-    uris = gtk_clipboard_wait_for_uris(get_clipboard());
-    if (uris == NULL) {
-        return NULL;
-    }
-    size = g_strv_length(uris);
-    result = env->NewObjectArray(size, jStringCls, NULL);
-
-    for (i = 0; i < size; ++i) {
-        path = uris[i];
-        if (g_str_has_prefix(path, "file://")) {
-            path += 7;
-        }
-        str = env->NewStringUTF(path);
-        env->SetObjectArrayElement(result, i, str);
-    }
-
-    g_strfreev(uris);
-    return result;
+    return uris_to_java(env, gtk_clipboard_wait_for_uris(get_clipboard()), files);
 }
 
 static jobject get_data_image(JNIEnv* env) {
@@ -362,6 +352,8 @@
 
 static void clipboard_owner_changed_callback(GtkClipboard *clipboard, GdkEventOwnerChange *event, jobject obj)
 {
+    is_clipboard_owner = is_clipboard_updated_by_glass;
+    is_clipboard_updated_by_glass = FALSE;
     mainEnv->CallVoidMethod(obj, jClipboardContentChanged);
     CHECK_JNI_EXCEPTION(mainEnv)
 }
@@ -408,10 +400,7 @@
 JNIEXPORT jboolean JNICALL Java_com_sun_glass_ui_gtk_GtkSystemClipboard_isOwner
   (JNIEnv *env, jobject obj)
 {
-    return JNI_FALSE; //There's no straightforward way how to check for this in GTK.
-                      // Returning false is safe however, as it just affects the case when the same application,
-                      // that has clipboard selection, checks for clipboard content. When this is false,
-                      // we have to use native X11 calls in this case.
+    return is_clipboard_owner ? JNI_TRUE : JNI_FALSE;
 }
 
 /*
@@ -438,6 +427,8 @@
         GtkTargetEntry dummy_targets = {(gchar*) "MIME_DUMMY_TARGET", 0, 0};
         gtk_clipboard_set_with_data(get_clipboard(), &dummy_targets, 0, set_data_func, clear_data_func, data);
     }
+
+    is_clipboard_updated_by_glass = TRUE;
 }
 
 /*
@@ -465,10 +456,12 @@
     init_atoms();
     if (g_strcmp0(cmime, "text/plain") == 0) {
         result = get_data_text(env);
+    } else if (g_strcmp0(cmime, "text/uri-list") == 0) {
+        result = get_data_uri_list(env, FALSE);
     } else if (g_str_has_prefix(cmime, "text/")) {
         result = get_data_raw(env, cmime, TRUE);
     } else if (g_strcmp0(cmime, "application/x-java-file-list") == 0) {
-        result = get_data_file_list(env);
+        result = get_data_uri_list(env, TRUE);
     } else if (g_strcmp0(cmime, "application/x-java-rawimage") == 0 ) {
         result = get_data_image(env);
     } else {
@@ -513,7 +506,7 @@
 
     gtk_clipboard_wait_for_targets(get_clipboard(), &targets, &ntargets);
 
-    convertible = (GdkAtom*) glass_try_malloc_n(ntargets * 2, sizeof(GdkAtom)); //theoretically, the number can double
+    convertible = (GdkAtom*) glass_try_malloc0_n(ntargets * 2, sizeof(GdkAtom)); //theoretically, the number can double
     if (!convertible) {
         if (ntargets > 0) {
             glass_throw_oom(env, "Failed to allocate mimes");
@@ -523,24 +516,45 @@
     }
 
     convertible_ptr = convertible;
+
+    bool uri_list_added = false;
+    bool text_added = false;
+    bool image_added = false;
+
     for (i = 0; i < ntargets; ++i) {
         //handle text targets
         //if (targets[i] == TEXT_TARGET || targets[i] == STRING_TARGET || targets[i] == UTF8_STRING_TARGET) {
-        if (gtk_targets_include_text(targets + i, 1)) {
+
+        if (gtk_targets_include_text(targets + i, 1) && !text_added) {
             *(convertible_ptr++) = MIME_TEXT_PLAIN_TARGET;
-        } else if (gtk_targets_include_image(targets + i, 1, TRUE)) {
+            text_added = true;
+        } else if (gtk_targets_include_image(targets + i, 1, TRUE) && !image_added) {
             *(convertible_ptr++) = MIME_JAVA_IMAGE;
+            image_added = true;
         }
-        //TODO text/x-moz-url ?
+        //TODO text/x-moz-url ? RT-17802
 
-        //XXX: URI targets are not necessary file targets, can we add the type anyway?
         if (targets[i] == MIME_TEXT_URI_LIST_TARGET) {
-            *(convertible_ptr++) = MIME_FILES_TARGET;
+            if (uri_list_added) {
+                continue;
+            }
+
+            gchar** uris = gtk_clipboard_wait_for_uris(get_clipboard());
+            if (uris) {
+                guint size = g_strv_length(uris);
+                guint files_cnt = get_files_count(uris);
+                if (files_cnt) {
+                    *(convertible_ptr++) = MIME_FILES_TARGET;
+                }
+                if (size - files_cnt) {
+                    *(convertible_ptr++) = MIME_TEXT_URI_LIST_TARGET;
+                }
+                g_strfreev(uris);
+            }
+            uri_list_added = true;
+        } else {
+            *(convertible_ptr++) = targets[i];
         }
-
-        name = gdk_atom_name(targets[i]);
-        *(convertible_ptr++) = targets[i];
-        g_free(name);
     }
 
     result = env->NewObjectArray(convertible_ptr - convertible, jStringCls, NULL);
--- a/modules/graphics/src/main/native-glass/gtk/glass_dnd.cpp	Mon Oct 07 16:25:34 2013 -0700
+++ b/modules/graphics/src/main/native-glass/gtk/glass_dnd.cpp	Tue Oct 08 14:31:21 2013 +0400
@@ -77,7 +77,7 @@
     TARGET_MIME_TEXT_PLAIN_ATOM = gdk_atom_intern_static_string("text/plain");
     TARGET_COMPOUND_TEXT_ATOM = gdk_atom_intern_static_string("COMPOUND_TEXT");
     TARGET_STRING_ATOM = gdk_atom_intern_static_string("STRING");
-    
+
     TARGET_MIME_URI_LIST_ATOM = gdk_atom_intern_static_string("text/uri-list");
     
     TARGET_MIME_PNG_ATOM = gdk_atom_intern_static_string("image/png");
@@ -122,6 +122,16 @@
 static jint dnd_get_performed_action();
 
 /************************* TARGET *********************************************/
+struct selection_data_ctx {
+    gboolean received;
+    guchar *data;
+    GdkAtom type;
+    gint format;
+    gint length;
+};
+
+static gboolean dnd_target_receive_data(JNIEnv *env, GdkAtom target, selection_data_ctx *selection_ctx);
+
 static struct {
     GdkDragContext *ctx;
     gboolean just_entered;
@@ -234,26 +244,38 @@
     if (!enter_ctx.mimes) {
         GList* targets = GLASS_GDK_DRAG_CONTEXT_LIST_TARGETS(enter_ctx.ctx);
         jobject set = env->NewObject(jHashSetCls, jHashSetInit, NULL);
-        
+
         while (targets) {
             GdkAtom target = GDK_POINTER_TO_ATOM(targets->data);
             gchar *name = gdk_atom_name(target);
-            
+
             if (target_is_text(target)) {
                 env->CallBooleanMethod(set, jSetAdd, env->NewStringUTF("text/plain"), NULL);
             }
-            
-            if (target_is_uri(target)) {
-                //TODO may not contain files
-                env->CallBooleanMethod(set, jSetAdd, env->NewStringUTF("application/x-java-file-list"), NULL);
-            }
-            
+
             if (target_is_image(target)) {
                 env->CallBooleanMethod(set, jSetAdd, env->NewStringUTF("application/x-java-rawimage"), NULL);
             }
-            
-            env->CallBooleanMethod(set, jSetAdd, env->NewStringUTF(name), NULL);
-            
+
+            if (target_is_uri(target)) {
+                selection_data_ctx ctx;
+                if (dnd_target_receive_data(env, TARGET_MIME_URI_LIST_ATOM, &ctx)) {
+                    gchar** uris = g_uri_list_extract_uris((gchar *) ctx.data);
+                    guint size = g_strv_length(uris);
+                    guint files_cnt = get_files_count(uris);
+                    if (files_cnt) {
+                        env->CallBooleanMethod(set, jSetAdd, env->NewStringUTF("application/x-java-file-list"), NULL);
+                    }
+                    if (size - files_cnt) {
+                        env->CallBooleanMethod(set, jSetAdd, env->NewStringUTF("text/uri-list"), NULL);
+                    }
+                    g_strfreev(uris);
+                }
+                g_free(ctx.data);
+            } else {
+                env->CallBooleanMethod(set, jSetAdd, env->NewStringUTF(name), NULL);
+            }
+
             g_free(name);
             targets = targets->next;
         }
@@ -273,14 +295,6 @@
     return translate_gdk_action_to_glass(GLASS_GDK_DRAG_CONTEXT_GET_ACTIONS(enter_ctx.ctx));
 }
 
-struct selection_data_ctx{
-    gboolean received;
-    guchar *data;
-    GdkAtom type;
-    gint format;
-    gint length;
-} ;
-
 static void wait_for_selection_data_hook(GdkEvent * event, void * data)
 {
     selection_data_ctx *ctx = (selection_data_ctx*)data;
@@ -328,9 +342,11 @@
     
     if (dnd_target_receive_data(env, TARGET_UTF8_STRING_ATOM, &ctx)) {
         result = env->NewStringUTF((char *)ctx.data);
+        g_free(ctx.data);
     }
     if (!result && dnd_target_receive_data(env, TARGET_MIME_TEXT_PLAIN_ATOM, &ctx)) {
         result = env->NewStringUTF((char *)ctx.data);
+        g_free(ctx.data);
     }
     // TODO find out how to convert from compound text
     // if (!result && dnd_target_receive_data(env, TARGET_COMPOUND_TEXT_ATOM, &ctx)) {
@@ -342,39 +358,22 @@
             result = env->NewStringUTF(str);
             g_free(str);
         }
+        g_free(ctx.data);
     }
-    g_free(ctx.data);
     return result;
 }
 
-static jobject dnd_target_get_list(JNIEnv *env)
+static jobject dnd_target_get_list(JNIEnv *env, gboolean files)
 {
-    gchar **strv, *path;
-    gchar *file_path = NULL;
-    jsize len, i;
-    jobjectArray result = NULL;
-    jstring str;
+    jobject result = NULL;
     selection_data_ctx ctx;
 
     if (dnd_target_receive_data(env, TARGET_MIME_URI_LIST_ATOM, &ctx)) {
-        strv = g_uri_list_extract_uris((gchar *)ctx.data);
-        len = g_strv_length(strv);
-        result = (jobjectArray)env->NewObjectArray(len, jStringCls, NULL);
-
-        for (i = 0; i < len; ++i) {
-            path = strv[i];
-            if (g_str_has_prefix(path, "file://")) {
-                file_path = g_filename_from_uri(path, NULL, NULL);
-            }
-            str = env->NewStringUTF(file_path ? file_path : path);
-            env->SetObjectArrayElement(result, i, str);
-            g_free(file_path);
-            file_path = NULL;
-        }
-        g_strfreev(strv);
+        result = uris_to_java(env, g_uri_list_extract_uris((gchar *)ctx.data), files);
+        g_free(ctx.data);
     }
-    g_free(ctx.data);
-    return (jobject)result;
+    
+    return result;
 }
 
 static jobject dnd_target_get_image(JNIEnv *env)
@@ -463,10 +462,12 @@
 
     if (g_strcmp0(cmime, "text/plain") == 0) {
         ret = dnd_target_get_string(env);
+    } else if (g_strcmp0(cmime, "text/uri-list") == 0) {
+        ret = dnd_target_get_list(env, FALSE);
     } else if (g_str_has_prefix(cmime, "text/")) {
         ret = dnd_target_get_raw(env, gdk_atom_intern(cmime, FALSE), TRUE);
     } else if (g_strcmp0(cmime, "application/x-java-file-list") == 0) {
-        ret = dnd_target_get_list(env);
+        ret = dnd_target_get_list(env, TRUE);
     } else if (g_strcmp0(cmime, "application/x-java-rawimage") == 0 ) {
         ret = dnd_target_get_image(env);
     } else {
@@ -660,63 +661,51 @@
     return result;
 }
 
-#define FILE_PREFIX "file://"
-#define FILE_PREFIX_N 7
-
-static void dnd_source_set_uri_file_list(GdkWindow *requestor, GdkAtom property, jobjectArray array)
-{
-    jsize ndata = mainEnv->GetArrayLength(array);
-    jsize i;
-    jsize string_size;
-    jstring string;
-    gchar *data, *data_ptr;
-    gint data_size = 0;
-    for (i = 0; i < ndata; ++i) {
-        string = (jstring)mainEnv->GetObjectArrayElement(array, i);
-        data_size += mainEnv->GetStringUTFLength(string) + FILE_PREFIX_N + 2;
-    }
-    
-    data_ptr = data = new gchar[data_size];
-    
-    for (i = 0; i < ndata; ++i) {
-        string = (jstring)mainEnv->GetObjectArrayElement(array, i);
-        string_size = mainEnv->GetStringUTFLength(string);
-        
-        g_strlcpy(data_ptr, FILE_PREFIX, FILE_PREFIX_N + 1);
-        mainEnv->GetStringUTFRegion(string, 0, string_size, data_ptr + FILE_PREFIX_N);
-        *(data_ptr += FILE_PREFIX_N + string_size) = '\r';
-        *(++data_ptr) = '\n';
-        ++data_ptr;
-    }
-    if (ndata > 0) {
-        *(data_ptr - 2) = 0;
-        --data_size;
-    }
-    
-    gdk_property_change(requestor, property, GDK_SELECTION_TYPE_STRING,
-                8, GDK_PROP_MODE_REPLACE, (guchar *) data, data_size);
-    
-    delete[] data;
-    
-}
-
 static gboolean dnd_source_set_uri_list(GdkWindow *requestor, GdkAtom property)
 {
-    jobject data;
-    gboolean is_data_set = FALSE;
-    if (data = dnd_source_get_data("text/uri-list")) {
-        const char *cstring = mainEnv->GetStringUTFChars((jstring)data, NULL);
-        gdk_property_change(requestor, property, GDK_SELECTION_TYPE_STRING,
-                8, GDK_PROP_MODE_REPLACE, (guchar *) cstring, strlen(cstring));
-        
-        mainEnv->ReleaseStringUTFChars((jstring)data, cstring);
-        is_data_set = TRUE;
-    } else if (data = dnd_source_get_data("application/x-java-file-list")) {
-        dnd_source_set_uri_file_list(requestor, property, (jobjectArray)data);
-        is_data_set = TRUE;
+    const gchar* url = NULL;
+    jstring jurl = NULL;
+
+    jobjectArray files_array = NULL;
+    gsize files_cnt = 0;
+
+    if (jurl = (jstring) dnd_source_get_data("text/uri-list")) {
+        url = mainEnv->GetStringUTFChars(jurl, NULL);
     }
 
-    return is_data_set;
+    if (files_array = (jobjectArray) dnd_source_get_data("application/x-java-file-list")) {
+        files_cnt = mainEnv->GetArrayLength(files_array);
+    }
+    if (!url && !files_cnt) {
+        return FALSE;
+    }
+
+    GString* res = g_string_new (NULL); //http://www.ietf.org/rfc/rfc2483.txt 
+
+    if (files_cnt > 0) {
+        for (gsize i = 0; i < files_cnt; ++i) {
+            jstring string = (jstring) mainEnv->GetObjectArrayElement(files_array, i);
+            const gchar* file = mainEnv->GetStringUTFChars(string, NULL);
+            gchar* uri = g_filename_to_uri(file, NULL, NULL);
+
+            g_string_append(res, uri);
+            g_string_append(res, URI_LIST_LINE_BREAK);
+
+            g_free(uri);
+            mainEnv->ReleaseStringUTFChars(string, file);
+        }
+    }
+    if (url) {
+        g_string_append(res, url);
+        g_string_append(res, URI_LIST_LINE_BREAK);
+        mainEnv->ReleaseStringUTFChars(jurl, url);
+    }
+
+    gdk_property_change(requestor, property, GDK_SELECTION_TYPE_STRING,
+            8, GDK_PROP_MODE_REPLACE, (guchar *) res->str, res->len);
+
+    g_string_free(res, TRUE);
+    return TRUE;
 }
 
 static gboolean dnd_source_set_raw(GdkWindow *requestor, GdkAtom property, GdkAtom target)
--- a/modules/graphics/src/main/native-glass/gtk/glass_general.cpp	Mon Oct 07 16:25:34 2013 -0700
+++ b/modules/graphics/src/main/native-glass/gtk/glass_general.cpp	Tue Oct 08 14:31:21 2013 +0400
@@ -300,3 +300,66 @@
 gpointer glass_try_malloc_n(gsize m, gsize n) {
     return glass_try_malloc_n(m, n, FALSE);
 }
+
+gsize get_files_count(gchar **uris) {
+    if (!uris) {
+        return 0;
+    }
+
+    guint size = g_strv_length(uris);
+    guint files_cnt = 0;
+
+    for (guint i = 0; i < size; ++i) {
+        if (g_str_has_prefix(uris[i], FILE_PREFIX)) {
+            files_cnt++;
+        }
+    }
+    return files_cnt;
+}
+
+// Note: passed uris will be freed by this function
+jobject uris_to_java(JNIEnv *env, gchar **uris, gboolean files) {
+    if (uris == NULL) {
+        return NULL;
+    }
+
+    jobject result = NULL;
+
+    guint size = g_strv_length(uris);
+    guint files_cnt = get_files_count(uris);
+
+    if (files) {
+        if (files_cnt) {
+            result = env->NewObjectArray(files_cnt, jStringCls, NULL);
+
+            for (gsize i = 0; i < size; ++i) {
+                if (g_str_has_prefix(uris[i], FILE_PREFIX)) {
+                    gchar* path = g_filename_from_uri(uris[i], NULL, NULL);
+                    jstring str = env->NewStringUTF(path);
+                    env->SetObjectArrayElement((jobjectArray) result, i, str);
+                    g_free(path);
+                }
+            }
+        }
+    } else if (size - files_cnt) {
+        GString* str = g_string_new(NULL); //http://www.ietf.org/rfc/rfc2483.txt
+
+        for (guint i = 0; i < size; ++i) {
+            if (!g_str_has_prefix(uris[i], FILE_PREFIX)
+                    && !g_str_has_prefix(uris[i], URI_LIST_COMMENT_PREFIX)) {
+                g_string_append(str, uris[i]);
+                g_string_append(str, URI_LIST_LINE_BREAK);
+            }
+        }
+
+        if (str->len > 2) {
+            g_string_erase(str, str->len - 2, 2);
+        }
+
+        result = env->NewStringUTF(str->str);
+
+        g_string_free(str, TRUE);
+    }
+    g_strfreev(uris);
+    return result;
+}
--- a/modules/graphics/src/main/native-glass/gtk/glass_general.h	Mon Oct 07 16:25:34 2013 -0700
+++ b/modules/graphics/src/main/native-glass/gtk/glass_general.h	Tue Oct 08 14:31:21 2013 +0400
@@ -36,6 +36,10 @@
 #define JLONG_TO_PTR(value) ((void*)(intptr_t)(value))
 #define PTR_TO_JLONG(value) ((jlong)(intptr_t)(value))
 
+#define FILE_PREFIX "file://"
+#define URI_LIST_COMMENT_PREFIX "#"
+#define URI_LIST_LINE_BREAK "\r\n" 
+
 extern JNIEnv* mainEnv; // Use only with main loop thread!!!
 
 #include <exception>
@@ -223,5 +227,9 @@
 
     gboolean check_and_clear_exception(JNIEnv *env);
 
+    gsize get_files_count(gchar **uris);
+
+    jobject uris_to_java(JNIEnv *env, gchar **uris, gboolean files);
+
 #endif        /* GLASS_GENERAL_H */