1 /*
   2  * Copyright 1999-2008 Sun Microsystems, Inc.  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.  Sun designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  22  * CA 95054 USA or visit www.sun.com if you need additional information or
  23  * have any questions.
  24  */
  25 
  26 #include <awt.h>
  27 #include <sun_awt_Win32GraphicsEnvironment.h>
  28 #include "awt_Canvas.h"
  29 #include "awt_Win32GraphicsDevice.h"
  30 #include "Devices.h"
  31 #include "WindowsFlags.h"
  32 #include "DllUtil.h"
  33 
  34 BOOL DWMIsCompositionEnabled();
  35 
  36 void initScreens(JNIEnv *env) {
  37 
  38     if (!Devices::UpdateInstance(env)) {
  39         JNU_ThrowInternalError(env, "Could not update the devices array.");
  40         return;
  41     }
  42 }
  43 
  44 /**
  45  * This function attempts to make a Win32 API call to
  46  *   BOOL SetProcessDPIAware(VOID);
  47  * which is only present on Windows Vista, and which instructs the
  48  * Vista Windows Display Manager that this application is High DPI Aware
  49  * and does not need to be scaled by the WDM and lied about the
  50  * actual system dpi.
  51  */
  52 static void
  53 SetProcessDPIAwareProperty()
  54 {
  55     typedef BOOL (WINAPI SetProcessDPIAwareFunc)(void);
  56     static BOOL bAlreadySet = FALSE;
  57 
  58     // setHighDPIAware is set in WindowsFlags.cpp
  59     if (!setHighDPIAware || bAlreadySet) {
  60         return;
  61     }
  62 
  63     bAlreadySet = TRUE;
  64 
  65     HMODULE hLibUser32Dll = ::LoadLibrary(TEXT("user32.dll"));
  66 
  67     if (hLibUser32Dll != NULL) {
  68         SetProcessDPIAwareFunc *lpSetProcessDPIAware =
  69             (SetProcessDPIAwareFunc*)GetProcAddress(hLibUser32Dll,
  70                                                     "SetProcessDPIAware");
  71         if (lpSetProcessDPIAware != NULL) {
  72             lpSetProcessDPIAware();
  73         }
  74         ::FreeLibrary(hLibUser32Dll);
  75     }
  76 }
  77 
  78 #define DWM_COMP_UNDEFINED (~(TRUE|FALSE))
  79 static int dwmIsCompositionEnabled = DWM_COMP_UNDEFINED;
  80 
  81 /**
  82  * This function is called from toolkit event handling code when
  83  * WM_DWMCOMPOSITIONCHANGED event is received
  84  */
  85 void DWMResetCompositionEnabled() {
  86     dwmIsCompositionEnabled = DWM_COMP_UNDEFINED;
  87     (void)DWMIsCompositionEnabled();
  88 }
  89 
  90 /**
  91  * Returns true if dwm composition is enabled, false if it is not applicable
  92  * (if the OS is not Vista) or dwm composition is disabled.
  93  */
  94 BOOL DWMIsCompositionEnabled() {
  95     // cheaper to check than whether it's vista or not
  96     if (dwmIsCompositionEnabled != DWM_COMP_UNDEFINED) {
  97         return (BOOL)dwmIsCompositionEnabled;
  98     }
  99 
 100     if (!IS_WINVISTA) {
 101         dwmIsCompositionEnabled = FALSE;
 102         return FALSE;
 103     }
 104 
 105     BOOL bRes = FALSE;
 106 
 107     try {
 108         BOOL bEnabled;
 109         HRESULT res = DwmAPI::DwmIsCompositionEnabled(&bEnabled);
 110         if (SUCCEEDED(res)) {
 111             bRes = bEnabled;
 112             J2dTraceLn1(J2D_TRACE_VERBOSE, " composition enabled: %d",bRes);
 113         } else {
 114             J2dTraceLn1(J2D_TRACE_ERROR,
 115                     "IsDWMCompositionEnabled: error %x when detecting"\
 116                     "if composition is enabled", res);
 117         }
 118     } catch (const DllUtil::Exception &) {
 119         J2dTraceLn(J2D_TRACE_ERROR,
 120                 "IsDWMCompositionEnabled: no DwmIsCompositionEnabled() "\
 121                 "in dwmapi.dll or dwmapi.dll cannot be loaded");
 122     }
 123 
 124     dwmIsCompositionEnabled = bRes;
 125 
 126     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
 127     JNU_CallStaticMethodByName(env, NULL,
 128                               "sun/awt/Win32GraphicsEnvironment",
 129                               "dwmCompositionChanged", "(Z)V", (jboolean)bRes);
 130     return bRes;
 131 }
 132 
 133 /*
 134  * Class:     sun_awt_Win32GraphicsEnvironment
 135  * Method:    initDisplay
 136  * Signature: ()V
 137  */
 138 JNIEXPORT void JNICALL
 139 Java_sun_awt_Win32GraphicsEnvironment_initDisplay(JNIEnv *env,
 140                                                   jclass thisClass)
 141 {
 142     // This method needs to be called prior to any display-related activity
 143     SetProcessDPIAwareProperty();
 144 
 145     DWMIsCompositionEnabled();
 146 
 147     initScreens(env);
 148 }
 149 
 150 /*
 151  * Class:     sun_awt_Win32GraphicsEnvironment
 152  * Method:    getNumScreens
 153  * Signature: ()I
 154  */
 155 JNIEXPORT jint JNICALL
 156 Java_sun_awt_Win32GraphicsEnvironment_getNumScreens(JNIEnv *env,
 157                                                     jobject thisobj)
 158 {
 159     Devices::InstanceAccess devices;
 160     return devices->GetNumDevices();
 161 }
 162 
 163 /*
 164  * Class:     sun_awt_Win32GraphicsEnvironment
 165  * Method:    getDefaultScreen
 166  * Signature: ()I
 167  */
 168 JNIEXPORT jint JNICALL
 169 Java_sun_awt_Win32GraphicsEnvironment_getDefaultScreen(JNIEnv *env,
 170                                                        jobject thisobj)
 171 {
 172     return AwtWin32GraphicsDevice::GetDefaultDeviceIndex();
 173 }
 174 
 175 /*
 176  * Class:     sun_awt_Win32GraphicsEnvironment
 177  * Method:    registerFontWithPlatform
 178  * Signature: (Ljava/lang/String;)V
 179  */
 180 JNIEXPORT void JNICALL
 181 Java_sun_awt_Win32GraphicsEnvironment_registerFontWithPlatform(JNIEnv *env,
 182                                                               jclass cl,
 183                                                               jstring fontName)
 184 {
 185     LPTSTR file = (LPTSTR)JNU_GetStringPlatformChars(env, fontName, JNI_FALSE);
 186     if (file) {
 187         ::AddFontResourceEx(file, FR_PRIVATE, NULL);
 188         JNU_ReleaseStringPlatformChars(env, fontName, file);
 189     }
 190 }
 191 
 192 
 193 /*
 194  * Class:     sun_awt_Win32GraphicsEnvironment
 195  * Method:    deRegisterFontWithPlatform
 196  * Signature: (Ljava/lang/String;)V
 197  *
 198  * This method intended for future use.
 199  */
 200 JNIEXPORT void JNICALL
 201 Java_sun_awt_Win32GraphicsEnvironment_deRegisterFontWithPlatform(JNIEnv *env,
 202                                                               jclass cl,
 203                                                               jstring fontName)
 204 {
 205     LPTSTR file = (LPTSTR)JNU_GetStringPlatformChars(env, fontName, JNI_FALSE);
 206     if (file) {
 207         ::RemoveFontResourceEx(file, FR_PRIVATE, NULL);
 208         JNU_ReleaseStringPlatformChars(env, fontName, file);
 209     }
 210 }
 211 
 212 #define EUDCKEY_JA_JP  L"EUDC\\932"
 213 #define EUDCKEY_ZH_CN  L"EUDC\\936"
 214 #define EUDCKEY_ZH_TW  L"EUDC\\950"
 215 #define EUDCKEY_KO_KR  L"EUDC\\949"
 216 #define LANGID_JA_JP   0x411
 217 #define LANGID_ZH_CN   0x0804
 218 #define LANGID_ZH_SG   0x1004
 219 #define LANGID_ZH_TW   0x0404
 220 #define LANGID_ZH_HK   0x0c04
 221 #define LANGID_ZH_MO   0x1404
 222 #define LANGID_KO_KR   0x0412
 223 
 224 
 225 JNIEXPORT jstring JNICALL
 226 Java_sun_awt_Win32GraphicsEnvironment_getEUDCFontFile(JNIEnv *env, jclass cl) {
 227     int    rc;
 228     HKEY   key;
 229     DWORD  type;
 230     WCHAR  fontPathBuf[MAX_PATH + 1];
 231     unsigned long fontPathLen = MAX_PATH + 1;
 232     WCHAR  tmpPath[MAX_PATH + 1];
 233     LPWSTR fontPath = fontPathBuf;
 234     LPWSTR eudcKey = NULL;
 235 
 236     LANGID langID = GetSystemDefaultLangID();
 237     //lookup for encoding ID, EUDC only supported in
 238     //codepage 932, 936, 949, 950 (and unicode)
 239     if (langID == LANGID_JA_JP) {
 240         eudcKey = EUDCKEY_JA_JP;
 241     } else if (langID == LANGID_ZH_CN || langID == LANGID_ZH_SG) {
 242         eudcKey = EUDCKEY_ZH_CN;
 243     } else if (langID == LANGID_ZH_HK || langID == LANGID_ZH_TW ||
 244                langID == LANGID_ZH_MO) {
 245       eudcKey = EUDCKEY_ZH_TW;
 246     } else if (langID == LANGID_KO_KR) {
 247         eudcKey = EUDCKEY_KO_KR;
 248     } else {
 249         return NULL;
 250     }
 251 
 252     rc = RegOpenKeyEx(HKEY_CURRENT_USER, eudcKey, 0, KEY_READ, &key);
 253     if (rc != ERROR_SUCCESS) {
 254         return NULL;
 255     }
 256     rc = RegQueryValueEx(key,
 257                          L"SystemDefaultEUDCFont",
 258                          0,
 259                          &type,
 260                          (LPBYTE)fontPath,
 261                          &fontPathLen);
 262     RegCloseKey(key);
 263     if (rc != ERROR_SUCCESS || type != REG_SZ) {
 264         return NULL;
 265     }
 266     fontPath[fontPathLen] = L'\0';
 267     if (wcsstr(fontPath, L"%SystemRoot%")) {
 268         //if the fontPath includes %SystemRoot%
 269         LPWSTR systemRoot = _wgetenv(L"SystemRoot");
 270         if (systemRoot != NULL
 271             && swprintf(tmpPath, L"%s%s", systemRoot, fontPath + 12) != -1) {
 272             fontPath = tmpPath;
 273         }
 274         else {
 275             return NULL;
 276         }
 277     } else if (wcscmp(fontPath, L"EUDC.TTE") == 0) {
 278         //else to see if it only inludes "EUDC.TTE"
 279         WCHAR systemRoot[MAX_PATH + 1];
 280         if (GetWindowsDirectory(systemRoot, MAX_PATH + 1) != 0) {
 281             swprintf(tmpPath, L"%s\\FONTS\\EUDC.TTE", systemRoot);
 282             fontPath = tmpPath;
 283         }
 284         else {
 285             return NULL;
 286         }
 287     }
 288     return JNU_NewStringPlatform(env, fontPath);
 289 }
 290 
 291 /*
 292  * Class:     sun_awt_Win32GraphicsEnvironment
 293  * Method:    getXResolution
 294  * Signature: ()I
 295  */
 296 JNIEXPORT jint JNICALL
 297 Java_sun_awt_Win32GraphicsEnvironment_getXResolution(JNIEnv *env, jobject wge)
 298 {
 299     TRY;
 300 
 301     HWND hWnd = ::GetDesktopWindow();
 302     HDC hDC = ::GetDC(hWnd);
 303     jint result = ::GetDeviceCaps(hDC, LOGPIXELSX);
 304     ::ReleaseDC(hWnd, hDC);
 305     return result;
 306 
 307     CATCH_BAD_ALLOC_RET(0);
 308 }
 309 
 310 /*
 311  * Class:     sun_awt_Win32GraphicsEnvironment
 312  * Method:    getYResolution
 313  * Signature: ()I
 314  */
 315 JNIEXPORT jint JNICALL
 316 Java_sun_awt_Win32GraphicsEnvironment_getYResolution(JNIEnv *env, jobject wge)
 317 {
 318     TRY;
 319 
 320     HWND hWnd = ::GetDesktopWindow();
 321     HDC hDC = ::GetDC(hWnd);
 322     jint result = ::GetDeviceCaps(hDC, LOGPIXELSY);
 323     ::ReleaseDC(hWnd, hDC);
 324     return result;
 325 
 326     CATCH_BAD_ALLOC_RET(0);
 327 }
 328 
 329 /*
 330  * Class:     sun_awt_Win32GraphicsEnvironment
 331  * Method:    isVistaOS
 332  * Signature: ()Z
 333  */
 334 JNIEXPORT jboolean JNICALL Java_sun_awt_Win32GraphicsEnvironment_isVistaOS
 335   (JNIEnv *env, jclass wgeclass)
 336 {
 337     return IS_WINVISTA;
 338 }