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