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