1 /*
2  * Copyright (c) 1997, 2021, 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; // should be guarded by AWT_LOCK()/AWT_UNLOCK()
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     char* XineramaQueryScreensName = "XineramaQueryScreens";
595 
596     gotXinExt = XQueryExtension(awt_display, XinExtName, &major_opcode,
597                                 &first_event, &first_error);
598 
599     if (!gotXinExt) {
600         DTRACE_PRINTLN("Xinerama extension is not available");
601         return;
602     }
603 
604     DTRACE_PRINTLN("Xinerama extension is available");
605 
606     /* load library */
607     libHandle = dlopen(VERSIONED_JNI_LIB_NAME("Xinerama", "1"),
608                        RTLD_LAZY | RTLD_GLOBAL);
609     if (libHandle == NULL) {
610 #if defined(_AIX)
611         libHandle = dlopen("libXext.a(shr_64.o)", RTLD_MEMBER | RTLD_LAZY | RTLD_GLOBAL);
612 #else
613         libHandle = dlopen(JNI_LIB_NAME("Xinerama"), RTLD_LAZY | RTLD_GLOBAL);
614 #endif
615     }
616     if (libHandle != NULL) {
617         XineramaQueryScreens = (XineramaQueryScreensFunc*)
618             dlsym(libHandle, XineramaQueryScreensName);
619 
620         if (XineramaQueryScreens == NULL) {
621             DTRACE_PRINTLN("couldn't load XineramaQueryScreens symbol");
622             dlclose(libHandle);
623         }
624     } else {
625         DTRACE_PRINTLN1("\ncouldn't open shared library: %s\n", dlerror());
626     }
627 }
628 
resetNativeData(int screen)629 static void resetNativeData(int screen) {
630     /*
631      * Reset references to the various configs; the actual native config data
632      * will be free'd later by the Disposer mechanism when the Java-level
633      * X11GraphicsConfig objects go away.  By setting these values to NULL,
634      * we ensure that they will be reinitialized as necessary (for example,
635      * see the getNumConfigs() method).
636      */
637     if (x11Screens[screen].configs) {
638         free(x11Screens[screen].configs);
639         x11Screens[screen].configs = NULL;
640     }
641     x11Screens[screen].defaultConfig = NULL;
642     x11Screens[screen].numConfigs = 0;
643 }
644 
645 /*
646  * Class:     sun_awt_X11GraphicsEnvironment
647  * Method:    initDevices
648  * Signature: (Z)V
649  */
650 JNIEXPORT void JNICALL
Java_sun_awt_X11GraphicsEnvironment_initNativeData(JNIEnv * env,jobject this)651 Java_sun_awt_X11GraphicsEnvironment_initNativeData(JNIEnv *env, jobject this) {
652     usingXinerama = False;
653     if (x11Screens) {
654         for (int i = 0; i < awt_numScreens; ++i) {
655             resetNativeData(i);
656         }
657         free((void *)x11Screens);
658         x11Screens = NULL;
659         awt_numScreens = 0;
660     }
661 
662     // will try xinerama first
663     if (XineramaQueryScreens) {
664         int32_t locNumScr = 0;
665         XineramaScreenInfo *xinInfo;
666         DTRACE_PRINTLN("calling XineramaQueryScreens func");
667         xinInfo = (*XineramaQueryScreens)(awt_display, &locNumScr);
668         if (xinInfo != NULL) {
669             if (locNumScr > XScreenCount(awt_display)) {
670                 DTRACE_PRINTLN("Enabling Xinerama support");
671                 usingXinerama = True;
672                 /* set global number of screens */
673                 DTRACE_PRINTLN1(" num screens = %i\n", locNumScr);
674                 awt_numScreens = locNumScr;
675             } else {
676                 DTRACE_PRINTLN("XineramaQueryScreens <= XScreenCount");
677             }
678             XFree(xinInfo);
679         } else {
680             DTRACE_PRINTLN("calling XineramaQueryScreens didn't work");
681         }
682     }
683     // if xinerama is not enabled or does not work will use X11
684     if (!usingXinerama) {
685         awt_numScreens =  XScreenCount(awt_display);
686     }
687     DTRACE_PRINTLN1("allocating %i screens\n", awt_numScreens);
688     /* Allocate screen data structure array */
689     x11Screens = calloc(awt_numScreens, sizeof(AwtScreenData));
690     if (x11Screens == NULL) {
691         JNU_ThrowOutOfMemoryError((JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2),
692                                   NULL);
693         return;
694     }
695 
696     for (int i = 0; i < awt_numScreens; i++) {
697         if (usingXinerama) {
698             /* All Xinerama screens use the same X11 root for now */
699             x11Screens[i].root = RootWindow(awt_display, 0);
700         }
701         else {
702             x11Screens[i].root = RootWindow(awt_display, i);
703         }
704         x11Screens[i].defaultConfig = makeDefaultConfig(env, i);
705         JNU_CHECK_EXCEPTION(env);
706     }
707 }
708 
709 Display *
awt_init_Display(JNIEnv * env,jobject this)710 awt_init_Display(JNIEnv *env, jobject this)
711 {
712     jclass klass;
713     Display *dpy;
714     char errmsg[128];
715     int i;
716 
717     if (awt_display) {
718         return awt_display;
719     }
720 
721     /* Load AWT lock-related methods in SunToolkit */
722     klass = (*env)->FindClass(env, "sun/awt/SunToolkit");
723     if (klass == NULL) return NULL;
724     GET_STATIC_METHOD(klass, awtLockMID, "awtLock", "()V");
725     GET_STATIC_METHOD(klass, awtUnlockMID, "awtUnlock", "()V");
726     GET_STATIC_METHOD(klass, awtWaitMID, "awtLockWait", "(J)V");
727     GET_STATIC_METHOD(klass, awtNotifyMID, "awtLockNotify", "()V");
728     GET_STATIC_METHOD(klass, awtNotifyAllMID, "awtLockNotifyAll", "()V");
729     tkClass = (*env)->NewGlobalRef(env, klass);
730     awtLockInited = JNI_TRUE;
731 
732     if (getenv("_AWT_IGNORE_XKB") != NULL &&
733         strlen(getenv("_AWT_IGNORE_XKB")) > 0) {
734         if (XkbIgnoreExtension(True)) {
735             printf("Ignoring XKB.\n");
736         }
737     }
738 
739     dpy = awt_display = XOpenDisplay(NULL);
740     if (!dpy) {
741         jio_snprintf(errmsg,
742                      sizeof(errmsg),
743                      "Can't connect to X11 window server using '%s' as the value of the DISPLAY variable.",
744                      (getenv("DISPLAY") == NULL) ? ":0.0" : getenv("DISPLAY"));
745         JNU_ThrowByName(env, "java/awt/AWTError", errmsg);
746         return NULL;
747     }
748 
749     XSetIOErrorHandler(xioerror_handler);
750     JNU_CallStaticMethodByName(env, NULL, "sun/awt/X11/XErrorHandlerUtil", "init", "(J)V",
751         ptr_to_jlong(awt_display));
752     JNU_CHECK_EXCEPTION_RETURN(env, NULL);
753 
754     /* set awt_numScreens, and whether or not we're using Xinerama */
755     xineramaInit();
756     return dpy;
757 }
758 
759 /*
760  * Class:     sun_awt_X11GraphicsEnvironment
761  * Method:    getDefaultScreenNum
762  * Signature: ()I
763  */
764 JNIEXPORT jint JNICALL
Java_sun_awt_X11GraphicsEnvironment_getDefaultScreenNum(JNIEnv * env,jobject this)765 Java_sun_awt_X11GraphicsEnvironment_getDefaultScreenNum(
766 JNIEnv *env, jobject this)
767 {
768     return DefaultScreen(awt_display);
769 }
770 
ensureConfigsInited(JNIEnv * env,int screen)771 static void ensureConfigsInited(JNIEnv* env, int screen) {
772    if (x11Screens[screen].numConfigs == 0) {
773        if (env == NULL) {
774            env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
775        }
776        getAllConfigs (env, screen, &(x11Screens[screen]));
777     }
778 }
779 
780 AwtGraphicsConfigDataPtr
getDefaultConfig(int screen)781 getDefaultConfig(int screen) {
782     ensureConfigsInited(NULL, screen);
783     return x11Screens[screen].defaultConfig;
784 }
785 
786 /*
787  * Class:     sun_awt_X11GraphicsEnvironment
788  * Method:    initDisplay
789  * Signature: (Z)V
790  */
791 JNIEXPORT void JNICALL
Java_sun_awt_X11GraphicsEnvironment_initDisplay(JNIEnv * env,jobject this,jboolean glxReq)792 Java_sun_awt_X11GraphicsEnvironment_initDisplay(JNIEnv *env, jobject this,
793                                                 jboolean glxReq)
794 {
795     glxRequested = glxReq;
796     (void) awt_init_Display(env, this);
797 }
798 
799 /*
800  * Class:     sun_awt_X11GraphicsEnvironment
801  * Method:    initGLX
802  * Signature: ()Z
803  */
804 JNIEXPORT jboolean JNICALL
Java_sun_awt_X11GraphicsEnvironment_initGLX(JNIEnv * env,jclass x11ge)805 Java_sun_awt_X11GraphicsEnvironment_initGLX(JNIEnv *env, jclass x11ge)
806 {
807     jboolean glxAvailable;
808 
809     AWT_LOCK();
810     glxAvailable = GLXGC_IsGLXAvailable();
811     AWT_UNLOCK();
812 
813     return glxAvailable;
814 }
815 
816 /*
817  * Class:     sun_awt_X11GraphicsEnvironment
818  * Method:    getNumScreens
819  * Signature: ()I
820  */
821 JNIEXPORT jint JNICALL
Java_sun_awt_X11GraphicsEnvironment_getNumScreens(JNIEnv * env,jobject this)822 Java_sun_awt_X11GraphicsEnvironment_getNumScreens(JNIEnv *env, jobject this)
823 {
824     return awt_numScreens;
825 }
826 
827 /*
828  * Class:     sun_awt_X11GraphicsDevice
829  * Method:    getDisplay
830  * Signature: ()J
831  */
832 JNIEXPORT jlong JNICALL
Java_sun_awt_X11GraphicsDevice_getDisplay(JNIEnv * env,jobject this)833 Java_sun_awt_X11GraphicsDevice_getDisplay(JNIEnv *env, jobject this)
834 {
835     return ptr_to_jlong(awt_display);
836 }
837 
838 #ifdef MITSHM
839 
840 static jint canUseShmExt = UNSET_MITSHM;
841 static jint canUseShmExtPixmaps = UNSET_MITSHM;
842 static jboolean xshmAttachFailed = JNI_FALSE;
843 
XShmAttachXErrHandler(Display * display,XErrorEvent * xerr)844 int XShmAttachXErrHandler(Display *display, XErrorEvent *xerr) {
845     if (xerr->minor_code == X_ShmAttach) {
846         xshmAttachFailed = JNI_TRUE;
847     }
848     return 0;
849 }
isXShmAttachFailed()850 jboolean isXShmAttachFailed() {
851     return xshmAttachFailed;
852 }
resetXShmAttachFailed()853 void resetXShmAttachFailed() {
854     xshmAttachFailed = JNI_FALSE;
855 }
856 
857 extern int mitShmPermissionMask;
858 
TryInitMITShm(JNIEnv * env,jint * shmExt,jint * shmPixmaps)859 void TryInitMITShm(JNIEnv *env, jint *shmExt, jint *shmPixmaps) {
860     XShmSegmentInfo shminfo;
861     int XShmMajor, XShmMinor;
862     int a, b, c;
863 
864     AWT_LOCK();
865     if (canUseShmExt != UNSET_MITSHM) {
866         *shmExt = canUseShmExt;
867         *shmPixmaps = canUseShmExtPixmaps;
868         AWT_UNLOCK();
869         return;
870     }
871 
872     *shmExt = canUseShmExt = CANT_USE_MITSHM;
873     *shmPixmaps = canUseShmExtPixmaps = CANT_USE_MITSHM;
874 
875     if (awt_display == (Display *)NULL) {
876         AWT_NOFLUSH_UNLOCK();
877         return;
878     }
879 
880     /**
881      * XShmQueryExtension returns False in remote server case.
882      * Unfortunately it also returns True in ssh case, so
883      * we need to test that we can actually do XShmAttach.
884      */
885     if (XShmQueryExtension(awt_display)) {
886         shminfo.shmid = shmget(IPC_PRIVATE, 0x10000,
887                                IPC_CREAT|mitShmPermissionMask);
888         if (shminfo.shmid < 0) {
889             AWT_UNLOCK();
890             J2dRlsTraceLn1(J2D_TRACE_ERROR,
891                            "TryInitMITShm: shmget has failed: %s",
892                            strerror(errno));
893             return;
894         }
895         shminfo.shmaddr = (char *) shmat(shminfo.shmid, 0, 0);
896         if (shminfo.shmaddr == ((char *) -1)) {
897             shmctl(shminfo.shmid, IPC_RMID, 0);
898             AWT_UNLOCK();
899             J2dRlsTraceLn1(J2D_TRACE_ERROR,
900                            "TryInitMITShm: shmat has failed: %s",
901                            strerror(errno));
902             return;
903         }
904         shminfo.readOnly = True;
905 
906         resetXShmAttachFailed();
907         /**
908          * The J2DXErrHandler handler will set xshmAttachFailed
909          * to JNI_TRUE if any Shm error has occured.
910          */
911         EXEC_WITH_XERROR_HANDLER(XShmAttachXErrHandler,
912                                  XShmAttach(awt_display, &shminfo));
913 
914         /**
915          * Get rid of the id now to reduce chances of leaking
916          * system resources.
917          */
918         shmctl(shminfo.shmid, IPC_RMID, 0);
919 
920         if (isXShmAttachFailed() == JNI_FALSE) {
921             canUseShmExt = CAN_USE_MITSHM;
922             /* check if we can use shared pixmaps */
923             XShmQueryVersion(awt_display, &XShmMajor, &XShmMinor,
924                              (Bool*)&canUseShmExtPixmaps);
925             canUseShmExtPixmaps = canUseShmExtPixmaps &&
926                 (XShmPixmapFormat(awt_display) == ZPixmap);
927             XShmDetach(awt_display, &shminfo);
928         }
929         shmdt(shminfo.shmaddr);
930         *shmExt = canUseShmExt;
931         *shmPixmaps = canUseShmExtPixmaps;
932     }
933     AWT_UNLOCK();
934 }
935 #endif /* MITSHM */
936 
937 /*
938  * Class:     sun_awt_X11GraphicsEnvironment
939  * Method:    checkShmExt
940  * Signature: ()I
941  */
942 JNIEXPORT jint JNICALL
Java_sun_awt_X11GraphicsEnvironment_checkShmExt(JNIEnv * env,jobject this)943 Java_sun_awt_X11GraphicsEnvironment_checkShmExt(JNIEnv *env, jobject this)
944 {
945 
946     int shmExt = NOEXT_MITSHM, shmPixmaps;
947 #ifdef MITSHM
948     TryInitMITShm(env, &shmExt, &shmPixmaps);
949 #endif
950     return shmExt;
951 }
952 
953 /*
954  * Class:     sun_awt_X11GraphicsEnvironment
955  * Method:    getDisplayString
956  * Signature: ()Ljava/lang/String
957  */
958 JNIEXPORT jstring JNICALL
Java_sun_awt_X11GraphicsEnvironment_getDisplayString(JNIEnv * env,jobject this)959 Java_sun_awt_X11GraphicsEnvironment_getDisplayString
960   (JNIEnv *env, jobject this)
961 {
962     return (*env)->NewStringUTF(env, DisplayString(awt_display));
963 }
964 
965 
966 /*
967  * Class:     sun_awt_X11GraphicsDevice
968  * Method:    getNumConfigs
969  * Signature: ()I
970  */
971 JNIEXPORT jint JNICALL
Java_sun_awt_X11GraphicsDevice_getNumConfigs(JNIEnv * env,jobject this,jint screen)972 Java_sun_awt_X11GraphicsDevice_getNumConfigs(
973 JNIEnv *env, jobject this, jint screen)
974 {
975     AWT_LOCK();
976     ensureConfigsInited(env, screen);
977     int configs = x11Screens[screen].numConfigs;
978     AWT_UNLOCK();
979     return configs;
980 }
981 
982 /*
983  * Class:     sun_awt_X11GraphicsDevice
984  * Method:    getConfigVisualId
985  * Signature: (I)I
986  */
987 JNIEXPORT jint JNICALL
Java_sun_awt_X11GraphicsDevice_getConfigVisualId(JNIEnv * env,jobject this,jint index,jint screen)988 Java_sun_awt_X11GraphicsDevice_getConfigVisualId(
989 JNIEnv *env, jobject this, jint index, jint screen)
990 {
991     int visNum;
992     AWT_LOCK();
993     ensureConfigsInited(env, screen);
994     jint id = (jint) (index == 0 ? x11Screens[screen].defaultConfig
995                                  : x11Screens[screen].configs[index])->awt_visInfo.visualid;
996     AWT_UNLOCK();
997     return id;
998 }
999 
1000 /*
1001  * Class:     sun_awt_X11GraphicsDevice
1002  * Method:    getConfigDepth
1003  * Signature: (I)I
1004  */
1005 JNIEXPORT jint JNICALL
Java_sun_awt_X11GraphicsDevice_getConfigDepth(JNIEnv * env,jobject this,jint index,jint screen)1006 Java_sun_awt_X11GraphicsDevice_getConfigDepth(
1007 JNIEnv *env, jobject this, jint index, jint screen)
1008 {
1009     int visNum;
1010     AWT_LOCK();
1011     ensureConfigsInited(env, screen);
1012     jint depth = (jint) (index == 0 ? x11Screens[screen].defaultConfig
1013                                     : x11Screens[screen].configs[index])->awt_visInfo.depth;
1014     AWT_UNLOCK();
1015     return depth;
1016 }
1017 
1018 /*
1019  * Class:     sun_awt_X11GraphicsDevice
1020  * Method:    getConfigColormap
1021  * Signature: (I)I
1022  */
1023 JNIEXPORT jint JNICALL
Java_sun_awt_X11GraphicsDevice_getConfigColormap(JNIEnv * env,jobject this,jint index,jint screen)1024 Java_sun_awt_X11GraphicsDevice_getConfigColormap(
1025 JNIEnv *env, jobject this, jint index, jint screen)
1026 {
1027     int visNum;
1028     AWT_LOCK();
1029     ensureConfigsInited(env, screen);
1030     jint colormap = (jint) (index == 0 ? x11Screens[screen].defaultConfig
1031                                        : x11Screens[screen].configs[index])->awt_cmap;
1032     AWT_UNLOCK();
1033     return colormap;
1034 }
1035 
1036 
1037 /*
1038  * Class:     sun_awt_X11GraphicsConfig
1039  * Method:    dispose
1040  * Signature: (J)V
1041  */
1042 JNIEXPORT void JNICALL
Java_sun_awt_X11GraphicsConfig_dispose(JNIEnv * env,jclass x11gc,jlong configData)1043 Java_sun_awt_X11GraphicsConfig_dispose
1044     (JNIEnv *env, jclass x11gc, jlong configData)
1045 {
1046     AwtGraphicsConfigDataPtr aData = (AwtGraphicsConfigDataPtr)
1047         jlong_to_ptr(configData);
1048 
1049     if (aData == NULL) {
1050         return;
1051     }
1052 
1053     AWT_LOCK();
1054     if (aData->awt_cmap) {
1055         XFreeColormap(awt_display, aData->awt_cmap);
1056     }
1057     if (aData->awtImage) {
1058         free(aData->awtImage);
1059     }
1060     if (aData->monoImage) {
1061         XFree(aData->monoImage);
1062     }
1063     if (aData->monoPixmap) {
1064         XFreePixmap(awt_display, aData->monoPixmap);
1065     }
1066     if (aData->monoPixmapGC) {
1067         XFreeGC(awt_display, aData->monoPixmapGC);
1068     }
1069     if (aData->color_data) {
1070         free(aData->color_data);
1071     }
1072     AWT_UNLOCK();
1073 
1074     if (aData->glxInfo) {
1075         /*
1076          * The native GLXGraphicsConfig data needs to be disposed separately
1077          * on the OGL queue flushing thread (should not be called while
1078          * the AWT lock is held).
1079          */
1080         JNU_CallStaticMethodByName(env, NULL,
1081                                    "sun/java2d/opengl/OGLRenderQueue",
1082                                    "disposeGraphicsConfig", "(J)V",
1083                                    ptr_to_jlong(aData->glxInfo));
1084     }
1085 
1086     free(aData);
1087 }
1088 
1089 /*
1090  * Class:     sun_awt_X11GraphicsConfig
1091  * Method:    getXResolution
1092  * Signature: ()I
1093  */
1094 JNIEXPORT jdouble JNICALL
Java_sun_awt_X11GraphicsConfig_getXResolution(JNIEnv * env,jobject this,jint screen)1095 Java_sun_awt_X11GraphicsConfig_getXResolution(
1096 JNIEnv *env, jobject this, jint screen)
1097 {
1098     return ((DisplayWidth(awt_display, screen) * 25.4) /
1099             DisplayWidthMM(awt_display, screen));
1100 }
1101 
1102 /*
1103  * Class:     sun_awt_X11GraphicsConfig
1104  * Method:    getYResolution
1105  * Signature: ()I
1106  */
1107 JNIEXPORT jdouble JNICALL
Java_sun_awt_X11GraphicsConfig_getYResolution(JNIEnv * env,jobject this,jint screen)1108 Java_sun_awt_X11GraphicsConfig_getYResolution(
1109 JNIEnv *env, jobject this, jint screen)
1110 {
1111     return ((DisplayHeight(awt_display, screen) * 25.4) /
1112             DisplayHeightMM(awt_display, screen));
1113 }
1114 
1115 
1116 /*
1117  * Class:     sun_awt_X11GraphicsConfig
1118  * Method:    getNumColors
1119  * Signature: ()I
1120  */
1121 JNIEXPORT jint JNICALL
Java_sun_awt_X11GraphicsConfig_getNumColors(JNIEnv * env,jobject this)1122 Java_sun_awt_X11GraphicsConfig_getNumColors(
1123 JNIEnv *env, jobject this)
1124 {
1125     AwtGraphicsConfigData *adata;
1126 
1127     adata = (AwtGraphicsConfigData *) JNU_GetLongFieldAsPtr(env, this,
1128                                               x11GraphicsConfigIDs.aData);
1129 
1130     return adata->awt_num_colors;
1131 }
1132 
1133 /*
1134  * Class:     sun_awt_X11GraphicsConfig
1135  * Method:    init
1136  * Signature: (I)V
1137  */
1138 JNIEXPORT void JNICALL
Java_sun_awt_X11GraphicsConfig_init(JNIEnv * env,jobject this,jint visualNum,jint screen)1139 Java_sun_awt_X11GraphicsConfig_init(
1140 JNIEnv *env, jobject this, jint visualNum, jint screen)
1141 {
1142     AwtGraphicsConfigData *adata = NULL;
1143     AWT_LOCK();
1144     AwtScreenData asd = x11Screens[screen];
1145     int i, n;
1146     int depth;
1147     XImage * tempImage;
1148 
1149     /* If haven't gotten all of the configs yet, do it now. */
1150     if (asd.numConfigs == 0) {
1151         getAllConfigs (env, screen, &asd);
1152     }
1153 
1154     /* Check the graphicsConfig for this visual */
1155     for (i = 0; i < asd.numConfigs; i++) {
1156         AwtGraphicsConfigDataPtr agcPtr = asd.configs[i];
1157         if ((jint)agcPtr->awt_visInfo.visualid == visualNum) {
1158            adata = agcPtr;
1159            break;
1160         }
1161     }
1162 
1163     /* If didn't find the visual, throw an exception... */
1164     if (adata == (AwtGraphicsConfigData *) NULL) {
1165         AWT_UNLOCK();
1166         JNU_ThrowIllegalArgumentException(env, "Unknown Visual Specified");
1167         return;
1168     }
1169 
1170     /*  adata->awt_cmap initialization has been deferred to
1171      *  makeColorModel call
1172      */
1173 
1174     JNU_SetLongFieldFromPtr(env, this, x11GraphicsConfigIDs.aData, adata);
1175 
1176     depth = adata->awt_visInfo.depth;
1177     tempImage = XCreateImage(awt_display,
1178                              adata->awt_visInfo.visual,
1179                              depth, ZPixmap, 0, NULL, 1, 1, 32, 0);
1180     adata->pixelStride = (tempImage->bits_per_pixel + 7) / 8;
1181     (*env)->SetIntField(env, this, x11GraphicsConfigIDs.bitsPerPixel,
1182                         (jint)tempImage->bits_per_pixel);
1183     XDestroyImage(tempImage);
1184     AWT_UNLOCK();
1185 }
1186 
1187 /*
1188  * Class:     sun_awt_X11GraphicsConfig
1189  * Method:    makeColorModel
1190  * Signature: ()Ljava/awt/image/ColorModel
1191  */
1192 JNIEXPORT jobject JNICALL
Java_sun_awt_X11GraphicsConfig_makeColorModel(JNIEnv * env,jobject this)1193 Java_sun_awt_X11GraphicsConfig_makeColorModel(
1194 JNIEnv *env, jobject this)
1195 {
1196     AwtGraphicsConfigData *adata;
1197     jobject colorModel;
1198 
1199     /*
1200      * If awt is not locked yet, return null since the toolkit is not
1201      * initialized yet.
1202      */
1203     if (!awtLockInited) {
1204         return NULL;
1205     }
1206 
1207     AWT_LOCK ();
1208 
1209     adata = (AwtGraphicsConfigData *) JNU_GetLongFieldAsPtr(env, this,
1210                                               x11GraphicsConfigIDs.aData);
1211 
1212     /* If colormap entry of adata is NULL, need to create it now */
1213     if (adata->awt_cmap == (Colormap) NULL) {
1214         awtJNI_CreateColorData (env, adata, 1);
1215     }
1216 
1217     /* Make Color Model object for this GraphicsConfiguration */
1218     colorModel = (*env)->ExceptionCheck(env)
1219                  ? NULL : awtJNI_GetColorModel (env, adata);
1220 
1221     AWT_UNLOCK ();
1222 
1223     return colorModel;
1224 }
1225 
1226 
1227 /*
1228  * Class:     sun_awt_X11GraphicsDevice
1229  * Method:    getBounds
1230  * Signature: ()Ljava/awt/Rectangle
1231  */
1232 JNIEXPORT jobject JNICALL
Java_sun_awt_X11GraphicsDevice_pGetBounds(JNIEnv * env,jobject this,jint screen)1233 Java_sun_awt_X11GraphicsDevice_pGetBounds(JNIEnv *env, jobject this, jint screen)
1234 {
1235     jclass clazz;
1236     jmethodID mid;
1237     jobject bounds = NULL;
1238     int32_t locNumScr = 0;
1239     XineramaScreenInfo *xinInfo;
1240 
1241     clazz = (*env)->FindClass(env, "java/awt/Rectangle");
1242     CHECK_NULL_RETURN(clazz, NULL);
1243     mid = (*env)->GetMethodID(env, clazz, "<init>", "(IIII)V");
1244     if (mid != NULL) {
1245         if (usingXinerama) {
1246             if (0 <= screen && screen < awt_numScreens) {
1247                 AWT_LOCK();
1248                 xinInfo = (*XineramaQueryScreens)(awt_display, &locNumScr);
1249                 AWT_UNLOCK();
1250                 if (xinInfo != NULL && locNumScr > 0) {
1251                     if (screen >= locNumScr) {
1252                         screen = 0; // fallback to the main screen
1253                     }
1254                     DASSERT(xinInfo[screen].screen_number == screen);
1255                     bounds = (*env)->NewObject(env, clazz, mid,
1256                                                xinInfo[screen].x_org,
1257                                                xinInfo[screen].y_org,
1258                                                xinInfo[screen].width,
1259                                                xinInfo[screen].height);
1260                     XFree(xinInfo);
1261                 }
1262             } else {
1263                 jclass exceptionClass = (*env)->FindClass(env, "java/lang/IllegalArgumentException");
1264                 if (exceptionClass != NULL) {
1265                     (*env)->ThrowNew(env, exceptionClass, "Illegal screen index");
1266                 }
1267             }
1268         }
1269         if (!bounds) {
1270             // Xinerama cannot provide correct bounds, will try X11
1271             XWindowAttributes xwa;
1272             memset(&xwa, 0, sizeof(xwa));
1273 
1274             AWT_LOCK ();
1275             XGetWindowAttributes(awt_display, RootWindow(awt_display, screen),
1276                     &xwa);
1277             AWT_UNLOCK ();
1278 
1279             bounds = (*env)->NewObject(env, clazz, mid, 0, 0,
1280                     xwa.width, xwa.height);
1281         }
1282 
1283         if ((*env)->ExceptionOccurred(env)) {
1284             return NULL;
1285         }
1286     }
1287     return bounds;
1288 }
1289 
1290 /*
1291  * Class:     sun_awt_X11GraphicsConfig
1292  * Method:    createBackBuffer
1293  * Signature: (JI)J
1294  */
1295 JNIEXPORT jlong JNICALL
Java_sun_awt_X11GraphicsConfig_createBackBuffer(JNIEnv * env,jobject this,jlong window,jint swapAction)1296 Java_sun_awt_X11GraphicsConfig_createBackBuffer
1297     (JNIEnv *env, jobject this, jlong window, jint swapAction)
1298 {
1299     int32_t v1, v2;
1300     XdbeBackBuffer ret = (unsigned long) 0;
1301     Window w = (Window)window;
1302     AWT_LOCK();
1303     if (!XdbeQueryExtension(awt_display, &v1, &v2)) {
1304         JNU_ThrowByName(env, "java/lang/Exception",
1305                         "Could not query double-buffer extension");
1306         AWT_UNLOCK();
1307         return (jlong)0;
1308     }
1309     ret = XdbeAllocateBackBufferName(awt_display, w,
1310                                      (XdbeSwapAction)swapAction);
1311     AWT_FLUSH_UNLOCK();
1312     return (jlong)ret;
1313 }
1314 
1315 /*
1316  * Class:     sun_awt_X11GraphicsConfig
1317  * Method:    destroyBackBuffer
1318  * Signature: (J)V
1319  */
1320 JNIEXPORT void JNICALL
Java_sun_awt_X11GraphicsConfig_destroyBackBuffer(JNIEnv * env,jobject this,jlong backBuffer)1321 Java_sun_awt_X11GraphicsConfig_destroyBackBuffer
1322     (JNIEnv *env, jobject this, jlong backBuffer)
1323 {
1324     AWT_LOCK();
1325     XdbeDeallocateBackBufferName(awt_display, (XdbeBackBuffer)backBuffer);
1326     AWT_FLUSH_UNLOCK();
1327 }
1328 
1329 /*
1330  * Class:     sun_awt_X11GraphicsConfig
1331  * Method:    swapBuffers
1332  * Signature: (JI)V
1333  */
1334 JNIEXPORT void JNICALL
Java_sun_awt_X11GraphicsConfig_swapBuffers(JNIEnv * env,jobject this,jlong window,jint swapAction)1335 Java_sun_awt_X11GraphicsConfig_swapBuffers
1336     (JNIEnv *env, jobject this,
1337      jlong window, jint swapAction)
1338 {
1339     XdbeSwapInfo swapInfo;
1340 
1341     AWT_LOCK();
1342 
1343     XdbeBeginIdiom(awt_display);
1344     swapInfo.swap_window = (Window)window;
1345     swapInfo.swap_action = (XdbeSwapAction)swapAction;
1346     if (!XdbeSwapBuffers(awt_display, &swapInfo, 1)) {
1347         JNU_ThrowInternalError(env, "Could not swap buffers");
1348     }
1349     XdbeEndIdiom(awt_display);
1350 
1351     AWT_FLUSH_UNLOCK();
1352 }
1353 
1354 /*
1355  * Class:     sun_awt_X11GraphicsConfig
1356  * Method:    isTranslucencyCapable
1357  * Signature: (J)V
1358  */
1359 JNIEXPORT jboolean JNICALL
Java_sun_awt_X11GraphicsConfig_isTranslucencyCapable(JNIEnv * env,jobject this,jlong configData)1360 Java_sun_awt_X11GraphicsConfig_isTranslucencyCapable
1361     (JNIEnv *env, jobject this, jlong configData)
1362 {
1363     AwtGraphicsConfigDataPtr aData = (AwtGraphicsConfigDataPtr)jlong_to_ptr(configData);
1364     if (aData == NULL) {
1365         return JNI_FALSE;
1366     }
1367     return aData->isTranslucencySupported ? JNI_TRUE : JNI_FALSE;
1368 }
1369 
1370 /*
1371  * Class:     sun_awt_X11GraphicsDevice
1372  * Method:    isDBESupported
1373  * Signature: ()Z
1374  */
1375 JNIEXPORT jboolean JNICALL
Java_sun_awt_X11GraphicsDevice_isDBESupported(JNIEnv * env,jobject this)1376 Java_sun_awt_X11GraphicsDevice_isDBESupported(JNIEnv *env, jobject this)
1377 {
1378     int opcode = 0, firstEvent = 0, firstError = 0;
1379     jboolean ret;
1380 
1381     AWT_LOCK();
1382     ret = (jboolean)XQueryExtension(awt_display, "DOUBLE-BUFFER",
1383                                     &opcode, &firstEvent, &firstError);
1384     AWT_FLUSH_UNLOCK();
1385     return ret;
1386 }
1387 
1388 /*
1389  * Class:     sun_awt_X11GraphicsDevice
1390  * Method:    getDoubleBufferVisuals
1391  * Signature: (I)V
1392  */
1393 JNIEXPORT void JNICALL
Java_sun_awt_X11GraphicsDevice_getDoubleBufferVisuals(JNIEnv * env,jobject this,jint screen)1394 Java_sun_awt_X11GraphicsDevice_getDoubleBufferVisuals(JNIEnv *env,
1395     jobject this, jint screen)
1396 {
1397     jclass clazz;
1398     jmethodID midAddVisual;
1399     Window rootWindow;
1400     int i, n = 1;
1401     XdbeScreenVisualInfo* visScreenInfo;
1402     int xinawareScreen;
1403 
1404     if (usingXinerama) {
1405         xinawareScreen = 0;
1406     }
1407     else {
1408         xinawareScreen = screen;
1409     }
1410 
1411     clazz = (*env)->GetObjectClass(env, this);
1412     midAddVisual = (*env)->GetMethodID(env, clazz, "addDoubleBufferVisual",
1413         "(I)V");
1414     CHECK_NULL(midAddVisual);
1415     AWT_LOCK();
1416     rootWindow = RootWindow(awt_display, xinawareScreen);
1417     visScreenInfo = XdbeGetVisualInfo(awt_display, &rootWindow, &n);
1418     if (visScreenInfo == NULL) {
1419         JNU_ThrowInternalError(env, "Could not get visual info");
1420         AWT_UNLOCK();
1421         return;
1422     }
1423     AWT_FLUSH_UNLOCK();
1424     for (i = 0; i < visScreenInfo->count; i++) {
1425         XdbeVisualInfo* visInfo = visScreenInfo->visinfo;
1426         (*env)->CallVoidMethod(env, this, midAddVisual, (visInfo[i]).visual);
1427         if ((*env)->ExceptionCheck(env)) {
1428             break;
1429         }
1430     }
1431 }
1432 
1433 /*
1434  * Class:     sun_awt_X11GraphicsEnvironment
1435  * Method:    pRunningXinerama
1436  * Signature: ()Z
1437  */
1438 JNIEXPORT jboolean JNICALL
Java_sun_awt_X11GraphicsEnvironment_pRunningXinerama(JNIEnv * env,jobject this)1439 Java_sun_awt_X11GraphicsEnvironment_pRunningXinerama(JNIEnv *env,
1440     jobject this)
1441 {
1442     return usingXinerama ? JNI_TRUE : JNI_FALSE;
1443 }
1444 
1445 /**
1446  * Begin DisplayMode/FullScreen support
1447  */
1448 
1449 #ifndef NO_XRANDR
1450 
1451 #define BIT_DEPTH_MULTI java_awt_DisplayMode_BIT_DEPTH_MULTI
1452 #define REFRESH_RATE_UNKNOWN java_awt_DisplayMode_REFRESH_RATE_UNKNOWN
1453 
1454 typedef Status
1455     (*XRRQueryVersionType) (Display *dpy, int *major_versionp, int *minor_versionp);
1456 typedef XRRScreenConfiguration*
1457     (*XRRGetScreenInfoType)(Display *dpy, Drawable root);
1458 typedef void
1459     (*XRRFreeScreenConfigInfoType)(XRRScreenConfiguration *config);
1460 typedef short*
1461     (*XRRConfigRatesType)(XRRScreenConfiguration *config,
1462                           int sizeID, int *nrates);
1463 typedef short
1464     (*XRRConfigCurrentRateType)(XRRScreenConfiguration *config);
1465 typedef XRRScreenSize*
1466     (*XRRConfigSizesType)(XRRScreenConfiguration *config,
1467                           int *nsizes);
1468 typedef SizeID
1469     (*XRRConfigCurrentConfigurationType)(XRRScreenConfiguration *config,
1470                                          Rotation *rotation);
1471 typedef Status
1472     (*XRRSetScreenConfigAndRateType)(Display *dpy,
1473                                      XRRScreenConfiguration *config,
1474                                      Drawable draw,
1475                                      int size_index,
1476                                      Rotation rotation,
1477                                      short rate,
1478                                      Time timestamp);
1479 typedef Rotation
1480     (*XRRConfigRotationsType)(XRRScreenConfiguration *config,
1481                               Rotation *current_rotation);
1482 
1483 typedef XRRScreenResources* (*XRRGetScreenResourcesType)(Display *dpy,
1484                                                                  Window window);
1485 
1486 typedef void (*XRRFreeScreenResourcesType)(XRRScreenResources *resources);
1487 
1488 typedef XRROutputInfo * (*XRRGetOutputInfoType)(Display *dpy,
1489                                 XRRScreenResources *resources, RROutput output);
1490 
1491 typedef void (*XRRFreeOutputInfoType)(XRROutputInfo *outputInfo);
1492 
1493 typedef XRRCrtcInfo* (*XRRGetCrtcInfoType)(Display *dpy,
1494                                     XRRScreenResources *resources, RRCrtc crtc);
1495 
1496 typedef void (*XRRFreeCrtcInfoType)(XRRCrtcInfo *crtcInfo);
1497 
1498 static XRRQueryVersionType               awt_XRRQueryVersion;
1499 static XRRGetScreenInfoType              awt_XRRGetScreenInfo;
1500 static XRRFreeScreenConfigInfoType       awt_XRRFreeScreenConfigInfo;
1501 static XRRConfigRatesType                awt_XRRConfigRates;
1502 static XRRConfigCurrentRateType          awt_XRRConfigCurrentRate;
1503 static XRRConfigSizesType                awt_XRRConfigSizes;
1504 static XRRConfigCurrentConfigurationType awt_XRRConfigCurrentConfiguration;
1505 static XRRSetScreenConfigAndRateType     awt_XRRSetScreenConfigAndRate;
1506 static XRRConfigRotationsType            awt_XRRConfigRotations;
1507 static XRRGetScreenResourcesType         awt_XRRGetScreenResources;
1508 static XRRFreeScreenResourcesType        awt_XRRFreeScreenResources;
1509 static XRRGetOutputInfoType              awt_XRRGetOutputInfo;
1510 static XRRFreeOutputInfoType             awt_XRRFreeOutputInfo;
1511 static XRRGetCrtcInfoType                awt_XRRGetCrtcInfo;
1512 static XRRFreeCrtcInfoType               awt_XRRFreeCrtcInfo;
1513 
1514 #define LOAD_XRANDR_FUNC(f) \
1515     do { \
1516         awt_##f = (f##Type)dlsym(pLibRandR, #f); \
1517         if (awt_##f == NULL) { \
1518             J2dRlsTraceLn1(J2D_TRACE_ERROR, \
1519                            "X11GD_InitXrandrFuncs: Could not load %s", #f); \
1520             dlclose(pLibRandR); \
1521             return JNI_FALSE; \
1522         } \
1523     } while (0)
1524 
1525 static jboolean
X11GD_InitXrandrFuncs(JNIEnv * env)1526 X11GD_InitXrandrFuncs(JNIEnv *env)
1527 {
1528     int rr_maj_ver = 0, rr_min_ver = 0;
1529 
1530     void *pLibRandR = dlopen(VERSIONED_JNI_LIB_NAME("Xrandr", "2"),
1531                              RTLD_LAZY | RTLD_LOCAL);
1532     if (pLibRandR == NULL) {
1533         pLibRandR = dlopen(JNI_LIB_NAME("Xrandr"), RTLD_LAZY | RTLD_LOCAL);
1534     }
1535     if (pLibRandR == NULL) {
1536         J2dRlsTraceLn(J2D_TRACE_ERROR,
1537                       "X11GD_InitXrandrFuncs: Could not open libXrandr.so.2");
1538         return JNI_FALSE;
1539     }
1540 
1541     LOAD_XRANDR_FUNC(XRRQueryVersion);
1542 
1543     if (!(*awt_XRRQueryVersion)(awt_display, &rr_maj_ver, &rr_min_ver)) {
1544         J2dRlsTraceLn(J2D_TRACE_ERROR,
1545                       "X11GD_InitXrandrFuncs: XRRQueryVersion returned an error status");
1546         dlclose(pLibRandR);
1547         return JNI_FALSE;
1548     }
1549 
1550     if (usingXinerama) {
1551         /*
1552          * We can proceed as long as this is RANDR 1.2 or above.
1553          * As of Xorg server 1.3 onwards the Xinerama backend may actually be
1554          * a fake one provided by RANDR itself. See Java bug 6636469 for info.
1555          */
1556         if (!(rr_maj_ver > 1 || (rr_maj_ver == 1 && rr_min_ver >= 2))) {
1557             J2dRlsTraceLn2(J2D_TRACE_INFO, "X11GD_InitXrandrFuncs: Can't use Xrandr. "
1558                            "Xinerama is active and Xrandr version is %d.%d",
1559                            rr_maj_ver, rr_min_ver);
1560             dlclose(pLibRandR);
1561             return JNI_FALSE;
1562         }
1563 
1564         /*
1565          * REMIND: Fullscreen mode doesn't work quite right with multi-monitor
1566          * setups and RANDR 1.2.
1567          */
1568         if ((rr_maj_ver == 1 && rr_min_ver <= 2) && awt_numScreens > 1) {
1569             J2dRlsTraceLn(J2D_TRACE_INFO, "X11GD_InitXrandrFuncs: Can't use Xrandr. "
1570                           "Multiple screens in use");
1571             dlclose(pLibRandR);
1572             return JNI_FALSE;
1573         }
1574     }
1575 
1576     LOAD_XRANDR_FUNC(XRRGetScreenInfo);
1577     LOAD_XRANDR_FUNC(XRRFreeScreenConfigInfo);
1578     LOAD_XRANDR_FUNC(XRRConfigRates);
1579     LOAD_XRANDR_FUNC(XRRConfigCurrentRate);
1580     LOAD_XRANDR_FUNC(XRRConfigSizes);
1581     LOAD_XRANDR_FUNC(XRRConfigCurrentConfiguration);
1582     LOAD_XRANDR_FUNC(XRRSetScreenConfigAndRate);
1583     LOAD_XRANDR_FUNC(XRRConfigRotations);
1584     LOAD_XRANDR_FUNC(XRRGetScreenResources);
1585     LOAD_XRANDR_FUNC(XRRFreeScreenResources);
1586     LOAD_XRANDR_FUNC(XRRGetOutputInfo);
1587     LOAD_XRANDR_FUNC(XRRFreeOutputInfo);
1588     LOAD_XRANDR_FUNC(XRRGetCrtcInfo);
1589     LOAD_XRANDR_FUNC(XRRFreeCrtcInfo);
1590 
1591     return JNI_TRUE;
1592 }
1593 
1594 static jobject
X11GD_CreateDisplayMode(JNIEnv * env,jint width,jint height,jint bitDepth,jint refreshRate)1595 X11GD_CreateDisplayMode(JNIEnv *env, jint width, jint height,
1596                         jint bitDepth, jint refreshRate)
1597 {
1598     jclass displayModeClass;
1599     jmethodID cid;
1600     jint validRefreshRate = refreshRate;
1601 
1602     displayModeClass = (*env)->FindClass(env, "java/awt/DisplayMode");
1603     CHECK_NULL_RETURN(displayModeClass, NULL);
1604     if (JNU_IsNull(env, displayModeClass)) {
1605         JNU_ThrowInternalError(env,
1606                                "Could not get display mode class");
1607         return NULL;
1608     }
1609 
1610     cid = (*env)->GetMethodID(env, displayModeClass, "<init>", "(IIII)V");
1611     CHECK_NULL_RETURN(cid, NULL);
1612     if (cid == NULL) {
1613         JNU_ThrowInternalError(env,
1614                                "Could not get display mode constructor");
1615         return NULL;
1616     }
1617 
1618     // early versions of xrandr may report "empty" rates (6880694)
1619     if (validRefreshRate <= 0) {
1620         validRefreshRate = REFRESH_RATE_UNKNOWN;
1621     }
1622 
1623     return (*env)->NewObject(env, displayModeClass, cid,
1624                              width, height, bitDepth, validRefreshRate);
1625 }
1626 
1627 static void
X11GD_AddDisplayMode(JNIEnv * env,jobject arrayList,jint width,jint height,jint bitDepth,jint refreshRate)1628 X11GD_AddDisplayMode(JNIEnv *env, jobject arrayList,
1629                      jint width, jint height,
1630                      jint bitDepth, jint refreshRate)
1631 {
1632     jobject displayMode = X11GD_CreateDisplayMode(env, width, height,
1633                                                   bitDepth, refreshRate);
1634     if (!JNU_IsNull(env, displayMode)) {
1635         jclass arrayListClass;
1636         jmethodID mid;
1637         arrayListClass = (*env)->GetObjectClass(env, arrayList);
1638         if (JNU_IsNull(env, arrayListClass)) {
1639             JNU_ThrowInternalError(env,
1640                                    "Could not get class java.util.ArrayList");
1641             return;
1642         }
1643         mid = (*env)->GetMethodID(env, arrayListClass, "add",
1644                                   "(Ljava/lang/Object;)Z");
1645         CHECK_NULL(mid);
1646         if (mid == NULL) {
1647             JNU_ThrowInternalError(env,
1648                 "Could not get method java.util.ArrayList.add()");
1649             return;
1650         }
1651         (*env)->CallObjectMethod(env, arrayList, mid, displayMode);
1652         (*env)->DeleteLocalRef(env, displayMode);
1653     }
1654 }
1655 
1656 #endif /* !NO_XRANDR */
1657 
1658 static void
X11GD_SetFullscreenMode(Window win,jboolean enabled)1659 X11GD_SetFullscreenMode(Window win, jboolean enabled)
1660 {
1661     Atom wmState = XInternAtom(awt_display, "_NET_WM_STATE", False);
1662     Atom wmStateFs = XInternAtom(awt_display,
1663                                  "_NET_WM_STATE_FULLSCREEN", False);
1664     XWindowAttributes attr;
1665     XEvent event;
1666 
1667     if (wmState == None || wmStateFs == None
1668             || !XGetWindowAttributes(awt_display, win, &attr)) {
1669         return;
1670     }
1671 
1672     memset(&event, 0, sizeof(event));
1673     event.xclient.type = ClientMessage;
1674     event.xclient.message_type = wmState;
1675     event.xclient.display = awt_display;
1676     event.xclient.window = win;
1677     event.xclient.format = 32;
1678     event.xclient.data.l[0] = enabled ? 1 : 0; // 1==add, 0==remove
1679     event.xclient.data.l[1] = wmStateFs;
1680 
1681     XSendEvent(awt_display, attr.root, False,
1682                SubstructureRedirectMask | SubstructureNotifyMask,
1683                &event);
1684     XSync(awt_display, False);
1685 }
1686 
1687 /*
1688  * Class:     sun_awt_X11GraphicsDevice
1689  * Method:    initXrandrExtension
1690  * Signature: ()Z
1691  */
1692 JNIEXPORT jboolean JNICALL
Java_sun_awt_X11GraphicsDevice_initXrandrExtension(JNIEnv * env,jclass x11gd)1693 Java_sun_awt_X11GraphicsDevice_initXrandrExtension
1694     (JNIEnv *env, jclass x11gd)
1695 {
1696 #if defined(NO_XRANDR)
1697     return JNI_FALSE;
1698 #else
1699     int opcode = 0, firstEvent = 0, firstError = 0;
1700     jboolean ret;
1701 
1702     AWT_LOCK();
1703     ret = (jboolean)XQueryExtension(awt_display, "RANDR",
1704                                     &opcode, &firstEvent, &firstError);
1705     if (ret) {
1706         ret = X11GD_InitXrandrFuncs(env);
1707     }
1708     AWT_FLUSH_UNLOCK();
1709 
1710     return ret;
1711 #endif /* NO_XRANDR */
1712 }
1713 
1714 /*
1715  * Class:     sun_awt_X11GraphicsDevice
1716  * Method:    getCurrentDisplayMode
1717  * Signature: (I)Ljava/awt/DisplayMode;
1718  */
1719 JNIEXPORT jobject JNICALL
Java_sun_awt_X11GraphicsDevice_getCurrentDisplayMode(JNIEnv * env,jclass x11gd,jint screen)1720 Java_sun_awt_X11GraphicsDevice_getCurrentDisplayMode
1721     (JNIEnv* env, jclass x11gd, jint screen)
1722 {
1723 #if defined(NO_XRANDR)
1724     return NULL;
1725 #else
1726     XRRScreenConfiguration *config;
1727     jobject displayMode = NULL;
1728 
1729     AWT_LOCK();
1730 
1731     if (screen < ScreenCount(awt_display)) {
1732 
1733         config = awt_XRRGetScreenInfo(awt_display,
1734                                       RootWindow(awt_display, screen));
1735         if (config != NULL) {
1736             Rotation rotation;
1737             short curRate;
1738             SizeID curSizeIndex;
1739             XRRScreenSize *sizes;
1740             int nsizes;
1741 
1742             curSizeIndex = awt_XRRConfigCurrentConfiguration(config, &rotation);
1743             sizes = awt_XRRConfigSizes(config, &nsizes);
1744             curRate = awt_XRRConfigCurrentRate(config);
1745 
1746             if ((sizes != NULL) &&
1747                 (curSizeIndex < nsizes))
1748             {
1749                 XRRScreenSize curSize = sizes[curSizeIndex];
1750                 displayMode = X11GD_CreateDisplayMode(env,
1751                                                       curSize.width,
1752                                                       curSize.height,
1753                                                       BIT_DEPTH_MULTI,
1754                                                       curRate);
1755             }
1756 
1757             awt_XRRFreeScreenConfigInfo(config);
1758         }
1759     }
1760 
1761     AWT_FLUSH_UNLOCK();
1762 
1763     return displayMode;
1764 #endif /* NO_XRANDR */
1765 }
1766 
1767 /*
1768  * Class:     sun_awt_X11GraphicsDevice
1769  * Method:    enumDisplayModes
1770  * Signature: (ILjava/util/ArrayList;)V
1771  */
1772 JNIEXPORT void JNICALL
Java_sun_awt_X11GraphicsDevice_enumDisplayModes(JNIEnv * env,jclass x11gd,jint screen,jobject arrayList)1773 Java_sun_awt_X11GraphicsDevice_enumDisplayModes
1774     (JNIEnv* env, jclass x11gd,
1775      jint screen, jobject arrayList)
1776 {
1777 #if !defined(NO_XRANDR)
1778 
1779     AWT_LOCK();
1780 
1781     if (XScreenCount(awt_display) > 0) {
1782 
1783         XRRScreenConfiguration *config;
1784 
1785         config = awt_XRRGetScreenInfo(awt_display,
1786                                       RootWindow(awt_display, screen));
1787         if (config != NULL) {
1788             int nsizes, i, j;
1789             XRRScreenSize *sizes = awt_XRRConfigSizes(config, &nsizes);
1790 
1791             if (sizes != NULL) {
1792                 for (i = 0; i < nsizes; i++) {
1793                     int nrates;
1794                     XRRScreenSize size = sizes[i];
1795                     short *rates = awt_XRRConfigRates(config, i, &nrates);
1796 
1797                     for (j = 0; j < nrates; j++) {
1798                         X11GD_AddDisplayMode(env, arrayList,
1799                                              size.width,
1800                                              size.height,
1801                                              BIT_DEPTH_MULTI,
1802                                              rates[j]);
1803                         if ((*env)->ExceptionCheck(env)) {
1804                             goto ret1;
1805                         }
1806                     }
1807                 }
1808             }
1809 ret1:
1810             awt_XRRFreeScreenConfigInfo(config);
1811         }
1812     }
1813 
1814     AWT_FLUSH_UNLOCK();
1815 #endif /* !NO_XRANDR */
1816 }
1817 
1818 /*
1819  * Class:     sun_awt_X11GraphicsDevice
1820  * Method:    configDisplayMode
1821  * Signature: (IIII)V
1822  */
1823 JNIEXPORT void JNICALL
Java_sun_awt_X11GraphicsDevice_configDisplayMode(JNIEnv * env,jclass x11gd,jint screen,jint width,jint height,jint refreshRate)1824 Java_sun_awt_X11GraphicsDevice_configDisplayMode
1825     (JNIEnv* env, jclass x11gd,
1826      jint screen, jint width, jint height, jint refreshRate)
1827 {
1828 #if !defined(NO_XRANDR)
1829     jboolean success = JNI_FALSE;
1830     XRRScreenConfiguration *config;
1831     Drawable root;
1832     Rotation currentRotation = RR_Rotate_0;
1833 
1834     AWT_LOCK();
1835 
1836     root = RootWindow(awt_display, screen);
1837     config = awt_XRRGetScreenInfo(awt_display, root);
1838     if (config != NULL) {
1839         jboolean foundConfig = JNI_FALSE;
1840         int chosenSizeIndex = -1;
1841         short chosenRate = -1;
1842         int nsizes;
1843         XRRScreenSize *sizes = awt_XRRConfigSizes(config, &nsizes);
1844         awt_XRRConfigRotations(config, &currentRotation);
1845 
1846         if (sizes != NULL) {
1847             int i, j;
1848 
1849             /* find the size index that matches the requested dimensions */
1850             for (i = 0; i < nsizes; i++) {
1851                 XRRScreenSize size = sizes[i];
1852 
1853                 if ((size.width == width) && (size.height == height)) {
1854                     /* we've found our size index... */
1855                     int nrates;
1856                     short *rates = awt_XRRConfigRates(config, i, &nrates);
1857 
1858                     /* now find rate that matches requested refresh rate */
1859                     for (j = 0; j < nrates; j++) {
1860                         if (rates[j] == refreshRate) {
1861                             /* we've found our rate; break out of the loop */
1862                             chosenSizeIndex = i;
1863                             chosenRate = rates[j];
1864                             foundConfig = JNI_TRUE;
1865                             break;
1866                         }
1867                     }
1868 
1869                     break;
1870                 }
1871             }
1872         }
1873 
1874         if (foundConfig) {
1875             Status status =
1876                 awt_XRRSetScreenConfigAndRate(awt_display, config, root,
1877                                               chosenSizeIndex,
1878                                               currentRotation,
1879                                               chosenRate,
1880                                               CurrentTime);
1881 
1882             /* issue XSync to ensure immediate mode change */
1883             XSync(awt_display, False);
1884 
1885             if (status == RRSetConfigSuccess) {
1886                 success = JNI_TRUE;
1887             }
1888         }
1889 
1890         awt_XRRFreeScreenConfigInfo(config);
1891     }
1892 
1893     AWT_FLUSH_UNLOCK();
1894 
1895     if (!success && !(*env)->ExceptionCheck(env)) {
1896         JNU_ThrowInternalError(env, "Could not set display mode");
1897     }
1898 #endif /* !NO_XRANDR */
1899 }
1900 
1901 /*
1902  * Class:     sun_awt_X11GraphicsDevice
1903  * Method:    enterFullScreenExclusive
1904  * Signature: (J)V
1905  */
1906 JNIEXPORT void JNICALL
Java_sun_awt_X11GraphicsDevice_enterFullScreenExclusive(JNIEnv * env,jclass x11gd,jlong window)1907 Java_sun_awt_X11GraphicsDevice_enterFullScreenExclusive
1908     (JNIEnv* env, jclass x11gd,
1909      jlong window)
1910 {
1911     Window win = (Window)window;
1912 
1913     AWT_LOCK();
1914     XSync(awt_display, False); /* ensures window is visible first */
1915     X11GD_SetFullscreenMode(win, JNI_TRUE);
1916     AWT_UNLOCK();
1917 }
1918 
1919 /*
1920  * Class:     sun_awt_X11GraphicsDevice
1921  * Method:    exitFullScreenExclusive
1922  * Signature: (J)V
1923  */
1924 JNIEXPORT void JNICALL
Java_sun_awt_X11GraphicsDevice_exitFullScreenExclusive(JNIEnv * env,jclass x11gd,jlong window)1925 Java_sun_awt_X11GraphicsDevice_exitFullScreenExclusive
1926     (JNIEnv* env, jclass x11gd,
1927      jlong window)
1928 {
1929     Window win = (Window)window;
1930 
1931     AWT_LOCK();
1932     X11GD_SetFullscreenMode(win, JNI_FALSE);
1933     AWT_UNLOCK();
1934 }
1935 
1936 /**
1937  * End DisplayMode/FullScreen support
1938  */
1939 
1940 /*
1941  * Class:     sun_awt_X11GraphicsDevice
1942  * Method:    getNativeScaleFactor
1943  * Signature: (I)D
1944  */
1945 JNIEXPORT jdouble JNICALL
Java_sun_awt_X11GraphicsDevice_getNativeScaleFactor(JNIEnv * env,jobject this,jint screen)1946 Java_sun_awt_X11GraphicsDevice_getNativeScaleFactor
1947     (JNIEnv *env, jobject this, jint screen) {
1948 
1949     return getNativeScaleFactor();
1950 }
1951