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