CLOSED TREE: TraceMonkey merge head. (a=blockers)
[mozilla-central.git] / widget / src / windows / nsUXThemeData.cpp
blob0ab5839ef9cf2be7dfab61775e3b829364003505
1 /* vim: se cin sw=2 ts=2 et : */
2 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
4 * ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
15 * License.
17 * The Original Code is the Mozilla browser.
19 * The Initial Developer of the Original Code is
20 * Netscape Communications Corporation.
21 * Portions created by the Initial Developer are Copyright (C) 1999
22 * the Initial Developer. All Rights Reserved.
24 * Contributor(s):
25 * Rob Arnold <robarnold@mozilla.com> (Original Author)
26 * Jim Mathies <jmathies@mozilla.com>
28 * Alternatively, the contents of this file may be used under the terms of
29 * either of the GNU General Public License Version 2 or later (the "GPL"),
30 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
31 * in which case the provisions of the GPL or the LGPL are applicable instead
32 * of those above. If you wish to allow use of your version of this file only
33 * under the terms of either the GPL or the LGPL, and not to allow others to
34 * use your version of this file under the terms of the MPL, indicate your
35 * decision by deleting the provisions above and replace them with the notice
36 * and other provisions required by the GPL or the LGPL. If you do not delete
37 * the provisions above, a recipient may use your version of this file under
38 * the terms of any one of the MPL, the GPL or the LGPL.
40 * ***** END LICENSE BLOCK ***** */
42 #include "nsUXThemeData.h"
43 #include "nsDebug.h"
44 // For GetWindowsVersion
45 #include "nsWindow.h"
46 #include "nsUXThemeConstants.h"
48 const PRUnichar
49 nsUXThemeData::kThemeLibraryName[] = L"uxtheme.dll";
50 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
51 const PRUnichar
52 nsUXThemeData::kDwmLibraryName[] = L"dwmapi.dll";
53 #endif
55 HANDLE
56 nsUXThemeData::sThemes[eUXNumClasses];
58 HMODULE
59 nsUXThemeData::sThemeDLL = NULL;
60 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
61 HMODULE
62 nsUXThemeData::sDwmDLL = NULL;
63 #endif
65 BOOL
66 nsUXThemeData::sFlatMenus = FALSE;
67 PRPackedBool
68 nsUXThemeData::sIsXPOrLater = PR_FALSE;
69 PRPackedBool
70 nsUXThemeData::sIsVistaOrLater = PR_FALSE;
72 PRBool nsUXThemeData::sTitlebarInfoPopulatedAero = PR_FALSE;
73 PRBool nsUXThemeData::sTitlebarInfoPopulatedThemed = PR_FALSE;
74 SIZE nsUXThemeData::sCommandButtons[4];
76 nsUXThemeData::OpenThemeDataPtr nsUXThemeData::openTheme = NULL;
77 nsUXThemeData::CloseThemeDataPtr nsUXThemeData::closeTheme = NULL;
78 nsUXThemeData::DrawThemeBackgroundPtr nsUXThemeData::drawThemeBG = NULL;
79 nsUXThemeData::DrawThemeEdgePtr nsUXThemeData::drawThemeEdge = NULL;
80 nsUXThemeData::GetThemeContentRectPtr nsUXThemeData::getThemeContentRect = NULL;
81 nsUXThemeData::GetThemeBackgroundRegionPtr nsUXThemeData::getThemeBackgroundRegion = NULL;
82 nsUXThemeData::GetThemePartSizePtr nsUXThemeData::getThemePartSize = NULL;
83 nsUXThemeData::GetThemeSysFontPtr nsUXThemeData::getThemeSysFont = NULL;
84 nsUXThemeData::GetThemeColorPtr nsUXThemeData::getThemeColor = NULL;
85 nsUXThemeData::GetThemeMarginsPtr nsUXThemeData::getThemeMargins = NULL;
86 nsUXThemeData::IsAppThemedPtr nsUXThemeData::isAppThemed = NULL;
87 nsUXThemeData::GetCurrentThemeNamePtr nsUXThemeData::getCurrentThemeName = NULL;
88 nsUXThemeData::GetThemeSysColorPtr nsUXThemeData::getThemeSysColor = NULL;
89 nsUXThemeData::IsThemeBackgroundPartiallyTransparentPtr nsUXThemeData::isThemeBackgroundPartiallyTransparent = NULL;
91 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
92 nsUXThemeData::DwmExtendFrameIntoClientAreaProc nsUXThemeData::dwmExtendFrameIntoClientAreaPtr = NULL;
93 nsUXThemeData::DwmIsCompositionEnabledProc nsUXThemeData::dwmIsCompositionEnabledPtr = NULL;
94 nsUXThemeData::DwmSetIconicThumbnailProc nsUXThemeData::dwmSetIconicThumbnailPtr = NULL;
95 nsUXThemeData::DwmSetIconicLivePreviewBitmapProc nsUXThemeData::dwmSetIconicLivePreviewBitmapPtr = NULL;
96 nsUXThemeData::DwmGetWindowAttributeProc nsUXThemeData::dwmGetWindowAttributePtr = NULL;
97 nsUXThemeData::DwmSetWindowAttributeProc nsUXThemeData::dwmSetWindowAttributePtr = NULL;
98 nsUXThemeData::DwmInvalidateIconicBitmapsProc nsUXThemeData::dwmInvalidateIconicBitmapsPtr = NULL;
99 nsUXThemeData::DwmDefWindowProcProc nsUXThemeData::dwmDwmDefWindowProcPtr = NULL;
100 #endif
102 void
103 nsUXThemeData::Teardown() {
104 Invalidate();
105 if(sThemeDLL)
106 FreeLibrary(sThemeDLL);
107 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
108 if(sDwmDLL)
109 FreeLibrary(sDwmDLL);
110 #endif
113 void
114 nsUXThemeData::Initialize()
116 ::ZeroMemory(sThemes, sizeof(sThemes));
117 NS_ASSERTION(!sThemeDLL, "nsUXThemeData being initialized twice!");
119 PRInt32 version = nsWindow::GetWindowsVersion();
120 sIsXPOrLater = version >= WINXP_VERSION;
121 sIsVistaOrLater = version >= VISTA_VERSION;
123 if (GetThemeDLL()) {
124 openTheme = (OpenThemeDataPtr)GetProcAddress(sThemeDLL, "OpenThemeData");
125 closeTheme = (CloseThemeDataPtr)GetProcAddress(sThemeDLL, "CloseThemeData");
126 drawThemeBG = (DrawThemeBackgroundPtr)GetProcAddress(sThemeDLL, "DrawThemeBackground");
127 drawThemeEdge = (DrawThemeEdgePtr)GetProcAddress(sThemeDLL, "DrawThemeEdge");
128 getThemeContentRect = (GetThemeContentRectPtr)GetProcAddress(sThemeDLL, "GetThemeBackgroundContentRect");
129 getThemeBackgroundRegion = (GetThemeBackgroundRegionPtr)GetProcAddress(sThemeDLL, "GetThemeBackgroundRegion");
130 getThemePartSize = (GetThemePartSizePtr)GetProcAddress(sThemeDLL, "GetThemePartSize");
131 getThemeSysFont = (GetThemeSysFontPtr)GetProcAddress(sThemeDLL, "GetThemeSysFont");
132 getThemeColor = (GetThemeColorPtr)GetProcAddress(sThemeDLL, "GetThemeColor");
133 getThemeMargins = (GetThemeMarginsPtr)GetProcAddress(sThemeDLL, "GetThemeMargins");
134 isAppThemed = (IsAppThemedPtr)GetProcAddress(sThemeDLL, "IsAppThemed");
135 getCurrentThemeName = (GetCurrentThemeNamePtr)GetProcAddress(sThemeDLL, "GetCurrentThemeName");
136 getThemeSysColor = (GetThemeSysColorPtr)GetProcAddress(sThemeDLL, "GetThemeSysColor");
137 isThemeBackgroundPartiallyTransparent = (IsThemeBackgroundPartiallyTransparentPtr)GetProcAddress(sThemeDLL, "IsThemeBackgroundPartiallyTransparent");
139 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
140 if (GetDwmDLL()) {
141 dwmExtendFrameIntoClientAreaPtr = (DwmExtendFrameIntoClientAreaProc)::GetProcAddress(sDwmDLL, "DwmExtendFrameIntoClientArea");
142 dwmIsCompositionEnabledPtr = (DwmIsCompositionEnabledProc)::GetProcAddress(sDwmDLL, "DwmIsCompositionEnabled");
143 dwmSetIconicThumbnailPtr = (DwmSetIconicThumbnailProc)::GetProcAddress(sDwmDLL, "DwmSetIconicThumbnail");
144 dwmSetIconicLivePreviewBitmapPtr = (DwmSetIconicLivePreviewBitmapProc)::GetProcAddress(sDwmDLL, "DwmSetIconicLivePreviewBitmap");
145 dwmGetWindowAttributePtr = (DwmGetWindowAttributeProc)::GetProcAddress(sDwmDLL, "DwmGetWindowAttribute");
146 dwmSetWindowAttributePtr = (DwmSetWindowAttributeProc)::GetProcAddress(sDwmDLL, "DwmSetWindowAttribute");
147 dwmInvalidateIconicBitmapsPtr = (DwmInvalidateIconicBitmapsProc)::GetProcAddress(sDwmDLL, "DwmInvalidateIconicBitmaps");
148 dwmDwmDefWindowProcPtr = (DwmDefWindowProcProc)::GetProcAddress(sDwmDLL, "DwmDefWindowProc");
149 CheckForCompositor(PR_TRUE);
151 #endif
153 Invalidate();
156 void
157 nsUXThemeData::Invalidate() {
158 for(int i = 0; i < eUXNumClasses; i++) {
159 if(sThemes[i]) {
160 closeTheme(sThemes[i]);
161 sThemes[i] = NULL;
164 if (sIsXPOrLater) {
165 BOOL useFlat = PR_FALSE;
166 sFlatMenus = ::SystemParametersInfo(SPI_GETFLATMENU, 0, &useFlat, 0) ?
167 useFlat : PR_FALSE;
168 } else {
169 // Contrary to Microsoft's documentation, SPI_GETFLATMENU will not fail
170 // on Windows 2000, and it is also possible (though unlikely) for WIN2K
171 // to be misconfigured in such a way that it would return true, so we
172 // shall give WIN2K special treatment
173 sFlatMenus = PR_FALSE;
177 HANDLE
178 nsUXThemeData::GetTheme(nsUXThemeClass cls) {
179 NS_ASSERTION(cls < eUXNumClasses, "Invalid theme class!");
180 if(!sThemeDLL)
181 return NULL;
182 if(!sThemes[cls])
184 sThemes[cls] = openTheme(NULL, GetClassName(cls));
186 return sThemes[cls];
189 HMODULE
190 nsUXThemeData::GetThemeDLL() {
191 if (!sThemeDLL && sIsXPOrLater)
192 sThemeDLL = ::LoadLibraryW(kThemeLibraryName);
193 return sThemeDLL;
196 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
197 HMODULE
198 nsUXThemeData::GetDwmDLL() {
199 if (!sDwmDLL && sIsVistaOrLater)
200 sDwmDLL = ::LoadLibraryW(kDwmLibraryName);
201 return sDwmDLL;
203 #endif
205 const wchar_t *nsUXThemeData::GetClassName(nsUXThemeClass cls) {
206 switch(cls) {
207 case eUXButton:
208 return L"Button";
209 case eUXEdit:
210 return L"Edit";
211 case eUXTooltip:
212 return L"Tooltip";
213 case eUXRebar:
214 return L"Rebar";
215 case eUXMediaRebar:
216 return L"Media::Rebar";
217 case eUXCommunicationsRebar:
218 return L"Communications::Rebar";
219 case eUXBrowserTabBarRebar:
220 return L"BrowserTabBar::Rebar";
221 case eUXToolbar:
222 return L"Toolbar";
223 case eUXMediaToolbar:
224 return L"Media::Toolbar";
225 case eUXCommunicationsToolbar:
226 return L"Communications::Toolbar";
227 case eUXProgress:
228 return L"Progress";
229 case eUXTab:
230 return L"Tab";
231 case eUXScrollbar:
232 return L"Scrollbar";
233 case eUXTrackbar:
234 return L"Trackbar";
235 case eUXSpin:
236 return L"Spin";
237 case eUXStatus:
238 return L"Status";
239 case eUXCombobox:
240 return L"Combobox";
241 case eUXHeader:
242 return L"Header";
243 case eUXListview:
244 return L"Listview";
245 case eUXMenu:
246 return L"Menu";
247 case eUXWindowFrame:
248 return L"Window";
249 default:
250 NS_NOTREACHED("unknown uxtheme class");
251 return L"";
255 // static
256 void
257 nsUXThemeData::InitTitlebarInfo()
259 // Pre-populate with generic metrics. These likley will not match
260 // the current theme, but they insure the buttons at least show up.
261 sCommandButtons[0].cx = GetSystemMetrics(SM_CXSIZE);
262 sCommandButtons[0].cy = GetSystemMetrics(SM_CYSIZE);
263 sCommandButtons[1].cx = sCommandButtons[2].cx = sCommandButtons[0].cx;
264 sCommandButtons[1].cy = sCommandButtons[2].cy = sCommandButtons[0].cy;
265 sCommandButtons[3].cx = sCommandButtons[0].cx * 3;
266 sCommandButtons[3].cy = sCommandButtons[0].cy;
268 // Use system metrics for pre-vista, otherwise trigger a
269 // refresh on the next layout.
270 sTitlebarInfoPopulatedAero = sTitlebarInfoPopulatedThemed =
271 (nsWindow::GetWindowsVersion() < VISTA_VERSION);
274 // static
275 void
276 nsUXThemeData::UpdateTitlebarInfo(HWND aWnd)
278 if (!aWnd)
279 return;
281 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_LONGHORN
282 if (!sTitlebarInfoPopulatedAero && nsUXThemeData::CheckForCompositor()) {
283 RECT captionButtons;
284 if (SUCCEEDED(nsUXThemeData::dwmGetWindowAttributePtr(aWnd,
285 DWMWA_CAPTION_BUTTON_BOUNDS,
286 &captionButtons,
287 sizeof(captionButtons)))) {
288 sCommandButtons[CMDBUTTONIDX_BUTTONBOX].cx = captionButtons.right - captionButtons.left - 3;
289 sCommandButtons[CMDBUTTONIDX_BUTTONBOX].cy = (captionButtons.bottom - captionButtons.top) - 1;
290 sTitlebarInfoPopulatedAero = PR_TRUE;
293 #endif
295 if (sTitlebarInfoPopulatedThemed)
296 return;
298 // Query a temporary, visible window with command buttons to get
299 // the right metrics.
300 nsAutoString className;
301 className.AssignLiteral(kClassNameTemp);
302 WNDCLASSW wc;
303 wc.style = 0;
304 wc.lpfnWndProc = ::DefWindowProcW;
305 wc.cbClsExtra = 0;
306 wc.cbWndExtra = 0;
307 wc.hInstance = nsToolkit::mDllInstance;
308 wc.hIcon = NULL;
309 wc.hCursor = NULL;
310 wc.hbrBackground = NULL;
311 wc.lpszMenuName = NULL;
312 wc.lpszClassName = className.get();
313 ::RegisterClassW(&wc);
315 // Create a transparent descendant of the window passed in. This
316 // keeps the window from showing up on the desktop or the taskbar.
317 // Note the parent (browser) window is usually still hidden, we
318 // don't want to display it, so we can't query it directly.
319 HWND hWnd = CreateWindowExW(WS_EX_LAYERED,
320 className.get(), L"",
321 WS_OVERLAPPEDWINDOW,
322 0, 0, 0, 0, aWnd, NULL,
323 nsToolkit::mDllInstance, NULL);
324 NS_ASSERTION(hWnd, "UpdateTitlebarInfo window creation failed.");
326 ShowWindow(hWnd, SW_SHOW);
327 TITLEBARINFOEX info = {0};
328 info.cbSize = sizeof(TITLEBARINFOEX);
329 SendMessage(hWnd, WM_GETTITLEBARINFOEX, 0, (LPARAM)&info);
330 DestroyWindow(hWnd);
332 // Only set if we have valid data for all three buttons we use.
333 if ((info.rgrect[2].right - info.rgrect[2].left) == 0 ||
334 (info.rgrect[3].right - info.rgrect[3].left) == 0 ||
335 (info.rgrect[5].right - info.rgrect[5].left) == 0) {
336 NS_WARNING("WM_GETTITLEBARINFOEX query failed to find usable metrics.");
337 return;
339 // minimize
340 sCommandButtons[0].cx = info.rgrect[2].right - info.rgrect[2].left;
341 sCommandButtons[0].cy = info.rgrect[2].bottom - info.rgrect[2].top;
342 // maximize/restore
343 sCommandButtons[1].cx = info.rgrect[3].right - info.rgrect[3].left;
344 sCommandButtons[1].cy = info.rgrect[3].bottom - info.rgrect[3].top;
345 // close
346 sCommandButtons[2].cx = info.rgrect[5].right - info.rgrect[5].left;
347 sCommandButtons[2].cy = info.rgrect[5].bottom - info.rgrect[5].top;
349 sTitlebarInfoPopulatedThemed = PR_TRUE;
352 // visual style (aero glass, aero basic)
353 // theme (aero, luna, zune)
354 // theme color (silver, olive, blue)
355 // system colors
357 struct THEMELIST {
358 LPCWSTR name;
359 int type;
362 const THEMELIST knownThemes[] = {
363 { L"aero.msstyles", WINTHEME_AERO },
364 { L"luna.msstyles", WINTHEME_LUNA },
365 { L"zune.msstyles", WINTHEME_ZUNE },
366 { L"royale.msstyles", WINTHEME_ROYALE }
369 const THEMELIST knownColors[] = {
370 { L"normalcolor", WINTHEMECOLOR_NORMAL },
371 { L"homestead", WINTHEMECOLOR_HOMESTEAD },
372 { L"metallic", WINTHEMECOLOR_METALLIC }
375 nsILookAndFeel::WindowsThemeIdentifier
376 nsUXThemeData::sThemeId = nsILookAndFeel::eWindowsTheme_Generic;
378 PRBool
379 nsUXThemeData::sIsDefaultWindowsTheme = PR_FALSE;
381 // static
382 nsILookAndFeel::WindowsThemeIdentifier
383 nsUXThemeData::GetNativeThemeId()
385 return sThemeId;
388 // static
389 PRBool nsUXThemeData::IsDefaultWindowTheme()
391 return sIsDefaultWindowsTheme;
394 // static
395 void
396 nsUXThemeData::UpdateNativeThemeInfo()
398 // Trigger a refresh of themed button metrics if needed
399 sTitlebarInfoPopulatedThemed = (nsWindow::GetWindowsVersion() < VISTA_VERSION);
401 sIsDefaultWindowsTheme = PR_FALSE;
402 sThemeId = nsILookAndFeel::eWindowsTheme_Generic;
404 if (!IsAppThemed() || !getCurrentThemeName) {
405 sThemeId = nsILookAndFeel::eWindowsTheme_Classic;
406 return;
409 WCHAR themeFileName[MAX_PATH + 1];
410 WCHAR themeColor[MAX_PATH + 1];
411 if (FAILED(getCurrentThemeName(themeFileName,
412 MAX_PATH,
413 themeColor,
414 MAX_PATH,
415 NULL, 0))) {
416 sThemeId = nsILookAndFeel::eWindowsTheme_Classic;
417 return;
420 LPCWSTR themeName = wcsrchr(themeFileName, L'\\');
421 themeName = themeName ? themeName + 1 : themeFileName;
423 WindowsTheme theme = WINTHEME_UNRECOGNIZED;
424 for (int i = 0; i < NS_ARRAY_LENGTH(knownThemes); ++i) {
425 if (!lstrcmpiW(themeName, knownThemes[i].name)) {
426 theme = (WindowsTheme)knownThemes[i].type;
427 break;
431 if (theme == WINTHEME_UNRECOGNIZED)
432 return;
434 if (theme == WINTHEME_AERO || theme == WINTHEME_LUNA)
435 sIsDefaultWindowsTheme = PR_TRUE;
437 if (theme != WINTHEME_LUNA) {
438 switch(theme) {
439 case WINTHEME_AERO:
440 sThemeId = nsILookAndFeel::eWindowsTheme_Aero;
441 return;
442 case WINTHEME_ZUNE:
443 sThemeId = nsILookAndFeel::eWindowsTheme_Zune;
444 return;
445 case WINTHEME_ROYALE:
446 sThemeId = nsILookAndFeel::eWindowsTheme_Royale;
447 return;
448 default:
449 NS_WARNING("unhandled theme type.");
450 return;
454 // calculate the luna color scheme
455 WindowsThemeColor color = WINTHEMECOLOR_UNRECOGNIZED;
456 for (int i = 0; i < NS_ARRAY_LENGTH(knownColors); ++i) {
457 if (!lstrcmpiW(themeColor, knownColors[i].name)) {
458 color = (WindowsThemeColor)knownColors[i].type;
459 break;
463 switch(color) {
464 case WINTHEMECOLOR_NORMAL:
465 sThemeId = nsILookAndFeel::eWindowsTheme_LunaBlue;
466 return;
467 case WINTHEMECOLOR_HOMESTEAD:
468 sThemeId = nsILookAndFeel::eWindowsTheme_LunaOlive;
469 return;
470 case WINTHEMECOLOR_METALLIC:
471 sThemeId = nsILookAndFeel::eWindowsTheme_LunaSilver;
472 return;
473 default:
474 NS_WARNING("unhandled theme color.");
475 return;