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