1 /* 2 * Copyright (c) 2002, 2006, 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 26 #include <X11/Xlib.h> 27 #include <X11/Xutil.h> 28 #include <X11/Xos.h> 29 #include <X11/Xatom.h> 30 #ifdef __linux__ 31 #include <execinfo.h> 32 #endif 33 34 #include <jvm.h> 35 #include <jni.h> 36 #include <jlong.h> 37 #include <jni_util.h> 38 39 #include "awt_p.h" 40 #include "awt_Component.h" 41 #include "awt_MenuComponent.h" 42 #include "awt_KeyboardFocusManager.h" 43 #include "awt_Font.h" 44 45 #include "sun_awt_X11_XToolkit.h" 46 #include "java_awt_SystemColor.h" 47 #include "java_awt_TrayIcon.h" 48 #include <X11/extensions/XTest.h> 49 50 uint32_t awt_NumLockMask = 0; 51 Boolean awt_ModLockIsShiftLock = False; 52 53 static int32_t num_buttons = 0; 54 int32_t getNumButtons(); 55 56 extern JavaVM *jvm; 57 58 // Tracing level 59 static int tracing = 0; 60 #ifdef PRINT 61 #undef PRINT 62 #endif 63 #ifdef PRINT2 64 #undef PRINT2 65 #endif 66 67 #define PRINT if (tracing) printf 68 #define PRINT2 if (tracing > 1) printf 69 70 71 struct ComponentIDs componentIDs; 72 73 struct MenuComponentIDs menuComponentIDs; 74 75 struct KeyboardFocusManagerIDs keyboardFocusManagerIDs; 76 77 #ifndef HEADLESS 78 79 extern Display* awt_init_Display(JNIEnv *env, jobject this); 80 81 extern struct MFontPeerIDs mFontPeerIDs; 82 83 JNIEXPORT void JNICALL 84 Java_sun_awt_X11_XFontPeer_initIDs 85 (JNIEnv *env, jclass cls) 86 { 87 mFontPeerIDs.xfsname = 88 (*env)->GetFieldID(env, cls, "xfsname", "Ljava/lang/String;"); 89 } 90 #endif /* !HEADLESS */ 91 92 /* This function gets called from the static initializer for FileDialog.java 93 to initialize the fieldIDs for fields that may be accessed from C */ 94 95 JNIEXPORT void JNICALL 96 Java_java_awt_FileDialog_initIDs 97 (JNIEnv *env, jclass cls) 98 { 99 100 } 101 102 JNIEXPORT void JNICALL 103 Java_sun_awt_X11_XToolkit_initIDs 104 (JNIEnv *env, jclass clazz) 105 { 106 jfieldID fid = (*env)->GetStaticFieldID(env, clazz, "numLockMask", "I"); 107 awt_NumLockMask = (*env)->GetStaticIntField(env, clazz, fid); 108 DTRACE_PRINTLN1("awt_NumLockMask = %u", awt_NumLockMask); 109 fid = (*env)->GetStaticFieldID(env, clazz, "modLockIsShiftLock", "I"); 110 awt_ModLockIsShiftLock = (*env)->GetStaticIntField(env, clazz, fid) != 0 ? True : False; 111 } 112 113 /* 114 * Class: sun_awt_X11_XToolkit 115 * Method: getDefaultXColormap 116 * Signature: ()J 117 */ 118 JNIEXPORT jlong JNICALL Java_sun_awt_X11_XToolkit_getDefaultXColormap 119 (JNIEnv *env, jclass clazz) 120 { 121 AwtGraphicsConfigDataPtr defaultConfig = 122 getDefaultConfig(DefaultScreen(awt_display)); 123 124 return (jlong) defaultConfig->awt_cmap; 125 } 126 127 JNIEXPORT jlong JNICALL Java_sun_awt_X11_XToolkit_getDefaultScreenData 128 (JNIEnv *env, jclass clazz) 129 { 130 return ptr_to_jlong(getDefaultConfig(DefaultScreen(awt_display))); 131 } 132 133 134 JNIEXPORT jint JNICALL 135 JNI_OnLoad(JavaVM *vm, void *reserved) 136 { 137 jvm = vm; 138 return JNI_VERSION_1_2; 139 } 140 141 /* 142 * Class: sun_awt_X11_XToolkit 143 * Method: nativeLoadSystemColors 144 * Signature: ([I)V 145 */ 146 JNIEXPORT void JNICALL Java_sun_awt_X11_XToolkit_nativeLoadSystemColors 147 (JNIEnv *env, jobject this, jintArray systemColors) 148 { 149 AwtGraphicsConfigDataPtr defaultConfig = 150 getDefaultConfig(DefaultScreen(awt_display)); 151 awtJNI_CreateColorData(env, defaultConfig, 1); 152 } 153 154 JNIEXPORT void JNICALL 155 Java_java_awt_Component_initIDs 156 (JNIEnv *env, jclass cls) 157 { 158 jclass keyclass = NULL; 159 160 161 componentIDs.x = (*env)->GetFieldID(env, cls, "x", "I"); 162 componentIDs.y = (*env)->GetFieldID(env, cls, "y", "I"); 163 componentIDs.width = (*env)->GetFieldID(env, cls, "width", "I"); 164 componentIDs.height = (*env)->GetFieldID(env, cls, "height", "I"); 165 componentIDs.isPacked = (*env)->GetFieldID(env, cls, "isPacked", "Z"); 166 componentIDs.peer = 167 (*env)->GetFieldID(env, cls, "peer", "Ljava/awt/peer/ComponentPeer;"); 168 componentIDs.background = 169 (*env)->GetFieldID(env, cls, "background", "Ljava/awt/Color;"); 170 componentIDs.foreground = 171 (*env)->GetFieldID(env, cls, "foreground", "Ljava/awt/Color;"); 172 componentIDs.graphicsConfig = 173 (*env)->GetFieldID(env, cls, "graphicsConfig", 174 "Ljava/awt/GraphicsConfiguration;"); 175 componentIDs.name = 176 (*env)->GetFieldID(env, cls, "name", "Ljava/lang/String;"); 177 178 /* Use _NoClientCode() methods for trusted methods, so that we 179 * know that we are not invoking client code on trusted threads 180 */ 181 componentIDs.getParent = 182 (*env)->GetMethodID(env, cls, "getParent_NoClientCode", 183 "()Ljava/awt/Container;"); 184 185 componentIDs.getLocationOnScreen = 186 (*env)->GetMethodID(env, cls, "getLocationOnScreen_NoTreeLock", 187 "()Ljava/awt/Point;"); 188 189 keyclass = (*env)->FindClass(env, "java/awt/event/KeyEvent"); 190 if (JNU_IsNull(env, keyclass)) { 191 return; 192 } 193 194 componentIDs.isProxyActive = 195 (*env)->GetFieldID(env, keyclass, "isProxyActive", 196 "Z"); 197 198 componentIDs.appContext = 199 (*env)->GetFieldID(env, cls, "appContext", 200 "Lsun/awt/AppContext;"); 201 202 (*env)->DeleteLocalRef(env, keyclass); 203 } 204 205 206 JNIEXPORT void JNICALL 207 Java_java_awt_Container_initIDs 208 (JNIEnv *env, jclass cls) 209 { 210 211 } 212 213 214 JNIEXPORT void JNICALL 215 Java_java_awt_Button_initIDs 216 (JNIEnv *env, jclass cls) 217 { 218 219 } 220 221 JNIEXPORT void JNICALL 222 Java_java_awt_Scrollbar_initIDs 223 (JNIEnv *env, jclass cls) 224 { 225 226 } 227 228 229 JNIEXPORT void JNICALL 230 Java_java_awt_Window_initIDs 231 (JNIEnv *env, jclass cls) 232 { 233 234 } 235 236 JNIEXPORT void JNICALL 237 Java_java_awt_Frame_initIDs 238 (JNIEnv *env, jclass cls) 239 { 240 241 } 242 243 244 JNIEXPORT void JNICALL 245 Java_java_awt_MenuComponent_initIDs(JNIEnv *env, jclass cls) 246 { 247 menuComponentIDs.appContext = 248 (*env)->GetFieldID(env, cls, "appContext", "Lsun/awt/AppContext;"); 249 } 250 251 JNIEXPORT void JNICALL 252 Java_java_awt_Cursor_initIDs(JNIEnv *env, jclass cls) 253 { 254 } 255 256 257 JNIEXPORT void JNICALL Java_java_awt_MenuItem_initIDs 258 (JNIEnv *env, jclass cls) 259 { 260 } 261 262 263 JNIEXPORT void JNICALL Java_java_awt_Menu_initIDs 264 (JNIEnv *env, jclass cls) 265 { 266 } 267 268 JNIEXPORT void JNICALL 269 Java_java_awt_TextArea_initIDs 270 (JNIEnv *env, jclass cls) 271 { 272 } 273 274 275 JNIEXPORT void JNICALL 276 Java_java_awt_Checkbox_initIDs 277 (JNIEnv *env, jclass cls) 278 { 279 } 280 281 282 JNIEXPORT void JNICALL Java_java_awt_ScrollPane_initIDs 283 (JNIEnv *env, jclass cls) 284 { 285 } 286 287 JNIEXPORT void JNICALL 288 Java_java_awt_TextField_initIDs 289 (JNIEnv *env, jclass cls) 290 { 291 } 292 293 JNIEXPORT jboolean JNICALL AWTIsHeadless() { 294 #ifdef HEADLESS 295 return JNI_TRUE; 296 #else 297 return JNI_FALSE; 298 #endif 299 } 300 301 JNIEXPORT void JNICALL Java_java_awt_Dialog_initIDs (JNIEnv *env, jclass cls) 302 { 303 } 304 305 306 /* ========================== Begin poll section ================================ */ 307 308 // Includes 309 310 #include <sys/time.h> 311 #include <limits.h> 312 #include <locale.h> 313 #include <pthread.h> 314 315 #include <dlfcn.h> 316 #include <fcntl.h> 317 318 #include <poll.h> 319 #ifndef POLLRDNORM 320 #define POLLRDNORM POLLIN 321 #endif 322 323 // Prototypes 324 325 static void waitForEvents(JNIEnv *, jlong); 326 static void awt_pipe_init(); 327 static void processOneEvent(XtInputMask iMask); 328 static void performPoll(JNIEnv *, jlong); 329 static void wakeUp(); 330 static void update_poll_timeout(int timeout_control); 331 static uint32_t get_poll_timeout(jlong nextTaskTime); 332 333 // Defines 334 335 #ifndef bzero 336 #define bzero(a,b) memset(a, 0, b) 337 #endif 338 339 #define AWT_POLL_BUFSIZE 100 /* bytes */ 340 #define AWT_READPIPE (awt_pipe_fds[0]) 341 #define AWT_WRITEPIPE (awt_pipe_fds[1]) 342 343 #define DEF_AWT_MAX_POLL_TIMEOUT ((uint32_t)500) /* milliseconds */ 344 #define DEF_AWT_FLUSH_TIMEOUT ((uint32_t)100) /* milliseconds */ 345 #define AWT_MIN_POLL_TIMEOUT ((uint32_t)0) /* milliseconds */ 346 347 #define TIMEOUT_TIMEDOUT 0 348 #define TIMEOUT_EVENTS 1 349 350 // Static fields 351 352 static uint32_t AWT_FLUSH_TIMEOUT = DEF_AWT_FLUSH_TIMEOUT; /* milliseconds */ 353 static uint32_t AWT_MAX_POLL_TIMEOUT = DEF_AWT_MAX_POLL_TIMEOUT; /* milliseconds */ 354 static pthread_t awt_MainThread = 0; 355 static int32_t awt_pipe_fds[2]; /* fds for wkaeup pipe */ 356 static Boolean awt_pipe_inited = False; /* make sure pipe is initialized before write */ 357 static jlong awt_next_flush_time = 0LL; /* 0 == no scheduled flush */ 358 static jlong awt_last_flush_time = 0LL; /* 0 == no scheduled flush */ 359 static uint32_t curPollTimeout; 360 static struct pollfd pollFds[2]; 361 static jlong poll_sleep_time = 0LL; // Used for tracing 362 static jlong poll_wakeup_time = 0LL; // Used for tracing 363 364 // AWT static poll timeout. Zero means "not set", aging algorithm is 365 // used. Static poll timeout values higher than 50 cause application 366 // look "slow" - they don't respond to user request fast 367 // enough. Static poll timeout value less than 10 are usually 368 // considered by schedulers as zero, so this might cause unnecessary 369 // CPU consumption by Java. The values between 10 - 50 are suggested 370 // for single client desktop configurations. For SunRay servers, it 371 // is highly recomended to use aging algorithm (set static poll timeout 372 // to 0). 373 static int32_t static_poll_timeout = 0; 374 375 static Bool isMainThread() { 376 return awt_MainThread == pthread_self(); 377 } 378 379 /* 380 * Creates the AWT utility pipe. This pipe exists solely so that 381 * we can cause the main event thread to wake up from a poll() or 382 * select() by writing to this pipe. 383 */ 384 static void 385 awt_pipe_init() { 386 387 if (awt_pipe_inited) { 388 return; 389 } 390 391 if ( pipe ( awt_pipe_fds ) == 0 ) 392 { 393 /* 394 ** the write wakes us up from the infinite sleep, which 395 ** then we cause a delay of AWT_FLUSHTIME and then we 396 ** flush. 397 */ 398 int32_t flags = 0; 399 /* set the pipe to be non-blocking */ 400 flags = fcntl ( AWT_READPIPE, F_GETFL, 0 ); 401 fcntl( AWT_READPIPE, F_SETFL, flags | O_NDELAY | O_NONBLOCK ); 402 flags = fcntl ( AWT_WRITEPIPE, F_GETFL, 0 ); 403 fcntl( AWT_WRITEPIPE, F_SETFL, flags | O_NDELAY | O_NONBLOCK ); 404 awt_pipe_inited = True; 405 } 406 else 407 { 408 AWT_READPIPE = -1; 409 AWT_WRITEPIPE = -1; 410 } 411 412 413 } /* awt_pipe_init() */ 414 415 /** 416 * Reads environment variables to initialize timeout fields. 417 */ 418 static void readEnv() { 419 char * value; 420 static Boolean env_read = False; 421 if (env_read) return; 422 423 env_read = True; 424 425 value = getenv("_AWT_MAX_POLL_TIMEOUT"); 426 if (value != NULL) { 427 AWT_MAX_POLL_TIMEOUT = atoi(value); 428 if (AWT_MAX_POLL_TIMEOUT == 0) { 429 AWT_MAX_POLL_TIMEOUT = DEF_AWT_MAX_POLL_TIMEOUT; 430 } 431 } 432 curPollTimeout = AWT_MAX_POLL_TIMEOUT/2; 433 434 value = getenv("_AWT_FLUSH_TIMEOUT"); 435 if (value != NULL) { 436 AWT_FLUSH_TIMEOUT = atoi(value); 437 if (AWT_FLUSH_TIMEOUT == 0) { 438 AWT_FLUSH_TIMEOUT = DEF_AWT_FLUSH_TIMEOUT; 439 } 440 } 441 442 value = getenv("_AWT_POLL_TRACING"); 443 if (value != NULL) { 444 tracing = atoi(value); 445 } 446 447 value = getenv("_AWT_STATIC_POLL_TIMEOUT"); 448 if (value != NULL) { 449 static_poll_timeout = atoi(value); 450 } 451 if (static_poll_timeout != 0) { 452 curPollTimeout = static_poll_timeout; 453 } 454 } 455 456 /** 457 * Returns the amount of milliseconds similar to System.currentTimeMillis() 458 */ 459 static jlong 460 awtJNI_TimeMillis(void) 461 { 462 struct timeval t; 463 464 gettimeofday(&t, 0); 465 466 return jlong_add(jlong_mul(jint_to_jlong(t.tv_sec), jint_to_jlong(1000)), 467 jint_to_jlong(t.tv_usec / 1000)); 468 } 469 470 /** 471 * Updates curPollTimeout according to the aging algorithm. 472 * @param timeout_control Either TIMEOUT_TIMEDOUT or TIMEOUT_EVENTS 473 */ 474 static void update_poll_timeout(int timeout_control) { 475 PRINT2("tout: %d\n", timeout_control); 476 477 // If static_poll_timeout is set, curPollTimeout has the fixed value 478 if (static_poll_timeout != 0) return; 479 480 // Update it otherwise 481 if (timeout_control == TIMEOUT_TIMEDOUT) { 482 /* add 1/4 (plus 1, in case the division truncates to 0) */ 483 curPollTimeout += ((curPollTimeout>>2) + 1); 484 curPollTimeout = min(AWT_MAX_POLL_TIMEOUT, curPollTimeout); 485 } else if (timeout_control == TIMEOUT_EVENTS) { 486 /* subtract 1/4 (plus 1, in case the division truncates to 0) */ 487 curPollTimeout -= ((curPollTimeout>>2) + 1); 488 curPollTimeout = max(AWT_MIN_POLL_TIMEOUT, curPollTimeout); 489 } 490 } 491 492 /* 493 * Gets the best timeout for the next call to poll(). 494 * 495 * @param nextTaskTime -1, if there are no tasks; next time when 496 * timeout task needs to be run, in millis(of currentTimeMillis) 497 */ 498 static uint32_t get_poll_timeout(jlong nextTaskTime) 499 { 500 jlong curTime = awtJNI_TimeMillis(); 501 uint32_t timeout = curPollTimeout; 502 uint32_t taskTimeout = (nextTaskTime == -1) ? AWT_MAX_POLL_TIMEOUT : (uint32_t)max(0, (int32_t)(nextTaskTime - curTime)); 503 uint32_t flushTimeout = (awt_next_flush_time > 0) ? (uint32_t)max(0, (int32_t)(awt_next_flush_time - curTime)) : AWT_MAX_POLL_TIMEOUT; 504 505 PRINT2("to: %d, ft: %d, to: %d, tt: %d, mil: %d\n", taskTimeout, flushTimeout, timeout, (int)nextTaskTime, (int)curTime); 506 507 // Adjust timeout to flush_time and task_time 508 return min(flushTimeout, min(taskTimeout, timeout)); 509 } /* awt_get_poll_timeout() */ 510 511 /* 512 * Waits for X/Xt events to appear on the pipe. Returns only when 513 * it is likely (but not definite) that there are events waiting to 514 * be processed. 515 * 516 * This routine also flushes the outgoing X queue, when the 517 * awt_next_flush_time has been reached. 518 * 519 * If fdAWTPipe is greater or equal than zero the routine also 520 * checks if there are events pending on the putback queue. 521 */ 522 void 523 waitForEvents(JNIEnv *env, jlong nextTaskTime) { 524 performPoll(env, nextTaskTime); 525 if ((awt_next_flush_time > 0) && (awtJNI_TimeMillis() >= awt_next_flush_time)) { 526 XFlush(awt_display); 527 awt_last_flush_time = awt_next_flush_time; 528 awt_next_flush_time = 0LL; 529 } 530 } /* waitForEvents() */ 531 532 JNIEXPORT void JNICALL Java_sun_awt_X11_XToolkit_waitForEvents (JNIEnv *env, jclass class, jlong nextTaskTime) { 533 waitForEvents(env, nextTaskTime); 534 } 535 536 JNIEXPORT void JNICALL Java_sun_awt_X11_XToolkit_awt_1toolkit_1init (JNIEnv *env, jclass class) { 537 awt_MainThread = pthread_self(); 538 539 awt_pipe_init(); 540 readEnv(); 541 } 542 543 JNIEXPORT void JNICALL Java_sun_awt_X11_XToolkit_awt_1output_1flush (JNIEnv *env, jclass class) { 544 awt_output_flush(); 545 } 546 547 JNIEXPORT void JNICALL Java_sun_awt_X11_XToolkit_wakeup_1poll (JNIEnv *env, jclass class) { 548 wakeUp(); 549 } 550 551 /* 552 * Polls both the X pipe and our AWT utility pipe. Returns 553 * when there is data on one of the pipes, or the operation times 554 * out. 555 * 556 * Not all Xt events come across the X pipe (e.g., timers 557 * and alternate inputs), so we must time out every now and 558 * then to check the Xt event queue. 559 * 560 * The fdAWTPipe will be empty when this returns. 561 */ 562 static void 563 performPoll(JNIEnv *env, jlong nextTaskTime) { 564 static Bool pollFdsInited = False; 565 static char read_buf[AWT_POLL_BUFSIZE + 1]; /* dummy buf to empty pipe */ 566 567 uint32_t timeout = get_poll_timeout(nextTaskTime); 568 int32_t result; 569 570 if (!pollFdsInited) { 571 pollFds[0].fd = ConnectionNumber(awt_display); 572 pollFds[0].events = POLLRDNORM; 573 pollFds[0].revents = 0; 574 575 pollFds[1].fd = AWT_READPIPE; 576 pollFds[1].events = POLLRDNORM; 577 pollFds[1].revents = 0; 578 pollFdsInited = True; 579 } else { 580 pollFds[0].revents = 0; 581 pollFds[1].revents = 0; 582 } 583 584 AWT_NOFLUSH_UNLOCK(); 585 586 /* ACTUALLY DO THE POLL() */ 587 if (timeout == 0) { 588 // be sure other threads get a chance 589 awtJNI_ThreadYield(env); 590 } 591 592 if (tracing) poll_sleep_time = awtJNI_TimeMillis(); 593 result = poll( pollFds, 2, (int32_t) timeout ); 594 if (tracing) poll_wakeup_time = awtJNI_TimeMillis(); 595 PRINT("%d of %d, res: %d\n", (int)(poll_wakeup_time-poll_sleep_time), (int)timeout, result); 596 597 AWT_LOCK(); 598 if (result == 0) { 599 /* poll() timed out -- update timeout value */ 600 update_poll_timeout(TIMEOUT_TIMEDOUT); 601 } 602 if (pollFds[1].revents) { 603 int count; 604 PRINT("Woke up\n"); 605 /* There is data on the AWT pipe - empty it */ 606 do { 607 count = read(AWT_READPIPE, read_buf, AWT_POLL_BUFSIZE ); 608 } while (count == AWT_POLL_BUFSIZE ); 609 } 610 if (pollFds[0].revents) { 611 // Events in X pipe 612 update_poll_timeout(TIMEOUT_EVENTS); 613 } 614 return; 615 616 } /* performPoll() */ 617 618 /** 619 * Schedules next auto-flush event or performs forced flush depending 620 * on the time of the previous flush. 621 */ 622 void awt_output_flush() { 623 if (awt_next_flush_time == 0) { 624 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 625 626 jlong curTime = awtJNI_TimeMillis(); // current time 627 jlong l_awt_last_flush_time = awt_last_flush_time; // last time we flushed queue 628 jlong next_flush_time = l_awt_last_flush_time + AWT_FLUSH_TIMEOUT; 629 630 if (curTime >= next_flush_time) { 631 // Enough time passed from last flush 632 PRINT("f1\n"); 633 AWT_LOCK(); 634 XFlush(awt_display); 635 awt_last_flush_time = curTime; 636 AWT_NOFLUSH_UNLOCK(); 637 } else { 638 awt_next_flush_time = next_flush_time; 639 PRINT("f2\n"); 640 wakeUp(); 641 } 642 } 643 } 644 645 646 /** 647 * Wakes-up poll() in performPoll 648 */ 649 static void wakeUp() { 650 static char wakeUp_char = 'p'; 651 if (!isMainThread() && awt_pipe_inited) { 652 write ( AWT_WRITEPIPE, &wakeUp_char, 1 ); 653 } 654 } 655 656 657 /* ========================== End poll section ================================= */ 658 659 /* 660 * Class: java_awt_KeyboardFocusManager 661 * Method: initIDs 662 * Signature: ()V 663 */ 664 JNIEXPORT void JNICALL 665 Java_java_awt_KeyboardFocusManager_initIDs 666 (JNIEnv *env, jclass cls) 667 { 668 } 669 670 /* 671 * Class: sun_awt_X11_XToolkit 672 * Method: getEnv 673 * Signature: (Ljava/lang/String;)Ljava/lang/String; 674 */ 675 JNIEXPORT jstring JNICALL Java_sun_awt_X11_XToolkit_getEnv 676 (JNIEnv *env , jclass clazz, jstring key) { 677 char *ptr = NULL; 678 const char *keystr = NULL; 679 jstring ret = NULL; 680 681 keystr = JNU_GetStringPlatformChars(env, key, NULL); 682 if (keystr) { 683 ptr = getenv(keystr); 684 if (ptr) { 685 ret = JNU_NewStringPlatform(env, (const char *) ptr); 686 } 687 JNU_ReleaseStringPlatformChars(env, key, (const char*)keystr); 688 } 689 return ret; 690 } 691 692 #ifdef __linux__ 693 void print_stack(void) 694 { 695 void *array[10]; 696 size_t size; 697 char **strings; 698 size_t i; 699 700 size = backtrace (array, 10); 701 strings = backtrace_symbols (array, size); 702 703 fprintf (stderr, "Obtained %zd stack frames.\n", size); 704 705 for (i = 0; i < size; i++) 706 fprintf (stderr, "%s\n", strings[i]); 707 708 free (strings); 709 } 710 #endif 711 712 Window get_xawt_root_shell(JNIEnv *env) { 713 static jclass classXRootWindow = NULL; 714 static jmethodID methodGetXRootWindow = NULL; 715 static Window xawt_root_shell = None; 716 717 if (xawt_root_shell == None){ 718 if (classXRootWindow == NULL){ 719 jclass cls_tmp = (*env)->FindClass(env, "sun/awt/X11/XRootWindow"); 720 if (!JNU_IsNull(env, cls_tmp)) { 721 classXRootWindow = (jclass)(*env)->NewGlobalRef(env, cls_tmp); 722 (*env)->DeleteLocalRef(env, cls_tmp); 723 } 724 } 725 if( classXRootWindow != NULL) { 726 methodGetXRootWindow = (*env)->GetStaticMethodID(env, classXRootWindow, "getXRootWindow", "()J"); 727 } 728 if( classXRootWindow != NULL && methodGetXRootWindow !=NULL ) { 729 xawt_root_shell = (Window) (*env)->CallStaticLongMethod(env, classXRootWindow, methodGetXRootWindow); 730 } 731 if ((*env)->ExceptionCheck(env)) { 732 (*env)->ExceptionDescribe(env); 733 (*env)->ExceptionClear(env); 734 } 735 } 736 return xawt_root_shell; 737 } 738 739 /* 740 * Old, compatibility, backdoor for DT. This is a different 741 * implementation. It keeps the signature, but acts on 742 * awt_root_shell, not the frame passed as an argument. Note, that 743 * the code that uses the old backdoor doesn't work correctly with 744 * gnome session proxy that checks for WM_COMMAND when the window is 745 * firts mapped, because DT code calls this old backdoor *after* the 746 * frame is shown or it would get NPE with old AWT (previous 747 * implementation of this backdoor) otherwise. Old style session 748 * managers (e.g. CDE) that check WM_COMMAND only during session 749 * checkpoint should work fine, though. 750 * 751 * NB: The function name looks deceptively like a JNI native method 752 * name. It's not! It's just a plain function. 753 */ 754 755 JNIEXPORT void JNICALL 756 Java_sun_awt_motif_XsessionWMcommand(JNIEnv *env, jobject this, 757 jobject frame, jstring jcommand) 758 { 759 const char *command; 760 XTextProperty text_prop; 761 char *c[1]; 762 int32_t status; 763 Window xawt_root_window; 764 765 AWT_LOCK(); 766 xawt_root_window = get_xawt_root_shell(env); 767 768 if ( xawt_root_window == None ) { 769 JNU_ThrowNullPointerException(env, "AWT root shell is unrealized"); 770 AWT_UNLOCK(); 771 return; 772 } 773 774 command = (char *) JNU_GetStringPlatformChars(env, jcommand, NULL); 775 c[0] = (char *)command; 776 status = XmbTextListToTextProperty(awt_display, c, 1, 777 XStdICCTextStyle, &text_prop); 778 779 if (status == Success || status > 0) { 780 XSetTextProperty(awt_display, xawt_root_window, 781 &text_prop, XA_WM_COMMAND); 782 if (text_prop.value != NULL) 783 XFree(text_prop.value); 784 } 785 JNU_ReleaseStringPlatformChars(env, jcommand, command); 786 AWT_UNLOCK(); 787 } 788 789 790 /* 791 * New DT backdoor to set WM_COMMAND. New code should use this 792 * backdoor and call it *before* the first frame is shown so that 793 * gnome session proxy can correctly handle it. 794 * 795 * NB: The function name looks deceptively like a JNI native method 796 * name. It's not! It's just a plain function. 797 */ 798 JNIEXPORT void JNICALL 799 Java_sun_awt_motif_XsessionWMcommand_New(JNIEnv *env, jobjectArray jargv) 800 { 801 static const char empty[] = ""; 802 803 int argc; 804 const char **cargv; 805 XTextProperty text_prop; 806 int status; 807 int i; 808 Window xawt_root_window; 809 810 AWT_LOCK(); 811 xawt_root_window = get_xawt_root_shell(env); 812 813 if (xawt_root_window == None) { 814 JNU_ThrowNullPointerException(env, "AWT root shell is unrealized"); 815 AWT_UNLOCK(); 816 return; 817 } 818 819 argc = (int)(*env)->GetArrayLength(env, jargv); 820 if (argc == 0) { 821 AWT_UNLOCK(); 822 return; 823 } 824 825 /* array of C strings */ 826 cargv = (const char **)calloc(argc, sizeof(char *)); 827 if (cargv == NULL) { 828 JNU_ThrowOutOfMemoryError(env, "Unable to allocate cargv"); 829 AWT_UNLOCK(); 830 return; 831 } 832 833 /* fill C array with platform chars of java strings */ 834 for (i = 0; i < argc; ++i) { 835 jstring js; 836 const char *cs; 837 838 cs = NULL; 839 js = (*env)->GetObjectArrayElement(env, jargv, i); 840 if (js != NULL) { 841 cs = JNU_GetStringPlatformChars(env, js, NULL); 842 } 843 if (cs == NULL) { 844 cs = empty; 845 } 846 cargv[i] = cs; 847 (*env)->DeleteLocalRef(env, js); 848 } 849 850 /* grr, X prototype doesn't declare cargv as const, thought it really is */ 851 status = XmbTextListToTextProperty(awt_display, (char **)cargv, argc, 852 XStdICCTextStyle, &text_prop); 853 if (status < 0) { 854 switch (status) { 855 case XNoMemory: 856 JNU_ThrowOutOfMemoryError(env, 857 "XmbTextListToTextProperty: XNoMemory"); 858 break; 859 case XLocaleNotSupported: 860 JNU_ThrowInternalError(env, 861 "XmbTextListToTextProperty: XLocaleNotSupported"); 862 break; 863 case XConverterNotFound: 864 JNU_ThrowNullPointerException(env, 865 "XmbTextListToTextProperty: XConverterNotFound"); 866 break; 867 default: 868 JNU_ThrowInternalError(env, 869 "XmbTextListToTextProperty: unknown error"); 870 } 871 } else { 872 873 XSetTextProperty(awt_display, xawt_root_window, 874 &text_prop, XA_WM_COMMAND); 875 } 876 877 for (i = 0; i < argc; ++i) { 878 jstring js; 879 880 if (cargv[i] == empty) 881 continue; 882 883 js = (*env)->GetObjectArrayElement(env, jargv, i); 884 JNU_ReleaseStringPlatformChars(env, js, cargv[i]); 885 (*env)->DeleteLocalRef(env, js); 886 } 887 if (text_prop.value != NULL) 888 XFree(text_prop.value); 889 AWT_UNLOCK(); 890 } 891 892 /* 893 * Class: java_awt_TrayIcon 894 * Method: initIDs 895 * Signature: ()V 896 */ 897 JNIEXPORT void JNICALL Java_java_awt_TrayIcon_initIDs(JNIEnv *env , jclass clazz) 898 { 899 } 900 901 902 /* 903 * Class: java_awt_Cursor 904 * Method: finalizeImpl 905 * Signature: ()V 906 */ 907 JNIEXPORT void JNICALL 908 Java_java_awt_Cursor_finalizeImpl(JNIEnv *env, jclass clazz, jlong pData) 909 { 910 Cursor xcursor; 911 912 xcursor = (Cursor)pData; 913 if (xcursor != None) { 914 AWT_LOCK(); 915 XFreeCursor(awt_display, xcursor); 916 AWT_UNLOCK(); 917 } 918 } 919 920 921 /* 922 * Class: sun_awt_X11_XToolkit 923 * Method: getNumberOfButtonsImpl 924 * Signature: ()I 925 */ 926 JNIEXPORT jint JNICALL Java_sun_awt_X11_XToolkit_getNumberOfButtonsImpl 927 (JNIEnv * env, jobject cls){ 928 if (num_buttons == 0) { 929 num_buttons = getNumButtons(); 930 } 931 return num_buttons; 932 } 933 934 int32_t getNumButtons() { 935 int32_t major_opcode, first_event, first_error; 936 int32_t xinputAvailable; 937 int32_t numDevices, devIdx, clsIdx; 938 XDeviceInfo* devices; 939 XDeviceInfo* aDevice; 940 XButtonInfo* bInfo; 941 int32_t local_num_buttons = 0; 942 943 /* 4700242: 944 * If XTest is asked to press a non-existant mouse button 945 * (i.e. press Button3 on a system configured with a 2-button mouse), 946 * then a crash may happen. To avoid this, we use the XInput 947 * extension to query for the number of buttons on the XPointer, and check 948 * before calling XTestFakeButtonEvent(). 949 */ 950 xinputAvailable = XQueryExtension(awt_display, INAME, &major_opcode, &first_event, &first_error); 951 DTRACE_PRINTLN3("RobotPeer: XQueryExtension(XINPUT) returns major_opcode = %d, first_event = %d, first_error = %d", 952 major_opcode, first_event, first_error); 953 if (xinputAvailable) { 954 devices = XListInputDevices(awt_display, &numDevices); 955 for (devIdx = 0; devIdx < numDevices; devIdx++) { 956 aDevice = &(devices[devIdx]); 957 #ifdef IsXExtensionPointer 958 if (aDevice->use == IsXExtensionPointer) { 959 for (clsIdx = 0; clsIdx < aDevice->num_classes; clsIdx++) { 960 if (aDevice->inputclassinfo[clsIdx].class == ButtonClass) { 961 bInfo = (XButtonInfo*)(&(aDevice->inputclassinfo[clsIdx])); 962 local_num_buttons = bInfo->num_buttons; 963 DTRACE_PRINTLN1("RobotPeer: XPointer has %d buttons", num_buttons); 964 break; 965 } 966 } 967 break; 968 } 969 #endif 970 if (local_num_buttons <= 0 ) { 971 if (aDevice->use == IsXPointer) { 972 for (clsIdx = 0; clsIdx < aDevice->num_classes; clsIdx++) { 973 if (aDevice->inputclassinfo[clsIdx].class == ButtonClass) { 974 bInfo = (XButtonInfo*)(&(aDevice->inputclassinfo[clsIdx])); 975 local_num_buttons = bInfo->num_buttons; 976 DTRACE_PRINTLN1("RobotPeer: XPointer has %d buttons", num_buttons); 977 break; 978 } 979 } 980 break; 981 } 982 } 983 } 984 985 XFreeDeviceList(devices); 986 } 987 else { 988 DTRACE_PRINTLN1("RobotPeer: XINPUT extension is unavailable, assuming %d mouse buttons", num_buttons); 989 } 990 if (local_num_buttons == 0 ) { 991 local_num_buttons = 3; 992 } 993 994 return local_num_buttons; 995 }