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