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