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