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