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