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