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