1 /* 2 * Copyright (c) 2011, 2018, 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 static jboolean displayValid = JNI_FALSE; 115 116 jboolean 117 is_display_valid() { 118 return displayValid; 119 } 120 121 JNIEXPORT jint JNICALL 122 JNI_OnLoad(JavaVM *jvm, void *reserved) 123 { 124 (void)reserved; 125 126 JNIEnv *env; 127 jclass clazz; 128 Display* display; 129 130 if (jvm->GetEnv((void **)&env, JNI_VERSION_1_6)) { 131 return JNI_ERR; /* JNI version not supported */ 132 } 133 134 clazz = env->FindClass("java/lang/String"); 135 if (env->ExceptionCheck()) return JNI_ERR; 136 jStringCls = (jclass) env->NewGlobalRef(clazz); 137 138 clazz = env->FindClass("java/nio/ByteBuffer"); 139 if (env->ExceptionCheck()) return JNI_ERR; 140 jByteBufferCls = (jclass) env->NewGlobalRef(clazz); 141 jByteBufferArray = env->GetMethodID(jByteBufferCls, "array", "()[B"); 142 if (env->ExceptionCheck()) return JNI_ERR; 143 jByteBufferWrap = env->GetStaticMethodID(jByteBufferCls, "wrap", "([B)Ljava/nio/ByteBuffer;"); 144 if (env->ExceptionCheck()) return JNI_ERR; 145 146 clazz = env->FindClass("java/lang/Runnable"); 147 if (env->ExceptionCheck()) return JNI_ERR; 148 149 jRunnableRun = env->GetMethodID(clazz, "run", "()V"); 150 if (env->ExceptionCheck()) return JNI_ERR; 151 152 clazz = env->FindClass("java/util/ArrayList"); 153 if (env->ExceptionCheck()) return JNI_ERR; 154 jArrayListCls = (jclass) env->NewGlobalRef(clazz); 155 jArrayListInit = env->GetMethodID(jArrayListCls, "<init>", "()V"); 156 if (env->ExceptionCheck()) return JNI_ERR; 157 jArrayListAdd = env->GetMethodID(jArrayListCls, "add", "(Ljava/lang/Object;)Z"); 158 if (env->ExceptionCheck()) return JNI_ERR; 159 jArrayListGetIdx = env->GetMethodID(jArrayListCls, "get", "(I)Ljava/lang/Object;"); 160 if (env->ExceptionCheck()) return JNI_ERR; 161 clazz = env->FindClass("com/sun/glass/ui/Pixels"); 162 if (env->ExceptionCheck()) return JNI_ERR; 163 jPixelsAttachData = env->GetMethodID(clazz, "attachData", "(J)V"); 164 if (env->ExceptionCheck()) return JNI_ERR; 165 166 clazz = env->FindClass("com/sun/glass/ui/gtk/GtkPixels"); 167 if (env->ExceptionCheck()) return JNI_ERR; 168 169 jGtkPixelsCls = (jclass) env->NewGlobalRef(clazz); 170 jGtkPixelsInit = env->GetMethodID(jGtkPixelsCls, "<init>", "(IILjava/nio/ByteBuffer;)V"); 171 if (env->ExceptionCheck()) return JNI_ERR; 172 173 clazz = env->FindClass("com/sun/glass/ui/Screen"); 174 if (env->ExceptionCheck()) return JNI_ERR; 175 jScreenCls = (jclass) env->NewGlobalRef(clazz); 176 jScreenInit = env->GetMethodID(jScreenCls, "<init>", "(JIIIIIIIIIIIF)V"); 177 if (env->ExceptionCheck()) return JNI_ERR; 178 jScreenNotifySettingsChanged = env->GetStaticMethodID(jScreenCls, "notifySettingsChanged", "()V"); 179 if (env->ExceptionCheck()) return JNI_ERR; 180 181 clazz = env->FindClass("com/sun/glass/ui/View"); 182 if (env->ExceptionCheck()) return JNI_ERR; 183 jViewNotifyResize = env->GetMethodID(clazz, "notifyResize", "(II)V"); 184 if (env->ExceptionCheck()) return JNI_ERR; 185 jViewNotifyMouse = env->GetMethodID(clazz, "notifyMouse", "(IIIIIIIZZ)V"); 186 if (env->ExceptionCheck()) return JNI_ERR; 187 jViewNotifyRepaint = env->GetMethodID(clazz, "notifyRepaint", "(IIII)V"); 188 if (env->ExceptionCheck()) return JNI_ERR; 189 jViewNotifyKey = env->GetMethodID(clazz, "notifyKey", "(II[CI)V"); 190 if (env->ExceptionCheck()) return JNI_ERR; 191 jViewNotifyView = env->GetMethodID(clazz, "notifyView", "(I)V"); 192 if (env->ExceptionCheck()) return JNI_ERR; 193 jViewNotifyDragEnter = env->GetMethodID(clazz, "notifyDragEnter", "(IIIII)I"); 194 if (env->ExceptionCheck()) return JNI_ERR; 195 jViewNotifyDragOver = env->GetMethodID(clazz, "notifyDragOver", "(IIIII)I"); 196 if (env->ExceptionCheck()) return JNI_ERR; 197 jViewNotifyDragDrop = env->GetMethodID(clazz, "notifyDragDrop", "(IIIII)I"); 198 if (env->ExceptionCheck()) return JNI_ERR; 199 jViewNotifyDragLeave = env->GetMethodID(clazz, "notifyDragLeave", "()V"); 200 if (env->ExceptionCheck()) return JNI_ERR; 201 jViewNotifyScroll = env->GetMethodID(clazz, "notifyScroll", "(IIIIDDIIIIIDD)V"); 202 if (env->ExceptionCheck()) return JNI_ERR; 203 jViewNotifyInputMethod = env->GetMethodID(clazz, "notifyInputMethod", "(Ljava/lang/String;[I[I[BIII)V"); 204 if (env->ExceptionCheck()) return JNI_ERR; 205 jViewNotifyMenu = env->GetMethodID(clazz, "notifyMenu", "(IIIIZ)V"); 206 if (env->ExceptionCheck()) return JNI_ERR; 207 jViewPtr = env->GetFieldID(clazz, "ptr", "J"); 208 if (env->ExceptionCheck()) return JNI_ERR; 209 210 clazz = env->FindClass("com/sun/glass/ui/gtk/GtkView"); 211 if (env->ExceptionCheck()) return JNI_ERR; 212 jViewNotifyInputMethodDraw = env->GetMethodID(clazz, "notifyInputMethodDraw", "(Ljava/lang/String;III[B)V"); 213 if (env->ExceptionCheck()) return JNI_ERR; 214 jViewNotifyInputMethodCaret = env->GetMethodID(clazz, "notifyInputMethodCaret", "(III)V"); 215 if (env->ExceptionCheck()) return JNI_ERR; 216 jViewNotifyPreeditMode = env->GetMethodID(clazz, "notifyPreeditMode", "(Z)V"); 217 if (env->ExceptionCheck()) return JNI_ERR; 218 219 clazz = env->FindClass("com/sun/glass/ui/Window"); 220 if (env->ExceptionCheck()) return JNI_ERR; 221 jWindowNotifyResize = env->GetMethodID(clazz, "notifyResize", "(III)V"); 222 if (env->ExceptionCheck()) return JNI_ERR; 223 jWindowNotifyMove = env->GetMethodID(clazz, "notifyMove", "(II)V"); 224 if (env->ExceptionCheck()) return JNI_ERR; 225 jWindowNotifyDestroy = env->GetMethodID(clazz, "notifyDestroy", "()V"); 226 if (env->ExceptionCheck()) return JNI_ERR; 227 jWindowNotifyClose = env->GetMethodID(clazz, "notifyClose", "()V"); 228 if (env->ExceptionCheck()) return JNI_ERR; 229 jWindowNotifyFocus = env->GetMethodID(clazz, "notifyFocus", "(I)V"); 230 if (env->ExceptionCheck()) return JNI_ERR; 231 jWindowNotifyFocusDisabled = env->GetMethodID(clazz, "notifyFocusDisabled", "()V"); 232 if (env->ExceptionCheck()) return JNI_ERR; 233 jWindowNotifyFocusUngrab = env->GetMethodID(clazz, "notifyFocusUngrab", "()V"); 234 if (env->ExceptionCheck()) return JNI_ERR; 235 jWindowNotifyMoveToAnotherScreen = env->GetMethodID(clazz, "notifyMoveToAnotherScreen", "(Lcom/sun/glass/ui/Screen;)V"); 236 if (env->ExceptionCheck()) return JNI_ERR; 237 jWindowNotifyLevelChanged = env->GetMethodID(clazz, "notifyLevelChanged", "(I)V"); 238 if (env->ExceptionCheck()) return JNI_ERR; 239 jWindowIsEnabled = env->GetMethodID(clazz, "isEnabled", "()Z"); 240 if (env->ExceptionCheck()) return JNI_ERR; 241 jWindowNotifyDelegatePtr = env->GetMethodID(clazz, "notifyDelegatePtr", "(J)V"); 242 if (env->ExceptionCheck()) return JNI_ERR; 243 jWindowPtr = env->GetFieldID(clazz, "ptr", "J"); 244 if (env->ExceptionCheck()) return JNI_ERR; 245 246 clazz = env->FindClass("com/sun/glass/ui/gtk/GtkWindow"); 247 if (env->ExceptionCheck()) return JNI_ERR; 248 jGtkWindowNotifyStateChanged = 249 env->GetMethodID(clazz, "notifyStateChanged", "(I)V"); 250 if (env->ExceptionCheck()) return JNI_ERR; 251 252 clazz = env->FindClass("com/sun/glass/ui/Clipboard"); 253 if (env->ExceptionCheck()) return JNI_ERR; 254 jClipboardContentChanged = env->GetMethodID(clazz, "contentChanged", "()V"); 255 if (env->ExceptionCheck()) return JNI_ERR; 256 257 clazz = env->FindClass("com/sun/glass/ui/Cursor"); 258 if (env->ExceptionCheck()) return JNI_ERR; 259 jCursorPtr = env->GetFieldID(clazz, "ptr", "J"); 260 if (env->ExceptionCheck()) return JNI_ERR; 261 262 clazz = env->FindClass("com/sun/glass/ui/Size"); 263 if (env->ExceptionCheck()) return JNI_ERR; 264 jSizeInit = env->GetMethodID(clazz, "<init>", "(II)V"); 265 if (env->ExceptionCheck()) return JNI_ERR; 266 267 clazz = env->FindClass("java/util/Map"); 268 if (env->ExceptionCheck()) return JNI_ERR; 269 jMapGet = env->GetMethodID(clazz, "get", "(Ljava/lang/Object;)Ljava/lang/Object;"); 270 if (env->ExceptionCheck()) return JNI_ERR; 271 jMapKeySet = env->GetMethodID(clazz, "keySet", "()Ljava/util/Set;"); 272 if (env->ExceptionCheck()) return JNI_ERR; 273 jMapContainsKey = env->GetMethodID(clazz, "containsKey", "(Ljava/lang/Object;)Z"); 274 if (env->ExceptionCheck()) return JNI_ERR; 275 276 clazz = env->FindClass("java/util/HashSet"); 277 if (env->ExceptionCheck()) return JNI_ERR; 278 jHashSetCls = (jclass) env->NewGlobalRef(clazz); 279 jHashSetInit = env->GetMethodID(jHashSetCls, "<init>", "()V"); 280 if (env->ExceptionCheck()) return JNI_ERR; 281 282 clazz = env->FindClass("java/util/Set"); 283 if (env->ExceptionCheck()) return JNI_ERR; 284 jSetAdd = env->GetMethodID(clazz, "add", "(Ljava/lang/Object;)Z"); 285 if (env->ExceptionCheck()) return JNI_ERR; 286 jSetSize = env->GetMethodID(clazz, "size", "()I"); 287 if (env->ExceptionCheck()) return JNI_ERR; 288 jSetToArray = env->GetMethodID(clazz, "toArray", "([Ljava/lang/Object;)[Ljava/lang/Object;"); 289 if (env->ExceptionCheck()) return JNI_ERR; 290 291 clazz = env->FindClass("java/lang/Iterable"); 292 if (env->ExceptionCheck()) return JNI_ERR; 293 jIterableIterator = env->GetMethodID(clazz, "iterator", "()Ljava/util/Iterator;"); 294 if (env->ExceptionCheck()) return JNI_ERR; 295 296 clazz = env->FindClass("java/util/Iterator"); 297 if (env->ExceptionCheck()) return JNI_ERR; 298 jIteratorHasNext = env->GetMethodID(clazz, "hasNext", "()Z"); 299 if (env->ExceptionCheck()) return JNI_ERR; 300 jIteratorNext = env->GetMethodID(clazz, "next", "()Ljava/lang/Object;"); 301 if (env->ExceptionCheck()) return JNI_ERR; 302 303 clazz = env->FindClass("com/sun/glass/ui/gtk/GtkApplication"); 304 if (env->ExceptionCheck()) return JNI_ERR; 305 jApplicationCls = (jclass) env->NewGlobalRef(clazz); 306 jApplicationDisplay = env->GetStaticFieldID(jApplicationCls, "display", "J"); 307 if (env->ExceptionCheck()) return JNI_ERR; 308 jApplicationScreen = env->GetStaticFieldID(jApplicationCls, "screen", "I"); 309 if (env->ExceptionCheck()) return JNI_ERR; 310 jApplicationVisualID = env->GetStaticFieldID(jApplicationCls, "visualID", "J"); 311 if (env->ExceptionCheck()) return JNI_ERR; 312 jApplicationReportException = env->GetStaticMethodID( 313 jApplicationCls, "reportException", "(Ljava/lang/Throwable;)V"); 314 if (env->ExceptionCheck()) return JNI_ERR; 315 jApplicationGetApplication = env->GetStaticMethodID( 316 jApplicationCls, "GetApplication", "()Lcom/sun/glass/ui/Application;"); 317 if (env->ExceptionCheck()) return JNI_ERR; 318 jApplicationGetName = env->GetMethodID(jApplicationCls, "getName", "()Ljava/lang/String;"); 319 if (env->ExceptionCheck()) return JNI_ERR; 320 321 return JNI_VERSION_1_6; 322 } 323 324 void 325 glass_throw_exception(JNIEnv * env, 326 const char * exceptionClass, 327 const char * exceptionMessage) { 328 jclass throwableClass = env->FindClass(exceptionClass); 329 if (check_and_clear_exception(env)) return; 330 env->ThrowNew(throwableClass, exceptionMessage); 331 check_and_clear_exception(env); 332 } 333 334 int 335 glass_throw_oom(JNIEnv * env, const char * message) { 336 glass_throw_exception(env, "java/lang/OutOfMemoryError", message); 337 // must return a non-zero value, see HANDLE_MEM_ALLOC_ERROR 338 return 1; 339 } 340 341 342 guint8* convert_BGRA_to_RGBA(const int* pixels, int stride, int height) { 343 guint8* new_pixels = (guint8*) g_malloc(height * stride); 344 int i = 0; 345 346 for (i = 0; i < height * stride; i += 4) { 347 new_pixels[i] = (guint8)(*pixels >> 16); 348 new_pixels[i + 1] = (guint8)(*pixels >> 8); 349 new_pixels[i + 2] = (guint8)(*pixels); 350 new_pixels[i + 3] = (guint8)(*pixels >> 24); 351 pixels++; 352 } 353 354 return new_pixels; 355 } 356 357 358 void dump_jstring_array(JNIEnv* env, jobjectArray arr) { 359 if (arr == NULL) { 360 LOG0("dump: Array is null\n") 361 return; 362 } 363 jsize len = env->GetArrayLength(arr); 364 LOG1("dump: length = %d\n", len) 365 int i = 0; 366 jboolean isCopy; 367 for(i = 0; i < len; i++) { 368 jstring jstr = (jstring) env->GetObjectArrayElement(arr, i); 369 check_and_clear_exception(env); 370 const char* str = env->GetStringUTFChars(jstr, &isCopy); 371 LOG2("dump: s[%d]: %s\n", i, str) 372 } 373 } 374 375 gboolean check_and_clear_exception(JNIEnv *env) { 376 jthrowable t = env->ExceptionOccurred(); 377 if (t) { 378 env->ExceptionClear(); 379 env->CallStaticVoidMethod(jApplicationCls, jApplicationReportException, t); 380 return TRUE; 381 } 382 return FALSE; 383 } 384 385 // The returned string should be freed with g_free(). 386 gchar* get_application_name() { 387 gchar* ret = NULL; 388 389 jobject japp = mainEnv->CallStaticObjectMethod(jApplicationCls, jApplicationGetApplication); 390 CHECK_JNI_EXCEPTION_RET(mainEnv, NULL); 391 jstring jname = (jstring) mainEnv->CallObjectMethod(japp, jApplicationGetName); 392 CHECK_JNI_EXCEPTION_RET(mainEnv, NULL); 393 if (const gchar *name = mainEnv->GetStringUTFChars(jname, NULL)) { 394 ret = g_strdup(name); 395 mainEnv->ReleaseStringUTFChars(jname, name); 396 } 397 return ret; 398 } 399 400 gpointer glass_try_malloc_n(gsize m, gsize n, 401 gboolean zer0 /* initialized to 0 if true*/) { 402 if (n > 0 && m > G_MAXSIZE / n) { 403 return NULL; 404 } 405 return (zer0) 406 ? g_try_malloc0(m * n) 407 : g_try_malloc(m * n); 408 } 409 410 /* 411 * Since we support glib 2.18 we can't use g_try_malloc_n and g_try_malloc0_n 412 * which was introduced in 2.24. 413 * glass_try_malloc_n and glass_try_malloc0_n is replacement for those functions 414 */ 415 gpointer glass_try_malloc0_n(gsize m, gsize n) { 416 return glass_try_malloc_n(m, n, TRUE); 417 } 418 419 gpointer glass_try_malloc_n(gsize m, gsize n) { 420 return glass_try_malloc_n(m, n, FALSE); 421 } 422 423 gsize get_files_count(gchar **uris) { 424 if (!uris) { 425 return 0; 426 } 427 428 guint size = g_strv_length(uris); 429 guint files_cnt = 0; 430 431 for (guint i = 0; i < size; ++i) { 432 if (g_str_has_prefix(uris[i], FILE_PREFIX)) { 433 files_cnt++; 434 } 435 } 436 return files_cnt; 437 } 438 439 // Note: passed uris will be freed by this function 440 jobject uris_to_java(JNIEnv *env, gchar **uris, gboolean files) { 441 if (uris == NULL) { 442 return NULL; 443 } 444 445 jobject result = NULL; 446 447 guint size = g_strv_length(uris); 448 guint files_cnt = get_files_count(uris); 449 450 if (files) { 451 if (files_cnt) { 452 result = env->NewObjectArray(files_cnt, jStringCls, NULL); 453 check_and_clear_exception(env); 454 455 for (gsize i = 0; i < size; ++i) { 456 if (g_str_has_prefix(uris[i], FILE_PREFIX)) { 457 gchar* path = g_filename_from_uri(uris[i], NULL, NULL); 458 jstring str = env->NewStringUTF(path); 459 check_and_clear_exception(env); 460 env->SetObjectArrayElement((jobjectArray) result, i, str); 461 check_and_clear_exception(env); 462 g_free(path); 463 } 464 } 465 } 466 } else if (size - files_cnt) { 467 GString* str = g_string_new(NULL); //http://www.ietf.org/rfc/rfc2483.txt 468 469 for (guint i = 0; i < size; ++i) { 470 if (!g_str_has_prefix(uris[i], FILE_PREFIX) 471 && !g_str_has_prefix(uris[i], URI_LIST_COMMENT_PREFIX)) { 472 g_string_append(str, uris[i]); 473 g_string_append(str, URI_LIST_LINE_BREAK); 474 } 475 } 476 477 if (str->len > 2) { 478 g_string_erase(str, str->len - 2, 2); 479 } 480 481 result = env->NewStringUTF(str->str); 482 check_and_clear_exception(env); 483 484 g_string_free(str, TRUE); 485 } 486 g_strfreev(uris); 487 return result; 488 } 489 490 //*************************************************************************** 491 492 typedef struct _DeviceGrabContext { 493 GdkWindow * window; 494 gboolean grabbed; 495 } DeviceGrabContext; 496 497 gboolean disableGrab = FALSE; 498 static gboolean configure_transparent_window(GtkWidget *window); 499 static void configure_opaque_window(GtkWidget *window); 500 501 static void grab_mouse_device(GdkDevice *device, DeviceGrabContext *context); 502 static void ungrab_mouse_device(GdkDevice *device); 503 504 gint glass_gdk_visual_get_depth (GdkVisual * visual) 505 { 506 // gdk_visual_get_depth is GTK 2.2 + 507 return gdk_visual_get_depth(visual); 508 } 509 510 GdkScreen * glass_gdk_window_get_screen(GdkWindow * gdkWindow) 511 { 512 #ifdef GLASS_GTK3 513 GdkVisual * gdkVisual = gdk_window_get_visual(gdkWindow); 514 return gdk_visual_get_screen(gdkVisual); 515 #else 516 return gdk_window_get_screen(gdkWindow); 517 #endif 518 } 519 520 gboolean 521 glass_gdk_mouse_devices_grab(GdkWindow *gdkWindow) { 522 #ifdef GLASS_GTK3_DISABLED 523 //this GTK 3 approach has synchronization issues covered in JDK-8176844 524 // As the approach is also deprecated in GTK 3.20+, revert back to using GTK 2 mechanism 525 526 if (disableGrab) { 527 return TRUE; 528 } 529 DeviceGrabContext context; 530 GList *devices = gdk_device_manager_list_devices ( 531 gdk_display_get_device_manager( 532 gdk_display_get_default()), 533 GDK_DEVICE_TYPE_MASTER); 534 535 context.window = gdkWindow; 536 context.grabbed = FALSE; 537 g_list_foreach(devices, (GFunc) grab_mouse_device, &context); 538 g_list_free(devices); 539 540 return context.grabbed; 541 #else 542 return glass_gdk_mouse_devices_grab_with_cursor(gdkWindow, NULL, TRUE); 543 #endif 544 } 545 546 gboolean 547 glass_gdk_mouse_devices_grab_with_cursor(GdkWindow *gdkWindow, GdkCursor *cursor, gboolean owner_events) { 548 if (disableGrab) { 549 return TRUE; 550 } 551 GdkGrabStatus status = gdk_pointer_grab(gdkWindow, owner_events, (GdkEventMask) 552 (GDK_POINTER_MOTION_MASK 553 | GDK_POINTER_MOTION_HINT_MASK 554 | GDK_BUTTON_MOTION_MASK 555 | GDK_BUTTON1_MOTION_MASK 556 | GDK_BUTTON2_MOTION_MASK 557 | GDK_BUTTON3_MOTION_MASK 558 | GDK_BUTTON_PRESS_MASK 559 | GDK_BUTTON_RELEASE_MASK), 560 NULL, cursor, GDK_CURRENT_TIME); 561 562 return (status == GDK_GRAB_SUCCESS) ? TRUE : FALSE; 563 } 564 565 void 566 glass_gdk_mouse_devices_ungrab() { 567 #ifdef GLASS_GTK3_DISABLED 568 //this GTK 3 approach has synchronization issues covered in JDK-8176844 569 // As the approach is also deprecated in GTK 3.20+, revert back to using GTK 2 mechanism 570 GList *devices = gdk_device_manager_list_devices( 571 gdk_display_get_device_manager( 572 gdk_display_get_default()), 573 GDK_DEVICE_TYPE_MASTER); 574 g_list_foreach(devices, (GFunc) ungrab_mouse_device, NULL); 575 g_list_free(devices); 576 #else 577 gdk_pointer_ungrab(GDK_CURRENT_TIME); 578 #endif 579 } 580 581 void 582 glass_gdk_master_pointer_grab(GdkWindow *window, GdkCursor *cursor) { 583 if (disableGrab) { 584 gdk_window_set_cursor(window, cursor); 585 return; 586 } 587 #ifdef GLASS_GTK3 588 gdk_device_grab(gdk_device_manager_get_client_pointer( 589 gdk_display_get_device_manager( 590 gdk_display_get_default())), 591 window, GDK_OWNERSHIP_NONE, FALSE, GDK_ALL_EVENTS_MASK, 592 cursor, GDK_CURRENT_TIME); 593 #else 594 gdk_pointer_grab(window, FALSE, (GdkEventMask) 595 (GDK_POINTER_MOTION_MASK 596 | GDK_BUTTON_MOTION_MASK 597 | GDK_BUTTON1_MOTION_MASK 598 | GDK_BUTTON2_MOTION_MASK 599 | GDK_BUTTON3_MOTION_MASK 600 | GDK_BUTTON_RELEASE_MASK), 601 NULL, cursor, GDK_CURRENT_TIME); 602 #endif 603 } 604 605 void 606 glass_gdk_master_pointer_ungrab() { 607 #ifdef GLASS_GTK3 608 gdk_device_ungrab(gdk_device_manager_get_client_pointer( 609 gdk_display_get_device_manager( 610 gdk_display_get_default())), 611 GDK_CURRENT_TIME); 612 #else 613 gdk_pointer_ungrab(GDK_CURRENT_TIME); 614 #endif 615 } 616 617 void 618 glass_gdk_master_pointer_get_position(gint *x, gint *y) { 619 #ifdef GLASS_GTK3 620 gdk_device_get_position(gdk_device_manager_get_client_pointer( 621 gdk_display_get_device_manager( 622 gdk_display_get_default())), 623 NULL, x, y); 624 #else 625 gdk_display_get_pointer(gdk_display_get_default(), NULL, x, y, NULL); 626 #endif 627 } 628 629 gboolean 630 glass_gdk_device_is_grabbed(GdkDevice *device) { 631 #ifdef GLASS_GTK3 632 return gdk_display_device_is_grabbed(gdk_display_get_default(), device); 633 #else 634 (void) device; 635 return gdk_display_pointer_is_grabbed(gdk_display_get_default()); 636 #endif 637 } 638 639 void 640 glass_gdk_device_ungrab(GdkDevice *device) { 641 #ifdef GLASS_GTK3 642 gdk_device_ungrab(device, GDK_CURRENT_TIME); 643 #else 644 (void) device; 645 gdk_pointer_ungrab(GDK_CURRENT_TIME); 646 #endif 647 } 648 649 GdkWindow * 650 glass_gdk_device_get_window_at_position(GdkDevice *device, gint *x, gint *y) { 651 #ifdef GLASS_GTK3 652 return gdk_device_get_window_at_position(device, x, y); 653 #else 654 (void) device; 655 return gdk_display_get_window_at_pointer(gdk_display_get_default(), x, y); 656 #endif 657 } 658 659 void 660 glass_gtk_configure_transparency_and_realize(GtkWidget *window, 661 gboolean transparent) { 662 gboolean isTransparent = glass_configure_window_transparency(window, transparent); 663 gtk_widget_realize(window); 664 } 665 666 void 667 glass_gtk_window_configure_from_visual(GtkWidget *widget, GdkVisual *visual) { 668 glass_widget_set_visual(widget, visual); 669 } 670 671 static gboolean 672 configure_transparent_window(GtkWidget *window) { 673 GdkScreen *default_screen = gdk_screen_get_default(); 674 GdkDisplay *default_display = gdk_display_get_default(); 675 676 #ifdef GLASS_GTK3 677 GdkVisual *visual = gdk_screen_get_rgba_visual(default_screen); 678 if (visual 679 && gdk_display_supports_composite(default_display) 680 && gdk_screen_is_composited(default_screen)) { 681 glass_widget_set_visual(window, visual); 682 return TRUE; 683 } 684 #else 685 GdkColormap *colormap = gdk_screen_get_rgba_colormap(default_screen); 686 if (colormap 687 && gdk_display_supports_composite(default_display) 688 && gdk_screen_is_composited(default_screen)) { 689 gtk_widget_set_colormap(window, colormap); 690 return TRUE; 691 } 692 #endif 693 694 return FALSE; 695 } 696 697 void 698 glass_gdk_window_get_size(GdkWindow *window, gint *w, gint *h) { 699 *w = gdk_window_get_width(window); 700 *h = gdk_window_get_height(window); 701 } 702 703 void 704 glass_gdk_display_get_pointer(GdkDisplay* display, gint* x, gint *y) { 705 #ifdef GLASS_GTK3 706 gdk_device_get_position( 707 gdk_device_manager_get_client_pointer( 708 gdk_display_get_device_manager(display)), NULL , x, y); 709 #else 710 gdk_display_get_pointer(display, NULL, x, y, NULL); 711 #endif 712 } 713 714 715 const guchar* 716 glass_gtk_selection_data_get_data_with_length( 717 GtkSelectionData * selectionData, 718 gint * length) { 719 if (selectionData == NULL) { 720 return NULL; 721 } 722 723 *length = gtk_selection_data_get_length(selectionData); 724 return gtk_selection_data_get_data(selectionData); 725 } 726 727 static void 728 configure_opaque_window(GtkWidget *window) { 729 (void) window; 730 /* We need to pick a visual that really is glx compatible 731 * instead of using the default visual 732 */ 733 /* see: JDK-8087516 for why this is commented out 734 glass_widget_set_visual(window, 735 gdk_screen_get_system_visual( 736 gdk_screen_get_default())); 737 */ 738 } 739 740 gboolean 741 glass_configure_window_transparency(GtkWidget *window, gboolean transparent) { 742 if (transparent) { 743 if (configure_transparent_window(window)) { 744 return TRUE; 745 } 746 747 fprintf(stderr,"Can't create transparent stage, because your screen doesn't" 748 " support alpha channel." 749 " You need to enable XComposite extension.\n"); 750 fflush(stderr); 751 } 752 753 configure_opaque_window(window); 754 return FALSE; 755 } 756 757 static void 758 grab_mouse_device(GdkDevice *device, DeviceGrabContext *context) { 759 GdkInputSource source = gdk_device_get_source(device); 760 if (source == GDK_SOURCE_MOUSE) { 761 #ifdef GLASS_GTK3 762 GdkGrabStatus status = gdk_device_grab(device, 763 context->window, 764 GDK_OWNERSHIP_NONE, 765 TRUE, 766 GDK_ALL_EVENTS_MASK, 767 NULL, 768 GDK_CURRENT_TIME); 769 #else 770 GdkGrabStatus status = GDK_GRAB_SUCCESS; 771 /* FIXME reachable by 2? 772 GdkGrabStatus status = gdk_device_grab(device, 773 context->window, 774 GDK_OWNERSHIP_NONE, 775 TRUE, 776 GDK_ALL_EVENTS_MASK, 777 NULL, 778 GDK_CURRENT_TIME); 779 */ 780 #endif 781 if (status == GDK_GRAB_SUCCESS) { 782 context->grabbed = TRUE; 783 } 784 } 785 } 786 787 static void 788 ungrab_mouse_device(GdkDevice *device) { 789 #ifdef GLASS_GTK3 790 GdkInputSource source = gdk_device_get_source(device); 791 if (source == GDK_SOURCE_MOUSE) { 792 gdk_device_ungrab(device, GDK_CURRENT_TIME); 793 } 794 #else 795 (void) device; 796 // not used on the GTK2 path 797 #endif 798 } 799 800 GdkPixbuf * 801 glass_pixbuf_from_window(GdkWindow *window, 802 gint srcx, gint srcy, 803 gint width, gint height) 804 { 805 GdkPixbuf * ret = NULL; 806 807 #ifdef GLASS_GTK3 808 ret = gdk_pixbuf_get_from_window (window, srcx, srcy, width, height); 809 #else 810 ret = gdk_pixbuf_get_from_drawable (NULL, 811 window, 812 NULL, 813 srcx, srcy, 814 0, 0, 815 width, height); 816 #endif 817 return ret; 818 } 819 820 void 821 glass_window_apply_shape_mask(GdkWindow *window, 822 void* data, uint width, uint height) 823 { 824 #ifdef GLASS_GTK3 825 (void) window; 826 (void) data; 827 (void) width; 828 (void) height; 829 #else 830 GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data((guchar *) data, 831 GDK_COLORSPACE_RGB, TRUE, 8, width, height, width * 4, NULL, NULL); 832 833 if (GDK_IS_PIXBUF(pixbuf)) { 834 GdkBitmap* mask = NULL; 835 gdk_pixbuf_render_pixmap_and_mask(pixbuf, NULL, &mask, 128); 836 837 gdk_window_input_shape_combine_mask(window, mask, 0, 0); 838 839 g_object_unref(pixbuf); 840 if (mask) { 841 g_object_unref(mask); 842 } 843 } 844 #endif 845 } 846 847 void 848 glass_window_reset_input_shape_mask(GdkWindow *window) 849 { 850 #ifdef GLASS_GTK3 851 gdk_window_input_shape_combine_region(window, NULL, 0, 0); 852 #else 853 gdk_window_input_shape_combine_mask(window, NULL, 0, 0); 854 #endif 855 } 856 857 GdkWindow * 858 glass_gdk_drag_context_get_dest_window (GdkDragContext * context) 859 { 860 return ((context != NULL) ? gdk_drag_context_get_dest_window(context) : NULL); 861 } 862 863 864 void glass_gdk_x11_display_set_window_scale (GdkDisplay *display, 865 gint scale) 866 { 867 #ifdef GLASS_GTK3 868 // Optional call, if it does not exist then GTK3 is not yet 869 // doing automatic scaling of coordinates so we do not need 870 // to override it. 871 wrapped_gdk_x11_display_set_window_scale(display, scale); 872 #else 873 (void) display; 874 (void) scale; 875 #endif 876 } 877 878 //-------- Glass utility ---------------------------------------- 879 880 void 881 glass_widget_set_visual(GtkWidget *widget, GdkVisual *visual) 882 { 883 #ifdef GLASS_GTK3 884 gtk_widget_set_visual (widget, visual); 885 #else 886 GdkColormap *colormap = gdk_colormap_new(visual, TRUE); 887 gtk_widget_set_colormap (widget, colormap); 888 #endif 889 } 890 891 guint glass_settings_get_guint_opt (const gchar *schema_name, 892 const gchar *key_name, 893 int defval) 894 { 895 GSettingsSchemaSource *default_schema_source = 896 wrapped_g_settings_schema_source_get_default(); 897 if (default_schema_source == NULL) { 898 if (gtk_verbose) { 899 fprintf(stderr, "No schema source dir found!\n"); 900 } 901 return defval; 902 } 903 GSettingsSchema *the_schema = 904 wrapped_g_settings_schema_source_lookup(default_schema_source, schema_name, TRUE); 905 if (the_schema == NULL) { 906 if (gtk_verbose) { 907 fprintf(stderr, "schema '%s' not found!\n", schema_name); 908 } 909 return defval; 910 } 911 if (!wrapped_g_settings_schema_has_key(the_schema, key_name)) { 912 if (gtk_verbose) { 913 fprintf(stderr, "key '%s' not found in schema '%s'!\n", key_name, schema_name); 914 } 915 return defval; 916 } 917 if (gtk_verbose) { 918 fprintf(stderr, "found schema '%s' and key '%s'\n", schema_name, key_name); 919 } 920 921 GSettings *gset = g_settings_new(schema_name); 922 923 wrapped_g_settings_schema_unref(the_schema); 924 925 return g_settings_get_uint(gset, key_name); 926 }