1 /* 2 * Copyright (c) 2011, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 #include "glass_general.h" 26 27 #include <jni.h> 28 #include <gtk/gtk.h> 29 30 char const * const GDK_WINDOW_DATA_CONTEXT = "glass_window_context"; 31 32 jclass jStringCls; 33 jclass jByteBufferCls; 34 jmethodID jByteBufferArray; 35 jmethodID jByteBufferWrap; 36 37 jclass jRunnableCls; 38 jmethodID jRunnableRun; 39 40 jclass jArrayListCls; 41 jmethodID jArrayListInit; 42 jmethodID jArrayListAdd; 43 jmethodID jArrayListGetIdx; 44 45 jmethodID jPixelsAttachData; 46 47 jclass jGtkPixelsCls; 48 jmethodID jGtkPixelsInit; 49 50 jclass jScreenCls; 51 jmethodID jScreenInit; 52 jmethodID jScreenNotifySettingsChanged; 53 54 jmethodID jViewNotifyResize; 55 jmethodID jViewNotifyMouse; 56 jmethodID jViewNotifyRepaint; 57 jmethodID jViewNotifyKey; 58 jmethodID jViewNotifyView; 59 jmethodID jViewNotifyDragEnter; 60 jmethodID jViewNotifyDragOver; 61 jmethodID jViewNotifyDragDrop; 62 jmethodID jViewNotifyDragLeave; 63 jmethodID jViewNotifyScroll; 64 jmethodID jViewNotifyInputMethod; 65 jmethodID jViewNotifyInputMethodDraw; 66 jmethodID jViewNotifyInputMethodCaret; 67 jmethodID jViewNotifyPreeditMode; 68 jmethodID jViewNotifyMenu; 69 jfieldID jViewPtr; 70 71 jmethodID jWindowNotifyResize; 72 jmethodID jWindowNotifyMove; 73 jmethodID jWindowNotifyDestroy; 74 jmethodID jWindowNotifyClose; 75 jmethodID jWindowNotifyFocus; 76 jmethodID jWindowNotifyFocusDisabled; 77 jmethodID jWindowNotifyFocusUngrab; 78 jmethodID jWindowNotifyMoveToAnotherScreen; 79 jmethodID jWindowNotifyLevelChanged; 80 jmethodID jWindowIsEnabled; 81 jmethodID jWindowNotifyDelegatePtr; 82 jfieldID jWindowPtr; 83 jfieldID jCursorPtr; 84 85 jmethodID jGtkWindowNotifyStateChanged; 86 87 jmethodID jClipboardContentChanged; 88 89 jmethodID jSizeInit; 90 91 jmethodID jMapGet; 92 jmethodID jMapKeySet; 93 jmethodID jMapContainsKey; 94 95 jclass jHashSetCls; 96 jmethodID jHashSetInit; 97 98 jmethodID jSetAdd; 99 jmethodID jSetSize; 100 jmethodID jSetToArray; 101 102 jmethodID jIterableIterator; 103 jmethodID jIteratorHasNext; 104 jmethodID jIteratorNext; 105 106 jclass jApplicationCls; 107 jfieldID jApplicationDisplay; 108 jfieldID jApplicationScreen; 109 jfieldID jApplicationVisualID; 110 jmethodID jApplicationReportException; 111 jmethodID jApplicationGetApplication; 112 jmethodID jApplicationGetName; 113 114 #pragma GCC diagnostic push 115 #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 116 void init_threads() { 117 gboolean is_g_thread_get_initialized = FALSE; 118 if (glib_check_version(2, 32, 0)) { // < 2.32 119 if (!glib_check_version(2, 20, 0)) { 120 is_g_thread_get_initialized = g_thread_get_initialized(); 121 } 122 if (!is_g_thread_get_initialized) { 123 // Calling g_thread_init() multiple times leads to crash on GLib < 2.24 124 // We can use g_thread_get_initialized () but it is available only for 125 // GLib >= 2.20. We rely on GThreadHelper for GLib < 2.20. 126 // g_thread_init is no longer necessary for GLib >=2.32 127 g_thread_init(NULL); 128 } 129 } 130 gdk_threads_init(); 131 } 132 #pragma GCC diagnostic pop 133 134 static jboolean displayValid = JNI_FALSE; 135 136 jboolean 137 is_display_valid() { 138 return displayValid; 139 } 140 141 JNIEXPORT jint JNICALL 142 JNI_OnLoad(JavaVM *jvm, void *reserved) 143 { 144 (void)reserved; 145 146 JNIEnv *env; 147 jclass clazz; 148 Display* display; 149 150 if (jvm->GetEnv((void **)&env, JNI_VERSION_1_6)) { 151 return JNI_ERR; /* JNI version not supported */ 152 } 153 154 clazz = env->FindClass("java/lang/String"); 155 if (env->ExceptionCheck()) return JNI_ERR; 156 jStringCls = (jclass) env->NewGlobalRef(clazz); 157 158 clazz = env->FindClass("java/nio/ByteBuffer"); 159 if (env->ExceptionCheck()) return JNI_ERR; 160 jByteBufferCls = (jclass) env->NewGlobalRef(clazz); 161 jByteBufferArray = env->GetMethodID(jByteBufferCls, "array", "()[B"); 162 if (env->ExceptionCheck()) return JNI_ERR; 163 jByteBufferWrap = env->GetStaticMethodID(jByteBufferCls, "wrap", "([B)Ljava/nio/ByteBuffer;"); 164 if (env->ExceptionCheck()) return JNI_ERR; 165 166 clazz = env->FindClass("java/lang/Runnable"); 167 if (env->ExceptionCheck()) return JNI_ERR; 168 169 jRunnableRun = env->GetMethodID(clazz, "run", "()V"); 170 if (env->ExceptionCheck()) return JNI_ERR; 171 172 clazz = env->FindClass("java/util/ArrayList"); 173 if (env->ExceptionCheck()) return JNI_ERR; 174 jArrayListCls = (jclass) env->NewGlobalRef(clazz); 175 jArrayListInit = env->GetMethodID(jArrayListCls, "<init>", "()V"); 176 if (env->ExceptionCheck()) return JNI_ERR; 177 jArrayListAdd = env->GetMethodID(jArrayListCls, "add", "(Ljava/lang/Object;)Z"); 178 if (env->ExceptionCheck()) return JNI_ERR; 179 jArrayListGetIdx = env->GetMethodID(jArrayListCls, "get", "(I)Ljava/lang/Object;"); 180 if (env->ExceptionCheck()) return JNI_ERR; 181 clazz = env->FindClass("com/sun/glass/ui/Pixels"); 182 if (env->ExceptionCheck()) return JNI_ERR; 183 jPixelsAttachData = env->GetMethodID(clazz, "attachData", "(J)V"); 184 if (env->ExceptionCheck()) return JNI_ERR; 185 186 clazz = env->FindClass("com/sun/glass/ui/gtk/GtkPixels"); 187 if (env->ExceptionCheck()) return JNI_ERR; 188 189 jGtkPixelsCls = (jclass) env->NewGlobalRef(clazz); 190 jGtkPixelsInit = env->GetMethodID(jGtkPixelsCls, "<init>", "(IILjava/nio/ByteBuffer;)V"); 191 if (env->ExceptionCheck()) return JNI_ERR; 192 193 clazz = env->FindClass("com/sun/glass/ui/Screen"); 194 if (env->ExceptionCheck()) return JNI_ERR; 195 jScreenCls = (jclass) env->NewGlobalRef(clazz); 196 jScreenInit = env->GetMethodID(jScreenCls, "<init>", "(JIIIIIIIIIIIF)V"); 197 if (env->ExceptionCheck()) return JNI_ERR; 198 jScreenNotifySettingsChanged = env->GetStaticMethodID(jScreenCls, "notifySettingsChanged", "()V"); 199 if (env->ExceptionCheck()) return JNI_ERR; 200 201 clazz = env->FindClass("com/sun/glass/ui/View"); 202 if (env->ExceptionCheck()) return JNI_ERR; 203 jViewNotifyResize = env->GetMethodID(clazz, "notifyResize", "(II)V"); 204 if (env->ExceptionCheck()) return JNI_ERR; 205 jViewNotifyMouse = env->GetMethodID(clazz, "notifyMouse", "(IIIIIIIZZ)V"); 206 if (env->ExceptionCheck()) return JNI_ERR; 207 jViewNotifyRepaint = env->GetMethodID(clazz, "notifyRepaint", "(IIII)V"); 208 if (env->ExceptionCheck()) return JNI_ERR; 209 jViewNotifyKey = env->GetMethodID(clazz, "notifyKey", "(II[CI)V"); 210 if (env->ExceptionCheck()) return JNI_ERR; 211 jViewNotifyView = env->GetMethodID(clazz, "notifyView", "(I)V"); 212 if (env->ExceptionCheck()) return JNI_ERR; 213 jViewNotifyDragEnter = env->GetMethodID(clazz, "notifyDragEnter", "(IIIII)I"); 214 if (env->ExceptionCheck()) return JNI_ERR; 215 jViewNotifyDragOver = env->GetMethodID(clazz, "notifyDragOver", "(IIIII)I"); 216 if (env->ExceptionCheck()) return JNI_ERR; 217 jViewNotifyDragDrop = env->GetMethodID(clazz, "notifyDragDrop", "(IIIII)I"); 218 if (env->ExceptionCheck()) return JNI_ERR; 219 jViewNotifyDragLeave = env->GetMethodID(clazz, "notifyDragLeave", "()V"); 220 if (env->ExceptionCheck()) return JNI_ERR; 221 jViewNotifyScroll = env->GetMethodID(clazz, "notifyScroll", "(IIIIDDIIIIIDD)V"); 222 if (env->ExceptionCheck()) return JNI_ERR; 223 jViewNotifyInputMethod = env->GetMethodID(clazz, "notifyInputMethod", "(Ljava/lang/String;[I[I[BIII)V"); 224 if (env->ExceptionCheck()) return JNI_ERR; 225 jViewNotifyMenu = env->GetMethodID(clazz, "notifyMenu", "(IIIIZ)V"); 226 if (env->ExceptionCheck()) return JNI_ERR; 227 jViewPtr = env->GetFieldID(clazz, "ptr", "J"); 228 if (env->ExceptionCheck()) return JNI_ERR; 229 230 clazz = env->FindClass("com/sun/glass/ui/gtk/GtkView"); 231 if (env->ExceptionCheck()) return JNI_ERR; 232 jViewNotifyInputMethodDraw = env->GetMethodID(clazz, "notifyInputMethodDraw", "(Ljava/lang/String;III[B)V"); 233 if (env->ExceptionCheck()) return JNI_ERR; 234 jViewNotifyInputMethodCaret = env->GetMethodID(clazz, "notifyInputMethodCaret", "(III)V"); 235 if (env->ExceptionCheck()) return JNI_ERR; 236 jViewNotifyPreeditMode = env->GetMethodID(clazz, "notifyPreeditMode", "(Z)V"); 237 if (env->ExceptionCheck()) return JNI_ERR; 238 239 clazz = env->FindClass("com/sun/glass/ui/Window"); 240 if (env->ExceptionCheck()) return JNI_ERR; 241 jWindowNotifyResize = env->GetMethodID(clazz, "notifyResize", "(III)V"); 242 if (env->ExceptionCheck()) return JNI_ERR; 243 jWindowNotifyMove = env->GetMethodID(clazz, "notifyMove", "(II)V"); 244 if (env->ExceptionCheck()) return JNI_ERR; 245 jWindowNotifyDestroy = env->GetMethodID(clazz, "notifyDestroy", "()V"); 246 if (env->ExceptionCheck()) return JNI_ERR; 247 jWindowNotifyClose = env->GetMethodID(clazz, "notifyClose", "()V"); 248 if (env->ExceptionCheck()) return JNI_ERR; 249 jWindowNotifyFocus = env->GetMethodID(clazz, "notifyFocus", "(I)V"); 250 if (env->ExceptionCheck()) return JNI_ERR; 251 jWindowNotifyFocusDisabled = env->GetMethodID(clazz, "notifyFocusDisabled", "()V"); 252 if (env->ExceptionCheck()) return JNI_ERR; 253 jWindowNotifyFocusUngrab = env->GetMethodID(clazz, "notifyFocusUngrab", "()V"); 254 if (env->ExceptionCheck()) return JNI_ERR; 255 jWindowNotifyMoveToAnotherScreen = env->GetMethodID(clazz, "notifyMoveToAnotherScreen", "(Lcom/sun/glass/ui/Screen;)V"); 256 if (env->ExceptionCheck()) return JNI_ERR; 257 jWindowNotifyLevelChanged = env->GetMethodID(clazz, "notifyLevelChanged", "(I)V"); 258 if (env->ExceptionCheck()) return JNI_ERR; 259 jWindowIsEnabled = env->GetMethodID(clazz, "isEnabled", "()Z"); 260 if (env->ExceptionCheck()) return JNI_ERR; 261 jWindowNotifyDelegatePtr = env->GetMethodID(clazz, "notifyDelegatePtr", "(J)V"); 262 if (env->ExceptionCheck()) return JNI_ERR; 263 jWindowPtr = env->GetFieldID(clazz, "ptr", "J"); 264 if (env->ExceptionCheck()) return JNI_ERR; 265 266 clazz = env->FindClass("com/sun/glass/ui/gtk/GtkWindow"); 267 if (env->ExceptionCheck()) return JNI_ERR; 268 jGtkWindowNotifyStateChanged = 269 env->GetMethodID(clazz, "notifyStateChanged", "(I)V"); 270 if (env->ExceptionCheck()) return JNI_ERR; 271 272 clazz = env->FindClass("com/sun/glass/ui/Clipboard"); 273 if (env->ExceptionCheck()) return JNI_ERR; 274 jClipboardContentChanged = env->GetMethodID(clazz, "contentChanged", "()V"); 275 if (env->ExceptionCheck()) return JNI_ERR; 276 277 clazz = env->FindClass("com/sun/glass/ui/Cursor"); 278 if (env->ExceptionCheck()) return JNI_ERR; 279 jCursorPtr = env->GetFieldID(clazz, "ptr", "J"); 280 if (env->ExceptionCheck()) return JNI_ERR; 281 282 clazz = env->FindClass("com/sun/glass/ui/Size"); 283 if (env->ExceptionCheck()) return JNI_ERR; 284 jSizeInit = env->GetMethodID(clazz, "<init>", "(II)V"); 285 if (env->ExceptionCheck()) return JNI_ERR; 286 287 clazz = env->FindClass("java/util/Map"); 288 if (env->ExceptionCheck()) return JNI_ERR; 289 jMapGet = env->GetMethodID(clazz, "get", "(Ljava/lang/Object;)Ljava/lang/Object;"); 290 if (env->ExceptionCheck()) return JNI_ERR; 291 jMapKeySet = env->GetMethodID(clazz, "keySet", "()Ljava/util/Set;"); 292 if (env->ExceptionCheck()) return JNI_ERR; 293 jMapContainsKey = env->GetMethodID(clazz, "containsKey", "(Ljava/lang/Object;)Z"); 294 if (env->ExceptionCheck()) return JNI_ERR; 295 296 clazz = env->FindClass("java/util/HashSet"); 297 if (env->ExceptionCheck()) return JNI_ERR; 298 jHashSetCls = (jclass) env->NewGlobalRef(clazz); 299 jHashSetInit = env->GetMethodID(jHashSetCls, "<init>", "()V"); 300 if (env->ExceptionCheck()) return JNI_ERR; 301 302 clazz = env->FindClass("java/util/Set"); 303 if (env->ExceptionCheck()) return JNI_ERR; 304 jSetAdd = env->GetMethodID(clazz, "add", "(Ljava/lang/Object;)Z"); 305 if (env->ExceptionCheck()) return JNI_ERR; 306 jSetSize = env->GetMethodID(clazz, "size", "()I"); 307 if (env->ExceptionCheck()) return JNI_ERR; 308 jSetToArray = env->GetMethodID(clazz, "toArray", "([Ljava/lang/Object;)[Ljava/lang/Object;"); 309 if (env->ExceptionCheck()) return JNI_ERR; 310 311 clazz = env->FindClass("java/lang/Iterable"); 312 if (env->ExceptionCheck()) return JNI_ERR; 313 jIterableIterator = env->GetMethodID(clazz, "iterator", "()Ljava/util/Iterator;"); 314 if (env->ExceptionCheck()) return JNI_ERR; 315 316 clazz = env->FindClass("java/util/Iterator"); 317 if (env->ExceptionCheck()) return JNI_ERR; 318 jIteratorHasNext = env->GetMethodID(clazz, "hasNext", "()Z"); 319 if (env->ExceptionCheck()) return JNI_ERR; 320 jIteratorNext = env->GetMethodID(clazz, "next", "()Ljava/lang/Object;"); 321 if (env->ExceptionCheck()) return JNI_ERR; 322 323 clazz = env->FindClass("com/sun/glass/ui/gtk/GtkApplication"); 324 if (env->ExceptionCheck()) return JNI_ERR; 325 jApplicationCls = (jclass) env->NewGlobalRef(clazz); 326 jApplicationDisplay = env->GetStaticFieldID(jApplicationCls, "display", "J"); 327 if (env->ExceptionCheck()) return JNI_ERR; 328 jApplicationScreen = env->GetStaticFieldID(jApplicationCls, "screen", "I"); 329 if (env->ExceptionCheck()) return JNI_ERR; 330 jApplicationVisualID = env->GetStaticFieldID(jApplicationCls, "visualID", "J"); 331 if (env->ExceptionCheck()) return JNI_ERR; 332 jApplicationReportException = env->GetStaticMethodID( 333 jApplicationCls, "reportException", "(Ljava/lang/Throwable;)V"); 334 if (env->ExceptionCheck()) return JNI_ERR; 335 jApplicationGetApplication = env->GetStaticMethodID( 336 jApplicationCls, "GetApplication", "()Lcom/sun/glass/ui/Application;"); 337 if (env->ExceptionCheck()) return JNI_ERR; 338 jApplicationGetName = env->GetMethodID(jApplicationCls, "getName", "()Ljava/lang/String;"); 339 if (env->ExceptionCheck()) return JNI_ERR; 340 341 // Before doing anything with GTK we validate that the DISPLAY can be opened 342 display = XOpenDisplay(NULL); 343 if (display != NULL) { 344 XCloseDisplay(display); 345 displayValid = JNI_TRUE; 346 } else { 347 // Invalid DISPLAY, skip initialization 348 return JNI_VERSION_1_6; 349 } 350 351 clazz = env->FindClass("sun/misc/GThreadHelper"); 352 if (env->ExceptionCheck()) return JNI_ERR; 353 if (clazz) { 354 jmethodID mid_getAndSetInitializationNeededFlag = env->GetStaticMethodID(clazz, "getAndSetInitializationNeededFlag", "()Z"); 355 if (env->ExceptionCheck()) return JNI_ERR; 356 jmethodID mid_lock = env->GetStaticMethodID(clazz, "lock", "()V"); 357 if (env->ExceptionCheck()) return JNI_ERR; 358 jmethodID mid_unlock = env->GetStaticMethodID(clazz, "unlock", "()V"); 359 if (env->ExceptionCheck()) return JNI_ERR; 360 361 env->CallStaticVoidMethod(clazz, mid_lock); 362 363 if (!env->CallStaticBooleanMethod(clazz, mid_getAndSetInitializationNeededFlag)) { 364 init_threads(); 365 } 366 367 env->CallStaticVoidMethod(clazz, mid_unlock); 368 } else { 369 env->ExceptionClear(); 370 init_threads(); 371 } 372 373 gdk_threads_enter(); 374 gtk_init(NULL, NULL); 375 376 return JNI_VERSION_1_6; 377 } 378 379 void 380 glass_throw_exception(JNIEnv * env, 381 const char * exceptionClass, 382 const char * exceptionMessage) { 383 jclass throwableClass = env->FindClass(exceptionClass); 384 if (check_and_clear_exception(env)) return; 385 env->ThrowNew(throwableClass, exceptionMessage); 386 check_and_clear_exception(env); 387 } 388 389 int 390 glass_throw_oom(JNIEnv * env, const char * message) { 391 glass_throw_exception(env, "java/lang/OutOfMemoryError", message); 392 // must return a non-zero value, see HANDLE_MEM_ALLOC_ERROR 393 return 1; 394 } 395 396 397 guint8* convert_BGRA_to_RGBA(const int* pixels, int stride, int height) { 398 guint8* new_pixels = (guint8*) g_malloc(height * stride); 399 int i = 0; 400 401 for (i = 0; i < height * stride; i += 4) { 402 new_pixels[i] = (guint8)(*pixels >> 16); 403 new_pixels[i + 1] = (guint8)(*pixels >> 8); 404 new_pixels[i + 2] = (guint8)(*pixels); 405 new_pixels[i + 3] = (guint8)(*pixels >> 24); 406 pixels++; 407 } 408 409 return new_pixels; 410 } 411 412 413 void dump_jstring_array(JNIEnv* env, jobjectArray arr) { 414 if (arr == NULL) { 415 LOG0("dump: Array is null\n") 416 return; 417 } 418 jsize len = env->GetArrayLength(arr); 419 LOG1("dump: length = %d\n", len) 420 int i = 0; 421 jboolean isCopy; 422 for(i = 0; i < len; i++) { 423 jstring jstr = (jstring) env->GetObjectArrayElement(arr, i); 424 check_and_clear_exception(env); 425 const char* str = env->GetStringUTFChars(jstr, &isCopy); 426 LOG2("dump: s[%d]: %s\n", i, str) 427 } 428 } 429 430 gboolean check_and_clear_exception(JNIEnv *env) { 431 jthrowable t = env->ExceptionOccurred(); 432 if (t) { 433 env->ExceptionClear(); 434 env->CallStaticVoidMethod(jApplicationCls, jApplicationReportException, t); 435 return TRUE; 436 } 437 return FALSE; 438 } 439 440 // The returned string should be freed with g_free(). 441 gchar* get_application_name() { 442 gchar* ret = NULL; 443 444 jobject japp = mainEnv->CallStaticObjectMethod(jApplicationCls, jApplicationGetApplication); 445 CHECK_JNI_EXCEPTION_RET(mainEnv, NULL); 446 jstring jname = (jstring) mainEnv->CallObjectMethod(japp, jApplicationGetName); 447 CHECK_JNI_EXCEPTION_RET(mainEnv, NULL); 448 if (const gchar *name = mainEnv->GetStringUTFChars(jname, NULL)) { 449 ret = g_strdup(name); 450 mainEnv->ReleaseStringUTFChars(jname, name); 451 } 452 return ret; 453 } 454 455 gpointer glass_try_malloc_n(gsize m, gsize n, 456 gboolean zer0 /* initialized to 0 if true*/) { 457 if (n > 0 && m > G_MAXSIZE / n) { 458 return NULL; 459 } 460 return (zer0) 461 ? g_try_malloc0(m * n) 462 : g_try_malloc(m * n); 463 } 464 465 /* 466 * Since we support glib 2.18 we can't use g_try_malloc_n and g_try_malloc0_n 467 * which was introduced in 2.24. 468 * glass_try_malloc_n and glass_try_malloc0_n is replacement for those functions 469 */ 470 gpointer glass_try_malloc0_n(gsize m, gsize n) { 471 return glass_try_malloc_n(m, n, TRUE); 472 } 473 474 gpointer glass_try_malloc_n(gsize m, gsize n) { 475 return glass_try_malloc_n(m, n, FALSE); 476 } 477 478 gsize get_files_count(gchar **uris) { 479 if (!uris) { 480 return 0; 481 } 482 483 guint size = g_strv_length(uris); 484 guint files_cnt = 0; 485 486 for (guint i = 0; i < size; ++i) { 487 if (g_str_has_prefix(uris[i], FILE_PREFIX)) { 488 files_cnt++; 489 } 490 } 491 return files_cnt; 492 } 493 494 // Note: passed uris will be freed by this function 495 jobject uris_to_java(JNIEnv *env, gchar **uris, gboolean files) { 496 if (uris == NULL) { 497 return NULL; 498 } 499 500 jobject result = NULL; 501 502 guint size = g_strv_length(uris); 503 guint files_cnt = get_files_count(uris); 504 505 if (files) { 506 if (files_cnt) { 507 result = env->NewObjectArray(files_cnt, jStringCls, NULL); 508 check_and_clear_exception(env); 509 510 for (gsize i = 0; i < size; ++i) { 511 if (g_str_has_prefix(uris[i], FILE_PREFIX)) { 512 gchar* path = g_filename_from_uri(uris[i], NULL, NULL); 513 jstring str = env->NewStringUTF(path); 514 check_and_clear_exception(env); 515 env->SetObjectArrayElement((jobjectArray) result, i, str); 516 check_and_clear_exception(env); 517 g_free(path); 518 } 519 } 520 } 521 } else if (size - files_cnt) { 522 GString* str = g_string_new(NULL); //http://www.ietf.org/rfc/rfc2483.txt 523 524 for (guint i = 0; i < size; ++i) { 525 if (!g_str_has_prefix(uris[i], FILE_PREFIX) 526 && !g_str_has_prefix(uris[i], URI_LIST_COMMENT_PREFIX)) { 527 g_string_append(str, uris[i]); 528 g_string_append(str, URI_LIST_LINE_BREAK); 529 } 530 } 531 532 if (str->len > 2) { 533 g_string_erase(str, str->len - 2, 2); 534 } 535 536 result = env->NewStringUTF(str->str); 537 check_and_clear_exception(env); 538 539 g_string_free(str, TRUE); 540 } 541 g_strfreev(uris); 542 return result; 543 }