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