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