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