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