1/*
2 * Copyright (c) 1997, 2019, 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 "jni_util.h"
27#include "awt_p.h"
28#include "awt.h"
29#include "color.h"
30#include <java_awt_DisplayMode.h>
31#include <sun_awt_X11GraphicsEnvironment.h>
32#include <sun_awt_X11GraphicsDevice.h>
33#include <sun_awt_X11GraphicsConfig.h>
34#ifndef HEADLESS
35#include <X11/extensions/Xdbe.h>
36#include <X11/XKBlib.h>
37#ifndef NO_XRANDR
38#include <X11/extensions/Xrandr.h>
39#endif
40#include "GLXGraphicsConfig.h"
41#endif /* !HEADLESS */
42
43#include <jni.h>
44#include <jni_util.h>
45#include <jvm.h>
46#include <jvm_md.h>
47#include <jlong.h>
48#include "systemScale.h"
49#include <stdlib.h>
50
51#include "awt_GraphicsEnv.h"
52#include "awt_util.h"
53#include "gdefs.h"
54#include <dlfcn.h>
55#include "Trace.h"
56
57#ifndef HEADLESS
58
59int awt_numScreens; /* Xinerama-aware number of screens */
60
61AwtScreenDataPtr x11Screens;
62
63/*
64 * Set in initDisplay() to indicate whether we should attempt to initialize
65 * GLX for the default configuration.
66 */
67static jboolean glxRequested = JNI_FALSE;
68
69#endif /* !HEADLESS */
70
71#ifdef HEADLESS
72#define Display void
73#endif /* HEADLESS */
74
75Display *awt_display;
76
77jclass tkClass = NULL;
78jmethodID awtLockMID = NULL;
79jmethodID awtUnlockMID = NULL;
80jmethodID awtWaitMID = NULL;
81jmethodID awtNotifyMID = NULL;
82jmethodID awtNotifyAllMID = NULL;
83jboolean awtLockInited = JNI_FALSE;
84
85/** Convenience macro for loading the lock-related method IDs. */
86#define GET_STATIC_METHOD(klass, method_id, method_name, method_sig) \
87 do { \
88 method_id = (*env)->GetStaticMethodID(env, klass, \
89 method_name, method_sig); \
90 if (method_id == NULL) return NULL; \
91 } while (0)
92
93struct X11GraphicsConfigIDs x11GraphicsConfigIDs;
94
95#ifndef HEADLESS
96int awtCreateX11Colormap(AwtGraphicsConfigDataPtr adata);
97#endif /* HEADLESS */
98
99static char *x11GraphicsConfigClassName = "sun/awt/X11GraphicsConfig";
100
101/* AWT and Xinerama
102 *
103 * As of fix 4356756, AWT is Xinerama-aware. X11GraphicsDevices are created for
104 * each screen of a Xinerama setup, though X11 itself still only sees a single
105 * display.
106 * In many places where we talk to X11, a xinawareScreen variable is used to
107 * pass the correct Display value, depending on the circumstances (a single
108 * X display, multiple X displays, or a single X display with multiple
109 * Xinerama screens).
110 */
111
112#define MAXFRAMEBUFFERS 16
113typedef struct {
114 int screen_number;
115 short x_org;
116 short y_org;
117 short width;
118 short height;
119} XineramaScreenInfo;
120
121typedef XineramaScreenInfo* XineramaQueryScreensFunc(Display*, int*);
122static XineramaQueryScreensFunc* XineramaQueryScreens = NULL;
123Bool usingXinerama = False;
124
125JNIEXPORT void JNICALL
126Java_sun_awt_X11GraphicsConfig_initIDs (JNIEnv *env, jclass cls)
127{
128 x11GraphicsConfigIDs.aData = NULL;
129 x11GraphicsConfigIDs.bitsPerPixel = NULL;
130
131 x11GraphicsConfigIDs.aData = (*env)->GetFieldID (env, cls, "aData", "J");
132 CHECK_NULL(x11GraphicsConfigIDs.aData);
133 x11GraphicsConfigIDs.bitsPerPixel = (*env)->GetFieldID (env, cls, "bitsPerPixel", "I");
134 CHECK_NULL(x11GraphicsConfigIDs.bitsPerPixel);
135}
136
137#ifndef HEADLESS
138
139/*
140 * XIOErrorHandler
141 */
142static int xioerror_handler(Display *disp)
143{
144 if (awtLockInited) {
145 if (errno == EPIPE) {
146 jio_fprintf(stderr, "X connection to %s host broken (explicit kill or server shutdown)\n", XDisplayName(NULL));
147 }
148 /*SignalError(lockedee->lastpc, lockedee, "fp/ade/gui/GUIException", "I/O error"); */
149 }
150 return 0;
151}
152
153static AwtGraphicsConfigDataPtr
154findWithTemplate(XVisualInfo *vinfo,
155 long mask)
156{
157
158 XVisualInfo *visualList;
159 XColor color;
160 AwtGraphicsConfigDataPtr defaultConfig;
161 int visualsMatched, i;
162
163 visualList = XGetVisualInfo(awt_display,
164 mask, vinfo, &visualsMatched);
165 if (visualList) {
166 int id = -1;
167 VisualID defaultVisual = XVisualIDFromVisual(DefaultVisual(awt_display, vinfo->screen));
168 defaultConfig = ZALLOC(_AwtGraphicsConfigData);
169 for (i = 0; i < visualsMatched; i++) {
170 memcpy(&defaultConfig->awt_visInfo, &visualList[i], sizeof(XVisualInfo));
171 defaultConfig->awt_depth = visualList[i].depth;
172
173 /* we can't use awtJNI_CreateColorData here, because it'll pull,
174 SystemColor, which in turn will cause toolkit to be reinitialized */
175 if (awtCreateX11Colormap(defaultConfig)) {
176 if (visualList[i].visualid == defaultVisual) {
177 id = i;
178 break;
179 } else if (-1 == id) {
180 // Keep 1st match for fallback
181 id = i;
182 }
183 }
184 }
185 if (-1 != id) {
186 memcpy(&defaultConfig->awt_visInfo, &visualList[id], sizeof(XVisualInfo));
187 defaultConfig->awt_depth = visualList[id].depth;
188 /* Allocate white and black pixels for this visual */
189 color.flags = DoRed | DoGreen | DoBlue;
190 color.red = color.green = color.blue = 0x0000;
191 XAllocColor(awt_display, defaultConfig->awt_cmap, &color);
192 x11Screens[visualList[id].screen].blackpixel = color.pixel;
193 color.flags = DoRed | DoGreen | DoBlue;
194 color.red = color.green = color.blue = 0xffff;
195 XAllocColor(awt_display, defaultConfig->awt_cmap, &color);
196 x11Screens[visualList[id].screen].whitepixel = color.pixel;
197
198 XFree(visualList);
199 return defaultConfig;
200 }
201 XFree(visualList);
202 free((void *)defaultConfig);
203 }
204 return NULL;
205}
206
207/* default config is based on X11 screen. All Xinerama screens of that X11
208 screen will have the same default config */
209/* Need more notes about which fields of the structure are based on the X
210 screen, and which are based on the Xinerama screen */
211static AwtGraphicsConfigDataPtr
212makeDefaultConfig(JNIEnv *env, int screen) {
213
214 AwtGraphicsConfigDataPtr defaultConfig;
215 int xinawareScreen = 0;
216 VisualID forcedVisualID = 0, defaultVisualID;
217 char *forcedVisualStr;
218 XVisualInfo vinfo;
219 long mask;
220
221 xinawareScreen = usingXinerama ? 0 : screen;
222 defaultVisualID =
223 XVisualIDFromVisual(DefaultVisual(awt_display, xinawareScreen));
224
225 memset(&vinfo, 0, sizeof(XVisualInfo));
226 vinfo.screen = xinawareScreen;
227
228 if ((forcedVisualStr = getenv("FORCEDEFVIS"))) {
229 mask = VisualIDMask | VisualScreenMask;
230 if (sscanf(forcedVisualStr, "%lx", &forcedVisualID) > 0 &&
231 forcedVisualID > 0)
232 {
233 vinfo.visualid = forcedVisualID;
234 } else {
235 vinfo.visualid = defaultVisualID;
236 }
237 } else {
238 VisualID bestGLXVisualID;
239 if (glxRequested &&
240 (bestGLXVisualID = GLXGC_FindBestVisual(env, xinawareScreen)) > 0)
241 {
242 /* we've found the best visual for use with GLX, so use it */
243 vinfo.visualid = bestGLXVisualID;
244 mask = VisualIDMask | VisualScreenMask;
245 } else {
246 /* otherwise, continue looking for the best X11 visual */
247 vinfo.depth = 24;
248 vinfo.class = TrueColor;
249 mask = VisualDepthMask | VisualScreenMask | VisualClassMask;
250 }
251 }
252
253 /* try the best, or forced visual */
254 defaultConfig = findWithTemplate(&vinfo, mask);
255 if (defaultConfig) {
256 return defaultConfig;
257 }
258
259 /* try the default visual */
260 vinfo.visualid = defaultVisualID;
261 mask = VisualIDMask | VisualScreenMask;
262 defaultConfig = findWithTemplate(&vinfo, mask);
263 if (defaultConfig) {
264 return defaultConfig;
265 }
266
267 /* try any TrueColor */
268 vinfo.class = TrueColor;
269 mask = VisualScreenMask | VisualClassMask;
270 defaultConfig = findWithTemplate(&vinfo, mask);
271 if (defaultConfig) {
272 return defaultConfig;
273 }
274
275 /* try 8-bit PseudoColor */
276 vinfo.depth = 8;
277 vinfo.class = PseudoColor;
278 mask = VisualDepthMask | VisualScreenMask | VisualClassMask;
279 defaultConfig = findWithTemplate(&vinfo, mask);
280 if (defaultConfig) {
281 return defaultConfig;
282 }
283
284 /* try any 8-bit */
285 vinfo.depth = 8;
286 mask = VisualDepthMask | VisualScreenMask;
287 defaultConfig = findWithTemplate(&vinfo, mask);
288 if (defaultConfig) {
289 return defaultConfig;
290 }
291
292 /* we tried everything, give up */
293 JNU_ThrowInternalError(env, "Can't find supported visual");
294 XCloseDisplay(awt_display);
295 awt_display = NULL;
296 return NULL;
297}
298
299static void
300getAllConfigs (JNIEnv *env, int screen, AwtScreenDataPtr screenDataPtr) {
301
302 int i;
303 int n8p=0, n12p=0, n8s=0, n8gs=0, n8sg=0, n1sg=0, nTrue=0;
304 int nConfig;
305 XVisualInfo *pVI8p, *pVI12p, *pVI8s, *pVITrue, *pVI8gs,
306 *pVI8sg, *pVI1sg = NULL, viTmp;
307 AwtGraphicsConfigDataPtr *graphicsConfigs;
308 AwtGraphicsConfigDataPtr defaultConfig;
309 int ind;
310 char errmsg[128];
311 int xinawareScreen;
312 void* xrenderLibHandle = NULL;
313 XRenderFindVisualFormatFunc* xrenderFindVisualFormat = NULL;
314 int major_opcode, first_event, first_error;
315
316 if (usingXinerama) {
317 xinawareScreen = 0;
318 }
319 else {
320 xinawareScreen = screen;
321 }
322
323 AWT_LOCK ();
324
325 viTmp.screen = xinawareScreen;
326
327 viTmp.depth = 8;
328 viTmp.class = PseudoColor;
329 viTmp.colormap_size = 256;
330 pVI8p = XGetVisualInfo (awt_display,
331 VisualDepthMask | VisualClassMask |
332 VisualColormapSizeMask | VisualScreenMask,
333 &viTmp, &n8p);
334
335 viTmp.depth = 12;
336 viTmp.class = PseudoColor;
337 viTmp.colormap_size = 4096;
338 pVI12p = XGetVisualInfo (awt_display,
339 VisualDepthMask | VisualClassMask |
340 VisualColormapSizeMask | VisualScreenMask,
341 &viTmp, &n12p);
342
343 viTmp.class = TrueColor;
344 pVITrue = XGetVisualInfo (awt_display,
345 VisualClassMask |
346 VisualScreenMask,
347 &viTmp, &nTrue);
348
349 viTmp.depth = 8;
350 viTmp.class = StaticColor;
351 pVI8s = XGetVisualInfo (awt_display, VisualDepthMask | VisualClassMask |
352 VisualScreenMask, &viTmp, &n8s);
353
354 viTmp.depth = 8;
355 viTmp.class = GrayScale;
356 viTmp.colormap_size = 256;
357 pVI8gs = XGetVisualInfo (awt_display,
358 VisualDepthMask | VisualClassMask |
359 VisualColormapSizeMask | VisualScreenMask,
360 &viTmp, &n8gs);
361 viTmp.depth = 8;
362 viTmp.class = StaticGray;
363 viTmp.colormap_size = 256;
364 pVI8sg = XGetVisualInfo (awt_display,
365 VisualDepthMask | VisualClassMask |
366 VisualColormapSizeMask | VisualScreenMask,
367 &viTmp, &n8sg);
368
369/* REMIND.. remove when we have support for the color classes below */
370/* viTmp.depth = 1; */
371/* viTmp.class = StaticGray; */
372/* pVI1sg = XGetVisualInfo (awt_display, VisualDepthMask | VisualClassMask, */
373/* viTmp, &n1sg); */
374
375 nConfig = n8p + n12p + n8s + n8gs + n8sg + n1sg + nTrue + 1;
376 graphicsConfigs = (AwtGraphicsConfigDataPtr *)
377 calloc(nConfig, sizeof(AwtGraphicsConfigDataPtr));
378 if (graphicsConfigs == NULL) {
379 JNU_ThrowOutOfMemoryError((JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2),
380 NULL);
381 AWT_UNLOCK();
382 return;
383 }
384
385 if (screenDataPtr->defaultConfig == NULL) {
386 /*
387 * After a display change event, the default config field will have
388 * been reset, so we need to recreate the default config here.
389 */
390 screenDataPtr->defaultConfig = makeDefaultConfig(env, screen);
391 }
392
393 defaultConfig = screenDataPtr->defaultConfig;
394 graphicsConfigs[0] = defaultConfig;
395 nConfig = 1; /* reserve index 0 for default config */
396
397 // Only use the RENDER extension if it is available on the X server
398 if (XQueryExtension(awt_display, "RENDER",
399 &major_opcode, &first_event, &first_error))
400 {
401 DTRACE_PRINTLN("RENDER extension available");
402 xrenderLibHandle = dlopen("libXrender.so.1", RTLD_LAZY | RTLD_GLOBAL);
403
404#ifdef MACOSX
405#define XRENDER_LIB "/usr/X11/lib/libXrender.dylib"
406#else
407#define XRENDER_LIB "libXrender.so"
408#endif
409
410 if (xrenderLibHandle == NULL) {
411 xrenderLibHandle = dlopen(XRENDER_LIB,
412 RTLD_LAZY | RTLD_GLOBAL);
413 }
414
415#if defined(__solaris__)
416 if (xrenderLibHandle == NULL) {
417 xrenderLibHandle = dlopen("/usr/lib/libXrender.so.1",
418 RTLD_LAZY | RTLD_GLOBAL);
419 }
420#elif defined(_AIX)
421 if (xrenderLibHandle == NULL) {
422 xrenderLibHandle = dlopen("libXrender.a(libXrender.so.0)",
423 RTLD_MEMBER | RTLD_LAZY | RTLD_GLOBAL);
424 }
425#endif
426 if (xrenderLibHandle != NULL) {
427 DTRACE_PRINTLN("Loaded libXrender");
428 xrenderFindVisualFormat =
429 (XRenderFindVisualFormatFunc*)dlsym(xrenderLibHandle,
430 "XRenderFindVisualFormat");
431 if (xrenderFindVisualFormat == NULL) {
432 DTRACE_PRINTLN1("Can't find 'XRenderFindVisualFormat' in libXrender (%s)", dlerror());
433 }
434 } else {
435 DTRACE_PRINTLN1("Can't load libXrender (%s)", dlerror());
436 }
437 } else {
438 DTRACE_PRINTLN("RENDER extension NOT available");
439 }
440
441 for (i = 0; i < nTrue; i++) {
442 if (XVisualIDFromVisual(pVITrue[i].visual) ==
443 XVisualIDFromVisual(defaultConfig->awt_visInfo.visual) ||
444 pVITrue[i].depth == 12) {
445 /* Skip the non-supported 12-bit TrueColor visual */
446 continue;
447 } else {
448 ind = nConfig++;
449 }
450 graphicsConfigs [ind] = ZALLOC (_AwtGraphicsConfigData);
451 graphicsConfigs [ind]->awt_depth = pVITrue [i].depth;
452 memcpy (&graphicsConfigs [ind]->awt_visInfo, &pVITrue [i],
453 sizeof (XVisualInfo));
454 if (xrenderFindVisualFormat != NULL) {
455 XRenderPictFormat *format = xrenderFindVisualFormat (awt_display,
456 pVITrue [i].visual);
457 if (format &&
458 format->type == PictTypeDirect &&
459 format->direct.alphaMask)
460 {
461 DTRACE_PRINTLN1("GraphicsConfig[%d] supports Translucency", ind);
462 graphicsConfigs [ind]->isTranslucencySupported = 1;
463 memcpy(&graphicsConfigs [ind]->renderPictFormat, format,
464 sizeof(*format));
465 } else {
466 DTRACE_PRINTLN1(format ?
467 "GraphicsConfig[%d] has no Translucency support" :
468 "Error calling 'XRenderFindVisualFormat'", ind);
469 }
470 }
471 }
472
473 if (xrenderLibHandle != NULL) {
474 dlclose(xrenderLibHandle);
475 xrenderLibHandle = NULL;
476 }
477
478 for (i = 0; i < n8p; i++) {
479 if (XVisualIDFromVisual(pVI8p[i].visual) ==
480 XVisualIDFromVisual(defaultConfig->awt_visInfo.visual)) {
481 continue;
482 } else {
483 ind = nConfig++;
484 }
485 graphicsConfigs [ind] = ZALLOC (_AwtGraphicsConfigData);
486 graphicsConfigs [ind]->awt_depth = pVI8p [i].depth;
487 memcpy (&graphicsConfigs [ind]->awt_visInfo, &pVI8p [i],
488 sizeof (XVisualInfo));
489 }
490
491 for (i = 0; i < n12p; i++) {
492 if (XVisualIDFromVisual(pVI12p[i].visual) ==
493 XVisualIDFromVisual(defaultConfig->awt_visInfo.visual)) {
494 continue;
495 } else {
496 ind = nConfig++;
497 }
498 graphicsConfigs [ind] = ZALLOC (_AwtGraphicsConfigData);
499 graphicsConfigs [ind]->awt_depth = pVI12p [i].depth;
500 memcpy (&graphicsConfigs [ind]->awt_visInfo, &pVI12p [i],
501 sizeof (XVisualInfo));
502 }
503
504 for (i = 0; i < n8s; i++) {
505 if (XVisualIDFromVisual(pVI8s[i].visual) ==
506 XVisualIDFromVisual(defaultConfig->awt_visInfo.visual)) {
507 continue;
508 } else {
509 ind = nConfig++;
510 }
511 graphicsConfigs [ind] = ZALLOC (_AwtGraphicsConfigData);
512 graphicsConfigs [ind]->awt_depth = pVI8s [i].depth;
513 memcpy (&graphicsConfigs [ind]->awt_visInfo, &pVI8s [i],
514 sizeof (XVisualInfo));
515 }
516
517 for (i = 0; i < n8gs; i++) {
518 if (XVisualIDFromVisual(pVI8gs[i].visual) ==
519 XVisualIDFromVisual(defaultConfig->awt_visInfo.visual)) {
520 continue;
521 } else {
522 ind = nConfig++;
523 }
524 graphicsConfigs [ind] = ZALLOC (_AwtGraphicsConfigData);
525 graphicsConfigs [ind]->awt_depth = pVI8gs [i].depth;
526 memcpy (&graphicsConfigs [ind]->awt_visInfo, &pVI8gs [i],
527 sizeof (XVisualInfo));
528 }
529
530 for (i = 0; i < n8sg; i++) {
531 if (XVisualIDFromVisual(pVI8sg[i].visual) ==
532 XVisualIDFromVisual(defaultConfig->awt_visInfo.visual)) {
533 continue;
534 } else {
535 ind = nConfig++;
536 }
537 graphicsConfigs [ind] = ZALLOC (_AwtGraphicsConfigData);
538 graphicsConfigs [ind]->awt_depth = pVI8sg [i].depth;
539 memcpy (&graphicsConfigs [ind]->awt_visInfo, &pVI8sg [i],
540 sizeof (XVisualInfo));
541 }
542
543 for (i = 0; i < n1sg; i++) {
544 if (XVisualIDFromVisual(pVI1sg[i].visual) ==
545 XVisualIDFromVisual(defaultConfig->awt_visInfo.visual)) {
546 continue;
547 } else {
548 ind = nConfig++;
549 }
550 graphicsConfigs [ind] = ZALLOC (_AwtGraphicsConfigData);
551 graphicsConfigs [ind]->awt_depth = pVI1sg [i].depth;
552 memcpy (&graphicsConfigs [ind]->awt_visInfo, &pVI1sg [i],
553 sizeof (XVisualInfo));
554 }
555
556 if (n8p != 0)
557 XFree (pVI8p);
558 if (n12p != 0)
559 XFree (pVI12p);
560 if (n8s != 0)
561 XFree (pVI8s);
562 if (n8gs != 0)
563 XFree (pVI8gs);
564 if (n8sg != 0)
565 XFree (pVI8sg);
566 if (n1sg != 0)
567 XFree (pVI1sg);
568
569 screenDataPtr->numConfigs = nConfig;
570 screenDataPtr->configs = graphicsConfigs;
571
572 AWT_UNLOCK ();
573}
574
575#ifndef HEADLESS
576
577/*
578 * Checks if Xinerama is running and perform Xinerama-related initialization.
579 */
580static void xineramaInit(void) {
581 char* XinExtName = "XINERAMA";
582 int32_t major_opcode, first_event, first_error;
583 Bool gotXinExt = False;
584 void* libHandle = NULL;
585 int32_t locNumScr = 0;
586 XineramaScreenInfo *xinInfo;
587 char* XineramaQueryScreensName = "XineramaQueryScreens";
588
589 gotXinExt = XQueryExtension(awt_display, XinExtName, &major_opcode,
590 &first_event, &first_error);
591
592 if (!gotXinExt) {
593 DTRACE_PRINTLN("Xinerama extension is not available");
594 return;
595 }
596
597 DTRACE_PRINTLN("Xinerama extension is available");
598
599 /* load library */
600 libHandle = dlopen(VERSIONED_JNI_LIB_NAME("Xinerama", "1"),
601 RTLD_LAZY | RTLD_GLOBAL);
602 if (libHandle == NULL) {
603#if defined(_AIX)
604 libHandle = dlopen("libXext.a(shr_64.o)", RTLD_MEMBER | RTLD_LAZY | RTLD_GLOBAL);
605#else
606 libHandle = dlopen(JNI_LIB_NAME("Xinerama"), RTLD_LAZY | RTLD_GLOBAL);
607#endif
608 }
609 if (libHandle != NULL) {
610 XineramaQueryScreens = (XineramaQueryScreensFunc*)
611 dlsym(libHandle, XineramaQueryScreensName);
612
613 if (XineramaQueryScreens == NULL) {
614 DTRACE_PRINTLN("couldn't load XineramaQueryScreens symbol");
615 dlclose(libHandle);
616 } else {
617 DTRACE_PRINTLN("calling XineramaQueryScreens func");
618 xinInfo = (*XineramaQueryScreens)(awt_display, &locNumScr);
619 if (xinInfo != NULL) {
620 if (locNumScr > XScreenCount(awt_display)) {
621 DTRACE_PRINTLN("Enabling Xinerama support");
622 usingXinerama = True;
623 /* set global number of screens */
624 DTRACE_PRINTLN1(" num screens = %i\n", locNumScr);
625 awt_numScreens = locNumScr;
626 } else {
627 DTRACE_PRINTLN("XineramaQueryScreens <= XScreenCount");
628 }
629 XFree(xinInfo);
630 } else {
631 DTRACE_PRINTLN("calling XineramaQueryScreens didn't work");
632 }
633 }
634 } else {
635 DTRACE_PRINTLN1("\ncouldn't open shared library: %s\n", dlerror());
636 }
637}
638#endif /* HEADLESS */
639
640Display *
641awt_init_Display(JNIEnv *env, jobject this)
642{
643 jclass klass;
644 Display *dpy;
645 char errmsg[128];
646 int i;
647
648 if (awt_display) {
649 return awt_display;
650 }
651
652 /* Load AWT lock-related methods in SunToolkit */
653 klass = (*env)->FindClass(env, "sun/awt/SunToolkit");
654 if (klass == NULL) return NULL;
655 GET_STATIC_METHOD(klass, awtLockMID, "awtLock", "()V");
656 GET_STATIC_METHOD(klass, awtUnlockMID, "awtUnlock", "()V");
657 GET_STATIC_METHOD(klass, awtWaitMID, "awtLockWait", "(J)V");
658 GET_STATIC_METHOD(klass, awtNotifyMID, "awtLockNotify", "()V");
659 GET_STATIC_METHOD(klass, awtNotifyAllMID, "awtLockNotifyAll", "()V");
660 tkClass = (*env)->NewGlobalRef(env, klass);
661 awtLockInited = JNI_TRUE;
662
663 if (getenv("_AWT_IGNORE_XKB") != NULL &&
664 strlen(getenv("_AWT_IGNORE_XKB")) > 0) {
665 if (XkbIgnoreExtension(True)) {
666 printf("Ignoring XKB.\n");
667 }
668 }
669
670 dpy = awt_display = XOpenDisplay(NULL);
671 if (!dpy) {
672 jio_snprintf(errmsg,
673 sizeof(errmsg),
674 "Can't connect to X11 window server using '%s' as the value of the DISPLAY variable.",
675 (getenv("DISPLAY") == NULL) ? ":0.0" : getenv("DISPLAY"));
676 JNU_ThrowByName(env, "java/awt/AWTError", errmsg);
677 return NULL;
678 }
679
680 XSetIOErrorHandler(xioerror_handler);
681 JNU_CallStaticMethodByName(env, NULL, "sun/awt/X11/XErrorHandlerUtil", "init", "(J)V",
682 ptr_to_jlong(awt_display));
683 JNU_CHECK_EXCEPTION_RETURN(env, NULL);
684
685 /* set awt_numScreens, and whether or not we're using Xinerama */
686 xineramaInit();
687
688 if (!usingXinerama) {
689 awt_numScreens = XScreenCount(awt_display);
690 }
691
692 DTRACE_PRINTLN1("allocating %i screens\n", awt_numScreens);
693 /* Allocate screen data structure array */
694 x11Screens = calloc(awt_numScreens, sizeof(AwtScreenData));
695 if (x11Screens == NULL) {
696 JNU_ThrowOutOfMemoryError((JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2),
697 NULL);
698 return NULL;
699 }
700
701 for (i = 0; i < awt_numScreens; i++) {
702 if (usingXinerama) {
703 /* All Xinerama screens use the same X11 root for now */
704 x11Screens[i].root = RootWindow(awt_display, 0);
705 }
706 else {
707 x11Screens[i].root = RootWindow(awt_display, i);
708 }
709 x11Screens[i].defaultConfig = makeDefaultConfig(env, i);
710 JNU_CHECK_EXCEPTION_RETURN(env, NULL);
711 }
712
713 return dpy;
714}
715#endif /* !HEADLESS */
716
717/*
718 * Class: sun_awt_X11GraphicsEnvironment
719 * Method: getDefaultScreenNum
720 * Signature: ()I
721 */
722JNIEXPORT jint JNICALL
723Java_sun_awt_X11GraphicsEnvironment_getDefaultScreenNum(
724JNIEnv *env, jobject this)
725{
726#ifdef HEADLESS
727 return (jint)0;
728#else
729 return DefaultScreen(awt_display);
730#endif /* !HEADLESS */
731}
732
733#ifndef HEADLESS
734static void ensureConfigsInited(JNIEnv* env, int screen) {
735 if (x11Screens[screen].numConfigs == 0) {
736 if (env == NULL) {
737 env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
738 }
739 getAllConfigs (env, screen, &(x11Screens[screen]));
740 }
741}
742#endif
743
744#ifdef HEADLESS
745void* getDefaultConfig(int screen) {
746 return NULL;
747}
748#else
749AwtGraphicsConfigDataPtr
750getDefaultConfig(int screen) {
751 ensureConfigsInited(NULL, screen);
752 return x11Screens[screen].defaultConfig;
753}
754
755AwtScreenDataPtr
756getScreenData(int screen) {
757 return &(x11Screens[screen]);
758}
759#endif /* !HEADLESS */
760
761/*
762 * Class: sun_awt_X11GraphicsEnvironment
763 * Method: initDisplay
764 * Signature: (Z)V
765 */
766JNIEXPORT void JNICALL
767Java_sun_awt_X11GraphicsEnvironment_initDisplay(JNIEnv *env, jobject this,
768 jboolean glxReq)
769{
770#ifndef HEADLESS
771 glxRequested = glxReq;
772 (void) awt_init_Display(env, this);
773#endif /* !HEADLESS */
774}
775
776/*
777 * Class: sun_awt_X11GraphicsEnvironment
778 * Method: initGLX
779 * Signature: ()Z
780 */
781JNIEXPORT jboolean JNICALL
782Java_sun_awt_X11GraphicsEnvironment_initGLX(JNIEnv *env, jclass x11ge)
783{
784#ifndef HEADLESS
785 jboolean glxAvailable;
786
787 AWT_LOCK();
788 glxAvailable = GLXGC_IsGLXAvailable();
789 AWT_UNLOCK();
790
791 return glxAvailable;
792#else
793 return JNI_FALSE;
794#endif /* !HEADLESS */
795}
796
797/*
798 * Class: sun_awt_X11GraphicsEnvironment
799 * Method: getNumScreens
800 * Signature: ()I
801 */
802JNIEXPORT jint JNICALL
803Java_sun_awt_X11GraphicsEnvironment_getNumScreens(JNIEnv *env, jobject this)
804{
805#ifdef HEADLESS
806 return (jint)0;
807#else
808 return awt_numScreens;
809#endif /* !HEADLESS */
810}
811
812/*
813 * Class: sun_awt_X11GraphicsDevice
814 * Method: getDisplay
815 * Signature: ()J
816 */
817JNIEXPORT jlong JNICALL
818Java_sun_awt_X11GraphicsDevice_getDisplay(JNIEnv *env, jobject this)
819{
820#ifdef HEADLESS
821 return NULL;
822#else
823 return ptr_to_jlong(awt_display);
824#endif /* !HEADLESS */
825}
826
827#ifdef MITSHM
828
829static jint canUseShmExt = UNSET_MITSHM;
830static jint canUseShmExtPixmaps = UNSET_MITSHM;
831static jboolean xshmAttachFailed = JNI_FALSE;
832
833int XShmAttachXErrHandler(Display *display, XErrorEvent *xerr) {
834 if (xerr->minor_code == X_ShmAttach) {
835 xshmAttachFailed = JNI_TRUE;
836 }
837 return 0;
838}
839jboolean isXShmAttachFailed() {
840 return xshmAttachFailed;
841}
842void resetXShmAttachFailed() {
843 xshmAttachFailed = JNI_FALSE;
844}
845
846extern int mitShmPermissionMask;
847
848void TryInitMITShm(JNIEnv *env, jint *shmExt, jint *shmPixmaps) {
849 XShmSegmentInfo shminfo;
850 int XShmMajor, XShmMinor;
851 int a, b, c;
852
853 AWT_LOCK();
854 if (canUseShmExt != UNSET_MITSHM) {
855 *shmExt = canUseShmExt;
856 *shmPixmaps = canUseShmExtPixmaps;
857 AWT_UNLOCK();
858 return;
859 }
860
861 *shmExt = canUseShmExt = CANT_USE_MITSHM;
862 *shmPixmaps = canUseShmExtPixmaps = CANT_USE_MITSHM;
863
864 if (awt_display == (Display *)NULL) {
865 AWT_NOFLUSH_UNLOCK();
866 return;
867 }
868
869 /**
870 * XShmQueryExtension returns False in remote server case.
871 * Unfortunately it also returns True in ssh case, so
872 * we need to test that we can actually do XShmAttach.
873 */
874 if (XShmQueryExtension(awt_display)) {
875 shminfo.shmid = shmget(IPC_PRIVATE, 0x10000,
876 IPC_CREAT|mitShmPermissionMask);
877 if (shminfo.shmid < 0) {
878 AWT_UNLOCK();
879 J2dRlsTraceLn1(J2D_TRACE_ERROR,
880 "TryInitMITShm: shmget has failed: %s",
881 strerror(errno));
882 return;
883 }
884 shminfo.shmaddr = (char *) shmat(shminfo.shmid, 0, 0);
885 if (shminfo.shmaddr == ((char *) -1)) {
886 shmctl(shminfo.shmid, IPC_RMID, 0);
887 AWT_UNLOCK();
888 J2dRlsTraceLn1(J2D_TRACE_ERROR,
889 "TryInitMITShm: shmat has failed: %s",
890 strerror(errno));
891 return;
892 }
893 shminfo.readOnly = True;
894
895 resetXShmAttachFailed();
896 /**
897 * The J2DXErrHandler handler will set xshmAttachFailed
898 * to JNI_TRUE if any Shm error has occured.
899 */
900 EXEC_WITH_XERROR_HANDLER(XShmAttachXErrHandler,
901 XShmAttach(awt_display, &shminfo));
902
903 /**
904 * Get rid of the id now to reduce chances of leaking
905 * system resources.
906 */
907 shmctl(shminfo.shmid, IPC_RMID, 0);
908
909 if (isXShmAttachFailed() == JNI_FALSE) {
910 canUseShmExt = CAN_USE_MITSHM;
911 /* check if we can use shared pixmaps */
912 XShmQueryVersion(awt_display, &XShmMajor, &XShmMinor,
913 (Bool*)&canUseShmExtPixmaps);
914 canUseShmExtPixmaps = canUseShmExtPixmaps &&
915 (XShmPixmapFormat(awt_display) == ZPixmap);
916 XShmDetach(awt_display, &shminfo);
917 }
918 shmdt(shminfo.shmaddr);
919 *shmExt = canUseShmExt;
920 *shmPixmaps = canUseShmExtPixmaps;
921 }
922 AWT_UNLOCK();
923}
924#endif /* MITSHM */
925
926/*
927 * Class: sun_awt_X11GraphicsEnvironment
928 * Method: checkShmExt
929 * Signature: ()I
930 */
931JNIEXPORT jint JNICALL
932Java_sun_awt_X11GraphicsEnvironment_checkShmExt(JNIEnv *env, jobject this)
933{
934
935 int shmExt = NOEXT_MITSHM, shmPixmaps;
936#ifdef MITSHM
937 TryInitMITShm(env, &shmExt, &shmPixmaps);
938#endif
939 return shmExt;
940}
941
942/*
943 * Class: sun_awt_X11GraphicsEnvironment
944 * Method: getDisplayString
945 * Signature: ()Ljava/lang/String
946 */
947JNIEXPORT jstring JNICALL
948Java_sun_awt_X11GraphicsEnvironment_getDisplayString
949 (JNIEnv *env, jobject this)
950{
951#ifdef HEADLESS
952 return (jstring)NULL;
953#else
954 return (*env)->NewStringUTF(env, DisplayString(awt_display));
955#endif /* HEADLESS */
956}
957
958
959/*
960 * Class: sun_awt_X11GraphicsDevice
961 * Method: getNumConfigs
962 * Signature: ()I
963 */
964JNIEXPORT jint JNICALL
965Java_sun_awt_X11GraphicsDevice_getNumConfigs(
966JNIEnv *env, jobject this, jint screen)
967{
968#ifdef HEADLESS
969 return (jint)0;
970#else
971 ensureConfigsInited(env, screen);
972 return x11Screens[screen].numConfigs;
973#endif /* !HEADLESS */
974}
975
976/*
977 * Class: sun_awt_X11GraphicsDevice
978 * Method: getConfigVisualId
979 * Signature: (I)I
980 */
981JNIEXPORT jint JNICALL
982Java_sun_awt_X11GraphicsDevice_getConfigVisualId(
983JNIEnv *env, jobject this, jint index, jint screen)
984{
985#ifdef HEADLESS
986 return (jint)0;
987#else
988 int visNum;
989
990 ensureConfigsInited(env, screen);
991 if (index == 0) {
992 return ((jint)x11Screens[screen].defaultConfig->awt_visInfo.visualid);
993 } else {
994 return ((jint)x11Screens[screen].configs[index]->awt_visInfo.visualid);
995 }
996#endif /* !HEADLESS */
997}
998
999/*
1000 * Class: sun_awt_X11GraphicsDevice
1001 * Method: getConfigDepth
1002 * Signature: (I)I
1003 */
1004JNIEXPORT jint JNICALL
1005Java_sun_awt_X11GraphicsDevice_getConfigDepth(
1006JNIEnv *env, jobject this, jint index, jint screen)
1007{
1008#ifdef HEADLESS
1009 return (jint)0;
1010#else
1011 int visNum;
1012
1013 ensureConfigsInited(env, screen);
1014 if (index == 0) {
1015 return ((jint)x11Screens[screen].defaultConfig->awt_visInfo.depth);
1016 } else {
1017 return ((jint)x11Screens[screen].configs[index]->awt_visInfo.depth);
1018 }
1019#endif /* !HEADLESS */
1020}
1021
1022/*
1023 * Class: sun_awt_X11GraphicsDevice
1024 * Method: getConfigColormap
1025 * Signature: (I)I
1026 */
1027JNIEXPORT jint JNICALL
1028Java_sun_awt_X11GraphicsDevice_getConfigColormap(
1029JNIEnv *env, jobject this, jint index, jint screen)
1030{
1031#ifdef HEADLESS
1032 return (jint)0;
1033#else
1034 int visNum;
1035
1036 ensureConfigsInited(env, screen);
1037 if (index == 0) {
1038 return ((jint)x11Screens[screen].defaultConfig->awt_cmap);
1039 } else {
1040 return ((jint)x11Screens[screen].configs[index]->awt_cmap);
1041 }
1042#endif /* !HEADLESS */
1043}
1044
1045/*
1046 * Class: sun_awt_X11GraphicsDevice
1047 * Method: resetNativeData
1048 * Signature: (I)V
1049 */
1050JNIEXPORT void JNICALL
1051Java_sun_awt_X11GraphicsDevice_resetNativeData
1052 (JNIEnv *env, jclass x11gd, jint screen)
1053{
1054#ifndef HEADLESS
1055 /*
1056 * Reset references to the various configs; the actual native config data
1057 * will be free'd later by the Disposer mechanism when the Java-level
1058 * X11GraphicsConfig objects go away. By setting these values to NULL,
1059 * we ensure that they will be reinitialized as necessary (for example,
1060 * see the getNumConfigs() method).
1061 */
1062 if (x11Screens[screen].configs) {
1063 free(x11Screens[screen].configs);
1064 x11Screens[screen].configs = NULL;
1065 }
1066 x11Screens[screen].defaultConfig = NULL;
1067 x11Screens[screen].numConfigs = 0;
1068#endif /* !HEADLESS */
1069}
1070
1071/*
1072 * Class: sun_awt_X11GraphicsConfig
1073 * Method: dispose
1074 * Signature: (J)V
1075 */
1076JNIEXPORT void JNICALL
1077Java_sun_awt_X11GraphicsConfig_dispose
1078 (JNIEnv *env, jclass x11gc, jlong configData)
1079{
1080#ifndef HEADLESS
1081 AwtGraphicsConfigDataPtr aData = (AwtGraphicsConfigDataPtr)
1082 jlong_to_ptr(configData);
1083
1084 if (aData == NULL) {
1085 return;
1086 }
1087
1088 AWT_LOCK();
1089 if (aData->awt_cmap) {
1090 XFreeColormap(awt_display, aData->awt_cmap);
1091 }
1092 if (aData->awtImage) {
1093 free(aData->awtImage);
1094 }
1095 if (aData->monoImage) {
1096 XFree(aData->monoImage);
1097 }
1098 if (aData->monoPixmap) {
1099 XFreePixmap(awt_display, aData->monoPixmap);
1100 }
1101 if (aData->monoPixmapGC) {
1102 XFreeGC(awt_display, aData->monoPixmapGC);
1103 }
1104 if (aData->color_data) {
1105 free(aData->color_data);
1106 }
1107 AWT_UNLOCK();
1108
1109 if (aData->glxInfo) {
1110 /*
1111 * The native GLXGraphicsConfig data needs to be disposed separately
1112 * on the OGL queue flushing thread (should not be called while
1113 * the AWT lock is held).
1114 */
1115 JNU_CallStaticMethodByName(env, NULL,
1116 "sun/java2d/opengl/OGLRenderQueue",
1117 "disposeGraphicsConfig", "(J)V",
1118 ptr_to_jlong(aData->glxInfo));
1119 }
1120
1121 free(aData);
1122#endif /* !HEADLESS */
1123}
1124
1125/*
1126 * Class: sun_awt_X11GraphicsConfig
1127 * Method: getXResolution
1128 * Signature: ()I
1129 */
1130JNIEXPORT jdouble JNICALL
1131Java_sun_awt_X11GraphicsConfig_getXResolution(
1132JNIEnv *env, jobject this, jint screen)
1133{
1134#ifdef HEADLESS
1135 return (jdouble)0;
1136#else
1137 return ((DisplayWidth(awt_display, screen) * 25.4) /
1138 DisplayWidthMM(awt_display, screen));
1139#endif /* !HEADLESS */
1140}
1141
1142/*
1143 * Class: sun_awt_X11GraphicsConfig
1144 * Method: getYResolution
1145 * Signature: ()I
1146 */
1147JNIEXPORT jdouble JNICALL
1148Java_sun_awt_X11GraphicsConfig_getYResolution(
1149JNIEnv *env, jobject this, jint screen)
1150{
1151#ifdef HEADLESS
1152 return (jdouble)0;
1153#else
1154 return ((DisplayHeight(awt_display, screen) * 25.4) /
1155 DisplayHeightMM(awt_display, screen));
1156#endif /* !HEADLESS */
1157}
1158
1159
1160/*
1161 * Class: sun_awt_X11GraphicsConfig
1162 * Method: getNumColors
1163 * Signature: ()I
1164 */
1165JNIEXPORT jint JNICALL
1166Java_sun_awt_X11GraphicsConfig_getNumColors(
1167JNIEnv *env, jobject this)
1168{
1169#ifdef HEADLESS
1170 return (jint)0;
1171#else
1172 AwtGraphicsConfigData *adata;
1173
1174 adata = (AwtGraphicsConfigData *) JNU_GetLongFieldAsPtr(env, this,
1175 x11GraphicsConfigIDs.aData);
1176
1177 return adata->awt_num_colors;
1178#endif /* !HEADLESS */
1179}
1180
1181/*
1182 * Class: sun_awt_X11GraphicsConfig
1183 * Method: init
1184 * Signature: (I)V
1185 */
1186JNIEXPORT void JNICALL
1187Java_sun_awt_X11GraphicsConfig_init(
1188JNIEnv *env, jobject this, jint visualNum, jint screen)
1189{
1190#ifndef HEADLESS
1191 AwtGraphicsConfigData *adata = NULL;
1192 AwtScreenData asd = x11Screens[screen];
1193 int i, n;
1194 int depth;
1195 XImage * tempImage;
1196
1197 /* If haven't gotten all of the configs yet, do it now. */
1198 if (asd.numConfigs == 0) {
1199 getAllConfigs (env, screen, &asd);
1200 }
1201
1202 /* Check the graphicsConfig for this visual */
1203 for (i = 0; i < asd.numConfigs; i++) {
1204 AwtGraphicsConfigDataPtr agcPtr = asd.configs[i];
1205 if ((jint)agcPtr->awt_visInfo.visualid == visualNum) {
1206 adata = agcPtr;
1207 break;
1208 }
1209 }
1210
1211 /* If didn't find the visual, throw an exception... */
1212 if (adata == (AwtGraphicsConfigData *) NULL) {
1213 JNU_ThrowIllegalArgumentException(env, "Unknown Visual Specified");
1214 return;
1215 }
1216
1217 /* adata->awt_cmap initialization has been deferred to
1218 * makeColorModel call
1219 */
1220
1221 JNU_SetLongFieldFromPtr(env, this, x11GraphicsConfigIDs.aData, adata);
1222
1223 depth = adata->awt_visInfo.depth;
1224 tempImage = XCreateImage(awt_display,
1225 adata->awt_visInfo.visual,
1226 depth, ZPixmap, 0, NULL, 1, 1, 32, 0);
1227 adata->pixelStride = (tempImage->bits_per_pixel + 7) / 8;
1228 (*env)->SetIntField(env, this, x11GraphicsConfigIDs.bitsPerPixel,
1229 (jint)tempImage->bits_per_pixel);
1230 XDestroyImage(tempImage);
1231#endif /* !HEADLESS */
1232}
1233
1234
1235
1236/*
1237 * Class: sun_awt_X11GraphicsConfig
1238 * Method: makeColorModel
1239 * Signature: ()Ljava/awt/image/ColorModel
1240 */
1241JNIEXPORT jobject JNICALL
1242Java_sun_awt_X11GraphicsConfig_makeColorModel(
1243JNIEnv *env, jobject this)
1244{
1245#ifdef HEADLESS
1246 return NULL;
1247#else
1248 AwtGraphicsConfigData *adata;
1249 jobject colorModel;
1250
1251 /*
1252 * If awt is not locked yet, return null since the toolkit is not
1253 * initialized yet.
1254 */
1255 if (!awtLockInited) {
1256 return NULL;
1257 }
1258
1259 AWT_LOCK ();
1260
1261 adata = (AwtGraphicsConfigData *) JNU_GetLongFieldAsPtr(env, this,
1262 x11GraphicsConfigIDs.aData);
1263
1264 /* If colormap entry of adata is NULL, need to create it now */
1265 if (adata->awt_cmap == (Colormap) NULL) {
1266 awtJNI_CreateColorData (env, adata, 1);
1267 }
1268
1269 /* Make Color Model object for this GraphicsConfiguration */
1270 colorModel = (*env)->ExceptionCheck(env)
1271 ? NULL : awtJNI_GetColorModel (env, adata);
1272
1273 AWT_UNLOCK ();
1274
1275 return colorModel;
1276#endif /* !HEADLESS */
1277}
1278
1279
1280/*
1281 * Class: sun_awt_X11GraphicsConfig
1282 * Method: getBounds
1283 * Signature: ()Ljava/awt/Rectangle
1284 */
1285JNIEXPORT jobject JNICALL
1286Java_sun_awt_X11GraphicsConfig_pGetBounds(JNIEnv *env, jobject this, jint screen)
1287{
1288#ifdef HEADLESS
1289 return NULL;
1290#else
1291 jclass clazz;
1292 jmethodID mid;
1293 jobject bounds = NULL;
1294 AwtGraphicsConfigDataPtr adata;
1295 int32_t locNumScr = 0;
1296 XineramaScreenInfo *xinInfo;
1297
1298 adata = (AwtGraphicsConfigDataPtr)
1299 JNU_GetLongFieldAsPtr(env, this, x11GraphicsConfigIDs.aData);
1300
1301 clazz = (*env)->FindClass(env, "java/awt/Rectangle");
1302 CHECK_NULL_RETURN(clazz, NULL);
1303 mid = (*env)->GetMethodID(env, clazz, "<init>", "(IIII)V");
1304 if (mid != NULL) {
1305 if (usingXinerama) {
1306 if (0 <= screen && screen < awt_numScreens) {
1307 AWT_LOCK();
1308 xinInfo = (*XineramaQueryScreens)(awt_display, &locNumScr);
1309 AWT_UNLOCK();
1310 if (xinInfo != NULL && locNumScr > 0) {
1311 if (screen >= locNumScr) {
1312 screen = 0; // fallback to the main screen
1313 }
1314 DASSERT(xinInfo[screen].screen_number == screen);
1315 bounds = (*env)->NewObject(env, clazz, mid,
1316 xinInfo[screen].x_org,
1317 xinInfo[screen].y_org,
1318 xinInfo[screen].width,
1319 xinInfo[screen].height);
1320 XFree(xinInfo);
1321 }
1322 } else {
1323 jclass exceptionClass = (*env)->FindClass(env, "java/lang/IllegalArgumentException");
1324 if (exceptionClass != NULL) {
1325 (*env)->ThrowNew(env, exceptionClass, "Illegal screen index");
1326 }
1327 }
1328 }
1329 if (!bounds) {
1330 // Xinerama cannot provide correct bounds, will try X11
1331 XWindowAttributes xwa;
1332 memset(&xwa, 0, sizeof(xwa));
1333
1334 AWT_LOCK ();
1335 XGetWindowAttributes(awt_display,
1336 RootWindow(awt_display, adata->awt_visInfo.screen),
1337 &xwa);
1338 AWT_UNLOCK ();
1339
1340 bounds = (*env)->NewObject(env, clazz, mid, 0, 0,
1341 xwa.width, xwa.height);
1342 }
1343
1344 if ((*env)->ExceptionOccurred(env)) {
1345 return NULL;
1346 }
1347 }
1348 return bounds;
1349#endif /* !HEADLESS */
1350}
1351
1352/*
1353 * Class: sun_awt_X11GraphicsConfig
1354 * Method: createBackBuffer
1355 * Signature: (JI)J
1356 */
1357JNIEXPORT jlong JNICALL
1358Java_sun_awt_X11GraphicsConfig_createBackBuffer
1359 (JNIEnv *env, jobject this, jlong window, jint swapAction)
1360{
1361 int32_t v1, v2;
1362 XdbeBackBuffer ret = (unsigned long) 0;
1363 Window w = (Window)window;
1364 AWT_LOCK();
1365 if (!XdbeQueryExtension(awt_display, &v1, &v2)) {
1366 JNU_ThrowByName(env, "java/lang/Exception",
1367 "Could not query double-buffer extension");
1368 AWT_UNLOCK();
1369 return (jlong)0;
1370 }
1371 ret = XdbeAllocateBackBufferName(awt_display, w,
1372 (XdbeSwapAction)swapAction);
1373 AWT_FLUSH_UNLOCK();
1374 return (jlong)ret;
1375}
1376
1377/*
1378 * Class: sun_awt_X11GraphicsConfig
1379 * Method: destroyBackBuffer
1380 * Signature: (J)V
1381 */
1382JNIEXPORT void JNICALL
1383Java_sun_awt_X11GraphicsConfig_destroyBackBuffer
1384 (JNIEnv *env, jobject this, jlong backBuffer)
1385{
1386 AWT_LOCK();
1387 XdbeDeallocateBackBufferName(awt_display, (XdbeBackBuffer)backBuffer);
1388 AWT_FLUSH_UNLOCK();
1389}
1390
1391/*
1392 * Class: sun_awt_X11GraphicsConfig
1393 * Method: swapBuffers
1394 * Signature: (JI)V
1395 */
1396JNIEXPORT void JNICALL
1397Java_sun_awt_X11GraphicsConfig_swapBuffers
1398 (JNIEnv *env, jobject this,
1399 jlong window, jint swapAction)
1400{
1401 XdbeSwapInfo swapInfo;
1402
1403 AWT_LOCK();
1404
1405 XdbeBeginIdiom(awt_display);
1406 swapInfo.swap_window = (Window)window;
1407 swapInfo.swap_action = (XdbeSwapAction)swapAction;
1408 if (!XdbeSwapBuffers(awt_display, &swapInfo, 1)) {
1409 JNU_ThrowInternalError(env, "Could not swap buffers");
1410 }
1411 XdbeEndIdiom(awt_display);
1412
1413 AWT_FLUSH_UNLOCK();
1414}
1415
1416/*
1417 * Class: sun_awt_X11GraphicsConfig
1418 * Method: isTranslucencyCapable
1419 * Signature: (J)V
1420 */
1421JNIEXPORT jboolean JNICALL
1422Java_sun_awt_X11GraphicsConfig_isTranslucencyCapable
1423 (JNIEnv *env, jobject this, jlong configData)
1424{
1425#ifdef HEADLESS
1426 return JNI_FALSE;
1427#else
1428 AwtGraphicsConfigDataPtr aData = (AwtGraphicsConfigDataPtr)jlong_to_ptr(configData);
1429 if (aData == NULL) {
1430 return JNI_FALSE;
1431 }
1432 return aData->isTranslucencySupported ? JNI_TRUE : JNI_FALSE;
1433#endif
1434}
1435
1436/*
1437 * Class: sun_awt_X11GraphicsDevice
1438 * Method: isDBESupported
1439 * Signature: ()Z
1440 */
1441JNIEXPORT jboolean JNICALL
1442Java_sun_awt_X11GraphicsDevice_isDBESupported(JNIEnv *env, jobject this)
1443{
1444#ifdef HEADLESS
1445 return JNI_FALSE;
1446#else
1447 int opcode = 0, firstEvent = 0, firstError = 0;
1448 jboolean ret;
1449
1450 AWT_LOCK();
1451 ret = (jboolean)XQueryExtension(awt_display, "DOUBLE-BUFFER",
1452 &opcode, &firstEvent, &firstError);
1453 AWT_FLUSH_UNLOCK();
1454 return ret;
1455#endif /* !HEADLESS */
1456}
1457
1458/*
1459 * Class: sun_awt_X11GraphicsDevice
1460 * Method: getDoubleBufferVisuals
1461 * Signature: (I)V
1462 */
1463JNIEXPORT void JNICALL
1464Java_sun_awt_X11GraphicsDevice_getDoubleBufferVisuals(JNIEnv *env,
1465 jobject this, jint screen)
1466{
1467#ifndef HEADLESS
1468 jclass clazz;
1469 jmethodID midAddVisual;
1470 Window rootWindow;
1471 int i, n = 1;
1472 XdbeScreenVisualInfo* visScreenInfo;
1473 int xinawareScreen;
1474
1475 if (usingXinerama) {
1476 xinawareScreen = 0;
1477 }
1478 else {
1479 xinawareScreen = screen;
1480 }
1481
1482 clazz = (*env)->GetObjectClass(env, this);
1483 midAddVisual = (*env)->GetMethodID(env, clazz, "addDoubleBufferVisual",
1484 "(I)V");
1485 CHECK_NULL(midAddVisual);
1486 AWT_LOCK();
1487 rootWindow = RootWindow(awt_display, xinawareScreen);
1488 visScreenInfo = XdbeGetVisualInfo(awt_display, &rootWindow, &n);
1489 if (visScreenInfo == NULL) {
1490 JNU_ThrowInternalError(env, "Could not get visual info");
1491 AWT_UNLOCK();
1492 return;
1493 }
1494 AWT_FLUSH_UNLOCK();
1495 for (i = 0; i < visScreenInfo->count; i++) {
1496 XdbeVisualInfo* visInfo = visScreenInfo->visinfo;
1497 (*env)->CallVoidMethod(env, this, midAddVisual, (visInfo[i]).visual);
1498 if ((*env)->ExceptionCheck(env)) {
1499 break;
1500 }
1501 }
1502#endif /* !HEADLESS */
1503}
1504
1505/*
1506 * Class: sun_awt_X11GraphicsEnvironment
1507 * Method: pRunningXinerama
1508 * Signature: ()Z
1509 */
1510JNIEXPORT jboolean JNICALL
1511Java_sun_awt_X11GraphicsEnvironment_pRunningXinerama(JNIEnv *env,
1512 jobject this)
1513{
1514#ifdef HEADLESS
1515 return JNI_FALSE;
1516#else
1517 return usingXinerama ? JNI_TRUE : JNI_FALSE;
1518#endif /* HEADLESS */
1519}
1520
1521/**
1522 * Begin DisplayMode/FullScreen support
1523 */
1524
1525#ifndef HEADLESS
1526
1527#ifndef NO_XRANDR
1528
1529#define BIT_DEPTH_MULTI java_awt_DisplayMode_BIT_DEPTH_MULTI
1530#define REFRESH_RATE_UNKNOWN java_awt_DisplayMode_REFRESH_RATE_UNKNOWN
1531
1532typedef Status
1533 (*XRRQueryVersionType) (Display *dpy, int *major_versionp, int *minor_versionp);
1534typedef XRRScreenConfiguration*
1535 (*XRRGetScreenInfoType)(Display *dpy, Drawable root);
1536typedef void
1537 (*XRRFreeScreenConfigInfoType)(XRRScreenConfiguration *config);
1538typedef short*
1539 (*XRRConfigRatesType)(XRRScreenConfiguration *config,
1540 int sizeID, int *nrates);
1541typedef short
1542 (*XRRConfigCurrentRateType)(XRRScreenConfiguration *config);
1543typedef XRRScreenSize*
1544 (*XRRConfigSizesType)(XRRScreenConfiguration *config,
1545 int *nsizes);
1546typedef SizeID
1547 (*XRRConfigCurrentConfigurationType)(XRRScreenConfiguration *config,
1548 Rotation *rotation);
1549typedef Status
1550 (*XRRSetScreenConfigAndRateType)(Display *dpy,
1551 XRRScreenConfiguration *config,
1552 Drawable draw,
1553 int size_index,
1554 Rotation rotation,
1555 short rate,
1556 Time timestamp);
1557typedef Rotation
1558 (*XRRConfigRotationsType)(XRRScreenConfiguration *config,
1559 Rotation *current_rotation);
1560
1561typedef XRRScreenResources* (*XRRGetScreenResourcesType)(Display *dpy,
1562 Window window);
1563
1564typedef void (*XRRFreeScreenResourcesType)(XRRScreenResources *resources);
1565
1566typedef XRROutputInfo * (*XRRGetOutputInfoType)(Display *dpy,
1567 XRRScreenResources *resources, RROutput output);
1568
1569typedef void (*XRRFreeOutputInfoType)(XRROutputInfo *outputInfo);
1570
1571typedef XRRCrtcInfo* (*XRRGetCrtcInfoType)(Display *dpy,
1572 XRRScreenResources *resources, RRCrtc crtc);
1573
1574typedef void (*XRRFreeCrtcInfoType)(XRRCrtcInfo *crtcInfo);
1575
1576static XRRQueryVersionType awt_XRRQueryVersion;
1577static XRRGetScreenInfoType awt_XRRGetScreenInfo;
1578static XRRFreeScreenConfigInfoType awt_XRRFreeScreenConfigInfo;
1579static XRRConfigRatesType awt_XRRConfigRates;
1580static XRRConfigCurrentRateType awt_XRRConfigCurrentRate;
1581static XRRConfigSizesType awt_XRRConfigSizes;
1582static XRRConfigCurrentConfigurationType awt_XRRConfigCurrentConfiguration;
1583static XRRSetScreenConfigAndRateType awt_XRRSetScreenConfigAndRate;
1584static XRRConfigRotationsType awt_XRRConfigRotations;
1585static XRRGetScreenResourcesType awt_XRRGetScreenResources;
1586static XRRFreeScreenResourcesType awt_XRRFreeScreenResources;
1587static XRRGetOutputInfoType awt_XRRGetOutputInfo;
1588static XRRFreeOutputInfoType awt_XRRFreeOutputInfo;
1589static XRRGetCrtcInfoType awt_XRRGetCrtcInfo;
1590static XRRFreeCrtcInfoType awt_XRRFreeCrtcInfo;
1591
1592#define LOAD_XRANDR_FUNC(f) \
1593 do { \
1594 awt_##f = (f##Type)dlsym(pLibRandR, #f); \
1595 if (awt_##f == NULL) { \
1596 J2dRlsTraceLn1(J2D_TRACE_ERROR, \
1597 "X11GD_InitXrandrFuncs: Could not load %s", #f); \
1598 dlclose(pLibRandR); \
1599 return JNI_FALSE; \
1600 } \
1601 } while (0)
1602
1603static jboolean
1604X11GD_InitXrandrFuncs(JNIEnv *env)
1605{
1606 int rr_maj_ver = 0, rr_min_ver = 0;
1607
1608 void *pLibRandR = dlopen(VERSIONED_JNI_LIB_NAME("Xrandr", "2"),
1609 RTLD_LAZY | RTLD_LOCAL);
1610 if (pLibRandR == NULL) {
1611 pLibRandR = dlopen(JNI_LIB_NAME("Xrandr"), RTLD_LAZY | RTLD_LOCAL);
1612 }
1613 if (pLibRandR == NULL) {
1614 J2dRlsTraceLn(J2D_TRACE_ERROR,
1615 "X11GD_InitXrandrFuncs: Could not open libXrandr.so.2");
1616 return JNI_FALSE;
1617 }
1618
1619 LOAD_XRANDR_FUNC(XRRQueryVersion);
1620
1621 if (!(*awt_XRRQueryVersion)(awt_display, &rr_maj_ver, &rr_min_ver)) {
1622 J2dRlsTraceLn(J2D_TRACE_ERROR,
1623 "X11GD_InitXrandrFuncs: XRRQueryVersion returned an error status");
1624 dlclose(pLibRandR);
1625 return JNI_FALSE;
1626 }
1627
1628 if (usingXinerama) {
1629 /*
1630 * We can proceed as long as this is RANDR 1.2 or above.
1631 * As of Xorg server 1.3 onwards the Xinerama backend may actually be
1632 * a fake one provided by RANDR itself. See Java bug 6636469 for info.
1633 */
1634 if (!(rr_maj_ver > 1 || (rr_maj_ver == 1 && rr_min_ver >= 2))) {
1635 J2dRlsTraceLn2(J2D_TRACE_INFO, "X11GD_InitXrandrFuncs: Can't use Xrandr. "
1636 "Xinerama is active and Xrandr version is %d.%d",
1637 rr_maj_ver, rr_min_ver);
1638 dlclose(pLibRandR);
1639 return JNI_FALSE;
1640 }
1641
1642 /*
1643 * REMIND: Fullscreen mode doesn't work quite right with multi-monitor
1644 * setups and RANDR 1.2.
1645 */
1646 if ((rr_maj_ver == 1 && rr_min_ver <= 2) && awt_numScreens > 1) {
1647 J2dRlsTraceLn(J2D_TRACE_INFO, "X11GD_InitXrandrFuncs: Can't use Xrandr. "
1648 "Multiple screens in use");
1649 dlclose(pLibRandR);
1650 return JNI_FALSE;
1651 }
1652 }
1653
1654 LOAD_XRANDR_FUNC(XRRGetScreenInfo);
1655 LOAD_XRANDR_FUNC(XRRFreeScreenConfigInfo);
1656 LOAD_XRANDR_FUNC(XRRConfigRates);
1657 LOAD_XRANDR_FUNC(XRRConfigCurrentRate);
1658 LOAD_XRANDR_FUNC(XRRConfigSizes);
1659 LOAD_XRANDR_FUNC(XRRConfigCurrentConfiguration);
1660 LOAD_XRANDR_FUNC(XRRSetScreenConfigAndRate);
1661 LOAD_XRANDR_FUNC(XRRConfigRotations);
1662 LOAD_XRANDR_FUNC(XRRGetScreenResources);
1663 LOAD_XRANDR_FUNC(XRRFreeScreenResources);
1664 LOAD_XRANDR_FUNC(XRRGetOutputInfo);
1665 LOAD_XRANDR_FUNC(XRRFreeOutputInfo);
1666 LOAD_XRANDR_FUNC(XRRGetCrtcInfo);
1667 LOAD_XRANDR_FUNC(XRRFreeCrtcInfo);
1668
1669 return JNI_TRUE;
1670}
1671
1672static jobject
1673X11GD_CreateDisplayMode(JNIEnv *env, jint width, jint height,
1674 jint bitDepth, jint refreshRate)
1675{
1676 jclass displayModeClass;
1677 jmethodID cid;
1678 jint validRefreshRate = refreshRate;
1679
1680 displayModeClass = (*env)->FindClass(env, "java/awt/DisplayMode");
1681 CHECK_NULL_RETURN(displayModeClass, NULL);
1682 if (JNU_IsNull(env, displayModeClass)) {
1683 JNU_ThrowInternalError(env,
1684 "Could not get display mode class");
1685 return NULL;
1686 }
1687
1688 cid = (*env)->GetMethodID(env, displayModeClass, "<init>", "(IIII)V");
1689 CHECK_NULL_RETURN(cid, NULL);
1690 if (cid == NULL) {
1691 JNU_ThrowInternalError(env,
1692 "Could not get display mode constructor");
1693 return NULL;
1694 }
1695
1696 // early versions of xrandr may report "empty" rates (6880694)
1697 if (validRefreshRate <= 0) {
1698 validRefreshRate = REFRESH_RATE_UNKNOWN;
1699 }
1700
1701 return (*env)->NewObject(env, displayModeClass, cid,
1702 width, height, bitDepth, validRefreshRate);
1703}
1704
1705static void
1706X11GD_AddDisplayMode(JNIEnv *env, jobject arrayList,
1707 jint width, jint height,
1708 jint bitDepth, jint refreshRate)
1709{
1710 jobject displayMode = X11GD_CreateDisplayMode(env, width, height,
1711 bitDepth, refreshRate);
1712 if (!JNU_IsNull(env, displayMode)) {
1713 jclass arrayListClass;
1714 jmethodID mid;
1715 arrayListClass = (*env)->GetObjectClass(env, arrayList);
1716 if (JNU_IsNull(env, arrayListClass)) {
1717 JNU_ThrowInternalError(env,
1718 "Could not get class java.util.ArrayList");
1719 return;
1720 }
1721 mid = (*env)->GetMethodID(env, arrayListClass, "add",
1722 "(Ljava/lang/Object;)Z");
1723 CHECK_NULL(mid);
1724 if (mid == NULL) {
1725 JNU_ThrowInternalError(env,
1726 "Could not get method java.util.ArrayList.add()");
1727 return;
1728 }
1729 (*env)->CallObjectMethod(env, arrayList, mid, displayMode);
1730 (*env)->DeleteLocalRef(env, displayMode);
1731 }
1732}
1733
1734#endif /* !NO_XRANDR */
1735
1736static void
1737X11GD_SetFullscreenMode(Window win, jboolean enabled)
1738{
1739 Atom wmState = XInternAtom(awt_display, "_NET_WM_STATE", False);
1740 Atom wmStateFs = XInternAtom(awt_display,
1741 "_NET_WM_STATE_FULLSCREEN", False);
1742 XWindowAttributes attr;
1743 XEvent event;
1744
1745 if (wmState == None || wmStateFs == None
1746 || !XGetWindowAttributes(awt_display, win, &attr)) {
1747 return;
1748 }
1749
1750 memset(&event, 0, sizeof(event));
1751 event.xclient.type = ClientMessage;
1752 event.xclient.message_type = wmState;
1753 event.xclient.display = awt_display;
1754 event.xclient.window = win;
1755 event.xclient.format = 32;
1756 event.xclient.data.l[0] = enabled ? 1 : 0; // 1==add, 0==remove
1757 event.xclient.data.l[1] = wmStateFs;
1758
1759 XSendEvent(awt_display, attr.root, False,
1760 SubstructureRedirectMask | SubstructureNotifyMask,
1761 &event);
1762 XSync(awt_display, False);
1763}
1764#endif /* !HEADLESS */
1765
1766/*
1767 * Class: sun_awt_X11GraphicsDevice
1768 * Method: initXrandrExtension
1769 * Signature: ()Z
1770 */
1771JNIEXPORT jboolean JNICALL
1772Java_sun_awt_X11GraphicsDevice_initXrandrExtension
1773 (JNIEnv *env, jclass x11gd)
1774{
1775#if defined(HEADLESS) || defined(NO_XRANDR)
1776 return JNI_FALSE;
1777#else
1778 int opcode = 0, firstEvent = 0, firstError = 0;
1779 jboolean ret;
1780
1781 AWT_LOCK();
1782 ret = (jboolean)XQueryExtension(awt_display, "RANDR",
1783 &opcode, &firstEvent, &firstError);
1784 if (ret) {
1785 ret = X11GD_InitXrandrFuncs(env);
1786 }
1787 AWT_FLUSH_UNLOCK();
1788
1789 return ret;
1790#endif /* HEADLESS */
1791}
1792
1793/*
1794 * Class: sun_awt_X11GraphicsDevice
1795 * Method: getCurrentDisplayMode
1796 * Signature: (I)Ljava/awt/DisplayMode;
1797 */
1798JNIEXPORT jobject JNICALL
1799Java_sun_awt_X11GraphicsDevice_getCurrentDisplayMode
1800 (JNIEnv* env, jclass x11gd, jint screen)
1801{
1802#if defined(HEADLESS) || defined(NO_XRANDR)
1803 return NULL;
1804#else
1805 XRRScreenConfiguration *config;
1806 jobject displayMode = NULL;
1807
1808 AWT_LOCK();
1809
1810 if (usingXinerama && XScreenCount(awt_display) > 0) {
1811 XRRScreenResources *res = awt_XRRGetScreenResources(awt_display,
1812 RootWindow(awt_display, 0));
1813 if (res) {
1814 if (res->noutput > screen) {
1815 XRROutputInfo *output_info = awt_XRRGetOutputInfo(awt_display,
1816 res, res->outputs[screen]);
1817 if (output_info) {
1818 if (output_info->crtc) {
1819 XRRCrtcInfo *crtc_info =
1820 awt_XRRGetCrtcInfo (awt_display, res,
1821 output_info->crtc);
1822 if (crtc_info) {
1823 if (crtc_info->mode) {
1824 int i;
1825 for (i = 0; i < res->nmode; i++) {
1826 XRRModeInfo *mode = &res->modes[i];
1827 if (mode->id == crtc_info->mode) {
1828 float rate = 0;
1829 if (mode->hTotal && mode->vTotal) {
1830 rate = ((float)mode->dotClock /
1831 ((float)mode->hTotal *
1832 (float)mode->vTotal));
1833 }
1834 displayMode = X11GD_CreateDisplayMode(
1835 env,
1836 mode->width,
1837 mode->height,
1838 BIT_DEPTH_MULTI,
1839 (int)(rate +.2));
1840 break;
1841 }
1842 }
1843 }
1844 awt_XRRFreeCrtcInfo(crtc_info);
1845 }
1846 }
1847 awt_XRRFreeOutputInfo(output_info);
1848 }
1849 }
1850 awt_XRRFreeScreenResources(res);
1851 }
1852 } else {
1853
1854 config = awt_XRRGetScreenInfo(awt_display,
1855 RootWindow(awt_display, screen));
1856 if (config != NULL) {
1857 Rotation rotation;
1858 short curRate;
1859 SizeID curSizeIndex;
1860 XRRScreenSize *sizes;
1861 int nsizes;
1862
1863 curSizeIndex = awt_XRRConfigCurrentConfiguration(config, &rotation);
1864 sizes = awt_XRRConfigSizes(config, &nsizes);
1865 curRate = awt_XRRConfigCurrentRate(config);
1866
1867 if ((sizes != NULL) &&
1868 (curSizeIndex < nsizes))
1869 {
1870 XRRScreenSize curSize = sizes[curSizeIndex];
1871 displayMode = X11GD_CreateDisplayMode(env,
1872 curSize.width,
1873 curSize.height,
1874 BIT_DEPTH_MULTI,
1875 curRate);
1876 }
1877
1878 awt_XRRFreeScreenConfigInfo(config);
1879 }
1880 }
1881
1882 AWT_FLUSH_UNLOCK();
1883
1884 return displayMode;
1885#endif /* HEADLESS */
1886}
1887
1888/*
1889 * Class: sun_awt_X11GraphicsDevice
1890 * Method: enumDisplayModes
1891 * Signature: (ILjava/util/ArrayList;)V
1892 */
1893JNIEXPORT void JNICALL
1894Java_sun_awt_X11GraphicsDevice_enumDisplayModes
1895 (JNIEnv* env, jclass x11gd,
1896 jint screen, jobject arrayList)
1897{
1898#if !defined(HEADLESS) && !defined(NO_XRANDR)
1899
1900 AWT_LOCK();
1901
1902 if (usingXinerama && XScreenCount(awt_display) > 0) {
1903 XRRScreenResources *res = awt_XRRGetScreenResources(awt_display,
1904 RootWindow(awt_display, 0));
1905 if (res) {
1906 if (res->noutput > screen) {
1907 XRROutputInfo *output_info = awt_XRRGetOutputInfo(awt_display,
1908 res, res->outputs[screen]);
1909 if (output_info) {
1910 int i;
1911 for (i = 0; i < output_info->nmode; i++) {
1912 RRMode m = output_info->modes[i];
1913 int j;
1914 XRRModeInfo *mode;
1915 for (j = 0; j < res->nmode; j++) {
1916 mode = &res->modes[j];
1917 if (mode->id == m) {
1918 float rate = 0;
1919 if (mode->hTotal && mode->vTotal) {
1920 rate = ((float)mode->dotClock /
1921 ((float)mode->hTotal *
1922 (float)mode->vTotal));
1923 }
1924 X11GD_AddDisplayMode(env, arrayList,
1925 mode->width, mode->height,
1926 BIT_DEPTH_MULTI, (int)(rate +.2));
1927 if ((*env)->ExceptionCheck(env)) {
1928 goto ret0;
1929 }
1930 break;
1931 }
1932 }
1933 }
1934ret0:
1935 awt_XRRFreeOutputInfo(output_info);
1936 }
1937 }
1938 awt_XRRFreeScreenResources(res);
1939 }
1940 } else {
1941 XRRScreenConfiguration *config;
1942
1943 config = awt_XRRGetScreenInfo(awt_display,
1944 RootWindow(awt_display, screen));
1945 if (config != NULL) {
1946 int nsizes, i, j;
1947 XRRScreenSize *sizes = awt_XRRConfigSizes(config, &nsizes);
1948
1949 if (sizes != NULL) {
1950 for (i = 0; i < nsizes; i++) {
1951 int nrates;
1952 XRRScreenSize size = sizes[i];
1953 short *rates = awt_XRRConfigRates(config, i, &nrates);
1954
1955 for (j = 0; j < nrates; j++) {
1956 X11GD_AddDisplayMode(env, arrayList,
1957 size.width,
1958 size.height,
1959 BIT_DEPTH_MULTI,
1960 rates[j]);
1961 if ((*env)->ExceptionCheck(env)) {
1962 goto ret1;
1963 }
1964 }
1965 }
1966 }
1967ret1:
1968 awt_XRRFreeScreenConfigInfo(config);
1969 }
1970 }
1971
1972 AWT_FLUSH_UNLOCK();
1973#endif /* !HEADLESS */
1974}
1975
1976/*
1977 * Class: sun_awt_X11GraphicsDevice
1978 * Method: configDisplayMode
1979 * Signature: (IIII)V
1980 */
1981JNIEXPORT void JNICALL
1982Java_sun_awt_X11GraphicsDevice_configDisplayMode
1983 (JNIEnv* env, jclass x11gd,
1984 jint screen, jint width, jint height, jint refreshRate)
1985{
1986#if !defined(HEADLESS) && !defined(NO_XRANDR)
1987 jboolean success = JNI_FALSE;
1988 XRRScreenConfiguration *config;
1989 Drawable root;
1990 Rotation currentRotation = RR_Rotate_0;
1991
1992 AWT_LOCK();
1993
1994 root = RootWindow(awt_display, screen);
1995 config = awt_XRRGetScreenInfo(awt_display, root);
1996 if (config != NULL) {
1997 jboolean foundConfig = JNI_FALSE;
1998 int chosenSizeIndex = -1;
1999 short chosenRate = -1;
2000 int nsizes;
2001 XRRScreenSize *sizes = awt_XRRConfigSizes(config, &nsizes);
2002 awt_XRRConfigRotations(config, &currentRotation);
2003
2004 if (sizes != NULL) {
2005 int i, j;
2006
2007 /* find the size index that matches the requested dimensions */
2008 for (i = 0; i < nsizes; i++) {
2009 XRRScreenSize size = sizes[i];
2010
2011 if ((size.width == width) && (size.height == height)) {
2012 /* we've found our size index... */
2013 int nrates;
2014 short *rates = awt_XRRConfigRates(config, i, &nrates);
2015
2016 /* now find rate that matches requested refresh rate */
2017 for (j = 0; j < nrates; j++) {
2018 if (rates[j] == refreshRate) {
2019 /* we've found our rate; break out of the loop */
2020 chosenSizeIndex = i;
2021 chosenRate = rates[j];
2022 foundConfig = JNI_TRUE;
2023 break;
2024 }
2025 }
2026
2027 break;
2028 }
2029 }
2030 }
2031
2032 if (foundConfig) {
2033 Status status =
2034 awt_XRRSetScreenConfigAndRate(awt_display, config, root,
2035 chosenSizeIndex,
2036 currentRotation,
2037 chosenRate,
2038 CurrentTime);
2039
2040 /* issue XSync to ensure immediate mode change */
2041 XSync(awt_display, False);
2042
2043 if (status == RRSetConfigSuccess) {
2044 success = JNI_TRUE;
2045 }
2046 }
2047
2048 awt_XRRFreeScreenConfigInfo(config);
2049 }
2050
2051 AWT_FLUSH_UNLOCK();
2052
2053 if (!success && !(*env)->ExceptionCheck(env)) {
2054 JNU_ThrowInternalError(env, "Could not set display mode");
2055 }
2056#endif /* !HEADLESS */
2057}
2058
2059/*
2060 * Class: sun_awt_X11GraphicsDevice
2061 * Method: enterFullScreenExclusive
2062 * Signature: (J)V
2063 */
2064JNIEXPORT void JNICALL
2065Java_sun_awt_X11GraphicsDevice_enterFullScreenExclusive
2066 (JNIEnv* env, jclass x11gd,
2067 jlong window)
2068{
2069#ifndef HEADLESS
2070 Window win = (Window)window;
2071
2072 AWT_LOCK();
2073 XSync(awt_display, False); /* ensures window is visible first */
2074 X11GD_SetFullscreenMode(win, JNI_TRUE);
2075 AWT_UNLOCK();
2076#endif /* !HEADLESS */
2077}
2078
2079/*
2080 * Class: sun_awt_X11GraphicsDevice
2081 * Method: exitFullScreenExclusive
2082 * Signature: (J)V
2083 */
2084JNIEXPORT void JNICALL
2085Java_sun_awt_X11GraphicsDevice_exitFullScreenExclusive
2086 (JNIEnv* env, jclass x11gd,
2087 jlong window)
2088{
2089#ifndef HEADLESS
2090 Window win = (Window)window;
2091
2092 AWT_LOCK();
2093 X11GD_SetFullscreenMode(win, JNI_FALSE);
2094 AWT_UNLOCK();
2095#endif /* !HEADLESS */
2096}
2097
2098/**
2099 * End DisplayMode/FullScreen support
2100 */
2101
2102static char *get_output_screen_name(JNIEnv *env, int screen) {
2103#ifdef NO_XRANDR
2104 return NULL;
2105#else
2106 if (!awt_XRRGetScreenResources || !awt_XRRGetOutputInfo) {
2107 return NULL;
2108 }
2109 char *name = NULL;
2110 AWT_LOCK();
2111 int scr = 0, out = 0;
2112 if (usingXinerama && XScreenCount(awt_display) > 0) {
2113 out = screen;
2114 } else {
2115 scr = screen;
2116 }
2117
2118 XRRScreenResources *res = awt_XRRGetScreenResources(awt_display,
2119 RootWindow(awt_display, scr));
2120 if (res) {
2121 if (res->noutput > out) {
2122 XRROutputInfo *output_info = awt_XRRGetOutputInfo(awt_display,
2123 res, res->outputs[out]);
2124 if (output_info) {
2125 if (output_info->name) {
2126 name = strdup(output_info->name);
2127 }
2128 awt_XRRFreeOutputInfo(output_info);
2129 }
2130 }
2131 awt_XRRFreeScreenResources(res);
2132 }
2133 AWT_UNLOCK();
2134 return name;
2135#endif /* NO_XRANDR */
2136}
2137
2138/*
2139 * Class: sun_awt_X11GraphicsDevice
2140 * Method: getNativeScaleFactor
2141 * Signature: (I)D
2142 */
2143JNIEXPORT jdouble JNICALL
2144Java_sun_awt_X11GraphicsDevice_getNativeScaleFactor
2145 (JNIEnv *env, jobject this, jint screen) {
2146 // in case of Xinerama individual screen scales are not supported
2147 char *name = get_output_screen_name(env, usingXinerama ? 0 : screen);
2148 double scale = getNativeScaleFactor(name);
2149 if (name) {
2150 free(name);
2151 }
2152 return scale;
2153}
2154