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