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