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