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