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