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