2 * Win32 5.1 msstyles theme format
4 * Copyright (C) 2003 Kevin Koltzau
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #include <wine/unicode.h>
25 /***********************************************************************
26 * Defines and global variables
29 static BOOL
MSSTYLES_GetNextInteger(LPCWSTR lpStringStart
, LPCWSTR lpStringEnd
, LPCWSTR
*lpValEnd
, int *value
);
30 static BOOL
MSSTYLES_GetNextToken(LPCWSTR lpStringStart
, LPCWSTR lpStringEnd
, LPCWSTR
*lpValEnd
, LPWSTR lpBuff
, DWORD buffSize
);
31 static HRESULT
MSSTYLES_GetFont (LPCWSTR lpStringStart
, LPCWSTR lpStringEnd
, LPCWSTR
*lpValEnd
, LOGFONTW
* logfont
);
33 extern int alphaBlendMode
;
35 #define MSSTYLES_VERSION 0x0003
37 static const WCHAR szThemesIniResource
[] = {
38 't','h','e','m','e','s','_','i','n','i','\0'
41 /***********************************************************************/
43 /**********************************************************************
44 * MSSTYLES_OpenThemeFile
46 * Load and validate a theme
49 * lpThemeFile Path to theme file to load
50 * pszColorName Color name wanted, can be NULL
51 * pszSizeName Size name wanted, can be NULL
54 * If pszColorName or pszSizeName are NULL, the default color/size will be used.
55 * If one/both are provided, they are validated against valid color/sizes and if
56 * a match is not found, the function fails.
58 HRESULT
MSSTYLES_OpenThemeFile(LPCWSTR lpThemeFile
, LPCWSTR pszColorName
, LPCWSTR pszSizeName
, PTHEME_FILE
*tf
)
63 static const WCHAR szPackThemVersionResource
[] = {
64 'P','A','C','K','T','H','E','M','_','V','E','R','S','I','O','N', '\0'
66 static const WCHAR szColorNamesResource
[] = {
67 'C','O','L','O','R','N','A','M','E','S','\0'
69 static const WCHAR szSizeNamesResource
[] = {
70 'S','I','Z','E','N','A','M','E','S','\0'
76 LPWSTR pszSelectedColor
= NULL
;
78 LPWSTR pszSelectedSize
= NULL
;
81 if (!gbThemeHooksActive
)
84 TRACE("Opening %s\n", debugstr_w(lpThemeFile
));
86 hTheme
= LoadLibraryExW(lpThemeFile
, NULL
, LOAD_LIBRARY_AS_DATAFILE
);
88 /* Validate that this is really a theme */
90 hr
= HRESULT_FROM_WIN32(GetLastError());
93 if(!(hrsc
= FindResourceW(hTheme
, MAKEINTRESOURCEW(1), szPackThemVersionResource
))) {
94 TRACE("No version resource found\n");
95 hr
= HRESULT_FROM_WIN32(ERROR_BAD_FORMAT
);
98 if((versize
= SizeofResource(hTheme
, hrsc
)) != 2)
100 TRACE("Version resource found, but wrong size: %d\n", versize
);
101 hr
= HRESULT_FROM_WIN32(ERROR_BAD_FORMAT
);
104 version
= *(WORD
*)LoadResource(hTheme
, hrsc
);
105 if(version
!= MSSTYLES_VERSION
)
107 TRACE("Version of theme file is unsupported: 0x%04x\n", version
);
108 hr
= HRESULT_FROM_WIN32(ERROR_BAD_FORMAT
);
112 if(!(hrsc
= FindResourceW(hTheme
, MAKEINTRESOURCEW(1), szColorNamesResource
))) {
113 TRACE("Color names resource not found\n");
114 hr
= HRESULT_FROM_WIN32(ERROR_BAD_FORMAT
);
117 pszColors
= LoadResource(hTheme
, hrsc
);
119 if(!(hrsc
= FindResourceW(hTheme
, MAKEINTRESOURCEW(1), szSizeNamesResource
))) {
120 TRACE("Size names resource not found\n");
121 hr
= HRESULT_FROM_WIN32(ERROR_BAD_FORMAT
);
124 pszSizes
= LoadResource(hTheme
, hrsc
);
126 /* Validate requested color against what's available from the theme */
130 if(!lstrcmpiW(pszColorName
, tmp
)) {
131 pszSelectedColor
= tmp
;
134 tmp
+= lstrlenW(tmp
)+1;
138 pszSelectedColor
= pszColors
; /* Use the default color */
140 /* Validate requested size against what's available from the theme */
144 if(!lstrcmpiW(pszSizeName
, tmp
)) {
145 pszSelectedSize
= tmp
;
148 tmp
+= lstrlenW(tmp
)+1;
152 pszSelectedSize
= pszSizes
; /* Use the default size */
154 if(!pszSelectedColor
|| !pszSelectedSize
) {
155 TRACE("Requested color/size (%s/%s) not found in theme\n",
156 debugstr_w(pszColorName
), debugstr_w(pszSizeName
));
157 hr
= E_PROP_ID_UNSUPPORTED
;
161 *tf
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(THEME_FILE
));
162 (*tf
)->hTheme
= hTheme
;
164 GetFullPathNameW(lpThemeFile
, MAX_PATH
, (*tf
)->szThemeFile
, NULL
);
166 (*tf
)->pszAvailColors
= pszColors
;
167 (*tf
)->pszAvailSizes
= pszSizes
;
168 (*tf
)->pszSelectedColor
= pszSelectedColor
;
169 (*tf
)->pszSelectedSize
= pszSelectedSize
;
170 (*tf
)->dwRefCount
= 1;
172 TRACE("Theme %p refcount: %d\n", *tf
, (*tf
)->dwRefCount
);
177 if(hTheme
) FreeLibrary(hTheme
);
181 /***********************************************************************
182 * MSSTYLES_CloseThemeFile
184 * Close theme file and free resources
186 void MSSTYLES_CloseThemeFile(PTHEME_FILE tf
)
191 TRACE("Theme %p refcount: %d\n", tf
, tf
->dwRefCount
);
193 if(!tf
->dwRefCount
) {
194 if(tf
->hTheme
) FreeLibrary(tf
->hTheme
);
197 PTHEME_CLASS pcls
= tf
->classes
;
198 tf
->classes
= pcls
->next
;
199 while(pcls
->partstate
) {
200 PTHEME_PARTSTATE ps
= pcls
->partstate
;
202 while(ps
->properties
) {
203 PTHEME_PROPERTY prop
= ps
->properties
;
204 ps
->properties
= prop
->next
;
205 HeapFree(GetProcessHeap(), 0, prop
);
208 pcls
->partstate
= ps
->next
;
209 HeapFree(GetProcessHeap(), 0, ps
);
211 HeapFree(GetProcessHeap(), 0, pcls
);
216 PTHEME_IMAGE img
= tf
->images
;
217 tf
->images
= img
->next
;
218 DeleteObject (img
->image
);
219 HeapFree (GetProcessHeap(), 0, img
);
221 HeapFree(GetProcessHeap(), 0, tf
);
226 /***********************************************************************
227 * MSSTYLES_ReferenceTheme
229 * Increase the reference count of the theme file
231 HRESULT
MSSTYLES_ReferenceTheme(PTHEME_FILE tf
)
234 TRACE("Theme %p refcount: %d\n", tf
, tf
->dwRefCount
);
238 /***********************************************************************
239 * MSSTYLES_GetThemeIni
241 * Retrieves themes.ini from a theme
243 PUXINI_FILE
MSSTYLES_GetThemeIni(PTHEME_FILE tf
)
245 return UXINI_LoadINI(tf
->hTheme
, szThemesIniResource
);
248 /***********************************************************************
249 * MSSTYLES_GetActiveThemeIni
251 * Retrieve the ini file for the selected color/style
253 static PUXINI_FILE
MSSTYLES_GetActiveThemeIni(PTHEME_FILE tf
)
255 static const WCHAR szFileResNamesResource
[] = {
256 'F','I','L','E','R','E','S','N','A','M','E','S','\0'
258 DWORD dwColorCount
= 0;
259 DWORD dwSizeCount
= 0;
260 DWORD dwColorNum
= 0;
263 DWORD dwResourceIndex
;
267 /* Count the number of available colors & styles, and determine the index number
268 of the color/style we are interested in
270 tmp
= tf
->pszAvailColors
;
272 if(!lstrcmpiW(tf
->pszSelectedColor
, tmp
))
273 dwColorNum
= dwColorCount
;
274 tmp
+= lstrlenW(tmp
)+1;
277 tmp
= tf
->pszAvailSizes
;
279 if(!lstrcmpiW(tf
->pszSelectedSize
, tmp
))
280 dwSizeNum
= dwSizeCount
;
281 tmp
+= lstrlenW(tmp
)+1;
285 if(!(hrsc
= FindResourceW(tf
->hTheme
, MAKEINTRESOURCEW(1), szFileResNamesResource
))) {
286 TRACE("FILERESNAMES map not found\n");
289 tmp
= LoadResource(tf
->hTheme
, hrsc
);
290 dwResourceIndex
= (dwSizeCount
* dwColorNum
) + dwSizeNum
;
291 for(i
=0; i
< dwResourceIndex
; i
++) {
292 tmp
+= lstrlenW(tmp
)+1;
294 return UXINI_LoadINI(tf
->hTheme
, tmp
);
298 /***********************************************************************
299 * MSSTYLES_ParseIniSectionName
301 * Parse an ini section name into its component parts
306 * [classname.part(state)]
307 * [application::classname]
308 * [application::classname(state)]
309 * [application::classname.part]
310 * [application::classname.part(state)]
313 * lpSection Section name
314 * dwLen Length of section name
315 * szAppName Location to store application name
316 * szClassName Location to store class name
317 * iPartId Location to store part id
318 * iStateId Location to store state id
320 static BOOL
MSSTYLES_ParseIniSectionName(LPCWSTR lpSection
, DWORD dwLen
, LPWSTR szAppName
, LPWSTR szClassName
, int *iPartId
, int *iStateId
)
323 WCHAR part
[60] = {'\0'};
324 WCHAR state
[60] = {'\0'};
327 lstrcpynW(sec
, lpSection
, min(dwLen
+1, sizeof(sec
)/sizeof(sec
[0])));
334 /* Get the application name */
335 tmp
= strchrW(comp
, ':');
339 lstrcpynW(szAppName
, comp
, MAX_THEME_APP_NAME
);
343 tmp
= strchrW(comp
, '.');
346 lstrcpynW(szClassName
, comp
, MAX_THEME_CLASS_NAME
);
348 /* now get the part & state */
349 tmp
= strchrW(comp
, '(');
352 lstrcpynW(part
, comp
, sizeof(part
)/sizeof(part
[0]));
354 /* now get the state */
355 tmp
= strchrW(comp
, ')');
359 lstrcpynW(state
, comp
, sizeof(state
)/sizeof(state
[0]));
362 lstrcpynW(part
, comp
, sizeof(part
)/sizeof(part
[0]));
366 tmp
= strchrW(comp
, '(');
369 lstrcpynW(szClassName
, comp
, MAX_THEME_CLASS_NAME
);
371 /* now get the state */
372 tmp
= strchrW(comp
, ')');
376 lstrcpynW(state
, comp
, sizeof(state
)/sizeof(state
[0]));
379 lstrcpynW(szClassName
, comp
, MAX_THEME_CLASS_NAME
);
382 if(!*szClassName
) return FALSE
;
383 return MSSTYLES_LookupPartState(szClassName
, part
[0]?part
:NULL
, state
[0]?state
:NULL
, iPartId
, iStateId
);
386 /***********************************************************************
393 * pszAppName App name to find
394 * pszClassName Class name to find
397 * The class found, or NULL
399 static PTHEME_CLASS
MSSTYLES_FindClass(PTHEME_FILE tf
, LPCWSTR pszAppName
, LPCWSTR pszClassName
)
401 PTHEME_CLASS cur
= tf
->classes
;
404 if(!*cur
->szAppName
&& !lstrcmpiW(pszClassName
, cur
->szClassName
))
408 if(!lstrcmpiW(pszAppName
, cur
->szAppName
) && !lstrcmpiW(pszClassName
, cur
->szClassName
))
416 /***********************************************************************
419 * Add a class to a theme file
423 * pszAppName App name to add
424 * pszClassName Class name to add
427 * The class added, or a class previously added with the same name
429 static PTHEME_CLASS
MSSTYLES_AddClass(PTHEME_FILE tf
, LPCWSTR pszAppName
, LPCWSTR pszClassName
)
431 PTHEME_CLASS cur
= MSSTYLES_FindClass(tf
, pszAppName
, pszClassName
);
434 cur
= HeapAlloc(GetProcessHeap(), 0, sizeof(THEME_CLASS
));
435 cur
->hTheme
= tf
->hTheme
;
436 lstrcpyW(cur
->szAppName
, pszAppName
);
437 lstrcpyW(cur
->szClassName
, pszClassName
);
438 cur
->next
= tf
->classes
;
439 cur
->partstate
= NULL
;
440 cur
->overrides
= NULL
;
445 /***********************************************************************
446 * MSSTYLES_FindPartState
452 * iPartId Part ID to find
453 * iStateId State ID to find
454 * tcNext Receives the next class in the override chain
457 * The part/state found, or NULL
459 PTHEME_PARTSTATE
MSSTYLES_FindPartState(PTHEME_CLASS tc
, int iPartId
, int iStateId
, PTHEME_CLASS
*tcNext
)
461 PTHEME_PARTSTATE cur
= tc
->partstate
;
463 if(cur
->iPartId
== iPartId
&& cur
->iStateId
== iStateId
) {
464 if(tcNext
) *tcNext
= tc
->overrides
;
469 if(tc
->overrides
) return MSSTYLES_FindPartState(tc
->overrides
, iPartId
, iStateId
, tcNext
);
473 /***********************************************************************
474 * MSSTYLES_AddPartState
476 * Add a part/state to a class
480 * iPartId Part ID to add
481 * iStateId State ID to add
484 * The part/state added, or a part/state previously added with the same IDs
486 static PTHEME_PARTSTATE
MSSTYLES_AddPartState(PTHEME_CLASS tc
, int iPartId
, int iStateId
)
488 PTHEME_PARTSTATE cur
= MSSTYLES_FindPartState(tc
, iPartId
, iStateId
, NULL
);
491 cur
= HeapAlloc(GetProcessHeap(), 0, sizeof(THEME_PARTSTATE
));
492 cur
->iPartId
= iPartId
;
493 cur
->iStateId
= iStateId
;
494 cur
->properties
= NULL
;
495 cur
->next
= tc
->partstate
;
500 /***********************************************************************
501 * MSSTYLES_LFindProperty
503 * Find a property within a property list
506 * tp property list to scan
507 * iPropertyPrimitive Type of value expected
508 * iPropertyId ID of the required value
511 * The property found, or NULL
513 static PTHEME_PROPERTY
MSSTYLES_LFindProperty(PTHEME_PROPERTY tp
, int iPropertyPrimitive
, int iPropertyId
)
515 PTHEME_PROPERTY cur
= tp
;
517 if(cur
->iPropertyId
== iPropertyId
) {
518 if(cur
->iPrimitiveType
== iPropertyPrimitive
) {
522 if(!iPropertyPrimitive
)
532 /***********************************************************************
533 * MSSTYLES_PSFindProperty
535 * Find a value within a part/state
538 * ps Part/state to search
539 * iPropertyPrimitive Type of value expected
540 * iPropertyId ID of the required value
543 * The property found, or NULL
545 static inline PTHEME_PROPERTY
MSSTYLES_PSFindProperty(PTHEME_PARTSTATE ps
, int iPropertyPrimitive
, int iPropertyId
)
547 return MSSTYLES_LFindProperty(ps
->properties
, iPropertyPrimitive
, iPropertyId
);
550 /***********************************************************************
551 * MSSTYLES_FindMetric
553 * Find a metric property for a theme file
557 * iPropertyPrimitive Type of value expected
558 * iPropertyId ID of the required value
561 * The property found, or NULL
563 PTHEME_PROPERTY
MSSTYLES_FindMetric(PTHEME_FILE tf
, int iPropertyPrimitive
, int iPropertyId
)
565 return MSSTYLES_LFindProperty(tf
->metrics
, iPropertyPrimitive
, iPropertyId
);
568 /***********************************************************************
569 * MSSTYLES_AddProperty
571 * Add a property to a part/state
575 * iPropertyPrimitive Primitive type of the property
576 * iPropertyId ID of the property
577 * lpValue Raw value (non-NULL terminated)
578 * dwValueLen Length of the value
581 * The property added, or a property previously added with the same IDs
583 static PTHEME_PROPERTY
MSSTYLES_AddProperty(PTHEME_PARTSTATE ps
, int iPropertyPrimitive
, int iPropertyId
, LPCWSTR lpValue
, DWORD dwValueLen
, BOOL isGlobal
)
585 PTHEME_PROPERTY cur
= MSSTYLES_PSFindProperty(ps
, iPropertyPrimitive
, iPropertyId
);
586 /* Should duplicate properties overwrite the original, or be ignored? */
589 cur
= HeapAlloc(GetProcessHeap(), 0, sizeof(THEME_PROPERTY
));
590 cur
->iPrimitiveType
= iPropertyPrimitive
;
591 cur
->iPropertyId
= iPropertyId
;
592 cur
->lpValue
= lpValue
;
593 cur
->dwValueLen
= dwValueLen
;
596 cur
->origin
= PO_STATE
;
598 cur
->origin
= PO_PART
;
600 cur
->origin
= PO_GLOBAL
;
602 cur
->origin
= PO_CLASS
;
604 cur
->next
= ps
->properties
;
605 ps
->properties
= cur
;
609 /***********************************************************************
612 * Add a property to a part/state
616 * iPropertyPrimitive Primitive type of the property
617 * iPropertyId ID of the property
618 * lpValue Raw value (non-NULL terminated)
619 * dwValueLen Length of the value
622 * The property added, or a property previously added with the same IDs
624 static PTHEME_PROPERTY
MSSTYLES_AddMetric(PTHEME_FILE tf
, int iPropertyPrimitive
, int iPropertyId
, LPCWSTR lpValue
, DWORD dwValueLen
)
626 PTHEME_PROPERTY cur
= MSSTYLES_FindMetric(tf
, iPropertyPrimitive
, iPropertyId
);
627 /* Should duplicate properties overwrite the original, or be ignored? */
630 cur
= HeapAlloc(GetProcessHeap(), 0, sizeof(THEME_PROPERTY
));
631 cur
->iPrimitiveType
= iPropertyPrimitive
;
632 cur
->iPropertyId
= iPropertyId
;
633 cur
->lpValue
= lpValue
;
634 cur
->dwValueLen
= dwValueLen
;
636 cur
->origin
= PO_GLOBAL
;
638 cur
->next
= tf
->metrics
;
643 /***********************************************************************
644 * MSSTYLES_ParseThemeIni
646 * Parse the theme ini for the selected color/style
651 void MSSTYLES_ParseThemeIni(PTHEME_FILE tf
)
653 static const WCHAR szSysMetrics
[] = {'S','y','s','M','e','t','r','i','c','s','\0'};
654 static const WCHAR szGlobals
[] = {'g','l','o','b','a','l','s','\0'};
656 PTHEME_CLASS globals
;
659 WCHAR szAppName
[MAX_THEME_APP_NAME
];
660 WCHAR szClassName
[MAX_THEME_CLASS_NAME
];
661 WCHAR szPropertyName
[MAX_THEME_VALUE_NAME
];
664 int iPropertyPrimitive
;
674 ini
= MSSTYLES_GetActiveThemeIni(tf
);
676 while((lpName
=UXINI_GetNextSection(ini
, &dwLen
)))
678 if(CompareStringW(LOCALE_SYSTEM_DEFAULT
, NORM_IGNORECASE
, lpName
, dwLen
, szSysMetrics
, -1) == CSTR_EQUAL
)
680 while((lpName
=UXINI_GetNextValue(ini
, &dwLen
, &lpValue
, &dwValueLen
)))
682 lstrcpynW(szPropertyName
, lpName
, min(dwLen
+1, sizeof(szPropertyName
)/sizeof(szPropertyName
[0])));
683 if(MSSTYLES_LookupProperty(szPropertyName
, &iPropertyPrimitive
, &iPropertyId
))
685 /* Catch all metrics, including colors */
686 MSSTYLES_AddMetric(tf
, iPropertyPrimitive
, iPropertyId
, lpValue
, dwValueLen
);
690 TRACE("Unknown system metric %s\n", debugstr_w(szPropertyName
));
696 if(MSSTYLES_ParseIniSectionName(lpName
, dwLen
, szAppName
, szClassName
, &iPartId
, &iStateId
))
698 BOOL isGlobal
= FALSE
;
699 if(!lstrcmpiW(szClassName
, szGlobals
))
703 cls
= MSSTYLES_AddClass(tf
, szAppName
, szClassName
);
704 ps
= MSSTYLES_AddPartState(cls
, iPartId
, iStateId
);
706 while((lpName
=UXINI_GetNextValue(ini
, &dwLen
, &lpValue
, &dwValueLen
)))
708 lstrcpynW(szPropertyName
, lpName
, min(dwLen
+1, sizeof(szPropertyName
)/sizeof(szPropertyName
[0])));
709 if(MSSTYLES_LookupProperty(szPropertyName
, &iPropertyPrimitive
, &iPropertyId
))
711 MSSTYLES_AddProperty(ps
, iPropertyPrimitive
, iPropertyId
, lpValue
, dwValueLen
, isGlobal
);
715 TRACE("Unknown property %s\n", debugstr_w(szPropertyName
));
721 /* App/Class combos override values defined by the base class, map these overrides */
722 globals
= MSSTYLES_FindClass(tf
, NULL
, szGlobals
);
728 cls
->overrides
= MSSTYLES_FindClass(tf
, NULL
, cls
->szClassName
);
731 TRACE("No overrides found for app %s class %s\n", debugstr_w(cls
->szAppName
), debugstr_w(cls
->szClassName
));
735 cls
->overrides
= globals
;
740 /* Everything overrides globals..except globals */
742 cls
->overrides
= globals
;
749 ERR("Failed to parse theme ini\n");
753 /***********************************************************************
754 * MSSTYLES_OpenThemeClass
756 * Open a theme class, uses the current active theme
759 * pszAppName Application name, for theme styles specific
760 * to a particular application
761 * pszClassList List of requested classes, semicolon delimited
763 PTHEME_CLASS
MSSTYLES_OpenThemeClass(PTHEME_FILE tf
, LPCWSTR pszAppName
, LPCWSTR pszClassList
)
765 PTHEME_CLASS cls
= NULL
;
766 WCHAR szClassName
[MAX_THEME_CLASS_NAME
];
775 start
= pszClassList
;
776 while((end
= strchrW(start
, ';'))) {
778 lstrcpynW(szClassName
, start
, min(len
+1, sizeof(szClassName
)/sizeof(szClassName
[0])));
780 cls
= MSSTYLES_FindClass(tf
, pszAppName
, szClassName
);
784 lstrcpynW(szClassName
, start
, sizeof(szClassName
)/sizeof(szClassName
[0]));
785 cls
= MSSTYLES_FindClass(tf
, pszAppName
, szClassName
);
788 TRACE("Opened app %s, class %s from list %s\n", debugstr_w(cls
->szAppName
), debugstr_w(cls
->szClassName
), debugstr_w(pszClassList
));
790 cls
->tf
->dwRefCount
++;
791 TRACE("Theme %p refcount: %d\n", tf
, tf
->dwRefCount
);
796 /***********************************************************************
797 * MSSTYLES_CloseThemeClass
799 * Close a theme class
802 * tc Theme class to close
805 * The MSSTYLES_CloseThemeFile decreases the refcount of the owning
806 * theme file and cleans it up, if needed.
808 HRESULT
MSSTYLES_CloseThemeClass(PTHEME_CLASS tc
)
810 MSSTYLES_CloseThemeFile (tc
->tf
);
814 /***********************************************************************
815 * MSSTYLES_FindProperty
817 * Locate a property in a class. Part and state IDs will be used as a
818 * preference, but may be ignored in the attempt to locate the property.
819 * Will scan the entire chain of overrides for this class.
821 PTHEME_PROPERTY
MSSTYLES_FindProperty(PTHEME_CLASS tc
, int iPartId
, int iStateId
, int iPropertyPrimitive
, int iPropertyId
)
823 PTHEME_CLASS next
= tc
;
827 TRACE("(%p, %d, %d, %d)\n", tc
, iPartId
, iStateId
, iPropertyId
);
828 /* Try and find an exact match on part & state */
829 while(next
&& (ps
= MSSTYLES_FindPartState(next
, iPartId
, iStateId
, &next
))) {
830 if((tp
= MSSTYLES_PSFindProperty(ps
, iPropertyPrimitive
, iPropertyId
))) {
834 /* If that fails, and we didn't already try it, search for just part */
837 /* As a last ditch attempt..go for just class */
838 else if(iPartId
!= 0)
843 if((tp
= MSSTYLES_FindProperty(tc
, iPartId
, iStateId
, iPropertyPrimitive
, iPropertyId
)))
848 /* Prepare a bitmap to be used for alpha blending */
849 static BOOL
prepare_alpha (HBITMAP bmp
, BOOL
* hasAlpha
)
857 if (!bmp
|| GetObjectW( bmp
, sizeof(dib
), &dib
) != sizeof(dib
))
860 if(dib
.dsBm
.bmBitsPixel
!= 32)
866 n
= dib
.dsBmih
.biHeight
* dib
.dsBmih
.biWidth
;
867 /* AlphaBlend() wants premultiplied alpha, so do that now */
871 p
[0] = (p
[0] * a
) >> 8;
872 p
[1] = (p
[1] * a
) >> 8;
873 p
[2] = (p
[2] * a
) >> 8;
880 HBITMAP
MSSTYLES_LoadBitmap (PTHEME_CLASS tc
, LPCWSTR lpFilename
, BOOL
* hasAlpha
)
882 WCHAR szFile
[MAX_PATH
];
885 lstrcpynW(szFile
, lpFilename
, sizeof(szFile
)/sizeof(szFile
[0]));
888 if(*tmp
== '\\') *tmp
= '_';
889 if(*tmp
== '/') *tmp
= '_';
890 if(*tmp
== '.') *tmp
= '_';
893 /* Try to locate in list of loaded images */
894 img
= tc
->tf
->images
;
897 if (lstrcmpiW (szFile
, img
->name
) == 0)
899 TRACE ("found %p %s: %p\n", img
, debugstr_w (img
->name
), img
->image
);
900 *hasAlpha
= img
->hasAlpha
;
905 /* Not found? Load from resources */
906 img
= HeapAlloc (GetProcessHeap(), 0, sizeof (THEME_IMAGE
));
907 img
->image
= LoadImageW(tc
->hTheme
, szFile
, IMAGE_BITMAP
, 0, 0, LR_CREATEDIBSECTION
);
908 prepare_alpha (img
->image
, hasAlpha
);
909 img
->hasAlpha
= *hasAlpha
;
910 /* ...and stow away for later reuse. */
911 lstrcpyW (img
->name
, szFile
);
912 img
->next
= tc
->tf
->images
;
913 tc
->tf
->images
= img
;
914 TRACE ("new %p %s: %p\n", img
, debugstr_w (img
->name
), img
->image
);
918 static BOOL
MSSTYLES_GetNextInteger(LPCWSTR lpStringStart
, LPCWSTR lpStringEnd
, LPCWSTR
*lpValEnd
, int *value
)
920 LPCWSTR cur
= lpStringStart
;
924 while(cur
< lpStringEnd
&& (*cur
< '0' || *cur
> '9' || *cur
== '-')) cur
++;
925 if(cur
>= lpStringEnd
) {
932 while(cur
< lpStringEnd
&& (*cur
>= '0' && *cur
<= '9')) {
933 total
= total
* 10 + (*cur
- '0');
936 if(gotNeg
) total
= -total
;
938 if(lpValEnd
) *lpValEnd
= cur
;
942 static BOOL
MSSTYLES_GetNextToken(LPCWSTR lpStringStart
, LPCWSTR lpStringEnd
, LPCWSTR
*lpValEnd
, LPWSTR lpBuff
, DWORD buffSize
) {
943 LPCWSTR cur
= lpStringStart
;
947 while(cur
< lpStringEnd
&& (isspace(*cur
) || *cur
== ',')) cur
++;
948 if(cur
>= lpStringEnd
) {
952 while(cur
< lpStringEnd
&& *cur
!= ',') cur
++;
954 while(isspace(*end
)) end
--;
956 lstrcpynW(lpBuff
, start
, min(buffSize
, end
-start
+1));
958 if(lpValEnd
) *lpValEnd
= cur
;
962 /***********************************************************************
963 * MSSTYLES_GetPropertyBool
965 * Retrieve a color value for a property
967 HRESULT
MSSTYLES_GetPropertyBool(PTHEME_PROPERTY tp
, BOOL
*pfVal
)
970 if(*tp
->lpValue
== 't' || *tp
->lpValue
== 'T')
975 /***********************************************************************
976 * MSSTYLES_GetPropertyColor
978 * Retrieve a color value for a property
980 HRESULT
MSSTYLES_GetPropertyColor(PTHEME_PROPERTY tp
, COLORREF
*pColor
)
984 int red
, green
, blue
;
987 lpEnd
= tp
->lpValue
+ tp
->dwValueLen
;
989 if(!MSSTYLES_GetNextInteger(lpCur
, lpEnd
, &lpCur
, &red
)) {
990 TRACE("Could not parse color property\n");
991 return E_PROP_ID_UNSUPPORTED
;
993 if(!MSSTYLES_GetNextInteger(lpCur
, lpEnd
, &lpCur
, &green
)) {
994 TRACE("Could not parse color property\n");
995 return E_PROP_ID_UNSUPPORTED
;
997 if(!MSSTYLES_GetNextInteger(lpCur
, lpEnd
, &lpCur
, &blue
)) {
998 TRACE("Could not parse color property\n");
999 return E_PROP_ID_UNSUPPORTED
;
1001 *pColor
= RGB(red
,green
,blue
);
1005 /***********************************************************************
1006 * MSSTYLES_GetPropertyColor
1008 * Retrieve a color value for a property
1010 static HRESULT
MSSTYLES_GetFont (LPCWSTR lpCur
, LPCWSTR lpEnd
,
1011 LPCWSTR
*lpValEnd
, LOGFONTW
* pFont
)
1013 static const WCHAR szBold
[] = {'b','o','l','d','\0'};
1014 static const WCHAR szItalic
[] = {'i','t','a','l','i','c','\0'};
1015 static const WCHAR szUnderline
[] = {'u','n','d','e','r','l','i','n','e','\0'};
1016 static const WCHAR szStrikeOut
[] = {'s','t','r','i','k','e','o','u','t','\0'};
1020 if(!MSSTYLES_GetNextToken(lpCur
, lpEnd
, &lpCur
, pFont
->lfFaceName
, LF_FACESIZE
)) {
1021 TRACE("Property is there, but failed to get face name\n");
1023 return E_PROP_ID_UNSUPPORTED
;
1025 if(!MSSTYLES_GetNextInteger(lpCur
, lpEnd
, &lpCur
, &pointSize
)) {
1026 TRACE("Property is there, but failed to get point size\n");
1028 return E_PROP_ID_UNSUPPORTED
;
1033 pointSize
= -MulDiv(pointSize
, GetDeviceCaps(hdc
, LOGPIXELSY
), 72);
1037 pFont
->lfHeight
= pointSize
;
1038 pFont
->lfWeight
= FW_REGULAR
;
1039 pFont
->lfCharSet
= DEFAULT_CHARSET
;
1040 while(MSSTYLES_GetNextToken(lpCur
, lpEnd
, &lpCur
, attr
, sizeof(attr
)/sizeof(attr
[0]))) {
1041 if(!lstrcmpiW(szBold
, attr
)) pFont
->lfWeight
= FW_BOLD
;
1042 else if(!lstrcmpiW(szItalic
, attr
)) pFont
->lfItalic
= TRUE
;
1043 else if(!lstrcmpiW(szUnderline
, attr
)) pFont
->lfUnderline
= TRUE
;
1044 else if(!lstrcmpiW(szStrikeOut
, attr
)) pFont
->lfStrikeOut
= TRUE
;
1050 HRESULT
MSSTYLES_GetPropertyFont(PTHEME_PROPERTY tp
, HDC hdc
, LOGFONTW
*pFont
)
1052 LPCWSTR lpCur
= tp
->lpValue
;
1053 LPCWSTR lpEnd
= tp
->lpValue
+ tp
->dwValueLen
;
1056 ZeroMemory(pFont
, sizeof(LOGFONTW
));
1057 hr
= MSSTYLES_GetFont (lpCur
, lpEnd
, &lpCur
, pFont
);
1062 /***********************************************************************
1063 * MSSTYLES_GetPropertyInt
1065 * Retrieve an int value for a property
1067 HRESULT
MSSTYLES_GetPropertyInt(PTHEME_PROPERTY tp
, int *piVal
)
1069 if(!MSSTYLES_GetNextInteger(tp
->lpValue
, (tp
->lpValue
+ tp
->dwValueLen
), NULL
, piVal
)) {
1070 TRACE("Could not parse int property\n");
1071 return E_PROP_ID_UNSUPPORTED
;
1076 /***********************************************************************
1077 * MSSTYLES_GetPropertyIntList
1079 * Retrieve an int list value for a property
1081 HRESULT
MSSTYLES_GetPropertyIntList(PTHEME_PROPERTY tp
, INTLIST
*pIntList
)
1084 LPCWSTR lpCur
= tp
->lpValue
;
1085 LPCWSTR lpEnd
= tp
->lpValue
+ tp
->dwValueLen
;
1087 for(i
=0; i
< MAX_INTLIST_COUNT
; i
++) {
1088 if(!MSSTYLES_GetNextInteger(lpCur
, lpEnd
, &lpCur
, &pIntList
->iValues
[i
]))
1091 pIntList
->iValueCount
= i
;
1095 /***********************************************************************
1096 * MSSTYLES_GetPropertyPosition
1098 * Retrieve a position value for a property
1100 HRESULT
MSSTYLES_GetPropertyPosition(PTHEME_PROPERTY tp
, POINT
*pPoint
)
1103 LPCWSTR lpCur
= tp
->lpValue
;
1104 LPCWSTR lpEnd
= tp
->lpValue
+ tp
->dwValueLen
;
1106 if(!MSSTYLES_GetNextInteger(lpCur
, lpEnd
, &lpCur
, &x
)) {
1107 TRACE("Could not parse position property\n");
1108 return E_PROP_ID_UNSUPPORTED
;
1110 if(!MSSTYLES_GetNextInteger(lpCur
, lpEnd
, &lpCur
, &y
)) {
1111 TRACE("Could not parse position property\n");
1112 return E_PROP_ID_UNSUPPORTED
;
1119 /***********************************************************************
1120 * MSSTYLES_GetPropertyString
1122 * Retrieve a string value for a property
1124 HRESULT
MSSTYLES_GetPropertyString(PTHEME_PROPERTY tp
, LPWSTR pszBuff
, int cchMaxBuffChars
)
1126 lstrcpynW(pszBuff
, tp
->lpValue
, min(tp
->dwValueLen
+1, cchMaxBuffChars
));
1130 /***********************************************************************
1131 * MSSTYLES_GetPropertyRect
1133 * Retrieve a rect value for a property
1135 HRESULT
MSSTYLES_GetPropertyRect(PTHEME_PROPERTY tp
, RECT
*pRect
)
1137 LPCWSTR lpCur
= tp
->lpValue
;
1138 LPCWSTR lpEnd
= tp
->lpValue
+ tp
->dwValueLen
;
1140 MSSTYLES_GetNextInteger(lpCur
, lpEnd
, &lpCur
, &pRect
->left
);
1141 MSSTYLES_GetNextInteger(lpCur
, lpEnd
, &lpCur
, &pRect
->top
);
1142 MSSTYLES_GetNextInteger(lpCur
, lpEnd
, &lpCur
, &pRect
->right
);
1143 if(!MSSTYLES_GetNextInteger(lpCur
, lpEnd
, &lpCur
, &pRect
->bottom
)) {
1144 TRACE("Could not parse rect property\n");
1145 return E_PROP_ID_UNSUPPORTED
;
1150 /***********************************************************************
1151 * MSSTYLES_GetPropertyMargins
1153 * Retrieve a margins value for a property
1155 HRESULT
MSSTYLES_GetPropertyMargins(PTHEME_PROPERTY tp
, RECT
*prc
, MARGINS
*pMargins
)
1157 LPCWSTR lpCur
= tp
->lpValue
;
1158 LPCWSTR lpEnd
= tp
->lpValue
+ tp
->dwValueLen
;
1160 MSSTYLES_GetNextInteger(lpCur
, lpEnd
, &lpCur
, &pMargins
->cxLeftWidth
);
1161 MSSTYLES_GetNextInteger(lpCur
, lpEnd
, &lpCur
, &pMargins
->cxRightWidth
);
1162 MSSTYLES_GetNextInteger(lpCur
, lpEnd
, &lpCur
, &pMargins
->cyTopHeight
);
1163 if(!MSSTYLES_GetNextInteger(lpCur
, lpEnd
, &lpCur
, &pMargins
->cyBottomHeight
)) {
1164 TRACE("Could not parse margins property\n");
1165 return E_PROP_ID_UNSUPPORTED
;