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