rev 60071 : 8211999: Window positioning bugs due to overlapping GraphicsDevice bounds (Windows/HiDPI)
Reviewed-by: XXX

   1 /*
   2  * Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 
  27 
  28 /**
  29  * This class holds the information for a particular graphics device.
  30  * Since a display change can cause the creation of new devices
  31  * at any time, there is no referencing of the devices array allowed.
  32  * Instead, anyone wishing to reference a device in the array (e.g.,
  33  * the current default device or a device for a given hWnd) must
  34  * call one of the static methods of this class with the index of
  35  * the device in question.  Those methods will then lock the devices
  36  * array and forward the request to the current device at that
  37  * array index.
  38  */
  39 
  40 #include <awt.h>
  41 #include <sun_awt_Win32GraphicsDevice.h>
  42 #include "awt_Canvas.h"
  43 #include "awt_Win32GraphicsDevice.h"
  44 #include "awt_Window.h"
  45 #include "java_awt_Transparency.h"
  46 #include "java_awt_color_ColorSpace.h"
  47 #include "sun_awt_Win32GraphicsDevice.h"
  48 #include "java_awt_image_DataBuffer.h"
  49 #include "dither.h"
  50 #include "img_util_md.h"
  51 #include "Devices.h"
  52 #include "systemScale.h"
  53 
  54 uns_ordered_dither_array img_oda_alpha;
  55 
  56 jclass      AwtWin32GraphicsDevice::indexCMClass;
  57 jclass      AwtWin32GraphicsDevice::wToolkitClass;
  58 jfieldID    AwtWin32GraphicsDevice::dynamicColorModelID;
  59 jfieldID    AwtWin32GraphicsDevice::indexCMrgbID;
  60 jfieldID    AwtWin32GraphicsDevice::indexCMcacheID;
  61 jmethodID   AwtWin32GraphicsDevice::paletteChangedMID;
  62 BOOL        AwtWin32GraphicsDevice::primaryPalettized;
  63 int         AwtWin32GraphicsDevice::primaryIndex = 0;
  64 
  65 
  66 /**
  67  * Construct this device.  Store the screen (index into the devices
  68  * array of this object), the array (used in static references via
  69  * particular device indices), the monitor/pMonitorInfo (which other
  70  * classes will inquire of this device), the bits per pixel of this
  71  * device, and information on whether the primary device is palettized.
  72  */
  73 AwtWin32GraphicsDevice::AwtWin32GraphicsDevice(int screen,
  74                                                HMONITOR mhnd, Devices *arr)
  75 {
  76     this->screen  = screen;
  77     this->devicesArray = arr;
  78     this->scaleX = 1;
  79     this->scaleY = 1;
  80     disableScaleAutoRefresh = FALSE;
  81     javaDevice = NULL;
  82     colorData = new ImgColorData;
  83     colorData->grayscale = GS_NOTGRAY;
  84     palette = NULL;
  85     cData = NULL;
  86     gpBitmapInfo = NULL;
  87     monitor = mhnd;
  88     pMonitorInfo = new MONITORINFOEX;
  89     pMonitorInfo->cbSize = sizeof(MONITORINFOEX);
  90     ::GetMonitorInfo(monitor, pMonitorInfo);
  91 
  92     // Set primary device info: other devices will need to know
  93     // whether the primary is palettized during the initialization
  94     // process
  95     HDC hDC = this->GetDC();
  96     colorData->bitsperpixel = ::GetDeviceCaps(hDC, BITSPIXEL);
  97     this->ReleaseDC(hDC);
  98     if (MONITORINFOF_PRIMARY & pMonitorInfo->dwFlags) {
  99         primaryIndex = screen;
 100         if (colorData->bitsperpixel > 8) {
 101             primaryPalettized = FALSE;
 102         } else {
 103             primaryPalettized = TRUE;
 104         }
 105     }
 106 }
 107 
 108 AwtWin32GraphicsDevice::~AwtWin32GraphicsDevice()
 109 {
 110     delete colorData;
 111     if (gpBitmapInfo) {
 112         free(gpBitmapInfo);
 113     }
 114     if (palette) {
 115         delete palette;
 116     }
 117     if (pMonitorInfo) {
 118         delete pMonitorInfo;
 119     }
 120     if (javaDevice) {
 121         JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 122         env->DeleteWeakGlobalRef(javaDevice);
 123     }
 124     if (cData != NULL) {
 125         freeICMColorData(cData);
 126     }
 127 }
 128 
 129 HDC AwtWin32GraphicsDevice::MakeDCFromMonitor(HMONITOR hmMonitor) {
 130     HDC retCode = NULL;
 131     if (NULL != hmMonitor) {
 132         MONITORINFOEX mieInfo;
 133 
 134         memset((void*)(&mieInfo), 0, sizeof(MONITORINFOEX));
 135         mieInfo.cbSize = sizeof(MONITORINFOEX);
 136 
 137         if (TRUE == ::GetMonitorInfo(hmMonitor, (LPMONITORINFOEX)(&mieInfo))) {
 138             HDC hDC = CreateDC(mieInfo.szDevice, NULL, NULL, NULL);
 139             if (NULL != hDC) {
 140                 retCode = hDC;
 141             }
 142         }
 143     }
 144     return retCode;
 145 }
 146 
 147 HDC AwtWin32GraphicsDevice::GetDC()
 148 {
 149     return MakeDCFromMonitor(monitor);
 150 }
 151 
 152 void AwtWin32GraphicsDevice::ReleaseDC(HDC hDC)
 153 {
 154     if (hDC != NULL) {
 155         ::DeleteDC(hDC);
 156     }
 157 }
 158 
 159 /**
 160  * Init this device.  This creates the bitmap structure
 161  * used to hold the device color data and initializes any
 162  * appropriate palette structures.
 163  */
 164 void AwtWin32GraphicsDevice::Initialize()
 165 {
 166     unsigned int ri, gi, bi;
 167     if (colorData->bitsperpixel < 8) {
 168         // REMIND: how to handle?
 169     }
 170 
 171     // Create a BitmapInfo object for color data
 172     if (!gpBitmapInfo) {
 173         try {
 174             gpBitmapInfo = (BITMAPINFO *)
 175                 safe_Malloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
 176         } catch (std::bad_alloc&) {
 177             throw;
 178         }
 179         gpBitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
 180     }
 181     gpBitmapInfo->bmiHeader.biBitCount = 0;
 182     HDC hBMDC = this->GetDC();
 183     HBITMAP hBM = ::CreateCompatibleBitmap(hBMDC, 1, 1);
 184     VERIFY(::GetDIBits(hBMDC, hBM, 0, 1, NULL, gpBitmapInfo, DIB_RGB_COLORS));
 185 
 186     if (colorData->bitsperpixel > 8) {
 187         if (MONITORINFOF_PRIMARY & pMonitorInfo->dwFlags) {
 188             primaryPalettized = FALSE;
 189         }
 190         if (colorData->bitsperpixel != 24) { // 15, 16, or 32 bpp
 191             int foo;
 192             gpBitmapInfo->bmiHeader.biCompression = BI_BITFIELDS;
 193             if (::GetDIBits(hBMDC, hBM, 0, 1, &foo, gpBitmapInfo,
 194                             DIB_RGB_COLORS) == 0)
 195             {
 196                 // Bug 4684966: If GetDIBits returns an error, we could
 197                 // get stuck in an infinite loop setting the colorData
 198                 // fields.  Hardcode bitColors to reasonable values instead.
 199                 // These values are picked according to standard masks
 200                 // for these bit depths on win9x, according to MSDN docs.
 201                 switch (colorData->bitsperpixel) {
 202                 case 15:
 203                     ((int *)gpBitmapInfo->bmiColors)[0] = 0x7c00;
 204                     ((int *)gpBitmapInfo->bmiColors)[1] = 0x03e0;
 205                     ((int *)gpBitmapInfo->bmiColors)[2] = 0x001f;
 206                     break;
 207                 case 16:
 208                     ((int *)gpBitmapInfo->bmiColors)[0] = 0xf800;
 209                     ((int *)gpBitmapInfo->bmiColors)[1] = 0x07e0;
 210                     ((int *)gpBitmapInfo->bmiColors)[2] = 0x001f;
 211                     break;
 212                 case 32:
 213                 default:
 214                     ((int *)gpBitmapInfo->bmiColors)[0] = 0xff0000;
 215                     ((int *)gpBitmapInfo->bmiColors)[1] = 0x00ff00;
 216                     ((int *)gpBitmapInfo->bmiColors)[2] = 0x0000ff;
 217                     break;
 218                 }
 219             }
 220             ri = ((unsigned int *)gpBitmapInfo->bmiColors)[0];
 221             colorData->rOff = 0;
 222             while ((ri & 1) == 0) {
 223                 colorData->rOff++;
 224                 ri >>= 1;
 225             }
 226             colorData->rScale = 0;
 227             while (ri < 0x80) {
 228                 colorData->rScale++;
 229                 ri <<= 1;
 230             }
 231             gi = ((unsigned int *)gpBitmapInfo->bmiColors)[1];
 232             colorData->gOff = 0;
 233             while ((gi & 1) == 0) {
 234                 colorData->gOff++;
 235                 gi >>= 1;
 236             }
 237             colorData->gScale = 0;
 238             while (gi < 0x80) {
 239                 colorData->gScale++;
 240                 gi <<= 1;
 241             }
 242             bi = ((unsigned int *)gpBitmapInfo->bmiColors)[2];
 243             colorData->bOff = 0;
 244             while ((bi & 1) == 0) {
 245                 colorData->bOff++;
 246                 bi >>= 1;
 247             }
 248             colorData->bScale = 0;
 249             while (bi < 0x80) {
 250                 colorData->bScale++;
 251                 bi <<= 1;
 252             }
 253             if (   (0 == colorData->bOff)
 254                 && (5 == colorData->gOff)
 255                 && (10 == colorData->rOff)
 256                 && (3 == colorData->bScale)
 257                 && (3 == colorData->gScale)
 258                 && (3 == colorData->rScale)) {
 259                 colorData->bitsperpixel = 15;
 260                 gpBitmapInfo->bmiHeader.biCompression = BI_RGB;
 261             }
 262         } else {    // 24 bpp
 263             gpBitmapInfo->bmiHeader.biBitCount = 24;
 264             gpBitmapInfo->bmiHeader.biCompression = BI_RGB;
 265 
 266             // Fill these values in as a convenience for the screen
 267             // ColorModel construction code below (see getColorModel())
 268             ((int *)gpBitmapInfo->bmiColors)[0] = 0x0000ff;
 269             ((int *)gpBitmapInfo->bmiColors)[1] = 0x00ff00;
 270             ((int *)gpBitmapInfo->bmiColors)[2] = 0xff0000;
 271         }
 272     } else {
 273         if (MONITORINFOF_PRIMARY & pMonitorInfo->dwFlags) {
 274             primaryPalettized = TRUE;
 275         }
 276         gpBitmapInfo->bmiHeader.biBitCount = 8;
 277         gpBitmapInfo->bmiHeader.biCompression = BI_RGB;
 278         gpBitmapInfo->bmiHeader.biClrUsed = 256;
 279         gpBitmapInfo->bmiHeader.biClrImportant = 256;
 280 
 281         // The initialization of cData is done prior to
 282         // calling palette->Update() since we need it
 283         // for calculating inverseGrayLut
 284         if (cData == NULL) {
 285             cData = (ColorData*)safe_Calloc(1, sizeof(ColorData));
 286             memset(cData, 0, sizeof(ColorData));
 287             initDitherTables(cData);
 288         }
 289 
 290         if (!palette) {
 291             palette = new AwtPalette(this);
 292         } else {
 293             palette->Update();
 294         }
 295         palette->UpdateLogical();
 296     }
 297     VERIFY(::DeleteObject(hBM));
 298     VERIFY(::DeleteDC(hBMDC));
 299 }
 300 
 301 /**
 302  * Creates a new colorModel given the current device configuration.
 303  * The dynamic flag determines whether we use the system palette
 304  * (dynamic == TRUE) or our custom palette in creating a new
 305  * IndexedColorModel.
 306  */
 307 jobject AwtWin32GraphicsDevice::GetColorModel(JNIEnv *env, jboolean dynamic)
 308 {
 309     jobject awt_colormodel;
 310     int i;
 311     if (colorData->bitsperpixel == 24) {
 312         awt_colormodel =
 313             JNU_NewObjectByName(env, "sun/awt/Win32ColorModel24", "()V");
 314     } else if (colorData->bitsperpixel > 8) {
 315         int *masks = (int *)gpBitmapInfo->bmiColors;
 316         int numbits = 0;
 317         unsigned int bits = (masks[0] | masks[1] | masks[2]);
 318         while (bits) {
 319             numbits++;
 320             bits >>= 1;
 321         }
 322         awt_colormodel = JNU_NewObjectByName(env,
 323                                              "java/awt/image/DirectColorModel",
 324                                              "(IIII)V", numbits,
 325                                              masks[0], masks[1], masks[2]);
 326     } else if (colorData->grayscale == GS_STATICGRAY) {
 327         jclass clazz;
 328         jclass clazz1;
 329         jmethodID mid;
 330         jobject cspace = NULL;
 331         jint bits[1];
 332         jintArray bitsArray;
 333 
 334         clazz1 = env->FindClass("java/awt/color/ColorSpace");
 335         CHECK_NULL_RETURN(clazz1, NULL);
 336         mid = env->GetStaticMethodID(clazz1, "getInstance",
 337               "(I)Ljava/awt/color/ColorSpace;");
 338         CHECK_NULL_RETURN(mid, NULL);
 339         cspace = env->CallStaticObjectMethod(clazz1, mid,
 340             java_awt_color_ColorSpace_CS_GRAY);
 341         CHECK_NULL_RETURN(cspace, NULL);
 342 
 343         bits[0] = 8;
 344         bitsArray = env->NewIntArray(1);
 345         if (bitsArray == 0) {
 346             return NULL;
 347         } else {
 348             env->SetIntArrayRegion(bitsArray, 0, 1, bits);
 349         }
 350 
 351         clazz = env->FindClass("java/awt/image/ComponentColorModel");
 352         CHECK_NULL_RETURN(clazz, NULL);
 353         mid = env->GetMethodID(clazz,"<init>",
 354             "(Ljava/awt/color/ColorSpace;[IZZII)V");
 355         CHECK_NULL_RETURN(mid, NULL);
 356 
 357         awt_colormodel = env->NewObject(clazz, mid,
 358                                         cspace,
 359                                         bitsArray,
 360                                         JNI_FALSE,
 361                                         JNI_FALSE,
 362                                         java_awt_Transparency_OPAQUE,
 363                                         java_awt_image_DataBuffer_TYPE_BYTE);
 364     } else {
 365         jintArray hRGB = env->NewIntArray(256);
 366         unsigned int *rgb = NULL, *rgbP = NULL;
 367         jboolean allvalid = JNI_TRUE;
 368         jbyte vbits[256/8];
 369         jobject validBits = NULL;
 370 
 371         CHECK_NULL_RETURN(hRGB, NULL);
 372         /* Create the LUT from the color map */
 373         try {
 374             rgb = (unsigned int *) env->GetPrimitiveArrayCritical(hRGB, 0);
 375             CHECK_NULL_RETURN(rgb, NULL);
 376             rgbP = rgb;
 377             if (!palette) {
 378                 palette = new AwtPalette(this);
 379                 palette->UpdateLogical();
 380             }
 381             if (colorData->grayscale == GS_INDEXGRAY) {
 382                 /* For IndexColorModel, pretend first 10 colors and last
 383                    10 colors are transparent black.  This makes
 384                    ICM.allgrayopaque true.
 385                 */
 386                 unsigned int *logicalEntries = palette->GetLogicalEntries();
 387 
 388                 for (i=0; i < 10; i++) {
 389                     rgbP[i] = 0x00000000;
 390                     rgbP[i+246] = 0x00000000;
 391                 }
 392                 memcpy(&rgbP[10], &logicalEntries[10], 236 * sizeof(RGBQUAD));
 393                 // We need to specify which entries in the colormap are
 394                 // valid so that the transparent black entries we have
 395                 // created do not affect the Transparency setting of the
 396                 // IndexColorModel.  The vbits array is used to construct
 397                 // a BigInteger such that the most significant bit of vbits[0]
 398                 // indicates the validity of the last color (#256) and the
 399                 // least significant bit of vbits[256/8] indicates the
 400                 // validity of the first color (#0).  We need to fill vbits
 401                 // with all 1's and then turn off the first and last 10 bits.
 402                 memset(vbits, 0xff, sizeof(vbits));
 403                 vbits[0] = 0;
 404                 vbits[1] = (jbyte) (0xff >> 2);
 405                 vbits[sizeof(vbits)-2] = (jbyte) (0xff << 2);
 406                 vbits[sizeof(vbits)-1] = 0;
 407                 allvalid = JNI_FALSE;
 408             } else {
 409                 if (!dynamic) {
 410                     // If we plan to use our custom palette (i.e., we are
 411                     // not running inside another app and we are not creating
 412                     // a dynamic colorModel object), then setup ICM with
 413                     // custom palette entries
 414                     unsigned int *logicalEntries = palette->GetLogicalEntries();
 415                     memcpy(rgbP, logicalEntries, 256 * sizeof(int));
 416                 } else {
 417                     // Else, use current system palette entries.
 418                     // REMIND: This may not give the result we want if
 419                     // we are running inside another app and that
 420                     // parent app is running in the background when we
 421                     // reach here.  We could at least cache an "ideal" set of
 422                     // system palette entries from the first time we are
 423                     // running in the foreground and then future ICM's will
 424                     // use that set instead.
 425                     unsigned int *systemEntries = palette->GetSystemEntries();
 426                     memcpy(rgbP, systemEntries, 256 * sizeof(int));
 427                 }
 428             }
 429         } catch (...) {
 430             env->ReleasePrimitiveArrayCritical(hRGB, rgb, 0);
 431             throw;
 432         }
 433 
 434         env->ReleasePrimitiveArrayCritical(hRGB, rgb, 0);
 435 
 436         // Construct a new color model
 437         if (!allvalid) {
 438             jbyteArray bArray = env->NewByteArray(sizeof(vbits));
 439             CHECK_NULL_RETURN(bArray, NULL);
 440             env->SetByteArrayRegion(bArray, 0, sizeof(vbits), vbits);
 441             validBits = JNU_NewObjectByName(env,
 442                                             "java/math/BigInteger",
 443                                             "([B)V", bArray);
 444             JNU_CHECK_EXCEPTION_RETURN(env, NULL);
 445         }
 446         awt_colormodel =
 447             JNU_NewObjectByName(env,
 448                                 "java/awt/image/IndexColorModel",
 449                                 "(II[IIILjava/math/BigInteger;)V",
 450                                 8, 256,
 451                                 hRGB, 0,
 452                                 java_awt_image_DataBuffer_TYPE_BYTE,
 453                                 validBits);
 454     }
 455     return awt_colormodel;
 456 }
 457 
 458 /**
 459  * Called from AwtPalette code when it is determined what grayscale
 460  * value (if any) the current logical palette has
 461  */
 462 void AwtWin32GraphicsDevice::SetGrayness(int grayValue)
 463 {
 464     colorData->grayscale = grayValue;
 465 }
 466 
 467 
 468 /**
 469  * Update our dynamic IndexedColorModel.  This happens after
 470  * a change to the system palette.  Any surfaces stored in vram
 471  * (Win32OffScreenSurfaceData and GDIWindowSurfaceData objects)
 472  * refer to this colorModel and use its lookup table and inverse
 473  * lookup to calculate correct index values for rgb colors.  So
 474  * the colorModel must always reflect the current state of the
 475  * system palette.
 476  */
 477 void AwtWin32GraphicsDevice::UpdateDynamicColorModel()
 478 {
 479     if (!javaDevice) {
 480         // javaDevice may not be set yet.  If not, return.  In
 481         // this situation, we probably don't need an update anyway
 482         // since the colorModel will be created with the correct
 483         // info when the java side is initialized.
 484         return;
 485     }
 486     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 487     jobject colorModel = env->GetObjectField(javaDevice,
 488         dynamicColorModelID);
 489     if (!colorModel) {
 490         return;
 491     }
 492     if (env->IsInstanceOf(colorModel, indexCMClass)) {
 493         // If colorModel not of type ICM then we're not in 8-bit mode and
 494         // don't need to update it
 495         jboolean isCopy;
 496         unsigned int *newEntries = palette->GetSystemEntries();
 497         jintArray rgbArray = (jintArray)env->GetObjectField(colorModel,
 498             AwtWin32GraphicsDevice::indexCMrgbID);
 499         jintArray cacheArray = (jintArray)env->GetObjectField(colorModel,
 500             AwtWin32GraphicsDevice::indexCMcacheID);
 501         if (!rgbArray || !cacheArray) {
 502             JNU_ThrowInternalError(env, "rgb or lookupcache array of IndexColorModel null");
 503             return;
 504         }
 505         int rgbLength = env->GetArrayLength(rgbArray);
 506         int cacheLength = env->GetArrayLength(cacheArray);
 507         jint *cmEntries = (jint *)env->GetPrimitiveArrayCritical(rgbArray, &isCopy);
 508         if (!cmEntries) {
 509             env->ExceptionClear();
 510             JNU_ThrowInternalError(env, "Problem retrieving rgb critical array");
 511             return;
 512         }
 513         jint *cache = (jint *)env->GetPrimitiveArrayCritical(cacheArray, &isCopy);
 514         if (!cache) {
 515             env->ExceptionClear();
 516             env->ReleasePrimitiveArrayCritical(rgbArray, cmEntries, JNI_ABORT);
 517             JNU_ThrowInternalError(env, "Problem retrieving cache critical array");
 518             return;
 519         }
 520         // Set the new rgb values
 521     int i;
 522     for (i = 0; i < rgbLength; ++i) {
 523             cmEntries[i] = newEntries[i];
 524         }
 525         // clear out the old cache
 526         for (i = 0; i < cacheLength; ++i) {
 527             cache[i] = 0;
 528         }
 529         env->ReleasePrimitiveArrayCritical(cacheArray, cache, 0);
 530         env->ReleasePrimitiveArrayCritical(rgbArray, cmEntries, 0);
 531 
 532         // Call WToolkit::paletteChanged() method; this will invalidate
 533         // the offscreen surfaces dependent on this dynamic colorModel
 534         // to ensure that they get redrawn with the correct color indices
 535         env->CallStaticVoidMethod(AwtWin32GraphicsDevice::wToolkitClass,
 536             paletteChangedMID);
 537     }
 538 }
 539 
 540 unsigned int *AwtWin32GraphicsDevice::GetSystemPaletteEntries()
 541 {
 542     // REMIND: What to do if palette NULL?  Need to throw
 543     // some kind of exception?
 544     return palette->GetSystemEntries();
 545 }
 546 
 547 unsigned char *AwtWin32GraphicsDevice::GetSystemInverseLUT()
 548 {
 549     // REMIND: What to do if palette NULL?  Need to throw
 550     // some kind of exception?
 551     return palette->GetSystemInverseLUT();
 552 }
 553 
 554 
 555 BOOL AwtWin32GraphicsDevice::UpdateSystemPalette()
 556 {
 557     if (colorData->bitsperpixel > 8) {
 558         return FALSE;
 559     } else {
 560         return palette->Update();
 561     }
 562 }
 563 
 564 HPALETTE AwtWin32GraphicsDevice::SelectPalette(HDC hDC)
 565 {
 566     if (palette) {
 567         return palette->Select(hDC);
 568     } else {
 569         return NULL;
 570     }
 571 }
 572 
 573 void AwtWin32GraphicsDevice::RealizePalette(HDC hDC)
 574 {
 575     if (palette) {
 576         palette->Realize(hDC);
 577     }
 578 }
 579 
 580 /**
 581  * Deterine which device the HWND exists on and return the
 582  * appropriate index into the devices array.
 583  */
 584 int AwtWin32GraphicsDevice::DeviceIndexForWindow(HWND hWnd)
 585 {
 586     HMONITOR mon = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
 587     int screen = AwtWin32GraphicsDevice::GetScreenFromHMONITOR(mon);
 588     return screen;
 589 }
 590 
 591 /**
 592  * Get the HPALETTE associated with this device
 593  */
 594 HPALETTE AwtWin32GraphicsDevice::GetPalette()
 595 {
 596     if (palette) {
 597         return palette->GetPalette();
 598     } else {
 599         return NULL;
 600     }
 601 }
 602 
 603 /**
 604  * Object referring to this device is releasing that reference.
 605  * This allows the array holding all devices to be released (once
 606  * all references to the array have gone away).
 607  */
 608 void AwtWin32GraphicsDevice::Release()
 609 {
 610     devicesArray->Release();
 611 }
 612 
 613 /**
 614  * Links this native object with its java Win32GraphicsDevice.
 615  * Need this link because the colorModel of the java device
 616  * may be updated from native code.
 617  */
 618 void AwtWin32GraphicsDevice::SetJavaDevice(JNIEnv *env, jobject objPtr)
 619 {
 620     javaDevice = env->NewWeakGlobalRef(objPtr);
 621 }
 622 
 623 /**
 624  * Sets horizontal and vertical scale factors
 625  */
 626 void AwtWin32GraphicsDevice::SetScale(float sx, float sy)
 627 {
 628     scaleX = sx;
 629     scaleY = sy;
 630 }
 631 
 632 int AwtWin32GraphicsDevice::ScaleUpX(int x)
 633 {
 634     return ClipRound(x * scaleX);
 635 }
 636 
 637 int AwtWin32GraphicsDevice::ScaleUpAbsX(int x)
 638 {
 639     LONG screen = pMonitorInfo->rcMonitor.left;
 640     return screen + ClipRound((x - screen) * scaleX);
 641 }
 642 
 643 int AwtWin32GraphicsDevice::ScaleUpY(int y)
 644 {
 645     return ClipRound(y * scaleY);
 646 }
 647 
 648 int AwtWin32GraphicsDevice::ScaleUpAbsY(int y)
 649 {
 650     LONG screen = pMonitorInfo->rcMonitor.top;
 651     return screen + ClipRound((y - screen) * scaleY);
 652 }
 653 
 654 int AwtWin32GraphicsDevice::ScaleDownX(int x)
 655 {
 656     return ClipRound(x / scaleX);
 657 }
 658 
 659 int AwtWin32GraphicsDevice::ScaleDownAbsX(int x)
 660 {
 661     LONG screen = pMonitorInfo->rcMonitor.left;
 662     return screen + ClipRound((x - screen) / scaleX);
 663 }
 664 
 665 int AwtWin32GraphicsDevice::ScaleDownY(int y)
 666 {
 667     return ClipRound(y / scaleY);
 668 }
 669 
 670 int AwtWin32GraphicsDevice::ScaleDownAbsY(int y)
 671 {
 672     LONG screen = pMonitorInfo->rcMonitor.top;
 673     return screen + ClipRound((y - screen) / scaleY);
 674 }
 675 
 676 int AwtWin32GraphicsDevice::ClipRound(double value)
 677 {
 678     value -= 0.5;
 679     if (value < INT_MIN)
 680     {
 681         return INT_MIN;
 682     }
 683 
 684     if (value > INT_MAX)
 685     {
 686         return INT_MAX;
 687     }
 688 
 689     return (int)ceil(value);
 690 }
 691 
 692 void AwtWin32GraphicsDevice::InitDesktopScales() {
 693     if (!disableScaleAutoRefresh) {
 694         float dpiX = -1.0f;
 695         float dpiY = -1.0f;
 696         GetScreenDpi(GetMonitor(), &dpiX, &dpiY);
 697         if (dpiX > 0 && dpiY > 0) {
 698             SetScale(dpiX / 96, dpiY / 96);
 699         }
 700     }
 701 }
 702 
 703 float AwtWin32GraphicsDevice::GetScaleX()
 704 {
 705     return scaleX;
 706 }
 707 
 708 float AwtWin32GraphicsDevice::GetScaleY()
 709 {
 710     return scaleY;
 711 }
 712 
 713 /**
 714  * Disables offscreen acceleration for this device.  This
 715  * sets a flag in the java object that is used to determine
 716  * whether offscreen surfaces can be created on the device.
 717  */
 718 void AwtWin32GraphicsDevice::DisableOffscreenAcceleration()
 719 {
 720     // REMIND: noop for now
 721 }
 722 
 723 void AwtWin32GraphicsDevice::DisableScaleAutoRefresh()
 724 {
 725     disableScaleAutoRefresh = TRUE;
 726 }
 727 
 728 /**
 729  * Invalidates the GraphicsDevice object associated with this
 730  * device by disabling offscreen acceleration and calling
 731  * invalidate(defIndex) on the java object.
 732  */
 733 void AwtWin32GraphicsDevice::Invalidate(JNIEnv *env)
 734 {
 735     int defIndex = AwtWin32GraphicsDevice::GetDefaultDeviceIndex();
 736     DisableOffscreenAcceleration();
 737     jobject javaDevice = GetJavaDevice();
 738     if (!JNU_IsNull(env, javaDevice)) {
 739         JNU_CallMethodByName(env, NULL, javaDevice, "invalidate",
 740                              "(I)V", defIndex);
 741     }
 742 }
 743 
 744 /**
 745  * Static deviceIndex-based methods
 746  *
 747  * The following methods take a deviceIndex for the list of devices
 748  * and perform the appropriate action on that device.  This way of
 749  * dereferencing the list of devices allows us to do appropriate
 750  * locks around the list to ensure multi-threaded safety.
 751  */
 752 
 753 
 754 jobject AwtWin32GraphicsDevice::GetColorModel(JNIEnv *env, jboolean dynamic,
 755                                               int deviceIndex)
 756 {
 757     Devices::InstanceAccess devices;
 758     return devices->GetDevice(deviceIndex)->GetColorModel(env, dynamic);
 759 }
 760 
 761 LPMONITORINFO AwtWin32GraphicsDevice::GetMonitorInfo(int deviceIndex)
 762 {
 763     Devices::InstanceAccess devices;
 764     return devices->GetDevice(deviceIndex)->GetMonitorInfo();
 765 }
 766 
 767 /**
 768  * This function updates the data in the MONITORINFOEX structure pointed to by
 769  * pMonitorInfo for all monitors on the system.  Added for 4654713.
 770  */
 771 void AwtWin32GraphicsDevice::ResetAllMonitorInfo()
 772 {
 773     //IE in some circumstances generates WM_SETTINGCHANGE message on appearance
 774     //and thus triggers this method
 775     //but we may not have the devices list initialized yet.
 776     if (!Devices::GetInstance()){
 777         return;
 778     }
 779     Devices::InstanceAccess devices;
 780     int devicesNum = devices->GetNumDevices();
 781     for (int deviceIndex = 0; deviceIndex < devicesNum; deviceIndex++) {
 782         HMONITOR monitor = devices->GetDevice(deviceIndex)->GetMonitor();
 783         ::GetMonitorInfo(monitor,
 784                          devices->GetDevice(deviceIndex)->pMonitorInfo);
 785     }
 786 }
 787 
 788 /**
 789  * This function updates the scale factor for all monitors on the system.
 790  */
 791 void AwtWin32GraphicsDevice::ResetAllDesktopScales()
 792 {
 793     if (!Devices::GetInstance()){
 794         return;
 795     }
 796     Devices::InstanceAccess devices;
 797     int devicesNum = devices->GetNumDevices();
 798     for (int deviceIndex = 0; deviceIndex < devicesNum; deviceIndex++) {
 799         devices->GetDevice(deviceIndex)->InitDesktopScales();
 800     }
 801 }
 802 
 803 void AwtWin32GraphicsDevice::DisableOffscreenAccelerationForDevice(
 804     HMONITOR hMonitor)
 805 {
 806     Devices::InstanceAccess devices;
 807     if (hMonitor == NULL) {
 808         devices->GetDevice(0)->DisableOffscreenAcceleration();
 809     } else {
 810         int devicesNum = devices->GetNumDevices();
 811         for (int i = 0; i < devicesNum; ++i) {
 812             if (devices->GetDevice(i)->GetMonitor() == hMonitor) {
 813                 devices->GetDevice(i)->DisableOffscreenAcceleration();
 814             }
 815         }
 816     }
 817 }
 818 
 819 HMONITOR AwtWin32GraphicsDevice::GetMonitor(int deviceIndex)
 820 {
 821     Devices::InstanceAccess devices;
 822     return devices->GetDevice(deviceIndex)->GetMonitor();
 823 }
 824 
 825 HPALETTE AwtWin32GraphicsDevice::GetPalette(int deviceIndex)
 826 {
 827     Devices::InstanceAccess devices;
 828     return devices->GetDevice(deviceIndex)->GetPalette();
 829 }
 830 
 831 void AwtWin32GraphicsDevice::UpdateDynamicColorModel(int deviceIndex)
 832 {
 833     Devices::InstanceAccess devices;
 834     devices->GetDevice(deviceIndex)->UpdateDynamicColorModel();
 835 }
 836 
 837 BOOL AwtWin32GraphicsDevice::UpdateSystemPalette(int deviceIndex)
 838 {
 839     Devices::InstanceAccess devices;
 840     return devices->GetDevice(deviceIndex)->UpdateSystemPalette();
 841 }
 842 
 843 HPALETTE AwtWin32GraphicsDevice::SelectPalette(HDC hDC, int deviceIndex)
 844 {
 845     Devices::InstanceAccess devices;
 846     return devices->GetDevice(deviceIndex)->SelectPalette(hDC);
 847 }
 848 
 849 void AwtWin32GraphicsDevice::RealizePalette(HDC hDC, int deviceIndex)
 850 {
 851     Devices::InstanceAccess devices;
 852     devices->GetDevice(deviceIndex)->RealizePalette(hDC);
 853 }
 854 
 855 ColorData *AwtWin32GraphicsDevice::GetColorData(int deviceIndex)
 856 {
 857     Devices::InstanceAccess devices;
 858     return devices->GetDevice(deviceIndex)->GetColorData();
 859 }
 860 
 861 /**
 862  * Return the grayscale value for the indicated device.
 863  */
 864 int AwtWin32GraphicsDevice::GetGrayness(int deviceIndex)
 865 {
 866     Devices::InstanceAccess devices;
 867     return devices->GetDevice(deviceIndex)->GetGrayness();
 868 }
 869 
 870 HDC AwtWin32GraphicsDevice::GetDCFromScreen(int screen) {
 871     J2dTraceLn1(J2D_TRACE_INFO,
 872                 "AwtWin32GraphicsDevice::GetDCFromScreen screen=%d", screen);
 873     Devices::InstanceAccess devices;
 874     AwtWin32GraphicsDevice *dev = devices->GetDevice(screen);
 875     return MakeDCFromMonitor(dev->GetMonitor());
 876 }
 877 
 878 /** Compare elements of MONITORINFOEX structures for the given HMONITORs.
 879  * If equal, return TRUE
 880  */
 881 BOOL AwtWin32GraphicsDevice::AreSameMonitors(HMONITOR mon1, HMONITOR mon2) {
 882     J2dTraceLn2(J2D_TRACE_INFO,
 883                 "AwtWin32GraphicsDevice::AreSameMonitors mhnd1=%x mhnd2=%x",
 884                 mon1, mon2);
 885     DASSERT(mon1 != NULL);
 886     DASSERT(mon2 != NULL);
 887 
 888     MONITORINFOEX mi1;
 889     MONITORINFOEX mi2;
 890 
 891     memset((void*)(&mi1), 0, sizeof(MONITORINFOEX));
 892     mi1.cbSize = sizeof(MONITORINFOEX);
 893     memset((void*)(&mi2), 0, sizeof(MONITORINFOEX));
 894     mi2.cbSize = sizeof(MONITORINFOEX);
 895 
 896     if (::GetMonitorInfo(mon1, &mi1) != 0 &&
 897         ::GetMonitorInfo(mon2, &mi2) != 0 )
 898     {
 899         if (::EqualRect(&mi1.rcMonitor, &mi2.rcMonitor) &&
 900             ::EqualRect(&mi1.rcWork, &mi2.rcWork) &&
 901             (mi1.dwFlags  == mi1.dwFlags))
 902         {
 903 
 904             J2dTraceLn(J2D_TRACE_VERBOSE, "  the monitors are the same");
 905             return TRUE;
 906         }
 907     }
 908     J2dTraceLn(J2D_TRACE_VERBOSE, "  the monitors are not the same");
 909     return FALSE;
 910 }
 911 
 912 int AwtWin32GraphicsDevice::GetScreenFromHMONITOR(HMONITOR mon) {
 913     J2dTraceLn1(J2D_TRACE_INFO,
 914                 "AwtWin32GraphicsDevice::GetScreenFromHMONITOR mhnd=%x", mon);
 915 
 916     DASSERT(mon != NULL);
 917     JNIEnv *env = (JNIEnv*) JNU_GetEnv(jvm, JNI_VERSION_1_2);
 918     if (!Devices::GetInstance()) {
 919        Devices::UpdateInstance(env);
 920     }
 921     Devices::InstanceAccess devices;
 922 
 923     for (int i = 0; i < devices->GetNumDevices(); i++) {
 924         HMONITOR mhnd = devices->GetDevice(i)->GetMonitor();
 925         if (AreSameMonitors(mon, mhnd)) {
 926             J2dTraceLn1(J2D_TRACE_VERBOSE, "  Found device: %d", i);
 927             return i;
 928         }
 929     }
 930 
 931     J2dTraceLn1(J2D_TRACE_WARNING,
 932                 "AwtWin32GraphicsDevice::GetScreenFromHMONITOR(): "\
 933                 "couldn't find screen for HMONITOR %x, returning default", mon);
 934     return AwtWin32GraphicsDevice::GetDefaultDeviceIndex();
 935 }
 936 
 937 
 938 /**
 939  * End of static deviceIndex-based methods
 940  */
 941 
 942 
 943     const DWORD REQUIRED_FLAGS = (   //Flags which must be set in
 944      PFD_SUPPORT_GDI |               //in the PixelFormatDescriptor.
 945      PFD_DRAW_TO_WINDOW);            //Used to choose the default config
 946                                      //and to check formats in
 947                                      //isPixFmtSupported()
 948 extern "C" {
 949 
 950 JNIEXPORT void JNICALL
 951 Java_sun_awt_Win32GraphicsDevice_initIDs(JNIEnv *env, jclass cls)
 952 {
 953     TRY;
 954 
 955     /* class ids */
 956     jclass iCMClass = env->FindClass("java/awt/image/IndexColorModel");
 957     CHECK_NULL(iCMClass);
 958     AwtWin32GraphicsDevice::indexCMClass = (jclass) env->NewGlobalRef(iCMClass);
 959     env->DeleteLocalRef(iCMClass);
 960     DASSERT(AwtWin32GraphicsDevice::indexCMClass);
 961     CHECK_NULL(AwtWin32GraphicsDevice::indexCMClass);
 962 
 963     jclass wTClass = env->FindClass("sun/awt/windows/WToolkit");
 964     CHECK_NULL(wTClass);
 965     AwtWin32GraphicsDevice::wToolkitClass = (jclass)env->NewGlobalRef(wTClass);
 966     env->DeleteLocalRef(wTClass);
 967     DASSERT(AwtWin32GraphicsDevice::wToolkitClass);
 968     CHECK_NULL(AwtWin32GraphicsDevice::wToolkitClass);
 969 
 970     /* field ids */
 971     AwtWin32GraphicsDevice::dynamicColorModelID = env->GetFieldID(cls,
 972         "dynamicColorModel", "Ljava/awt/image/ColorModel;");
 973     DASSERT(AwtWin32GraphicsDevice::dynamicColorModelID);
 974     CHECK_NULL(AwtWin32GraphicsDevice::dynamicColorModelID);
 975 
 976     AwtWin32GraphicsDevice::indexCMrgbID =
 977         env->GetFieldID(AwtWin32GraphicsDevice::indexCMClass, "rgb", "[I");
 978     DASSERT(AwtWin32GraphicsDevice::indexCMrgbID);
 979     CHECK_NULL(AwtWin32GraphicsDevice::indexCMrgbID);
 980 
 981     AwtWin32GraphicsDevice::indexCMcacheID =
 982         env->GetFieldID(AwtWin32GraphicsDevice::indexCMClass,
 983         "lookupcache", "[I");
 984     DASSERT(AwtWin32GraphicsDevice::indexCMcacheID);
 985     CHECK_NULL(AwtWin32GraphicsDevice::indexCMcacheID);
 986 
 987     /* method ids */
 988     AwtWin32GraphicsDevice::paletteChangedMID = env->GetStaticMethodID(
 989         AwtWin32GraphicsDevice::wToolkitClass, "paletteChanged", "()V");
 990     DASSERT(AwtWin32GraphicsDevice::paletteChangedMID);
 991     CHECK_NULL(AwtWin32GraphicsDevice::paletteChangedMID);
 992 
 993     // Only want to call this once per session
 994     make_uns_ordered_dither_array(img_oda_alpha, 256);
 995 
 996     // workaround JDK-6477756, ignore return value to keep dll in memory
 997     JDK_LoadSystemLibrary("opengl32.dll");
 998 
 999     CATCH_BAD_ALLOC;
1000 }
1001 
1002 } /* extern "C" */
1003 
1004 
1005 /*
1006  * Class:     sun_awt_Win32GraphicsDevice
1007  * Method:    getMaxConfigsImpl
1008  * Signature: ()I
1009  */
1010 
1011 JNIEXPORT jint JNICALL Java_sun_awt_Win32GraphicsDevice_getMaxConfigsImpl
1012     (JNIEnv* jniEnv, jobject theThis, jint screen) {
1013         TRY;
1014     HDC hDC = AwtWin32GraphicsDevice::GetDCFromScreen(screen);
1015 
1016     PIXELFORMATDESCRIPTOR pfd;
1017     int max = ::DescribePixelFormat(hDC, 1, sizeof(PIXELFORMATDESCRIPTOR),
1018         &pfd);
1019     if (hDC != NULL) {
1020         VERIFY(::DeleteDC(hDC));
1021         hDC = NULL;
1022     }
1023     //If ::DescribePixelFormat() fails, max = 0
1024     //In this case, we return 1 config with visual number 0
1025     if (max == 0) {
1026         max = 1;
1027     }
1028     return (jint)max;
1029         CATCH_BAD_ALLOC_RET(0);
1030 }
1031 
1032 /*
1033  * Class:     sun_awt_Win32GraphicsDevice
1034  * Method:    isPixFmtSupported
1035  * Signature: (I)Z
1036  */
1037 
1038 JNIEXPORT jboolean JNICALL Java_sun_awt_Win32GraphicsDevice_isPixFmtSupported
1039     (JNIEnv* env, jobject theThis, jint pixFmtID, jint screen) {
1040         TRY;
1041     jboolean suppColor = JNI_TRUE;
1042     HDC hDC = AwtWin32GraphicsDevice::GetDCFromScreen(screen);
1043 
1044     if (pixFmtID == 0) {
1045         return true;
1046     }
1047 
1048     PIXELFORMATDESCRIPTOR pfd;
1049     int max = ::DescribePixelFormat(hDC, (int)pixFmtID,
1050         sizeof(PIXELFORMATDESCRIPTOR), &pfd);
1051     DASSERT(max);
1052 
1053     //Check for supported ColorModel
1054     if ((pfd.cColorBits < 8) ||
1055        ((pfd.cColorBits == 8) && (pfd.iPixelType != PFD_TYPE_COLORINDEX))) {
1056         //Note: this still allows for PixelFormats with > 8 color bits
1057         //which use COLORINDEX instead of RGB.  This seems to work fine,
1058         //although issues may crop up involving PFD_NEED_PALETTE, which
1059         //is not currently taken into account.
1060         //If changes are made, they should also be reflected in
1061         //getDefaultPixID.
1062         suppColor = JNI_FALSE;
1063     }
1064 
1065     if (hDC != NULL) {
1066         VERIFY(::DeleteDC(hDC));
1067         hDC = NULL;
1068     }
1069     return (((pfd.dwFlags & REQUIRED_FLAGS) == REQUIRED_FLAGS) && suppColor) ?
1070      JNI_TRUE : JNI_FALSE;
1071         CATCH_BAD_ALLOC_RET(FALSE);
1072 }
1073 
1074 /*
1075  * Class:     sun_awt_Win32GraphicsDevice
1076  * Method:    getDefaultPixIDImpl
1077  * Signature: (I)I
1078  */
1079 
1080 JNIEXPORT jint JNICALL Java_sun_awt_Win32GraphicsDevice_getDefaultPixIDImpl
1081     (JNIEnv* env, jobject theThis, jint screen) {
1082         TRY;
1083     int pixFmtID = 0;
1084     HDC hDC = AwtWin32GraphicsDevice::GetDCFromScreen(screen);
1085 
1086     PIXELFORMATDESCRIPTOR pfd = {
1087         sizeof(PIXELFORMATDESCRIPTOR),
1088         1,               //version
1089         REQUIRED_FLAGS,  //flags
1090         0,               //iPixelType
1091         0,               //cColorBits
1092         0,0,0,0,0,0,0,0, //cRedBits, cRedShift, green, blue, alpha
1093         0,0,0,0,0,       //cAccumBits, cAccumRedBits, green, blue, alpha
1094         0,0,0,0,0,0,0,0  //etc.
1095     };
1096 
1097     //If 8-bit mode, must use Indexed mode
1098     if (8 == ::GetDeviceCaps(hDC, BITSPIXEL)) {
1099         pfd.iPixelType = PFD_TYPE_COLORINDEX;
1100     }
1101 
1102     pixFmtID = ::ChoosePixelFormat(hDC, &pfd);
1103     if (pixFmtID == 0) {
1104         //Return 0 if GDI call fails.
1105         if (hDC != NULL) {
1106             VERIFY(::DeleteDC(hDC));
1107             hDC = NULL;
1108         }
1109         return pixFmtID;
1110     }
1111 
1112     if (JNI_FALSE == Java_sun_awt_Win32GraphicsDevice_isPixFmtSupported(
1113      env, theThis, pixFmtID, screen)) {
1114         /* Can't find a suitable pixel format ID.  Fall back on 0. */
1115         pixFmtID = 0;
1116     }
1117 
1118     VERIFY(::DeleteDC(hDC));
1119     hDC = NULL;
1120     return (jint)pixFmtID;
1121         CATCH_BAD_ALLOC_RET(0);
1122 }
1123 
1124 /*
1125  * Class:     sun_awt_Win32GraphicsDevice
1126  * Method:    enterFullScreenExclusive
1127  * Signature: (Ljava/awt/peer/WindowPeer;)V
1128  */
1129 
1130 JNIEXPORT void JNICALL
1131 Java_sun_awt_Win32GraphicsDevice_enterFullScreenExclusive(
1132         JNIEnv* env, jobject graphicsDevice,
1133         jint screen, jobject windowPeer) {
1134 
1135     TRY;
1136 
1137     PDATA pData;
1138     JNI_CHECK_PEER_RETURN(windowPeer);
1139 
1140     AwtWindow *window = (AwtWindow *)pData;  // safe cast since we are called
1141                                              // with the WWindowPeer object
1142     HWND hWnd = window->GetHWnd();
1143 
1144     if (!::SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0,
1145                         SWP_NOMOVE|SWP_NOOWNERZORDER|SWP_NOSIZE))
1146     {
1147         J2dTraceLn1(J2D_TRACE_ERROR,
1148                     "Error %d setting topmost attribute to fs window",
1149                     ::GetLastError());
1150     }
1151 
1152     CATCH_BAD_ALLOC;
1153 }
1154 
1155 /*
1156  * Class:     sun_awt_Win32GraphicsDevice
1157  * Method:    exitFullScreenExclusive
1158  * Signature: (Ljava/awt/peer/WindowPeer;)V
1159  */
1160 
1161 JNIEXPORT void JNICALL
1162 Java_sun_awt_Win32GraphicsDevice_exitFullScreenExclusive(
1163         JNIEnv* env, jobject graphicsDevice,
1164         jint screen, jobject windowPeer) {
1165 
1166     TRY;
1167 
1168     PDATA pData;
1169     JNI_CHECK_PEER_RETURN(windowPeer);
1170 
1171     AwtWindow *window = (AwtWindow *)pData;  // safe cast since we are called
1172                                              // with the WWindowPeer object
1173     HWND hWnd = window->GetHWnd();
1174 
1175     jobject target = env->GetObjectField(windowPeer, AwtObject::targetID);
1176     jboolean alwaysOnTop = JNU_GetFieldByName(env, NULL, target, "alwaysOnTop", "Z").z;
1177     env->DeleteLocalRef(target);
1178 
1179     if (!::SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 0, 0,
1180                         SWP_NOMOVE|SWP_NOOWNERZORDER|SWP_NOSIZE))
1181     {
1182         J2dTraceLn1(J2D_TRACE_ERROR,
1183                     "Error %d unsetting topmost attribute to fs window",
1184                     ::GetLastError());
1185     }
1186 
1187     // We should restore alwaysOnTop state as it's anyway dropped here
1188     Java_sun_awt_windows_WWindowPeer_setAlwaysOnTopNative(env, windowPeer, alwaysOnTop);
1189 
1190     CATCH_BAD_ALLOC;
1191 }
1192 
1193 jobject CreateDisplayMode(JNIEnv* env, jint width, jint height,
1194     jint bitDepth, jint refreshRate) {
1195 
1196     TRY;
1197 
1198     jclass displayModeClass = env->FindClass("java/awt/DisplayMode");
1199     if (JNU_IsNull(env, displayModeClass)) {
1200         env->ExceptionClear();
1201         JNU_ThrowInternalError(env, "Could not get display mode class");
1202         return NULL;
1203     }
1204 
1205     jmethodID cid = env->GetMethodID(displayModeClass, "<init>", "(IIII)V");
1206     if (cid == NULL) {
1207         env->ExceptionClear();
1208         JNU_ThrowInternalError(env, "Could not get display mode constructor");
1209         return NULL;
1210     }
1211 
1212     jobject displayMode = env->NewObject(displayModeClass, cid, width,
1213         height, bitDepth, refreshRate);
1214     return displayMode;
1215 
1216     CATCH_BAD_ALLOC_RET(NULL);
1217 }
1218 
1219 /**
1220  * A utility function which retrieves a DISPLAY_DEVICE information
1221  * given a screen number.
1222  *
1223  * If the function was able to find an attached device for the given screen
1224  * number, the lpDisplayDevice will be initialized with the data and
1225  * the function will return TRUE, otherwise it returns FALSE and contents
1226  * of the structure pointed to by lpDisplayDevice is undefined.
1227  */
1228 static BOOL
1229 GetAttachedDisplayDevice(int screen, DISPLAY_DEVICE *lpDisplayDevice)
1230 {
1231     DWORD dwDeviceNum = 0;
1232     lpDisplayDevice->cb = sizeof(DISPLAY_DEVICE);
1233     while (EnumDisplayDevices(NULL, dwDeviceNum, lpDisplayDevice, 0) &&
1234            dwDeviceNum < 20) // avoid infinite loop with buggy drivers
1235     {
1236         if (lpDisplayDevice->StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) {
1237             Devices::InstanceAccess devices;
1238             MONITORINFOEX *pMonInfo =
1239                 (LPMONITORINFOEX)devices->GetDevice(screen)->GetMonitorInfo();
1240             // make sure the device names match
1241             if (wcscmp(pMonInfo->szDevice, lpDisplayDevice->DeviceName) == 0) {
1242                 return TRUE;
1243             }
1244         }
1245         dwDeviceNum++;
1246     }
1247     return FALSE;
1248 }
1249 
1250 /*
1251  * Class:     sun_awt_Win32GraphicsDevice
1252  * Method:    getCurrentDisplayMode
1253  * Signature: (IZ)Ljava/awt/DisplayMode;
1254  */
1255 JNIEXPORT jobject JNICALL
1256 Java_sun_awt_Win32GraphicsDevice_getCurrentDisplayMode
1257     (JNIEnv* env, jobject graphicsDevice, jint screen)
1258 {
1259     TRY;
1260 
1261     DEVMODE dm;
1262     LPTSTR pName = NULL;
1263 
1264     dm.dmSize = sizeof(dm);
1265     dm.dmDriverExtra = 0;
1266 
1267     DISPLAY_DEVICE displayDevice;
1268     if (GetAttachedDisplayDevice(screen, &displayDevice)) {
1269         pName = displayDevice.DeviceName;
1270     }
1271     if (!EnumDisplaySettings(pName, ENUM_CURRENT_SETTINGS, &dm))
1272     {
1273         return NULL;
1274     }
1275 
1276     return CreateDisplayMode(env, dm.dmPelsWidth,
1277         dm.dmPelsHeight, dm.dmBitsPerPel, dm.dmDisplayFrequency);
1278 
1279     CATCH_BAD_ALLOC_RET(NULL);
1280 }
1281 
1282 /*
1283  * Class:     sun_awt_Win32GraphicsDevice
1284  * Method:    configDisplayMode
1285  * Signature: (IIIIZ)V
1286  */
1287 JNIEXPORT void JNICALL
1288 Java_sun_awt_Win32GraphicsDevice_configDisplayMode
1289     (JNIEnv* env, jobject graphicsDevice, jint screen, jobject windowPeer,
1290      jint width, jint height, jint bitDepth, jint refreshRate)
1291 {
1292     TRY;
1293 
1294         DEVMODE dm;
1295 
1296     dm.dmSize = sizeof(dm);
1297     dm.dmDriverExtra = 0;
1298     dm.dmPelsWidth = width;
1299     dm.dmPelsHeight = height;
1300     dm.dmBitsPerPel = bitDepth;
1301     dm.dmDisplayFrequency = refreshRate;
1302     dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT |
1303         DM_BITSPERPEL | DM_DISPLAYFREQUENCY;
1304 
1305     // ChangeDisplaySettings works only on the primary screen.
1306     // ChangeDisplaySettingsEx is not available on NT,
1307     // so it'd be nice not to break it if we can help it.
1308     if (screen == AwtWin32GraphicsDevice::GetDefaultDeviceIndex()) {
1309         if (::ChangeDisplaySettings(&dm, CDS_FULLSCREEN) !=
1310             DISP_CHANGE_SUCCESSFUL)
1311         {
1312             JNU_ThrowInternalError(env,
1313                                    "Could not set display mode");
1314         }
1315         return;
1316     }
1317 
1318     DISPLAY_DEVICE displayDevice;
1319     if (!GetAttachedDisplayDevice(screen, &displayDevice) ||
1320         (::ChangeDisplaySettingsEx(displayDevice.DeviceName, &dm, NULL, CDS_FULLSCREEN, NULL) !=
1321           DISP_CHANGE_SUCCESSFUL))
1322     {
1323         JNU_ThrowInternalError(env,
1324                                "Could not set display mode");
1325     }
1326 
1327     CATCH_BAD_ALLOC;
1328 }
1329 
1330 class EnumDisplayModeParam {
1331 public:
1332     EnumDisplayModeParam(JNIEnv* e, jobject a) : env(e), arrayList(a) {}
1333     JNIEnv* env;
1334     jobject arrayList;
1335 };
1336 
1337 void addDisplayMode(JNIEnv* env, jobject arrayList, jint width,
1338     jint height, jint bitDepth, jint refreshRate) {
1339 
1340     TRY;
1341 
1342     jobject displayMode = CreateDisplayMode(env, width, height,
1343         bitDepth, refreshRate);
1344     if (!JNU_IsNull(env, displayMode)) {
1345         jclass arrayListClass = env->GetObjectClass(arrayList);
1346         if (JNU_IsNull(env, arrayListClass)) {
1347             JNU_ThrowInternalError(env,
1348                 "Could not get class java.util.ArrayList");
1349             return;
1350         }
1351         jmethodID mid = env->GetMethodID(arrayListClass, "add",
1352         "(Ljava/lang/Object;)Z");
1353         if (mid == NULL) {
1354             env->ExceptionClear();
1355             JNU_ThrowInternalError(env,
1356                 "Could not get method java.util.ArrayList.add()");
1357             return;
1358         }
1359         env->CallObjectMethod(arrayList, mid, displayMode);
1360         env->DeleteLocalRef(displayMode);
1361     }
1362 
1363     CATCH_BAD_ALLOC;
1364 }
1365 
1366 /*
1367  * Class:     sun_awt_Win32GraphicsDevice
1368  * Method:    enumDisplayModes
1369  * Signature: (Ljava/util/ArrayList;Z)V
1370  */
1371 JNIEXPORT void JNICALL Java_sun_awt_Win32GraphicsDevice_enumDisplayModes
1372     (JNIEnv* env, jobject graphicsDevice, jint screen, jobject arrayList)
1373 {
1374 
1375     TRY;
1376 
1377     DEVMODE dm;
1378     LPTSTR pName = NULL;
1379     DISPLAY_DEVICE displayDevice;
1380 
1381 
1382     if (GetAttachedDisplayDevice(screen, &displayDevice)) {
1383         pName = displayDevice.DeviceName;
1384     }
1385 
1386     dm.dmSize = sizeof(dm);
1387     dm.dmDriverExtra = 0;
1388 
1389     BOOL bContinue = TRUE;
1390     for (int i = 0; bContinue; i++) {
1391         bContinue = EnumDisplaySettings(pName, i, &dm);
1392         if (dm.dmBitsPerPel >= 8) {
1393             addDisplayMode(env, arrayList, dm.dmPelsWidth, dm.dmPelsHeight,
1394                            dm.dmBitsPerPel, dm.dmDisplayFrequency);
1395             JNU_CHECK_EXCEPTION(env);
1396         }
1397     }
1398 
1399     CATCH_BAD_ALLOC;
1400 }
1401 
1402 /*
1403  * Class:     sun_awt_Win32GraphicsDevice
1404  * Method:    makeColorModel
1405  * Signature: ()Ljava/awt/image/ColorModel
1406  */
1407 
1408 JNIEXPORT jobject JNICALL
1409     Java_sun_awt_Win32GraphicsDevice_makeColorModel
1410     (JNIEnv *env, jobject thisPtr, jint screen, jboolean dynamic)
1411 {
1412     Devices::InstanceAccess devices;
1413     return devices->GetDevice(screen)->GetColorModel(env, dynamic);
1414 }
1415 
1416 /*
1417  * Class:     sun_awt_Win32GraphicsDevice
1418  * Method:    initDevice
1419  * Signature: (I)V
1420  */
1421 JNIEXPORT void JNICALL
1422     Java_sun_awt_Win32GraphicsDevice_initDevice
1423     (JNIEnv *env, jobject thisPtr, jint screen)
1424 {
1425     Devices::InstanceAccess devices;
1426     devices->GetDevice(screen)->SetJavaDevice(env, thisPtr);
1427 }
1428 
1429 /*
1430  * Class:     sun_awt_Win32GraphicsDevice
1431  * Method:    setNativeScale
1432  * Signature: (I,F,F)V
1433  */
1434 JNIEXPORT void JNICALL
1435     Java_sun_awt_Win32GraphicsDevice_setNativeScale
1436     (JNIEnv *env, jobject thisPtr, jint screen, jfloat scaleX, jfloat scaleY)
1437 {
1438     Devices::InstanceAccess devices;
1439     AwtWin32GraphicsDevice *device = devices->GetDevice(screen);
1440 
1441     if (device != NULL ) {
1442         device->DisableScaleAutoRefresh();
1443         device->SetScale(scaleX, scaleY);
1444     }
1445 }
1446 
1447 /*
1448  * Class:     sun_awt_Win32GraphicsDevice
1449  * Method:    getNativeScaleX
1450  * Signature: (I)F
1451  */
1452 JNIEXPORT jfloat JNICALL
1453     Java_sun_awt_Win32GraphicsDevice_getNativeScaleX
1454     (JNIEnv *env, jobject thisPtr, jint screen)
1455 {
1456     Devices::InstanceAccess devices;
1457     AwtWin32GraphicsDevice *device = devices->GetDevice(screen);
1458     return (device == NULL) ? 1 : device->GetScaleX();
1459 }
1460 
1461 /*
1462  * Class:     sun_awt_Win32GraphicsDevice
1463  * Method:    getNativeScaleY
1464  * Signature: (I)F
1465  */
1466 JNIEXPORT jfloat JNICALL
1467     Java_sun_awt_Win32GraphicsDevice_getNativeScaleY
1468     (JNIEnv *env, jobject thisPtr, jint screen)
1469 {
1470     Devices::InstanceAccess devices;
1471     AwtWin32GraphicsDevice *device = devices->GetDevice(screen);
1472     return (device == NULL) ? 1 : device->GetScaleY();
1473 }
1474 
1475 /*
1476 * Class:     sun_awt_Win32GraphicsDevice
1477 * Method:    initNativeScale
1478 * Signature: (I)V;
1479 */
1480 JNIEXPORT void JNICALL
1481 Java_sun_awt_Win32GraphicsDevice_initNativeScale
1482 (JNIEnv *env, jobject thisPtr, jint screen)
1483 {
1484     Devices::InstanceAccess devices;
1485     AwtWin32GraphicsDevice *device = devices->GetDevice(screen);
1486 
1487     if (device != NULL) {
1488         device->InitDesktopScales();
1489     }
1490 }
1491 
--- EOF ---