1/*
2 * Copyright (c) 1999, 2016, 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#include "awt.h"
27#include "mmsystem.h"
28#include "jlong.h"
29#include "awt_DesktopProperties.h"
30#include "awt_Toolkit.h"
31#include "sun_awt_windows_WDesktopProperties.h"
32#include "java_awt_Font.h"
33#include "awtmsg.h"
34#include "zmouse.h"
35#include <shellapi.h>
36#include <shlobj.h>
37
38#include "math.h"
39
40#if defined(_MSC_VER) && _MSC_VER >= 1800
41#  define ROUND_TO_INT(num)    ((int) round(num))
42#else
43#  define ROUND_TO_INT(num)    ((int) floor((num) + 0.5))
44#endif
45
46// WDesktopProperties fields
47jfieldID AwtDesktopProperties::pDataID = 0;
48jmethodID AwtDesktopProperties::setBooleanPropertyID = 0;
49jmethodID AwtDesktopProperties::setIntegerPropertyID = 0;
50jmethodID AwtDesktopProperties::setStringPropertyID = 0;
51jmethodID AwtDesktopProperties::setColorPropertyID = 0;
52jmethodID AwtDesktopProperties::setFontPropertyID = 0;
53jmethodID AwtDesktopProperties::setSoundPropertyID = 0;
54
55AwtDesktopProperties::AwtDesktopProperties(jobject self) {
56    this->self = GetEnv()->NewGlobalRef(self);
57    GetEnv()->SetLongField( self, AwtDesktopProperties::pDataID,
58                            ptr_to_jlong(this) );
59}
60
61AwtDesktopProperties::~AwtDesktopProperties() {
62    GetEnv()->DeleteGlobalRef(self);
63}
64
65//
66// Reads Windows parameters and sets the corresponding values
67// in WDesktopProperties
68//
69void AwtDesktopProperties::GetWindowsParameters() {
70    if (GetEnv()->EnsureLocalCapacity(MAX_PROPERTIES) < 0) {
71        DASSERT(0);
72        return;
73    }
74    // this number defines the set of properties available, it is incremented
75    // whenever more properties are added (in a public release of course)
76    // for example, version 1 defines the properties available in Java SDK version 1.3.
77    SetIntegerProperty( TEXT("win.properties.version"), AWT_DESKTOP_PROPERTIES_VERSION);
78    GetNonClientParameters();
79    GetIconParameters();
80    GetColorParameters();
81    GetCaretParameters();
82    GetOtherParameters();
83    GetSoundEvents();
84    GetSystemProperties();
85    if (IS_WINXP) {
86        GetXPStyleProperties();
87    }
88}
89
90void getInvScale(float &invScaleX, float &invScaleY) {
91    static int dpiX = -1;
92    static int dpiY = -1;
93    if (dpiX == -1 || dpiY == -1) {
94        HWND hWnd = ::GetDesktopWindow();
95        HDC hDC = ::GetDC(hWnd);
96        dpiX = ::GetDeviceCaps(hDC, LOGPIXELSX);
97        dpiY = ::GetDeviceCaps(hDC, LOGPIXELSY);
98        ::ReleaseDC(hWnd, hDC);
99    }
100
101    invScaleX = (dpiX == 0.0f) ? 1.0f : 96.0f / dpiX;
102    invScaleY = (dpiY == 0.0f) ? 1.0f : 96.0f / dpiY;
103}
104
105int rescale(int value, float invScale){
106    return invScale == 1.0f ? value : ROUND_TO_INT(value * invScale);
107}
108
109void AwtDesktopProperties::GetSystemProperties() {
110    HDC dc = CreateDC(TEXT("DISPLAY"), NULL, NULL, NULL);
111
112    if (dc != NULL) {
113        try {
114            float invScaleX;
115            float invScaleY;
116            getInvScale(invScaleX, invScaleY);
117            SetFontProperty(dc, ANSI_FIXED_FONT, TEXT("win.ansiFixed.font"), 1.0f);
118            SetFontProperty(dc, ANSI_VAR_FONT, TEXT("win.ansiVar.font"), 1.0f);
119            SetFontProperty(dc, DEVICE_DEFAULT_FONT, TEXT("win.deviceDefault.font"), 1.0f);
120            SetFontProperty(dc, DEFAULT_GUI_FONT, TEXT("win.defaultGUI.font"), invScaleY);
121            SetFontProperty(dc, OEM_FIXED_FONT, TEXT("win.oemFixed.font"), 1.0f);
122            SetFontProperty(dc, SYSTEM_FONT, TEXT("win.system.font"), 1.0f);
123            SetFontProperty(dc, SYSTEM_FIXED_FONT, TEXT("win.systemFixed.font"), 1.0f);
124        }
125        catch (std::bad_alloc&) {
126            DeleteDC(dc);
127            throw;
128        }
129        DeleteDC(dc);
130    }
131}
132
133
134// Does the actual lookup for shell dialog font (MS Shell Dlg).  fontName
135// contains the name to lookup (either MS Shell Dlg or MS Shell Dlg 2) and
136// handle contains a reference toe the registry entry to look in.
137// This will return NULL or a pointer to the resolved name.
138// Note that it uses malloc() and returns the pointer to allocated
139// memory, so remember to use free() when you are done with its
140// result.
141static LPTSTR resolveShellDialogFont(LPTSTR fontName, HKEY handle) {
142    DWORD valueType, valueSize;
143    if (RegQueryValueEx((HKEY)handle, fontName, NULL,
144                        &valueType, NULL, &valueSize) != 0) {
145        // Couldn't find it
146        return NULL;
147    }
148    if (valueType != REG_SZ) {
149        // Not the expected type
150        return NULL;
151    }
152    LPTSTR buffer = (LPTSTR)safe_Malloc(valueSize);
153    if (RegQueryValueEx((HKEY)handle, fontName, NULL,
154                        &valueType, (unsigned char *)buffer, &valueSize) != 0) {
155        // Error fetching
156        free(buffer);
157        return NULL;
158    }
159    return buffer;
160}
161
162// Determines what the font MS Shell Dlg maps to.
163// Note that it uses malloc() and returns the pointer to allocated
164// memory, so remember to use free() when you are done with its
165// result.
166static LPTSTR resolveShellDialogFont() {
167    LPTSTR subKey = TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes");
168
169    HKEY handle;
170    if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, subKey, 0, KEY_READ, &handle) != 0) {
171        return NULL;
172    }
173    // Prefer MS Shell Dlg 2.
174    LPTSTR font = resolveShellDialogFont(TEXT("MS Shell Dlg 2"), handle);
175    if (font == NULL) {
176        font = resolveShellDialogFont(TEXT("MS Shell Dlg"), handle);
177    }
178    RegCloseKey(handle);
179    return font;
180}
181
182// Local function for getting values from the Windows registry
183// Note that it uses malloc() and returns the pointer to allocated
184// memory, so remember to use free() when you are done with its
185// result.
186static LPTSTR getWindowsPropFromReg(LPTSTR subKey, LPTSTR valueName, DWORD *valueType) {
187    HKEY handle;
188    if (RegOpenKeyEx(HKEY_CURRENT_USER, subKey, 0, KEY_READ, &handle) != 0) {
189        return NULL;
190    }
191    // valueSize is in bytes, while valueChar is in characters.
192    DWORD valueSize, valueChar;
193    if (RegQueryValueEx((HKEY)handle, valueName, NULL,
194                        valueType, NULL, &valueSize) != 0) {
195        RegCloseKey(handle);
196        return NULL;
197    }
198    LPTSTR buffer = (LPTSTR)safe_Malloc(valueSize);
199    if (RegQueryValueEx((HKEY)handle, valueName, NULL,
200                        valueType, (unsigned char *)buffer, &valueSize) != 0) {
201        free(buffer);
202        RegCloseKey(handle);
203        return NULL;
204    }
205    RegCloseKey(handle);
206
207    if (*valueType == REG_EXPAND_SZ) {
208        // Pending: buffer must be null-terminated at this point
209        valueChar = ExpandEnvironmentStrings(buffer, NULL, 0);
210        LPTSTR buffer2 = (LPTSTR)SAFE_SIZE_ARRAY_ALLOC(safe_Malloc, valueChar, sizeof(TCHAR));
211        ExpandEnvironmentStrings(buffer, buffer2, valueChar);
212        free(buffer);
213        return buffer2;
214    } else if (*valueType == REG_SZ) {
215        return buffer;
216    } else if (*valueType == REG_DWORD) {
217        return buffer;
218    } else {
219        free(buffer);
220        return NULL;
221    }
222}
223
224static LPTSTR getXPStylePropFromReg(LPTSTR valueName) {
225    DWORD valueType;
226    return getWindowsPropFromReg(TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\ThemeManager"),
227                                 valueName, &valueType);
228}
229
230
231// Used in AwtMenuItem to determine the color of top menus,
232// since they depend on XP style. ThemeActive property is
233// '1' for XP Style, '0' for Windows classic style.
234BOOL AwtDesktopProperties::IsXPStyle() {
235    LPTSTR style = getXPStylePropFromReg(TEXT("ThemeActive"));
236    BOOL result = (style != NULL && *style == _T('1'));
237    free(style);
238    return result;
239}
240
241void AwtDesktopProperties::GetXPStyleProperties() {
242    LPTSTR value;
243
244    value = getXPStylePropFromReg(TEXT("ThemeActive"));
245    try {
246        SetBooleanProperty(TEXT("win.xpstyle.themeActive"), (value != NULL && *value == _T('1')));
247        if (value != NULL) {
248            free(value);
249            value = NULL;
250        }
251        value = getXPStylePropFromReg(TEXT("DllName"));
252        if (value != NULL) {
253            SetStringProperty(TEXT("win.xpstyle.dllName"), value);
254            free(value);
255            value = NULL;
256        }
257        value = getXPStylePropFromReg(TEXT("SizeName"));
258        if (value != NULL) {
259            SetStringProperty(TEXT("win.xpstyle.sizeName"), value);
260            free(value);
261            value = NULL;
262        }
263        value = getXPStylePropFromReg(TEXT("ColorName"));
264        if (value != NULL) {
265            SetStringProperty(TEXT("win.xpstyle.colorName"), value);
266            free(value);
267        }
268    }
269    catch (std::bad_alloc&) {
270        if (value != NULL) {
271            free(value);
272        }
273        throw;
274    }
275}
276
277
278void AwtDesktopProperties::GetNonClientParameters() {
279    //
280    // general window properties
281    //
282    NONCLIENTMETRICS    ncmetrics;
283
284    // Fix for 6944516: specify correct size for ncmetrics on WIN2K/XP
285    // Microsoft recommend to subtract the size of  'iPaddedBorderWidth' field
286    // when running on XP. However this can't be referenced at compile time
287    // with the older SDK, so there use 'lfMessageFont' plus its size.
288    if (!IS_WINVISTA) {
289#if defined(_MSC_VER) && (_MSC_VER >= 1600)
290        ncmetrics.cbSize = offsetof(NONCLIENTMETRICS, iPaddedBorderWidth);
291#else
292        ncmetrics.cbSize = offsetof(NONCLIENTMETRICS,lfMessageFont) + sizeof(LOGFONT);
293#endif
294    } else {
295        ncmetrics.cbSize = sizeof(ncmetrics);
296    }
297    VERIFY( SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncmetrics.cbSize, &ncmetrics, FALSE) );
298
299    float invScaleX;
300    float invScaleY;
301    getInvScale(invScaleX, invScaleY);
302
303    SetFontProperty(TEXT("win.frame.captionFont"), ncmetrics.lfCaptionFont, invScaleY);
304    SetIntegerProperty(TEXT("win.frame.captionHeight"), rescale(ncmetrics.iCaptionHeight, invScaleY));
305    SetIntegerProperty(TEXT("win.frame.captionButtonWidth"), rescale(ncmetrics.iCaptionWidth, invScaleX));
306    SetIntegerProperty(TEXT("win.frame.captionButtonHeight"), rescale(ncmetrics.iCaptionHeight, invScaleY));
307    SetFontProperty(TEXT("win.frame.smallCaptionFont"), ncmetrics.lfSmCaptionFont, invScaleY);
308    SetIntegerProperty(TEXT("win.frame.smallCaptionHeight"), rescale(ncmetrics.iSmCaptionHeight, invScaleY));
309    SetIntegerProperty(TEXT("win.frame.smallCaptionButtonWidth"), rescale(ncmetrics.iSmCaptionWidth, invScaleX));
310    SetIntegerProperty(TEXT("win.frame.smallCaptionButtonHeight"), rescale(ncmetrics.iSmCaptionHeight, invScaleY));
311    SetIntegerProperty(TEXT("win.frame.sizingBorderWidth"), rescale(ncmetrics.iBorderWidth, invScaleX));
312
313    // menu properties
314    SetFontProperty(TEXT("win.menu.font"), ncmetrics.lfMenuFont, invScaleY);
315    SetIntegerProperty(TEXT("win.menu.height"), rescale(ncmetrics.iMenuHeight, invScaleY));
316    SetIntegerProperty(TEXT("win.menu.buttonWidth"), rescale(ncmetrics.iMenuWidth, invScaleX));
317
318    // scrollbar properties
319    SetIntegerProperty(TEXT("win.scrollbar.width"), rescale(ncmetrics.iScrollWidth, invScaleX));
320    SetIntegerProperty(TEXT("win.scrollbar.height"), rescale(ncmetrics.iScrollHeight, invScaleY));
321
322    // status bar and tooltip properties
323    SetFontProperty(TEXT("win.status.font"), ncmetrics.lfStatusFont, invScaleY);
324    SetFontProperty(TEXT("win.tooltip.font"), ncmetrics.lfStatusFont, invScaleY);
325
326    // message box properties
327    SetFontProperty(TEXT("win.messagebox.font"), ncmetrics.lfMessageFont, invScaleY);
328}
329
330void AwtDesktopProperties::GetIconParameters() {
331    //
332    // icon properties
333    //
334    ICONMETRICS iconmetrics;
335
336    iconmetrics.cbSize = sizeof(iconmetrics);
337    VERIFY( SystemParametersInfo(SPI_GETICONMETRICS, iconmetrics.cbSize, &iconmetrics, FALSE) );
338
339    float invScaleX;
340    float invScaleY;
341    getInvScale(invScaleX, invScaleY);
342    SetIntegerProperty(TEXT("win.icon.hspacing"), rescale(iconmetrics.iHorzSpacing, invScaleX));
343    SetIntegerProperty(TEXT("win.icon.vspacing"), rescale(iconmetrics.iVertSpacing, invScaleY));
344    SetBooleanProperty(TEXT("win.icon.titleWrappingOn"), iconmetrics.iTitleWrap != 0);
345    SetFontProperty(TEXT("win.icon.font"), iconmetrics.lfFont, invScaleY);
346}
347/*
348 Windows settings for these are also in the registry
349 They exist as system wide HKLM: HKEY_LOCAL_MACHINE and
350 HKCU: HKEY_CURRENT_USER.
351 HKCU\Control Panel\Desktop\FontSmoothing :  "0=OFF",  "2=ON"
352 HKCU\Control Panel\Desktop\FontSmoothingType: 1=Standard, 2=LCD
353 HKCU\Control Panel\Desktop\FontSmoothingGamma: 1000->2200
354 HKCU\Control Panel\Desktop\FontSmoothingOrientation: 0=BGR, 1=RGB
355
356 SystemParametersInfo supplies the first three of these but does not
357 however expose the Orientation. That has to come from the registry.
358
359 We go to some small lengths in here to not make queries we don't need.
360 Eg if we previously were using standard font smoothing and we still are
361 then its unlikely that any change in gamma will have occurred except
362 by a program which changed it, and even if it did, we don't need to pick
363 it up until someone turns on the LCD option.
364 To do: this loop is called once per top-level window so an app with
365 N windows will get notified N times. It would save us a small amount of
366 redundant work if I could identify the message as being one already processed
367 for another window.
368 Also presumably a repaint that specifies only a partially damaged window
369 isn't one that needs this checking.
370*/
371
372#define FONTSMOOTHING_OFF 0
373#define FONTSMOOTHING_ON  1
374#define FONTSMOOTHING_STANDARD 1
375#define FONTSMOOTHING_LCD 2
376#define LCD_RGB_ORDER 1
377#define LCD_BGR_ORDER 0
378
379
380int GetLCDSubPixelOrder() {
381    LONG order=99;
382    LONG bufferSize = 4;
383    HKEY hkeyDesktop;
384    static LPCTSTR DESKTOPKEY = TEXT("Control Panel\\Desktop");
385    LONG ret = RegOpenKeyEx(HKEY_CURRENT_USER,
386                            DESKTOPKEY, 0L, KEY_READ, &hkeyDesktop);
387    if (ret != ERROR_SUCCESS) {
388        return LCD_RGB_ORDER;
389    }
390    ret = RegQueryValueEx(hkeyDesktop, TEXT("FontSmoothingOrientation"),
391                          NULL, NULL, (LPBYTE)&order, (LPDWORD)&bufferSize);
392    RegCloseKey(hkeyDesktop);
393    if (ret != ERROR_SUCCESS) {
394        return LCD_RGB_ORDER;
395    } else {
396        return (int)order;
397    }
398}
399
400void CheckFontSmoothingSettings(HWND hWnd) {
401    static BOOL firstTime = TRUE;
402    static BOOL lastFontSmoothing = FALSE;
403    static UINT lastFontSmoothingType = FONTSMOOTHING_ON;
404    static UINT lastFontSmoothingContrast = 1400;
405    static UINT lastSubpixelOrder = LCD_RGB_ORDER;
406
407    /* If we are called with a window handle it is because there is a
408     * message to repaint at least some part of the window which typically
409     * is not because of the desktop font settings change. Much more likely
410     * its a normal repaint event. If it is because of the rare settings
411     * change in that case the update region will be the entire window.
412     * Try to as cheaply as possible determine if this is not a call
413     * to repaint the whole window by assuming that all such calls will
414     * have an update region whose origin is 0,0. Only in that case will
415     * we take the hit of checking the settings.
416     * Thus we avoid taking the hit of the other calls for most partial
417     * expose events, which will never be the result of changes to desktop
418     * font settings.
419     */
420    if (hWnd != NULL) {
421        RECT r;
422        if (!::GetUpdateRect(hWnd, &r, FALSE) || r.top != 0 || r.left != 0) {
423            return;
424        }
425    }
426
427    BOOL fontSmoothing = FALSE, settingsChanged;
428    UINT fontSmoothingType=0, fontSmoothingContrast=0, subPixelOrder=0;
429
430    if (firstTime) {
431        SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &fontSmoothing, 0);
432        if (IS_WINXP) {
433            SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0,
434                                 &fontSmoothingType, 0);
435            SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0,
436                                 &fontSmoothingContrast, 0);
437        }
438        lastFontSmoothing = fontSmoothing;
439        lastFontSmoothingType = fontSmoothingType;
440        lastFontSmoothingContrast = fontSmoothingContrast;
441        firstTime = FALSE;
442        return;
443    } else {
444        SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &fontSmoothing, 0);
445        settingsChanged = fontSmoothing != lastFontSmoothing;
446        if (!settingsChanged && fontSmoothing == FONTSMOOTHING_OFF) {
447            /* no need to check the other settings in this case. */
448            return;
449        }
450        if (IS_WINXP) {
451            SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0,
452                                 &fontSmoothingType, 0);
453            settingsChanged |= fontSmoothingType != lastFontSmoothingType;
454            if (!settingsChanged &&
455                fontSmoothingType == FONTSMOOTHING_STANDARD) {
456                /* No need to check any LCD specific settings */
457                return;
458            } else {
459                SystemParametersInfo(SPI_GETFONTSMOOTHINGCONTRAST, 0,
460                                     &fontSmoothingContrast, 0);
461                settingsChanged |=
462                    fontSmoothingContrast != lastFontSmoothingContrast;
463                if (fontSmoothingType == FONTSMOOTHING_LCD) {
464                    // Order is a registry entry so more expensive to check.x
465                    subPixelOrder = GetLCDSubPixelOrder();
466                    settingsChanged |= subPixelOrder != lastSubpixelOrder;
467                }
468            }
469        } else {
470            if (settingsChanged && fontSmoothing == FONTSMOOTHING_ON) {
471                fontSmoothingType = FONTSMOOTHING_STANDARD;
472            }
473        }
474    }
475    if (settingsChanged) {
476        /* Some of these values may not have been queried, but it shouldn't
477         * matter as what's important is to track changes in values we are
478         * actually using. The up-call we make here will cause the actual
479         * values for everything to get queried and set into the desktop
480         * properties.
481         */
482        lastFontSmoothing = fontSmoothing;
483        lastFontSmoothingType = fontSmoothingType;
484        lastFontSmoothingContrast = fontSmoothingContrast;
485        lastSubpixelOrder = subPixelOrder;
486
487        jobject peer = AwtToolkit::GetInstance().GetPeer();
488        if (peer != NULL) {
489            AwtToolkit::GetEnv()->CallVoidMethod(peer,
490                                     AwtToolkit::windowsSettingChangeMID);
491        }
492    }
493}
494
495void AwtDesktopProperties::GetColorParameters() {
496
497    SetColorProperty(TEXT("win.frame.activeCaptionGradientColor"),
498                     GetSysColor(COLOR_GRADIENTACTIVECAPTION));
499    SetColorProperty(TEXT("win.frame.inactiveCaptionGradientColor"),
500                     GetSysColor(COLOR_GRADIENTINACTIVECAPTION));
501    SetColorProperty(TEXT("win.item.hotTrackedColor"),
502                     GetSysColor(COLOR_HOTLIGHT));
503    SetColorProperty(TEXT("win.3d.darkShadowColor"), GetSysColor(COLOR_3DDKSHADOW));
504    SetColorProperty(TEXT("win.3d.backgroundColor"), GetSysColor(COLOR_3DFACE));
505    SetColorProperty(TEXT("win.3d.highlightColor"), GetSysColor(COLOR_3DHIGHLIGHT));
506    SetColorProperty(TEXT("win.3d.lightColor"), GetSysColor(COLOR_3DLIGHT));
507    SetColorProperty(TEXT("win.3d.shadowColor"), GetSysColor(COLOR_3DSHADOW));
508    SetColorProperty(TEXT("win.button.textColor"), GetSysColor(COLOR_BTNTEXT));
509    SetColorProperty(TEXT("win.desktop.backgroundColor"), GetSysColor(COLOR_DESKTOP));
510    SetColorProperty(TEXT("win.frame.activeCaptionColor"), GetSysColor(COLOR_ACTIVECAPTION));
511    SetColorProperty(TEXT("win.frame.activeBorderColor"), GetSysColor(COLOR_ACTIVEBORDER));
512
513    // ?? ?? ??
514    SetColorProperty(TEXT("win.frame.color"), GetSysColor(COLOR_WINDOWFRAME)); // ?? WHAT THE HECK DOES THIS MEAN ??
515    // ?? ?? ??
516
517    SetColorProperty(TEXT("win.frame.backgroundColor"), GetSysColor(COLOR_WINDOW));
518    SetColorProperty(TEXT("win.frame.captionTextColor"), GetSysColor(COLOR_CAPTIONTEXT));
519    SetColorProperty(TEXT("win.frame.inactiveBorderColor"), GetSysColor(COLOR_INACTIVEBORDER));
520    SetColorProperty(TEXT("win.frame.inactiveCaptionColor"), GetSysColor(COLOR_INACTIVECAPTION));
521    SetColorProperty(TEXT("win.frame.inactiveCaptionTextColor"), GetSysColor(COLOR_INACTIVECAPTIONTEXT));
522    SetColorProperty(TEXT("win.frame.textColor"), GetSysColor(COLOR_WINDOWTEXT));
523    SetColorProperty(TEXT("win.item.highlightColor"), GetSysColor(COLOR_HIGHLIGHT));
524    SetColorProperty(TEXT("win.item.highlightTextColor"), GetSysColor(COLOR_HIGHLIGHTTEXT));
525    SetColorProperty(TEXT("win.mdi.backgroundColor"), GetSysColor(COLOR_APPWORKSPACE));
526    SetColorProperty(TEXT("win.menu.backgroundColor"), GetSysColor(COLOR_MENU));
527    SetColorProperty(TEXT("win.menu.textColor"), GetSysColor(COLOR_MENUTEXT));
528    // COLOR_MENUBAR is only defined on WindowsXP. Our binaries are
529    // built on NT, hence the below ifdef.
530#ifndef COLOR_MENUBAR
531#define COLOR_MENUBAR 30
532#endif
533    SetColorProperty(TEXT("win.menubar.backgroundColor"),
534                                GetSysColor(IS_WINXP ? COLOR_MENUBAR : COLOR_MENU));
535    SetColorProperty(TEXT("win.scrollbar.backgroundColor"), GetSysColor(COLOR_SCROLLBAR));
536    SetColorProperty(TEXT("win.text.grayedTextColor"), GetSysColor(COLOR_GRAYTEXT));
537    SetColorProperty(TEXT("win.tooltip.backgroundColor"), GetSysColor(COLOR_INFOBK));
538    SetColorProperty(TEXT("win.tooltip.textColor"), GetSysColor(COLOR_INFOTEXT));
539}
540
541void AwtDesktopProperties::GetOtherParameters() {
542    // TODO BEGIN: On NT4, some setttings don't trigger WM_SETTINGCHANGE --
543    // check whether this has been fixed on Windows 2000 and Windows 98
544    // ECH 10/6/2000 seems to be fixed on NT4 SP5, but not on 98
545    SetBooleanProperty(TEXT("win.frame.fullWindowDragsOn"), GetBooleanParameter(SPI_GETDRAGFULLWINDOWS));
546    SetBooleanProperty(TEXT("win.text.fontSmoothingOn"), GetBooleanParameter(SPI_GETFONTSMOOTHING));
547    // TODO END
548
549    if (IS_WINXP) {
550        SetIntegerProperty(TEXT("win.text.fontSmoothingType"),
551                           GetIntegerParameter(SPI_GETFONTSMOOTHINGTYPE));
552        SetIntegerProperty(TEXT("win.text.fontSmoothingContrast"),
553                           GetIntegerParameter(SPI_GETFONTSMOOTHINGCONTRAST));
554        SetIntegerProperty(TEXT("win.text.fontSmoothingOrientation"),
555                           GetLCDSubPixelOrder());
556    }
557
558    int cxdrag = GetSystemMetrics(SM_CXDRAG);
559    int cydrag = GetSystemMetrics(SM_CYDRAG);
560    SetIntegerProperty(TEXT("win.drag.width"), cxdrag);
561    SetIntegerProperty(TEXT("win.drag.height"), cydrag);
562    SetIntegerProperty(TEXT("DnD.gestureMotionThreshold"), max(cxdrag, cydrag)/2);
563    SetIntegerProperty(TEXT("awt.mouse.numButtons"), AwtToolkit::GetNumberOfButtons());
564
565    SetIntegerProperty(TEXT("awt.multiClickInterval"), GetDoubleClickTime());
566
567    // BEGIN cross-platform properties
568    // Note that these are cross-platform properties, but are being stuck into
569    // WDesktopProperties.  WToolkit.lazilyLoadDesktopProperty() can find them,
570    // but if a Toolkit subclass uses the desktopProperties
571    // member, these properties won't be there. -bchristi, echawkes
572    // This property is called "win.frame.fullWindowDragsOn" above
573    // This is one of the properties that don't trigger WM_SETTINGCHANGE
574    SetBooleanProperty(TEXT("awt.dynamicLayoutSupported"), GetBooleanParameter(SPI_GETDRAGFULLWINDOWS));
575    SetBooleanProperty(TEXT("awt.wheelMousePresent"),
576                       ::GetSystemMetrics(SM_MOUSEWHEELPRESENT));
577
578    // END cross-platform properties
579
580    //DWORD   menuShowDelay;
581    //SystemParametersInfo(SPI_GETMENUSHOWDELAY, 0, &menuShowDelay, 0);
582    // SetIntegerProperty(TEXT("win.menu.showDelay"), menuShowDelay);
583    SetBooleanProperty(TEXT("win.frame.captionGradientsOn"), GetBooleanParameter(SPI_GETGRADIENTCAPTIONS));
584    SetBooleanProperty(TEXT("win.item.hotTrackingOn"), GetBooleanParameter(SPI_GETHOTTRACKING));
585
586    SetBooleanProperty(TEXT("win.menu.keyboardCuesOn"), GetBooleanParameter(SPI_GETKEYBOARDCUES));
587
588    // High contrast accessibility property
589    HIGHCONTRAST contrast;
590    contrast.cbSize = sizeof(HIGHCONTRAST);
591    if (SystemParametersInfo(SPI_GETHIGHCONTRAST, sizeof(HIGHCONTRAST),
592                             &contrast, 0) != 0 &&
593              (contrast.dwFlags & HCF_HIGHCONTRASTON) == HCF_HIGHCONTRASTON) {
594      SetBooleanProperty(TEXT("win.highContrast.on"), TRUE);
595    }
596    else {
597      SetBooleanProperty(TEXT("win.highContrast.on"), FALSE);
598    }
599
600    SHELLFLAGSTATE sfs;
601    ::SHGetSettings(&sfs, SSF_SHOWALLOBJECTS | SSF_SHOWATTRIBCOL);
602    if (sfs.fShowAllObjects) {
603        SetBooleanProperty(TEXT("awt.file.showHiddenFiles"), TRUE);
604    }
605    else {
606        SetBooleanProperty(TEXT("awt.file.showHiddenFiles"), FALSE);
607    }
608    if (sfs.fShowAttribCol) {
609        SetBooleanProperty(TEXT("awt.file.showAttribCol"), TRUE);
610    }
611    else {
612        SetBooleanProperty(TEXT("awt.file.showAttribCol"), FALSE);
613    }
614
615    LPTSTR value;
616    DWORD valueType;
617
618    // Shell Icon BPP - only honored on platforms before XP
619    value = getWindowsPropFromReg(TEXT("Control Panel\\Desktop\\WindowMetrics"),
620                                  TEXT("Shell Icon BPP"), &valueType);
621
622    try {
623        if (value != NULL) {
624            if (valueType == REG_SZ) {
625                SetStringProperty(TEXT("win.icon.shellIconBPP"), value);
626            }
627            free(value);
628            value = NULL;
629        }
630
631
632        // The following registry settings control the file chooser places bar
633        // under the Windows L&F. These settings are not present by default, but
634        // can be enabled using the TweakUI tool from Microsoft. For more info,
635        // see http://msdn.microsoft.com/msdnmag/issues/1100/Registry/
636
637        // NoPlacesBar is a REG_DWORD, with values 0 or 1
638        value = getWindowsPropFromReg(TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\comdlg32"),
639                                      TEXT("NoPlacesBar"), &valueType);
640        if (value != NULL) {
641            if (valueType == REG_DWORD) {
642                SetBooleanProperty(TEXT("win.comdlg.noPlacesBar"), (BOOL)((int)*value != 0));
643            }
644            free(value);
645        }
646    }
647    catch (std::bad_alloc&) {
648        if (value != NULL) {
649            free(value);
650        }
651        throw;
652    }
653
654    LPTSTR valueName = TEXT("PlaceN");
655    LPTSTR valueNameBuf = (LPTSTR)SAFE_SIZE_ARRAY_ALLOC(safe_Malloc, (lstrlen(valueName) + 1), sizeof(TCHAR));
656    lstrcpy(valueNameBuf, valueName);
657
658    LPTSTR propKey = TEXT("win.comdlg.placesBarPlaceN");
659
660    LPTSTR propKeyBuf;
661    try {
662        propKeyBuf = (LPTSTR)SAFE_SIZE_ARRAY_ALLOC(safe_Malloc, (lstrlen(propKey) + 1), sizeof(TCHAR));
663    }
664    catch (std::bad_alloc&) {
665        free(valueNameBuf);
666        throw;
667    }
668    lstrcpy(propKeyBuf, propKey);
669
670    int i = 0;
671    do {
672        valueNameBuf[5] = _T('0' + i++);
673        propKeyBuf[25] = valueNameBuf[5];
674
675        LPTSTR key = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\comdlg32\\PlacesBar");
676        try {
677            value = NULL;
678            if ((value = getWindowsPropFromReg(key, valueNameBuf, &valueType)) != NULL) {
679                if (valueType == REG_DWORD) {
680                    // Value is a CSIDL
681                    SetIntegerProperty(propKeyBuf, (int)*value);
682                } else {
683                    // Value is a path
684                    SetStringProperty(propKeyBuf, value);
685                }
686                free(value);
687            }
688        }
689        catch (std::bad_alloc&) {
690            if (value != NULL) {
691                free(value);
692            }
693            free(propKeyBuf);
694            free(valueNameBuf);
695            throw;
696        }
697    } while (value != NULL);
698
699    free(propKeyBuf);
700    free(valueNameBuf);
701}
702
703void AwtDesktopProperties::GetSoundEvents() {
704    /////
705    SetSoundProperty(TEXT("win.sound.default"), TEXT(".Default"));
706    SetSoundProperty(TEXT("win.sound.close"), TEXT("Close"));
707    SetSoundProperty(TEXT("win.sound.maximize"), TEXT("Maximize"));
708    SetSoundProperty(TEXT("win.sound.minimize"), TEXT("Minimize"));
709    SetSoundProperty(TEXT("win.sound.menuCommand"), TEXT("MenuCommand"));
710    SetSoundProperty(TEXT("win.sound.menuPopup"), TEXT("MenuPopup"));
711    SetSoundProperty(TEXT("win.sound.open"), TEXT("Open"));
712    SetSoundProperty(TEXT("win.sound.restoreDown"), TEXT("RestoreDown"));
713    SetSoundProperty(TEXT("win.sound.restoreUp"), TEXT("RestoreUp"));
714    /////
715    SetSoundProperty(TEXT("win.sound.asterisk"), TEXT("SystemAsterisk"));
716    SetSoundProperty(TEXT("win.sound.exclamation"), TEXT("SystemExclamation"));
717    SetSoundProperty(TEXT("win.sound.exit"), TEXT("SystemExit"));
718    SetSoundProperty(TEXT("win.sound.hand"), TEXT("SystemHand"));
719    SetSoundProperty(TEXT("win.sound.question"), TEXT("SystemQuestion"));
720    SetSoundProperty(TEXT("win.sound.start"), TEXT("SystemStart"));
721}
722
723void AwtDesktopProperties::GetCaretParameters() {
724    SetIntegerProperty(TEXT("win.caret.width"), GetIntegerParameter(SPI_GETCARETWIDTH));
725}
726
727BOOL AwtDesktopProperties::GetBooleanParameter(UINT spi) {
728    BOOL        flag;
729    SystemParametersInfo(spi, 0, &flag, 0);
730    DASSERT(flag == TRUE || flag == FALSE); // should be simple boolean value
731    return flag;
732}
733
734UINT AwtDesktopProperties::GetIntegerParameter(UINT spi) {
735    UINT retValue;
736    SystemParametersInfo(spi, 0, &retValue, 0);
737    return retValue;
738}
739
740void AwtDesktopProperties::SetStringProperty(LPCTSTR propName, LPTSTR value) {
741    jstring key = JNU_NewStringPlatform(GetEnv(), propName);
742    if (key == NULL) {
743        throw std::bad_alloc();
744    }
745    jstring jValue = JNU_NewStringPlatform(GetEnv(), value);
746    if (jValue == NULL) {
747        GetEnv()->DeleteLocalRef(key);
748        throw std::bad_alloc();
749    }
750    GetEnv()->CallVoidMethod(self,
751                             AwtDesktopProperties::setStringPropertyID,
752                             key, jValue);
753    GetEnv()->DeleteLocalRef(jValue);
754    GetEnv()->DeleteLocalRef(key);
755}
756
757void AwtDesktopProperties::SetIntegerProperty(LPCTSTR propName, int value) {
758
759    jstring key = JNU_NewStringPlatform(GetEnv(), propName);
760    if (key == NULL) {
761        throw std::bad_alloc();
762    }
763    GetEnv()->CallVoidMethod(self,
764                             AwtDesktopProperties::setIntegerPropertyID,
765                             key, (jint)value);
766    GetEnv()->DeleteLocalRef(key);
767}
768
769void AwtDesktopProperties::SetBooleanProperty(LPCTSTR propName, BOOL value) {
770    jstring key = JNU_NewStringPlatform(GetEnv(), propName);
771    if (key == NULL) {
772        throw std::bad_alloc();
773    }
774    GetEnv()->CallVoidMethod(self,
775                             AwtDesktopProperties::setBooleanPropertyID,
776                             key, value ? JNI_TRUE : JNI_FALSE);
777    GetEnv()->DeleteLocalRef(key);
778}
779
780void AwtDesktopProperties::SetColorProperty(LPCTSTR propName, DWORD value) {
781    jstring key = JNU_NewStringPlatform(GetEnv(), propName);
782    if (key == NULL) {
783        throw std::bad_alloc();
784    }
785    GetEnv()->CallVoidMethod(self,
786                             AwtDesktopProperties::setColorPropertyID,
787                             key, GetRValue(value), GetGValue(value),
788                             GetBValue(value));
789    GetEnv()->DeleteLocalRef(key);
790}
791
792void AwtDesktopProperties::SetFontProperty(HDC dc, int fontID,
793    LPCTSTR propName, float invScale) {
794        HGDIOBJ font = GetStockObject(fontID);
795    if (font != NULL && SelectObject(dc, font) != NULL) {
796        int length = GetTextFace(dc, 0, NULL);
797
798        if (length > 0) {
799            LPTSTR face = new TCHAR[length];
800
801            if (GetTextFace(dc, length, face) > 0) {
802                TEXTMETRIC metrics;
803
804                if (GetTextMetrics(dc, &metrics) > 0) {
805                    jstring fontName = NULL;
806                    if (!wcscmp(face, L"MS Shell Dlg")) {
807                        // MS Shell Dlg is an indirect font name, find the
808                        // real face name from the registry.
809                        LPTSTR shellDialogFace = resolveShellDialogFont();
810                        if (shellDialogFace != NULL) {
811                            fontName = JNU_NewStringPlatform(GetEnv(),
812                                                             shellDialogFace);
813                            free(shellDialogFace);
814                        }
815                        else {
816                            // Couldn't determine mapping for MS Shell Dlg,
817                            // fall back to Microsoft Sans Serif
818                            fontName = JNU_NewStringPlatform(GetEnv(),
819                                                    L"Microsoft Sans Serif");
820                        }
821                    }
822                    else {
823                        fontName = JNU_NewStringPlatform(GetEnv(), face);
824                    }
825                    if (fontName == NULL) {
826                        delete[] face;
827                        throw std::bad_alloc();
828                    }
829
830                    jint pointSize = rescale(metrics.tmHeight -
831                                     metrics.tmInternalLeading, invScale);
832                    jint style = java_awt_Font_PLAIN;
833
834                    if (metrics.tmWeight >= FW_BOLD) {
835                        style =  java_awt_Font_BOLD;
836                    }
837                    if (metrics.tmItalic ) {
838                        style |= java_awt_Font_ITALIC;
839                    }
840
841                    jstring key = JNU_NewStringPlatform(GetEnv(), propName);
842                    if (key == NULL) {
843                        GetEnv()->DeleteLocalRef(fontName);
844                        delete[] face;
845                        throw std::bad_alloc();
846                    }
847                    GetEnv()->CallVoidMethod(self,
848                              AwtDesktopProperties::setFontPropertyID,
849                              key, fontName, style, pointSize);
850                    GetEnv()->DeleteLocalRef(key);
851                    GetEnv()->DeleteLocalRef(fontName);
852                }
853            }
854            delete[] face;
855        }
856    }
857}
858
859void AwtDesktopProperties::SetFontProperty(LPCTSTR propName, const LOGFONT & font,
860    float invScale) {
861    jstring fontName;
862    jint pointSize;
863    jint style;
864
865    fontName = JNU_NewStringPlatform(GetEnv(), font.lfFaceName);
866    if (fontName == NULL) {
867        throw std::bad_alloc();
868    }
869#if 0
870    HDC         hdc;
871    int         pixelsPerInch = GetDeviceCaps(hdc, LOGPIXELSY);
872    // convert font size specified in pixels to font size in points
873    hdc = GetDC(NULL);
874    pointSize = (-font.lfHeight)*72/pixelsPerInch;
875    ReleaseDC(NULL, hdc);
876#endif
877    // Java uses point sizes, but assumes 1 pixel = 1 point
878    pointSize = rescale(-font.lfHeight, invScale);
879
880    // convert Windows font style to Java style
881    style = java_awt_Font_PLAIN;
882    DTRACE_PRINTLN1("weight=%d", font.lfWeight);
883    if ( font.lfWeight >= FW_BOLD ) {
884        style =  java_awt_Font_BOLD;
885    }
886    if ( font.lfItalic ) {
887        style |= java_awt_Font_ITALIC;
888    }
889
890    jstring key = JNU_NewStringPlatform(GetEnv(), propName);
891    if (key == NULL) {
892        GetEnv()->DeleteLocalRef(fontName);
893        throw std::bad_alloc();
894    }
895    GetEnv()->CallVoidMethod(self, AwtDesktopProperties::setFontPropertyID,
896                             key, fontName, style, pointSize);
897    GetEnv()->DeleteLocalRef(key);
898    GetEnv()->DeleteLocalRef(fontName);
899}
900
901void AwtDesktopProperties::SetSoundProperty(LPCTSTR propName, LPCTSTR winEventName) {
902    jstring key = JNU_NewStringPlatform(GetEnv(), propName);
903    if (key == NULL) {
904        throw std::bad_alloc();
905    }
906    jstring event = JNU_NewStringPlatform(GetEnv(), winEventName);
907    if (event == NULL) {
908        GetEnv()->DeleteLocalRef(key);
909        throw std::bad_alloc();
910    }
911    GetEnv()->CallVoidMethod(self,
912                             AwtDesktopProperties::setSoundPropertyID,
913                             key, event);
914    GetEnv()->DeleteLocalRef(event);
915    GetEnv()->DeleteLocalRef(key);
916}
917
918void AwtDesktopProperties::PlayWindowsSound(LPCTSTR event) {
919    // stop any currently playing sounds
920    ::PlaySound(NULL, NULL, SND_PURGE);
921    // play the sound for the given event name
922    ::PlaySound(event, NULL, SND_ASYNC|SND_ALIAS|SND_NODEFAULT);
923}
924
925///////////////////////////////////////////////////////////////////////////////////////////////////
926
927static AwtDesktopProperties * GetCppThis(JNIEnv *env, jobject self) {
928    jlong longProps = env->GetLongField(self, AwtDesktopProperties::pDataID);
929    AwtDesktopProperties * props =
930        (AwtDesktopProperties *)jlong_to_ptr(longProps);
931    DASSERT( !IsBadReadPtr(props, sizeof(*props)) );
932    return props;
933}
934
935JNIEXPORT void JNICALL
936Java_sun_awt_windows_WDesktopProperties_initIDs(JNIEnv *env, jclass cls) {
937    TRY;
938
939    AwtDesktopProperties::pDataID = env->GetFieldID(cls, "pData", "J");
940    DASSERT(AwtDesktopProperties::pDataID != 0);
941    CHECK_NULL(AwtDesktopProperties::pDataID);
942
943    AwtDesktopProperties::setBooleanPropertyID =
944        env->GetMethodID(cls, "setBooleanProperty", "(Ljava/lang/String;Z)V");
945    DASSERT(AwtDesktopProperties::setBooleanPropertyID != 0);
946    CHECK_NULL(AwtDesktopProperties::setBooleanPropertyID);
947
948    AwtDesktopProperties::setIntegerPropertyID =
949        env->GetMethodID(cls, "setIntegerProperty", "(Ljava/lang/String;I)V");
950    DASSERT(AwtDesktopProperties::setIntegerPropertyID != 0);
951    CHECK_NULL(AwtDesktopProperties::setIntegerPropertyID);
952
953    AwtDesktopProperties::setStringPropertyID =
954        env->GetMethodID(cls, "setStringProperty", "(Ljava/lang/String;Ljava/lang/String;)V");
955    DASSERT(AwtDesktopProperties::setStringPropertyID != 0);
956    CHECK_NULL(AwtDesktopProperties::setStringPropertyID);
957
958    AwtDesktopProperties::setColorPropertyID =
959        env->GetMethodID(cls, "setColorProperty", "(Ljava/lang/String;III)V");
960    DASSERT(AwtDesktopProperties::setColorPropertyID != 0);
961    CHECK_NULL(AwtDesktopProperties::setColorPropertyID);
962
963    AwtDesktopProperties::setFontPropertyID =
964        env->GetMethodID(cls, "setFontProperty", "(Ljava/lang/String;Ljava/lang/String;II)V");
965    DASSERT(AwtDesktopProperties::setFontPropertyID != 0);
966    CHECK_NULL(AwtDesktopProperties::setFontPropertyID);
967
968    AwtDesktopProperties::setSoundPropertyID =
969        env->GetMethodID(cls, "setSoundProperty", "(Ljava/lang/String;Ljava/lang/String;)V");
970    DASSERT(AwtDesktopProperties::setSoundPropertyID != 0);
971    CHECK_NULL(AwtDesktopProperties::setSoundPropertyID);
972
973    CATCH_BAD_ALLOC;
974}
975
976JNIEXPORT void JNICALL
977Java_sun_awt_windows_WDesktopProperties_init(JNIEnv *env, jobject self) {
978    TRY;
979
980    new AwtDesktopProperties(self);
981
982    CATCH_BAD_ALLOC;
983}
984
985JNIEXPORT void JNICALL
986Java_sun_awt_windows_WDesktopProperties_getWindowsParameters(JNIEnv *env, jobject self) {
987    TRY;
988
989    GetCppThis(env, self)->GetWindowsParameters();
990
991    CATCH_BAD_ALLOC;
992}
993
994JNIEXPORT void JNICALL
995Java_sun_awt_windows_WDesktopProperties_playWindowsSound(JNIEnv *env, jobject self, jstring event) {
996    TRY;
997
998    LPCTSTR winEventName;
999    winEventName = JNU_GetStringPlatformChars(env, event, NULL);
1000    if ( winEventName == NULL ) {
1001        return;
1002    }
1003    GetCppThis(env, self)->PlayWindowsSound(winEventName);
1004    JNU_ReleaseStringPlatformChars(env, event, winEventName);
1005
1006    CATCH_BAD_ALLOC;
1007}
1008