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