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
52uint32_t awt_NumLockMask = 0;
53Boolean  awt_ModLockIsShiftLock = False;
54
55static int32_t num_buttons = 0;
56int32_t getNumButtons();
57
58extern JavaVM *jvm;
59
60// Tracing level
61static 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
73struct ComponentIDs componentIDs;
74
75struct MenuComponentIDs menuComponentIDs;
76
77#ifndef HEADLESS
78
79extern Display* awt_init_Display(JNIEnv *env, jobject this);
80extern void freeNativeStringArray(char **array, jsize length);
81extern char** stringArrayToNative(JNIEnv *env, jobjectArray array, jsize * ret_length);
82
83struct XFontPeerIDs xFontPeerIDs;
84
85JNIEXPORT void JNICALL
86Java_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
97JNIEXPORT void JNICALL
98Java_java_awt_FileDialog_initIDs
99  (JNIEnv *env, jclass cls)
100{
101
102}
103
104JNIEXPORT void JNICALL
105Java_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 */
122JNIEXPORT 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 */
133JNIEXPORT 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
142JNIEXPORT 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
149JNIEXPORT jint JNICALL
150DEF_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 */
161JNIEXPORT 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
169JNIEXPORT void JNICALL
170Java_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
232JNIEXPORT void JNICALL
233Java_java_awt_Container_initIDs
234  (JNIEnv *env, jclass cls)
235{
236
237}
238
239
240JNIEXPORT void JNICALL
241Java_java_awt_Button_initIDs
242  (JNIEnv *env, jclass cls)
243{
244
245}
246
247JNIEXPORT void JNICALL
248Java_java_awt_Scrollbar_initIDs
249  (JNIEnv *env, jclass cls)
250{
251
252}
253
254
255JNIEXPORT void JNICALL
256Java_java_awt_Window_initIDs
257  (JNIEnv *env, jclass cls)
258{
259
260}
261
262JNIEXPORT void JNICALL
263Java_java_awt_Frame_initIDs
264  (JNIEnv *env, jclass cls)
265{
266
267}
268
269
270JNIEXPORT void JNICALL
271Java_java_awt_MenuComponent_initIDs(JNIEnv *env, jclass cls)
272{
273    menuComponentIDs.appContext =
274      (*env)->GetFieldID(env, cls, "appContext", "Lsun/awt/AppContext;");
275}
276
277JNIEXPORT void JNICALL
278Java_java_awt_Cursor_initIDs(JNIEnv *env, jclass cls)
279{
280}
281
282
283JNIEXPORT void JNICALL Java_java_awt_MenuItem_initIDs
284  (JNIEnv *env, jclass cls)
285{
286}
287
288
289JNIEXPORT void JNICALL Java_java_awt_Menu_initIDs
290  (JNIEnv *env, jclass cls)
291{
292}
293
294JNIEXPORT void JNICALL
295Java_java_awt_TextArea_initIDs
296  (JNIEnv *env, jclass cls)
297{
298}
299
300
301JNIEXPORT void JNICALL
302Java_java_awt_Checkbox_initIDs
303  (JNIEnv *env, jclass cls)
304{
305}
306
307
308JNIEXPORT void JNICALL Java_java_awt_ScrollPane_initIDs
309  (JNIEnv *env, jclass cls)
310{
311}
312
313JNIEXPORT void JNICALL
314Java_java_awt_TextField_initIDs
315  (JNIEnv *env, jclass cls)
316{
317}
318
319JNIEXPORT jboolean JNICALL AWTIsHeadless() {
320#ifdef HEADLESS
321    return JNI_TRUE;
322#else
323    return JNI_FALSE;
324#endif
325}
326
327JNIEXPORT 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
351static void     waitForEvents(JNIEnv *, jlong);
352static void     awt_pipe_init();
353static Boolean  performPoll(JNIEnv *, jlong);
354static void     wakeUp();
355static void     update_poll_timeout(int timeout_control);
356static 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
385static int          awt_poll_alg = AWT_POLL_AGING_SLOW;
386
387static uint32_t AWT_FLUSH_TIMEOUT  =  DEF_AWT_FLUSH_TIMEOUT; /* milliseconds */
388static uint32_t AWT_MAX_POLL_TIMEOUT = DEF_AWT_MAX_POLL_TIMEOUT; /* milliseconds */
389static pthread_t    awt_MainThread = 0;
390static int32_t      awt_pipe_fds[2];                   /* fds for wkaeup pipe */
391static Boolean      awt_pipe_inited = False;           /* make sure pipe is initialized before write */
392static jlong        awt_next_flush_time = 0LL; /* 0 == no scheduled flush */
393static jlong        awt_last_flush_time = 0LL; /* 0 == no scheduled flush */
394static uint32_t     curPollTimeout;
395static struct pollfd pollFds[2];
396static jlong        poll_sleep_time = 0LL; // Used for tracing
397static 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).
408static int32_t static_poll_timeout = 0;
409
410static 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 */
419static void
420awt_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 */
453static 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 */
512static jlong
513awtJNI_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 */
527static 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 */
568static 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 */
613void
614waitForEvents(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
625JNIEXPORT void JNICALL Java_sun_awt_X11_XToolkit_waitForEvents (JNIEnv *env, jclass class, jlong nextTaskTime) {
626    waitForEvents(env, nextTaskTime);
627}
628
629JNIEXPORT 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
636JNIEXPORT void JNICALL Java_sun_awt_X11_XToolkit_awt_1output_1flush (JNIEnv *env, jclass class) {
637    awt_output_flush();
638}
639
640JNIEXPORT 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 */
655static Boolean
656performPoll(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 */
720void 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 */
747static 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 */
762JNIEXPORT void JNICALL
763Java_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 */
773JNIEXPORT 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__
791void 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
810Window 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
853JNIEXPORT void JNICALL
854Java_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 */
898JNIEXPORT void JNICALL
899Java_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 */
957JNIEXPORT 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 */
967JNIEXPORT void JNICALL
968Java_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 */
986JNIEXPORT 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
994int32_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 */
1062JNIEXPORT 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 */
1078JNIEXPORT 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}
1091