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