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