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  */
AwtWin32GraphicsDevice(int screen,HMONITOR mhnd,Devices * arr)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 
~AwtWin32GraphicsDevice()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 
MakeDCFromMonitor(HMONITOR hmMonitor)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 
GetDC()143 HDC AwtWin32GraphicsDevice::GetDC()
144 {
145     return MakeDCFromMonitor(monitor);
146 }
147 
ReleaseDC(HDC hDC)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  */
Initialize()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  */
GetColorModel(JNIEnv * env,jboolean dynamic)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  */
SetGrayness(int grayValue)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  */
UpdateDynamicColorModel()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 
GetSystemPaletteEntries()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 
GetSystemInverseLUT()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 
UpdateSystemPalette()551 BOOL AwtWin32GraphicsDevice::UpdateSystemPalette()
552 {
553     if (colorData->bitsperpixel > 8) {
554         return FALSE;
555     } else {
556         return palette->Update();
557     }
558 }
559 
SelectPalette(HDC hDC)560 HPALETTE AwtWin32GraphicsDevice::SelectPalette(HDC hDC)
561 {
562     if (palette) {
563         return palette->Select(hDC);
564     } else {
565         return NULL;
566     }
567 }
568 
RealizePalette(HDC hDC)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  */
DeviceIndexForWindow(HWND hWnd)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  */
GetPalette()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  */
Release()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  */
SetJavaDevice(JNIEnv * env,jobject objPtr)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  */
DisableOffscreenAcceleration()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  */
Invalidate(JNIEnv * env)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 
GetColorModel(JNIEnv * env,jboolean dynamic,int deviceIndex)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 
GetMonitorInfo(int deviceIndex)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  */
ResetAllMonitorInfo()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 
DisableOffscreenAccelerationForDevice(HMONITOR hMonitor)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 
GetMonitor(int deviceIndex)705 HMONITOR AwtWin32GraphicsDevice::GetMonitor(int deviceIndex)
706 {
707     Devices::InstanceAccess devices;
708     return devices->GetDevice(deviceIndex)->GetMonitor();
709 }
710 
GetPalette(int deviceIndex)711 HPALETTE AwtWin32GraphicsDevice::GetPalette(int deviceIndex)
712 {
713     Devices::InstanceAccess devices;
714     return devices->GetDevice(deviceIndex)->GetPalette();
715 }
716 
UpdateDynamicColorModel(int deviceIndex)717 void AwtWin32GraphicsDevice::UpdateDynamicColorModel(int deviceIndex)
718 {
719     Devices::InstanceAccess devices;
720     devices->GetDevice(deviceIndex)->UpdateDynamicColorModel();
721 }
722 
UpdateSystemPalette(int deviceIndex)723 BOOL AwtWin32GraphicsDevice::UpdateSystemPalette(int deviceIndex)
724 {
725     Devices::InstanceAccess devices;
726     return devices->GetDevice(deviceIndex)->UpdateSystemPalette();
727 }
728 
SelectPalette(HDC hDC,int deviceIndex)729 HPALETTE AwtWin32GraphicsDevice::SelectPalette(HDC hDC, int deviceIndex)
730 {
731     Devices::InstanceAccess devices;
732     return devices->GetDevice(deviceIndex)->SelectPalette(hDC);
733 }
734 
RealizePalette(HDC hDC,int deviceIndex)735 void AwtWin32GraphicsDevice::RealizePalette(HDC hDC, int deviceIndex)
736 {
737     Devices::InstanceAccess devices;
738     devices->GetDevice(deviceIndex)->RealizePalette(hDC);
739 }
740 
GetColorData(int deviceIndex)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  */
GetGrayness(int deviceIndex)750 int AwtWin32GraphicsDevice::GetGrayness(int deviceIndex)
751 {
752     Devices::InstanceAccess devices;
753     return devices->GetDevice(deviceIndex)->GetGrayness();
754 }
755 
GetDCFromScreen(int screen)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  */
AreSameMonitors(HMONITOR mon1,HMONITOR mon2)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 
GetScreenFromHMONITOR(HMONITOR mon)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
Java_sun_awt_Win32GraphicsDevice_initIDs(JNIEnv * env,jclass cls)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     // workaround JDK-6477756, ignore return value to keep dll in memory
879     JDK_LoadSystemLibrary("opengl32.dll");
880 
881     CATCH_BAD_ALLOC;
882 }
883 
884 } /* extern "C" */
885 
886 
887 /*
888  * Class:     sun_awt_Win32GraphicsDevice
889  * Method:    getMaxConfigsImpl
890  * Signature: ()I
891  */
892 
Java_sun_awt_Win32GraphicsDevice_getMaxConfigsImpl(JNIEnv * jniEnv,jobject theThis,jint screen)893 JNIEXPORT jint JNICALL Java_sun_awt_Win32GraphicsDevice_getMaxConfigsImpl
894     (JNIEnv* jniEnv, jobject theThis, jint screen) {
895         TRY;
896     HDC hDC = AwtWin32GraphicsDevice::GetDCFromScreen(screen);
897 
898     PIXELFORMATDESCRIPTOR pfd;
899     int max = ::DescribePixelFormat(hDC, 1, sizeof(PIXELFORMATDESCRIPTOR),
900         &pfd);
901     if (hDC != NULL) {
902         VERIFY(::DeleteDC(hDC));
903         hDC = NULL;
904     }
905     //If ::DescribePixelFormat() fails, max = 0
906     //In this case, we return 1 config with visual number 0
907     if (max == 0) {
908         max = 1;
909     }
910     return (jint)max;
911         CATCH_BAD_ALLOC_RET(0);
912 }
913 
914 /*
915  * Class:     sun_awt_Win32GraphicsDevice
916  * Method:    isPixFmtSupported
917  * Signature: (I)Z
918  */
919 
Java_sun_awt_Win32GraphicsDevice_isPixFmtSupported(JNIEnv * env,jobject theThis,jint pixFmtID,jint screen)920 JNIEXPORT jboolean JNICALL Java_sun_awt_Win32GraphicsDevice_isPixFmtSupported
921     (JNIEnv* env, jobject theThis, jint pixFmtID, jint screen) {
922         TRY;
923     jboolean suppColor = JNI_TRUE;
924     HDC hDC = AwtWin32GraphicsDevice::GetDCFromScreen(screen);
925 
926     if (pixFmtID == 0) {
927         return true;
928     }
929 
930     PIXELFORMATDESCRIPTOR pfd;
931     int max = ::DescribePixelFormat(hDC, (int)pixFmtID,
932         sizeof(PIXELFORMATDESCRIPTOR), &pfd);
933     DASSERT(max);
934 
935     //Check for supported ColorModel
936     if ((pfd.cColorBits < 8) ||
937        ((pfd.cColorBits == 8) && (pfd.iPixelType != PFD_TYPE_COLORINDEX))) {
938         //Note: this still allows for PixelFormats with > 8 color bits
939         //which use COLORINDEX instead of RGB.  This seems to work fine,
940         //although issues may crop up involving PFD_NEED_PALETTE, which
941         //is not currently taken into account.
942         //If changes are made, they should also be reflected in
943         //getDefaultPixID.
944         suppColor = JNI_FALSE;
945     }
946 
947     if (hDC != NULL) {
948         VERIFY(::DeleteDC(hDC));
949         hDC = NULL;
950     }
951     return (((pfd.dwFlags & REQUIRED_FLAGS) == REQUIRED_FLAGS) && suppColor) ?
952      JNI_TRUE : JNI_FALSE;
953         CATCH_BAD_ALLOC_RET(FALSE);
954 }
955 
956 /*
957  * Class:     sun_awt_Win32GraphicsDevice
958  * Method:    getDefaultPixIDImpl
959  * Signature: (I)I
960  */
961 
Java_sun_awt_Win32GraphicsDevice_getDefaultPixIDImpl(JNIEnv * env,jobject theThis,jint screen)962 JNIEXPORT jint JNICALL Java_sun_awt_Win32GraphicsDevice_getDefaultPixIDImpl
963     (JNIEnv* env, jobject theThis, jint screen) {
964         TRY;
965     int pixFmtID = 0;
966     HDC hDC = AwtWin32GraphicsDevice::GetDCFromScreen(screen);
967 
968     PIXELFORMATDESCRIPTOR pfd = {
969         sizeof(PIXELFORMATDESCRIPTOR),
970         1,               //version
971         REQUIRED_FLAGS,  //flags
972         0,               //iPixelType
973         0,               //cColorBits
974         0,0,0,0,0,0,0,0, //cRedBits, cRedShift, green, blue, alpha
975         0,0,0,0,0,       //cAccumBits, cAccumRedBits, green, blue, alpha
976         0,0,0,0,0,0,0,0  //etc.
977     };
978 
979     //If 8-bit mode, must use Indexed mode
980     if (8 == ::GetDeviceCaps(hDC, BITSPIXEL)) {
981         pfd.iPixelType = PFD_TYPE_COLORINDEX;
982     }
983 
984     pixFmtID = ::ChoosePixelFormat(hDC, &pfd);
985     if (pixFmtID == 0) {
986         //Return 0 if GDI call fails.
987         if (hDC != NULL) {
988             VERIFY(::DeleteDC(hDC));
989             hDC = NULL;
990         }
991         return pixFmtID;
992     }
993 
994     if (JNI_FALSE == Java_sun_awt_Win32GraphicsDevice_isPixFmtSupported(
995      env, theThis, pixFmtID, screen)) {
996         /* Can't find a suitable pixel format ID.  Fall back on 0. */
997         pixFmtID = 0;
998     }
999 
1000     VERIFY(::DeleteDC(hDC));
1001     hDC = NULL;
1002     return (jint)pixFmtID;
1003         CATCH_BAD_ALLOC_RET(0);
1004 }
1005 
1006 /*
1007  * Class:     sun_awt_Win32GraphicsDevice
1008  * Method:    enterFullScreenExclusive
1009  * Signature: (Ljava/awt/peer/WindowPeer;)V
1010  */
1011 
1012 JNIEXPORT void JNICALL
Java_sun_awt_Win32GraphicsDevice_enterFullScreenExclusive(JNIEnv * env,jobject graphicsDevice,jint screen,jobject windowPeer)1013 Java_sun_awt_Win32GraphicsDevice_enterFullScreenExclusive(
1014         JNIEnv* env, jobject graphicsDevice,
1015         jint screen, jobject windowPeer) {
1016 
1017     TRY;
1018 
1019     PDATA pData;
1020     JNI_CHECK_PEER_RETURN(windowPeer);
1021 
1022     AwtWindow *window = (AwtWindow *)pData;  // safe cast since we are called
1023                                              // with the WWindowPeer object
1024     HWND hWnd = window->GetHWnd();
1025 
1026     if (!::SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0,
1027                         SWP_NOMOVE|SWP_NOOWNERZORDER|SWP_NOSIZE))
1028     {
1029         J2dTraceLn1(J2D_TRACE_ERROR,
1030                     "Error %d setting topmost attribute to fs window",
1031                     ::GetLastError());
1032     }
1033 
1034     CATCH_BAD_ALLOC;
1035 }
1036 
1037 /*
1038  * Class:     sun_awt_Win32GraphicsDevice
1039  * Method:    exitFullScreenExclusive
1040  * Signature: (Ljava/awt/peer/WindowPeer;)V
1041  */
1042 
1043 JNIEXPORT void JNICALL
Java_sun_awt_Win32GraphicsDevice_exitFullScreenExclusive(JNIEnv * env,jobject graphicsDevice,jint screen,jobject windowPeer)1044 Java_sun_awt_Win32GraphicsDevice_exitFullScreenExclusive(
1045         JNIEnv* env, jobject graphicsDevice,
1046         jint screen, jobject windowPeer) {
1047 
1048     TRY;
1049 
1050     PDATA pData;
1051     JNI_CHECK_PEER_RETURN(windowPeer);
1052 
1053     AwtWindow *window = (AwtWindow *)pData;  // safe cast since we are called
1054                                              // with the WWindowPeer object
1055     HWND hWnd = window->GetHWnd();
1056 
1057     jobject target = env->GetObjectField(windowPeer, AwtObject::targetID);
1058     jboolean alwaysOnTop = JNU_GetFieldByName(env, NULL, target, "alwaysOnTop", "Z").z;
1059     env->DeleteLocalRef(target);
1060 
1061     if (!::SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 0, 0,
1062                         SWP_NOMOVE|SWP_NOOWNERZORDER|SWP_NOSIZE))
1063     {
1064         J2dTraceLn1(J2D_TRACE_ERROR,
1065                     "Error %d unsetting topmost attribute to fs window",
1066                     ::GetLastError());
1067     }
1068 
1069     // We should restore alwaysOnTop state as it's anyway dropped here
1070     Java_sun_awt_windows_WWindowPeer_setAlwaysOnTopNative(env, windowPeer, alwaysOnTop);
1071 
1072     CATCH_BAD_ALLOC;
1073 }
1074 
CreateDisplayMode(JNIEnv * env,jint width,jint height,jint bitDepth,jint refreshRate)1075 jobject CreateDisplayMode(JNIEnv* env, jint width, jint height,
1076     jint bitDepth, jint refreshRate) {
1077 
1078     TRY;
1079 
1080     jclass displayModeClass = env->FindClass("java/awt/DisplayMode");
1081     if (JNU_IsNull(env, displayModeClass)) {
1082         env->ExceptionClear();
1083         JNU_ThrowInternalError(env, "Could not get display mode class");
1084         return NULL;
1085     }
1086 
1087     jmethodID cid = env->GetMethodID(displayModeClass, "<init>", "(IIII)V");
1088     if (cid == NULL) {
1089         env->ExceptionClear();
1090         JNU_ThrowInternalError(env, "Could not get display mode constructor");
1091         return NULL;
1092     }
1093 
1094     jobject displayMode = env->NewObject(displayModeClass, cid, width,
1095         height, bitDepth, refreshRate);
1096     return displayMode;
1097 
1098     CATCH_BAD_ALLOC_RET(NULL);
1099 }
1100 
1101 /**
1102  * A utility function which retrieves a DISPLAY_DEVICE information
1103  * given a screen number.
1104  *
1105  * If the function was able to find an attached device for the given screen
1106  * number, the lpDisplayDevice will be initialized with the data and
1107  * the function will return TRUE, otherwise it returns FALSE and contents
1108  * of the structure pointed to by lpDisplayDevice is undefined.
1109  */
1110 static BOOL
GetAttachedDisplayDevice(int screen,DISPLAY_DEVICE * lpDisplayDevice)1111 GetAttachedDisplayDevice(int screen, DISPLAY_DEVICE *lpDisplayDevice)
1112 {
1113     DWORD dwDeviceNum = 0;
1114     lpDisplayDevice->cb = sizeof(DISPLAY_DEVICE);
1115     while (EnumDisplayDevices(NULL, dwDeviceNum, lpDisplayDevice, 0) &&
1116            dwDeviceNum < 20) // avoid infinite loop with buggy drivers
1117     {
1118         if (lpDisplayDevice->StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) {
1119             Devices::InstanceAccess devices;
1120             MONITORINFOEX *pMonInfo =
1121                 (LPMONITORINFOEX)devices->GetDevice(screen)->GetMonitorInfo();
1122             // make sure the device names match
1123             if (wcscmp(pMonInfo->szDevice, lpDisplayDevice->DeviceName) == 0) {
1124                 return TRUE;
1125             }
1126         }
1127         dwDeviceNum++;
1128     }
1129     return FALSE;
1130 }
1131 
1132 /*
1133  * Class:     sun_awt_Win32GraphicsDevice
1134  * Method:    getCurrentDisplayMode
1135  * Signature: (IZ)Ljava/awt/DisplayMode;
1136  */
1137 JNIEXPORT jobject JNICALL
Java_sun_awt_Win32GraphicsDevice_getCurrentDisplayMode(JNIEnv * env,jobject graphicsDevice,jint screen)1138 Java_sun_awt_Win32GraphicsDevice_getCurrentDisplayMode
1139     (JNIEnv* env, jobject graphicsDevice, jint screen)
1140 {
1141     TRY;
1142 
1143     DEVMODE dm;
1144     LPTSTR pName = NULL;
1145 
1146     dm.dmSize = sizeof(dm);
1147     dm.dmDriverExtra = 0;
1148 
1149     DISPLAY_DEVICE displayDevice;
1150     if (GetAttachedDisplayDevice(screen, &displayDevice)) {
1151         pName = displayDevice.DeviceName;
1152     }
1153     if (!EnumDisplaySettings(pName, ENUM_CURRENT_SETTINGS, &dm))
1154     {
1155         return NULL;
1156     }
1157 
1158     return CreateDisplayMode(env, dm.dmPelsWidth,
1159         dm.dmPelsHeight, dm.dmBitsPerPel, dm.dmDisplayFrequency);
1160 
1161     CATCH_BAD_ALLOC_RET(NULL);
1162 }
1163 
1164 /*
1165  * Class:     sun_awt_Win32GraphicsDevice
1166  * Method:    configDisplayMode
1167  * Signature: (IIIIZ)V
1168  */
1169 JNIEXPORT void JNICALL
Java_sun_awt_Win32GraphicsDevice_configDisplayMode(JNIEnv * env,jobject graphicsDevice,jint screen,jobject windowPeer,jint width,jint height,jint bitDepth,jint refreshRate)1170 Java_sun_awt_Win32GraphicsDevice_configDisplayMode
1171     (JNIEnv* env, jobject graphicsDevice, jint screen, jobject windowPeer,
1172      jint width, jint height, jint bitDepth, jint refreshRate)
1173 {
1174     TRY;
1175 
1176         DEVMODE dm;
1177 
1178     dm.dmSize = sizeof(dm);
1179     dm.dmDriverExtra = 0;
1180     dm.dmPelsWidth = width;
1181     dm.dmPelsHeight = height;
1182     dm.dmBitsPerPel = bitDepth;
1183     dm.dmDisplayFrequency = refreshRate;
1184     dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT |
1185         DM_BITSPERPEL | DM_DISPLAYFREQUENCY;
1186 
1187     // ChangeDisplaySettings works only on the primary screen.
1188     // ChangeDisplaySettingsEx is not available on NT,
1189     // so it'd be nice not to break it if we can help it.
1190     if (screen == AwtWin32GraphicsDevice::GetDefaultDeviceIndex()) {
1191         if (::ChangeDisplaySettings(&dm, CDS_FULLSCREEN) !=
1192             DISP_CHANGE_SUCCESSFUL)
1193         {
1194             JNU_ThrowInternalError(env,
1195                                    "Could not set display mode");
1196         }
1197         return;
1198     }
1199 
1200     DISPLAY_DEVICE displayDevice;
1201     if (!GetAttachedDisplayDevice(screen, &displayDevice) ||
1202         (::ChangeDisplaySettingsEx(displayDevice.DeviceName, &dm, NULL, CDS_FULLSCREEN, NULL) !=
1203           DISP_CHANGE_SUCCESSFUL))
1204     {
1205         JNU_ThrowInternalError(env,
1206                                "Could not set display mode");
1207     }
1208 
1209     CATCH_BAD_ALLOC;
1210 }
1211 
1212 class EnumDisplayModeParam {
1213 public:
EnumDisplayModeParam(JNIEnv * e,jobject a)1214     EnumDisplayModeParam(JNIEnv* e, jobject a) : env(e), arrayList(a) {}
1215     JNIEnv* env;
1216     jobject arrayList;
1217 };
1218 
addDisplayMode(JNIEnv * env,jobject arrayList,jint width,jint height,jint bitDepth,jint refreshRate)1219 void addDisplayMode(JNIEnv* env, jobject arrayList, jint width,
1220     jint height, jint bitDepth, jint refreshRate) {
1221 
1222     TRY;
1223 
1224     jobject displayMode = CreateDisplayMode(env, width, height,
1225         bitDepth, refreshRate);
1226     if (!JNU_IsNull(env, displayMode)) {
1227         jclass arrayListClass = env->GetObjectClass(arrayList);
1228         if (JNU_IsNull(env, arrayListClass)) {
1229             JNU_ThrowInternalError(env,
1230                 "Could not get class java.util.ArrayList");
1231             return;
1232         }
1233         jmethodID mid = env->GetMethodID(arrayListClass, "add",
1234         "(Ljava/lang/Object;)Z");
1235         if (mid == NULL) {
1236             env->ExceptionClear();
1237             JNU_ThrowInternalError(env,
1238                 "Could not get method java.util.ArrayList.add()");
1239             return;
1240         }
1241         env->CallObjectMethod(arrayList, mid, displayMode);
1242         env->DeleteLocalRef(displayMode);
1243     }
1244 
1245     CATCH_BAD_ALLOC;
1246 }
1247 
1248 /*
1249  * Class:     sun_awt_Win32GraphicsDevice
1250  * Method:    enumDisplayModes
1251  * Signature: (Ljava/util/ArrayList;Z)V
1252  */
Java_sun_awt_Win32GraphicsDevice_enumDisplayModes(JNIEnv * env,jobject graphicsDevice,jint screen,jobject arrayList)1253 JNIEXPORT void JNICALL Java_sun_awt_Win32GraphicsDevice_enumDisplayModes
1254     (JNIEnv* env, jobject graphicsDevice, jint screen, jobject arrayList)
1255 {
1256 
1257     TRY;
1258 
1259     DEVMODE dm;
1260     LPTSTR pName = NULL;
1261     DISPLAY_DEVICE displayDevice;
1262 
1263 
1264     if (GetAttachedDisplayDevice(screen, &displayDevice)) {
1265         pName = displayDevice.DeviceName;
1266     }
1267 
1268     dm.dmSize = sizeof(dm);
1269     dm.dmDriverExtra = 0;
1270 
1271     BOOL bContinue = TRUE;
1272     for (int i = 0; bContinue; i++) {
1273         bContinue = EnumDisplaySettings(pName, i, &dm);
1274         if (dm.dmBitsPerPel >= 8) {
1275             addDisplayMode(env, arrayList, dm.dmPelsWidth, dm.dmPelsHeight,
1276                            dm.dmBitsPerPel, dm.dmDisplayFrequency);
1277             JNU_CHECK_EXCEPTION(env);
1278         }
1279     }
1280 
1281     CATCH_BAD_ALLOC;
1282 }
1283 
1284 /*
1285  * Class:     sun_awt_Win32GraphicsDevice
1286  * Method:    makeColorModel
1287  * Signature: ()Ljava/awt/image/ColorModel
1288  */
1289 
1290 JNIEXPORT jobject JNICALL
Java_sun_awt_Win32GraphicsDevice_makeColorModel(JNIEnv * env,jobject thisPtr,jint screen,jboolean dynamic)1291     Java_sun_awt_Win32GraphicsDevice_makeColorModel
1292     (JNIEnv *env, jobject thisPtr, jint screen, jboolean dynamic)
1293 {
1294     Devices::InstanceAccess devices;
1295     return devices->GetDevice(screen)->GetColorModel(env, dynamic);
1296 }
1297 
1298 /*
1299  * Class:     sun_awt_Win32GraphicsDevice
1300  * Method:    initDevice
1301  * Signature: (I)V
1302  */
1303 JNIEXPORT void JNICALL
Java_sun_awt_Win32GraphicsDevice_initDevice(JNIEnv * env,jobject thisPtr,jint screen)1304     Java_sun_awt_Win32GraphicsDevice_initDevice
1305     (JNIEnv *env, jobject thisPtr, jint screen)
1306 {
1307     Devices::InstanceAccess devices;
1308     devices->GetDevice(screen)->SetJavaDevice(env, thisPtr);
1309 }
1310