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