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