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 extern int alphaBlendMode
;
31 #define MSSTYLES_VERSION 0x0003
33 static const WCHAR szThemesIniResource
[] = {
34 't','h','e','m','e','s','_','i','n','i','\0'
37 /***********************************************************************/
39 /**********************************************************************
40 * MSSTYLES_OpenThemeFile
42 * Load and validate a theme
45 * lpThemeFile Path to theme file to load
46 * pszColorName Color name wanted, can be NULL
47 * pszSizeName Size name wanted, can be NULL
50 * If pszColorName or pszSizeName are NULL, the default color/size will be used.
51 * If one/both are provided, they are validated against valid color/sizes and if
52 * a match is not found, the function fails.
54 HRESULT
MSSTYLES_OpenThemeFile(LPCWSTR lpThemeFile
, LPCWSTR pszColorName
, LPCWSTR pszSizeName
, PTHEME_FILE
*tf
)
59 static const WCHAR szPackThemVersionResource
[] = {
60 'P','A','C','K','T','H','E','M','_','V','E','R','S','I','O','N', '\0'
62 static const WCHAR szColorNamesResource
[] = {
63 'C','O','L','O','R','N','A','M','E','S','\0'
65 static const WCHAR szSizeNamesResource
[] = {
66 'S','I','Z','E','N','A','M','E','S','\0'
72 LPWSTR pszSelectedColor
= NULL
;
74 LPWSTR pszSelectedSize
= NULL
;
77 TRACE("Opening %s\n", debugstr_w(lpThemeFile
));
79 hTheme
= LoadLibraryExW(lpThemeFile
, NULL
, LOAD_LIBRARY_AS_DATAFILE
);
81 /* Validate that this is really a theme */
83 hr
= HRESULT_FROM_WIN32(GetLastError());
86 if(!(hrsc
= FindResourceW(hTheme
, MAKEINTRESOURCEW(1), szPackThemVersionResource
))) {
87 TRACE("No version resource found\n");
88 hr
= HRESULT_FROM_WIN32(ERROR_BAD_FORMAT
);
91 if((versize
= SizeofResource(hTheme
, hrsc
)) != 2)
93 TRACE("Version resource found, but wrong size: %d\n", versize
);
94 hr
= HRESULT_FROM_WIN32(ERROR_BAD_FORMAT
);
97 version
= *(WORD
*)LoadResource(hTheme
, hrsc
);
98 if(version
!= MSSTYLES_VERSION
)
100 TRACE("Version of theme file is unsupported: 0x%04x\n", version
);
101 hr
= HRESULT_FROM_WIN32(ERROR_BAD_FORMAT
);
105 if(!(hrsc
= FindResourceW(hTheme
, MAKEINTRESOURCEW(1), szColorNamesResource
))) {
106 TRACE("Color names resource not found\n");
107 hr
= HRESULT_FROM_WIN32(ERROR_BAD_FORMAT
);
110 pszColors
= LoadResource(hTheme
, hrsc
);
112 if(!(hrsc
= FindResourceW(hTheme
, MAKEINTRESOURCEW(1), szSizeNamesResource
))) {
113 TRACE("Size names resource not found\n");
114 hr
= HRESULT_FROM_WIN32(ERROR_BAD_FORMAT
);
117 pszSizes
= LoadResource(hTheme
, hrsc
);
119 /* Validate requested color against what's available from the theme */
123 if(!lstrcmpiW(pszColorName
, tmp
)) {
124 pszSelectedColor
= tmp
;
127 tmp
+= lstrlenW(tmp
)+1;
131 pszSelectedColor
= pszColors
; /* Use the default color */
133 /* Validate requested size against what's available from the theme */
137 if(!lstrcmpiW(pszSizeName
, tmp
)) {
138 pszSelectedSize
= tmp
;
141 tmp
+= lstrlenW(tmp
)+1;
145 pszSelectedSize
= pszSizes
; /* Use the default size */
147 if(!pszSelectedColor
|| !pszSelectedSize
) {
148 TRACE("Requested color/size (%s/%s) not found in theme\n",
149 debugstr_w(pszColorName
), debugstr_w(pszSizeName
));
150 hr
= E_PROP_ID_UNSUPPORTED
;
154 *tf
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(THEME_FILE
));
155 (*tf
)->hTheme
= hTheme
;
157 GetFullPathNameW(lpThemeFile
, MAX_PATH
, (*tf
)->szThemeFile
, NULL
);
159 (*tf
)->pszAvailColors
= pszColors
;
160 (*tf
)->pszAvailSizes
= pszSizes
;
161 (*tf
)->pszSelectedColor
= pszSelectedColor
;
162 (*tf
)->pszSelectedSize
= pszSelectedSize
;
163 (*tf
)->dwRefCount
= 1;
165 TRACE("Theme %p refcount: %d\n", *tf
, (*tf
)->dwRefCount
);
170 if(hTheme
) FreeLibrary(hTheme
);
174 /***********************************************************************
175 * MSSTYLES_CloseThemeFile
177 * Close theme file and free resources
179 void MSSTYLES_CloseThemeFile(PTHEME_FILE tf
)
184 TRACE("Theme %p refcount: %d\n", tf
, tf
->dwRefCount
);
186 if(!tf
->dwRefCount
) {
187 if(tf
->hTheme
) FreeLibrary(tf
->hTheme
);
190 PTHEME_CLASS pcls
= tf
->classes
;
191 tf
->classes
= pcls
->next
;
192 while(pcls
->partstate
) {
193 PTHEME_PARTSTATE ps
= pcls
->partstate
;
195 while(ps
->properties
) {
196 PTHEME_PROPERTY prop
= ps
->properties
;
197 ps
->properties
= prop
->next
;
198 HeapFree(GetProcessHeap(), 0, prop
);
201 pcls
->partstate
= ps
->next
;
202 HeapFree(GetProcessHeap(), 0, ps
);
204 HeapFree(GetProcessHeap(), 0, pcls
);
209 PTHEME_IMAGE img
= tf
->images
;
210 tf
->images
= img
->next
;
211 DeleteObject (img
->image
);
212 HeapFree (GetProcessHeap(), 0, img
);
214 HeapFree(GetProcessHeap(), 0, tf
);
219 /***********************************************************************
220 * MSSTYLES_ReferenceTheme
222 * Increase the reference count of the theme file
224 HRESULT
MSSTYLES_ReferenceTheme(PTHEME_FILE tf
)
227 TRACE("Theme %p refcount: %d\n", tf
, tf
->dwRefCount
);
231 /***********************************************************************
232 * MSSTYLES_GetThemeIni
234 * Retrieves themes.ini from a theme
236 PUXINI_FILE
MSSTYLES_GetThemeIni(PTHEME_FILE tf
)
238 return UXINI_LoadINI(tf
->hTheme
, szThemesIniResource
);
241 /***********************************************************************
242 * MSSTYLES_GetActiveThemeIni
244 * Retrieve the ini file for the selected color/style
246 static PUXINI_FILE
MSSTYLES_GetActiveThemeIni(PTHEME_FILE tf
)
248 static const WCHAR szFileResNamesResource
[] = {
249 'F','I','L','E','R','E','S','N','A','M','E','S','\0'
251 DWORD dwColorCount
= 0;
252 DWORD dwSizeCount
= 0;
253 DWORD dwColorNum
= 0;
256 DWORD dwResourceIndex
;
260 /* Count the number of available colors & styles, and determine the index number
261 of the color/style we are interested in
263 tmp
= tf
->pszAvailColors
;
265 if(!lstrcmpiW(tf
->pszSelectedColor
, tmp
))
266 dwColorNum
= dwColorCount
;
267 tmp
+= lstrlenW(tmp
)+1;
270 tmp
= tf
->pszAvailSizes
;
272 if(!lstrcmpiW(tf
->pszSelectedSize
, tmp
))
273 dwSizeNum
= dwSizeCount
;
274 tmp
+= lstrlenW(tmp
)+1;
278 if(!(hrsc
= FindResourceW(tf
->hTheme
, MAKEINTRESOURCEW(1), szFileResNamesResource
))) {
279 TRACE("FILERESNAMES map not found\n");
282 tmp
= LoadResource(tf
->hTheme
, hrsc
);
283 dwResourceIndex
= (dwSizeCount
* dwColorNum
) + dwSizeNum
;
284 for(i
=0; i
< dwResourceIndex
; i
++) {
285 tmp
+= lstrlenW(tmp
)+1;
287 return UXINI_LoadINI(tf
->hTheme
, tmp
);
291 /***********************************************************************
292 * MSSTYLES_ParseIniSectionName
294 * Parse an ini section name into its component parts
299 * [classname.part(state)]
300 * [application::classname]
301 * [application::classname(state)]
302 * [application::classname.part]
303 * [application::classname.part(state)]
306 * lpSection Section name
307 * dwLen Length of section name
308 * szAppName Location to store application name
309 * szClassName Location to store class name
310 * iPartId Location to store part id
311 * iStateId Location to store state id
313 static BOOL
MSSTYLES_ParseIniSectionName(LPCWSTR lpSection
, DWORD dwLen
, LPWSTR szAppName
, LPWSTR szClassName
, int *iPartId
, int *iStateId
)
316 WCHAR part
[60] = {'\0'};
317 WCHAR state
[60] = {'\0'};
320 lstrcpynW(sec
, lpSection
, min(dwLen
+1, sizeof(sec
)/sizeof(sec
[0])));
327 /* Get the application name */
328 tmp
= strchrW(comp
, ':');
332 lstrcpynW(szAppName
, comp
, MAX_THEME_APP_NAME
);
336 tmp
= strchrW(comp
, '.');
339 lstrcpynW(szClassName
, comp
, MAX_THEME_CLASS_NAME
);
341 /* now get the part & state */
342 tmp
= strchrW(comp
, '(');
345 lstrcpynW(part
, comp
, sizeof(part
)/sizeof(part
[0]));
347 /* now get the state */
348 tmp
= strchrW(comp
, ')');
352 lstrcpynW(state
, comp
, sizeof(state
)/sizeof(state
[0]));
355 lstrcpynW(part
, comp
, sizeof(part
)/sizeof(part
[0]));
359 tmp
= strchrW(comp
, '(');
362 lstrcpynW(szClassName
, comp
, MAX_THEME_CLASS_NAME
);
364 /* now get the state */
365 tmp
= strchrW(comp
, ')');
369 lstrcpynW(state
, comp
, sizeof(state
)/sizeof(state
[0]));
372 lstrcpynW(szClassName
, comp
, MAX_THEME_CLASS_NAME
);
375 if(!*szClassName
) return FALSE
;
376 return MSSTYLES_LookupPartState(szClassName
, part
[0]?part
:NULL
, state
[0]?state
:NULL
, iPartId
, iStateId
);
379 /***********************************************************************
386 * pszAppName App name to find
387 * pszClassName Class name to find
390 * The class found, or NULL
392 static PTHEME_CLASS
MSSTYLES_FindClass(PTHEME_FILE tf
, LPCWSTR pszAppName
, LPCWSTR pszClassName
)
394 PTHEME_CLASS cur
= tf
->classes
;
397 if(!*cur
->szAppName
&& !lstrcmpiW(pszClassName
, cur
->szClassName
))
401 if(!lstrcmpiW(pszAppName
, cur
->szAppName
) && !lstrcmpiW(pszClassName
, cur
->szClassName
))
409 /***********************************************************************
412 * Add a class to a theme file
416 * pszAppName App name to add
417 * pszClassName Class name to add
420 * The class added, or a class previously added with the same name
422 static PTHEME_CLASS
MSSTYLES_AddClass(PTHEME_FILE tf
, LPCWSTR pszAppName
, LPCWSTR pszClassName
)
424 PTHEME_CLASS cur
= MSSTYLES_FindClass(tf
, pszAppName
, pszClassName
);
427 cur
= HeapAlloc(GetProcessHeap(), 0, sizeof(THEME_CLASS
));
428 cur
->hTheme
= tf
->hTheme
;
429 lstrcpyW(cur
->szAppName
, pszAppName
);
430 lstrcpyW(cur
->szClassName
, pszClassName
);
431 cur
->next
= tf
->classes
;
432 cur
->partstate
= NULL
;
433 cur
->overrides
= NULL
;
438 /***********************************************************************
439 * MSSTYLES_FindPartState
445 * iPartId Part ID to find
446 * iStateId State ID to find
447 * tcNext Receives the next class in the override chain
450 * The part/state found, or NULL
452 PTHEME_PARTSTATE
MSSTYLES_FindPartState(PTHEME_CLASS tc
, int iPartId
, int iStateId
, PTHEME_CLASS
*tcNext
)
454 PTHEME_PARTSTATE cur
= tc
->partstate
;
456 if(cur
->iPartId
== iPartId
&& cur
->iStateId
== iStateId
) {
457 if(tcNext
) *tcNext
= tc
->overrides
;
462 if(tc
->overrides
) return MSSTYLES_FindPartState(tc
->overrides
, iPartId
, iStateId
, tcNext
);
466 /***********************************************************************
467 * MSSTYLES_AddPartState
469 * Add a part/state to a class
473 * iPartId Part ID to add
474 * iStateId State ID to add
477 * The part/state added, or a part/state previously added with the same IDs
479 static PTHEME_PARTSTATE
MSSTYLES_AddPartState(PTHEME_CLASS tc
, int iPartId
, int iStateId
)
481 PTHEME_PARTSTATE cur
= MSSTYLES_FindPartState(tc
, iPartId
, iStateId
, NULL
);
484 cur
= HeapAlloc(GetProcessHeap(), 0, sizeof(THEME_PARTSTATE
));
485 cur
->iPartId
= iPartId
;
486 cur
->iStateId
= iStateId
;
487 cur
->properties
= NULL
;
488 cur
->next
= tc
->partstate
;
493 /***********************************************************************
494 * MSSTYLES_LFindProperty
496 * Find a property within a property list
499 * tp property list to scan
500 * iPropertyPrimitive Type of value expected
501 * iPropertyId ID of the required value
504 * The property found, or NULL
506 static PTHEME_PROPERTY
MSSTYLES_LFindProperty(PTHEME_PROPERTY tp
, int iPropertyPrimitive
, int iPropertyId
)
508 PTHEME_PROPERTY cur
= tp
;
510 if(cur
->iPropertyId
== iPropertyId
) {
511 if(cur
->iPrimitiveType
== iPropertyPrimitive
) {
515 if(!iPropertyPrimitive
)
525 /***********************************************************************
526 * MSSTYLES_PSFindProperty
528 * Find a value within a part/state
531 * ps Part/state to search
532 * iPropertyPrimitive Type of value expected
533 * iPropertyId ID of the required value
536 * The property found, or NULL
538 static inline PTHEME_PROPERTY
MSSTYLES_PSFindProperty(PTHEME_PARTSTATE ps
, int iPropertyPrimitive
, int iPropertyId
)
540 return MSSTYLES_LFindProperty(ps
->properties
, iPropertyPrimitive
, iPropertyId
);
543 /***********************************************************************
544 * MSSTYLES_FindMetric
546 * Find a metric property for a theme file
550 * iPropertyPrimitive Type of value expected
551 * iPropertyId ID of the required value
554 * The property found, or NULL
556 PTHEME_PROPERTY
MSSTYLES_FindMetric(PTHEME_FILE tf
, int iPropertyPrimitive
, int iPropertyId
)
558 return MSSTYLES_LFindProperty(tf
->metrics
, iPropertyPrimitive
, iPropertyId
);
561 /***********************************************************************
562 * MSSTYLES_AddProperty
564 * Add a property to a part/state
568 * iPropertyPrimitive Primitive type of the property
569 * iPropertyId ID of the property
570 * lpValue Raw value (non-NULL terminated)
571 * dwValueLen Length of the value
574 * The property added, or a property previously added with the same IDs
576 static PTHEME_PROPERTY
MSSTYLES_AddProperty(PTHEME_PARTSTATE ps
, int iPropertyPrimitive
, int iPropertyId
, LPCWSTR lpValue
, DWORD dwValueLen
, BOOL isGlobal
)
578 PTHEME_PROPERTY cur
= MSSTYLES_PSFindProperty(ps
, iPropertyPrimitive
, iPropertyId
);
579 /* Should duplicate properties overwrite the original, or be ignored? */
582 cur
= HeapAlloc(GetProcessHeap(), 0, sizeof(THEME_PROPERTY
));
583 cur
->iPrimitiveType
= iPropertyPrimitive
;
584 cur
->iPropertyId
= iPropertyId
;
585 cur
->lpValue
= lpValue
;
586 cur
->dwValueLen
= dwValueLen
;
589 cur
->origin
= PO_STATE
;
591 cur
->origin
= PO_PART
;
593 cur
->origin
= PO_GLOBAL
;
595 cur
->origin
= PO_CLASS
;
597 cur
->next
= ps
->properties
;
598 ps
->properties
= cur
;
602 /***********************************************************************
605 * Add a property to a part/state
609 * iPropertyPrimitive Primitive type of the property
610 * iPropertyId ID of the property
611 * lpValue Raw value (non-NULL terminated)
612 * dwValueLen Length of the value
615 * The property added, or a property previously added with the same IDs
617 static PTHEME_PROPERTY
MSSTYLES_AddMetric(PTHEME_FILE tf
, int iPropertyPrimitive
, int iPropertyId
, LPCWSTR lpValue
, DWORD dwValueLen
)
619 PTHEME_PROPERTY cur
= MSSTYLES_FindMetric(tf
, iPropertyPrimitive
, iPropertyId
);
620 /* Should duplicate properties overwrite the original, or be ignored? */
623 cur
= HeapAlloc(GetProcessHeap(), 0, sizeof(THEME_PROPERTY
));
624 cur
->iPrimitiveType
= iPropertyPrimitive
;
625 cur
->iPropertyId
= iPropertyId
;
626 cur
->lpValue
= lpValue
;
627 cur
->dwValueLen
= dwValueLen
;
629 cur
->origin
= PO_GLOBAL
;
631 cur
->next
= tf
->metrics
;
636 /***********************************************************************
637 * MSSTYLES_ParseThemeIni
639 * Parse the theme ini for the selected color/style
644 void MSSTYLES_ParseThemeIni(PTHEME_FILE tf
)
646 static const WCHAR szSysMetrics
[] = {'S','y','s','M','e','t','r','i','c','s','\0'};
647 static const WCHAR szGlobals
[] = {'g','l','o','b','a','l','s','\0'};
649 PTHEME_CLASS globals
;
652 WCHAR szAppName
[MAX_THEME_APP_NAME
];
653 WCHAR szClassName
[MAX_THEME_CLASS_NAME
];
654 WCHAR szPropertyName
[MAX_THEME_VALUE_NAME
];
657 int iPropertyPrimitive
;
667 ini
= MSSTYLES_GetActiveThemeIni(tf
);
669 while((lpName
=UXINI_GetNextSection(ini
, &dwLen
)))
671 if(CompareStringW(LOCALE_SYSTEM_DEFAULT
, NORM_IGNORECASE
, lpName
, dwLen
, szSysMetrics
, -1) == CSTR_EQUAL
)
673 while((lpName
=UXINI_GetNextValue(ini
, &dwLen
, &lpValue
, &dwValueLen
)))
675 lstrcpynW(szPropertyName
, lpName
, min(dwLen
+1, sizeof(szPropertyName
)/sizeof(szPropertyName
[0])));
676 if(MSSTYLES_LookupProperty(szPropertyName
, &iPropertyPrimitive
, &iPropertyId
))
678 /* Catch all metrics, including colors */
679 MSSTYLES_AddMetric(tf
, iPropertyPrimitive
, iPropertyId
, lpValue
, dwValueLen
);
683 TRACE("Unknown system metric %s\n", debugstr_w(szPropertyName
));
689 if(MSSTYLES_ParseIniSectionName(lpName
, dwLen
, szAppName
, szClassName
, &iPartId
, &iStateId
))
691 BOOL isGlobal
= FALSE
;
692 if(!lstrcmpiW(szClassName
, szGlobals
))
696 cls
= MSSTYLES_AddClass(tf
, szAppName
, szClassName
);
697 ps
= MSSTYLES_AddPartState(cls
, iPartId
, iStateId
);
699 while((lpName
=UXINI_GetNextValue(ini
, &dwLen
, &lpValue
, &dwValueLen
)))
701 lstrcpynW(szPropertyName
, lpName
, min(dwLen
+1, sizeof(szPropertyName
)/sizeof(szPropertyName
[0])));
702 if(MSSTYLES_LookupProperty(szPropertyName
, &iPropertyPrimitive
, &iPropertyId
))
704 MSSTYLES_AddProperty(ps
, iPropertyPrimitive
, iPropertyId
, lpValue
, dwValueLen
, isGlobal
);
708 TRACE("Unknown property %s\n", debugstr_w(szPropertyName
));
714 /* App/Class combos override values defined by the base class, map these overrides */
715 globals
= MSSTYLES_FindClass(tf
, NULL
, szGlobals
);
721 cls
->overrides
= MSSTYLES_FindClass(tf
, NULL
, cls
->szClassName
);
724 TRACE("No overrides found for app %s class %s\n", debugstr_w(cls
->szAppName
), debugstr_w(cls
->szClassName
));
728 cls
->overrides
= globals
;
733 /* Everything overrides globals..except globals */
735 cls
->overrides
= globals
;
742 ERR("Failed to parse theme ini\n");
746 /***********************************************************************
747 * MSSTYLES_OpenThemeClass
749 * Open a theme class, uses the current active theme
752 * pszAppName Application name, for theme styles specific
753 * to a particular application
754 * pszClassList List of requested classes, semicolon delimited
756 PTHEME_CLASS
MSSTYLES_OpenThemeClass(PTHEME_FILE tf
, LPCWSTR pszAppName
, LPCWSTR pszClassList
)
758 PTHEME_CLASS cls
= NULL
;
760 PTHEME_CLASS defaultCls
= NULL
;
762 WCHAR szClassName
[MAX_THEME_CLASS_NAME
];
771 start
= pszClassList
;
772 while((end
= strchrW(start
, ';'))) {
774 lstrcpynW(szClassName
, start
, min(len
+1, sizeof(szClassName
)/sizeof(szClassName
[0])));
776 cls
= MSSTYLES_FindClass(tf
, pszAppName
, szClassName
);
780 defaultCls
= MSSTYLES_FindClass(tf
, NULL
, szClassName
);
784 lstrcpynW(szClassName
, start
, sizeof(szClassName
)/sizeof(szClassName
[0]));
785 cls
= MSSTYLES_FindClass(tf
, pszAppName
, szClassName
);
788 defaultCls
= MSSTYLES_FindClass(tf
, NULL
, szClassName
);
792 TRACE("Opened app %s, class %s from list %s\n", debugstr_w(cls
->szAppName
), debugstr_w(cls
->szClassName
), debugstr_w(pszClassList
));
794 cls
->tf
->dwRefCount
++;
795 TRACE("Theme %p refcount: %d\n", tf
, tf
->dwRefCount
);
801 TRACE("Opened default class %s from list %s\n", debugstr_w(cls
->szClassName
), debugstr_w(pszClassList
));
803 cls
->tf
->dwRefCount
++;
804 TRACE("Theme %p refcount: %d\n", tf
, tf
->dwRefCount
);
810 /***********************************************************************
811 * MSSTYLES_CloseThemeClass
813 * Close a theme class
816 * tc Theme class to close
819 * The MSSTYLES_CloseThemeFile decreases the refcount of the owning
820 * theme file and cleans it up, if needed.
822 HRESULT
MSSTYLES_CloseThemeClass(PTHEME_CLASS tc
)
824 MSSTYLES_CloseThemeFile (tc
->tf
);
828 /***********************************************************************
829 * MSSTYLES_FindProperty
831 * Locate a property in a class. Part and state IDs will be used as a
832 * preference, but may be ignored in the attempt to locate the property.
833 * Will scan the entire chain of overrides for this class.
835 PTHEME_PROPERTY
MSSTYLES_FindProperty(PTHEME_CLASS tc
, int iPartId
, int iStateId
, int iPropertyPrimitive
, int iPropertyId
)
837 PTHEME_CLASS next
= tc
;
841 TRACE("(%p, %d, %d, %d)\n", tc
, iPartId
, iStateId
, iPropertyId
);
842 /* Try and find an exact match on part & state */
843 while(next
&& (ps
= MSSTYLES_FindPartState(next
, iPartId
, iStateId
, &next
))) {
844 if((tp
= MSSTYLES_PSFindProperty(ps
, iPropertyPrimitive
, iPropertyId
))) {
848 /* If that fails, and we didn't already try it, search for just part */
851 /* As a last ditch attempt..go for just class */
852 else if(iPartId
!= 0)
857 if((tp
= MSSTYLES_FindProperty(tc
, iPartId
, iStateId
, iPropertyPrimitive
, iPropertyId
)))
862 /* Prepare a bitmap to be used for alpha blending */
863 static BOOL
prepare_alpha (HBITMAP bmp
, BOOL
* hasAlpha
)
871 if (!bmp
|| GetObjectW( bmp
, sizeof(dib
), &dib
) != sizeof(dib
))
874 if(dib
.dsBm
.bmBitsPixel
!= 32)
880 n
= dib
.dsBmih
.biHeight
* dib
.dsBmih
.biWidth
;
881 /* AlphaBlend() wants premultiplied alpha, so do that now */
885 p
[0] = (p
[0] * a
) >> 8;
886 p
[1] = (p
[1] * a
) >> 8;
887 p
[2] = (p
[2] * a
) >> 8;
894 HBITMAP
MSSTYLES_LoadBitmap (PTHEME_CLASS tc
, LPCWSTR lpFilename
, BOOL
* hasAlpha
)
896 WCHAR szFile
[MAX_PATH
];
899 lstrcpynW(szFile
, lpFilename
, sizeof(szFile
)/sizeof(szFile
[0]));
902 if(*tmp
== '\\') *tmp
= '_';
903 if(*tmp
== '/') *tmp
= '_';
904 if(*tmp
== '.') *tmp
= '_';
907 /* Try to locate in list of loaded images */
908 img
= tc
->tf
->images
;
911 if (lstrcmpiW (szFile
, img
->name
) == 0)
913 TRACE ("found %p %s: %p\n", img
, debugstr_w (img
->name
), img
->image
);
914 *hasAlpha
= img
->hasAlpha
;
919 /* Not found? Load from resources */
920 img
= HeapAlloc (GetProcessHeap(), 0, sizeof (THEME_IMAGE
));
921 img
->image
= LoadImageW(tc
->hTheme
, szFile
, IMAGE_BITMAP
, 0, 0, LR_CREATEDIBSECTION
);
922 prepare_alpha (img
->image
, hasAlpha
);
923 img
->hasAlpha
= *hasAlpha
;
924 /* ...and stow away for later reuse. */
925 lstrcpyW (img
->name
, szFile
);
926 img
->next
= tc
->tf
->images
;
927 tc
->tf
->images
= img
;
928 TRACE ("new %p %s: %p\n", img
, debugstr_w (img
->name
), img
->image
);
932 static BOOL
MSSTYLES_GetNextInteger(LPCWSTR lpStringStart
, LPCWSTR lpStringEnd
, LPCWSTR
*lpValEnd
, int *value
)
934 LPCWSTR cur
= lpStringStart
;
938 while(cur
< lpStringEnd
&& ((*cur
< '0' || *cur
> '9') && *cur
!= '-')) cur
++;
939 if(cur
>= lpStringEnd
) {
946 while(cur
< lpStringEnd
&& (*cur
>= '0' && *cur
<= '9')) {
947 total
= total
* 10 + (*cur
- '0');
950 if(gotNeg
) total
= -total
;
952 if(lpValEnd
) *lpValEnd
= cur
;
956 static BOOL
MSSTYLES_GetNextToken(LPCWSTR lpStringStart
, LPCWSTR lpStringEnd
, LPCWSTR
*lpValEnd
, LPWSTR lpBuff
, DWORD buffSize
) {
957 LPCWSTR cur
= lpStringStart
;
961 while(cur
< lpStringEnd
&& (isspace(*cur
) || *cur
== ',')) cur
++;
962 if(cur
>= lpStringEnd
) {
966 while(cur
< lpStringEnd
&& *cur
!= '\n'&& *cur
!= ',') cur
++;
968 while(isspace(*(end
-1))) end
--;
970 lstrcpynW(lpBuff
, start
, min(buffSize
, end
-start
+1));
972 if(lpValEnd
) *lpValEnd
= cur
;
976 /***********************************************************************
977 * MSSTYLES_GetPropertyBool
979 * Retrieve a color value for a property
981 HRESULT
MSSTYLES_GetPropertyBool(PTHEME_PROPERTY tp
, BOOL
*pfVal
)
984 if(*tp
->lpValue
== 't' || *tp
->lpValue
== 'T')
989 /***********************************************************************
990 * MSSTYLES_GetPropertyColor
992 * Retrieve a color value for a property
994 HRESULT
MSSTYLES_GetPropertyColor(PTHEME_PROPERTY tp
, COLORREF
*pColor
)
998 int red
, green
, blue
;
1000 lpCur
= tp
->lpValue
;
1001 lpEnd
= tp
->lpValue
+ tp
->dwValueLen
;
1003 if(!MSSTYLES_GetNextInteger(lpCur
, lpEnd
, &lpCur
, &red
)) {
1004 TRACE("Could not parse color property\n");
1005 return E_PROP_ID_UNSUPPORTED
;
1007 if(!MSSTYLES_GetNextInteger(lpCur
, lpEnd
, &lpCur
, &green
)) {
1008 TRACE("Could not parse color property\n");
1009 return E_PROP_ID_UNSUPPORTED
;
1011 if(!MSSTYLES_GetNextInteger(lpCur
, lpEnd
, &lpCur
, &blue
)) {
1012 TRACE("Could not parse color property\n");
1013 return E_PROP_ID_UNSUPPORTED
;
1015 *pColor
= RGB(red
,green
,blue
);
1019 /***********************************************************************
1020 * MSSTYLES_GetPropertyColor
1022 * Retrieve a color value for a property
1024 static HRESULT
MSSTYLES_GetFont (LPCWSTR lpCur
, LPCWSTR lpEnd
,
1025 LPCWSTR
*lpValEnd
, LOGFONTW
* pFont
)
1027 static const WCHAR szBold
[] = {'b','o','l','d','\0'};
1028 static const WCHAR szItalic
[] = {'i','t','a','l','i','c','\0'};
1029 static const WCHAR szUnderline
[] = {'u','n','d','e','r','l','i','n','e','\0'};
1030 static const WCHAR szStrikeOut
[] = {'s','t','r','i','k','e','o','u','t','\0'};
1034 if(!MSSTYLES_GetNextToken(lpCur
, lpEnd
, &lpCur
, pFont
->lfFaceName
, LF_FACESIZE
)) {
1035 TRACE("Property is there, but failed to get face name\n");
1037 return E_PROP_ID_UNSUPPORTED
;
1039 if(!MSSTYLES_GetNextInteger(lpCur
, lpEnd
, &lpCur
, &pointSize
)) {
1040 TRACE("Property is there, but failed to get point size\n");
1042 return E_PROP_ID_UNSUPPORTED
;
1047 pointSize
= -MulDiv(pointSize
, GetDeviceCaps(hdc
, LOGPIXELSY
), 72);
1051 pFont
->lfHeight
= pointSize
;
1052 pFont
->lfWeight
= FW_REGULAR
;
1053 pFont
->lfCharSet
= DEFAULT_CHARSET
;
1054 while(MSSTYLES_GetNextToken(lpCur
, lpEnd
, &lpCur
, attr
, sizeof(attr
)/sizeof(attr
[0]))) {
1055 if(!lstrcmpiW(szBold
, attr
)) pFont
->lfWeight
= FW_BOLD
;
1056 else if(!lstrcmpiW(szItalic
, attr
)) pFont
->lfItalic
= TRUE
;
1057 else if(!lstrcmpiW(szUnderline
, attr
)) pFont
->lfUnderline
= TRUE
;
1058 else if(!lstrcmpiW(szStrikeOut
, attr
)) pFont
->lfStrikeOut
= TRUE
;
1064 HRESULT
MSSTYLES_GetPropertyFont(PTHEME_PROPERTY tp
, HDC hdc
, LOGFONTW
*pFont
)
1066 LPCWSTR lpCur
= tp
->lpValue
;
1067 LPCWSTR lpEnd
= tp
->lpValue
+ tp
->dwValueLen
;
1070 ZeroMemory(pFont
, sizeof(LOGFONTW
));
1071 hr
= MSSTYLES_GetFont (lpCur
, lpEnd
, &lpCur
, pFont
);
1076 /***********************************************************************
1077 * MSSTYLES_GetPropertyInt
1079 * Retrieve an int value for a property
1081 HRESULT
MSSTYLES_GetPropertyInt(PTHEME_PROPERTY tp
, int *piVal
)
1083 if(!MSSTYLES_GetNextInteger(tp
->lpValue
, (tp
->lpValue
+ tp
->dwValueLen
), NULL
, piVal
)) {
1084 TRACE("Could not parse int property\n");
1085 return E_PROP_ID_UNSUPPORTED
;
1090 /***********************************************************************
1091 * MSSTYLES_GetPropertyIntList
1093 * Retrieve an int list value for a property
1095 HRESULT
MSSTYLES_GetPropertyIntList(PTHEME_PROPERTY tp
, INTLIST
*pIntList
)
1098 LPCWSTR lpCur
= tp
->lpValue
;
1099 LPCWSTR lpEnd
= tp
->lpValue
+ tp
->dwValueLen
;
1101 for(i
=0; i
< MAX_INTLIST_COUNT
; i
++) {
1102 if(!MSSTYLES_GetNextInteger(lpCur
, lpEnd
, &lpCur
, &pIntList
->iValues
[i
]))
1105 pIntList
->iValueCount
= i
;
1109 /***********************************************************************
1110 * MSSTYLES_GetPropertyPosition
1112 * Retrieve a position value for a property
1114 HRESULT
MSSTYLES_GetPropertyPosition(PTHEME_PROPERTY tp
, POINT
*pPoint
)
1117 LPCWSTR lpCur
= tp
->lpValue
;
1118 LPCWSTR lpEnd
= tp
->lpValue
+ tp
->dwValueLen
;
1120 if(!MSSTYLES_GetNextInteger(lpCur
, lpEnd
, &lpCur
, &x
)) {
1121 TRACE("Could not parse position property\n");
1122 return E_PROP_ID_UNSUPPORTED
;
1124 if(!MSSTYLES_GetNextInteger(lpCur
, lpEnd
, &lpCur
, &y
)) {
1125 TRACE("Could not parse position property\n");
1126 return E_PROP_ID_UNSUPPORTED
;
1133 /***********************************************************************
1134 * MSSTYLES_GetPropertyString
1136 * Retrieve a string value for a property
1138 HRESULT
MSSTYLES_GetPropertyString(PTHEME_PROPERTY tp
, LPWSTR pszBuff
, int cchMaxBuffChars
)
1140 lstrcpynW(pszBuff
, tp
->lpValue
, min(tp
->dwValueLen
+1, cchMaxBuffChars
));
1144 /***********************************************************************
1145 * MSSTYLES_GetPropertyRect
1147 * Retrieve a rect value for a property
1149 HRESULT
MSSTYLES_GetPropertyRect(PTHEME_PROPERTY tp
, RECT
*pRect
)
1151 LPCWSTR lpCur
= tp
->lpValue
;
1152 LPCWSTR lpEnd
= tp
->lpValue
+ tp
->dwValueLen
;
1154 MSSTYLES_GetNextInteger(lpCur
, lpEnd
, &lpCur
, &pRect
->left
);
1155 MSSTYLES_GetNextInteger(lpCur
, lpEnd
, &lpCur
, &pRect
->top
);
1156 MSSTYLES_GetNextInteger(lpCur
, lpEnd
, &lpCur
, &pRect
->right
);
1157 if(!MSSTYLES_GetNextInteger(lpCur
, lpEnd
, &lpCur
, &pRect
->bottom
)) {
1158 TRACE("Could not parse rect property\n");
1159 return E_PROP_ID_UNSUPPORTED
;
1164 /***********************************************************************
1165 * MSSTYLES_GetPropertyMargins
1167 * Retrieve a margins value for a property
1169 HRESULT
MSSTYLES_GetPropertyMargins(PTHEME_PROPERTY tp
, RECT
*prc
, MARGINS
*pMargins
)
1171 LPCWSTR lpCur
= tp
->lpValue
;
1172 LPCWSTR lpEnd
= tp
->lpValue
+ tp
->dwValueLen
;
1174 MSSTYLES_GetNextInteger(lpCur
, lpEnd
, &lpCur
, &pMargins
->cxLeftWidth
);
1175 MSSTYLES_GetNextInteger(lpCur
, lpEnd
, &lpCur
, &pMargins
->cxRightWidth
);
1176 MSSTYLES_GetNextInteger(lpCur
, lpEnd
, &lpCur
, &pMargins
->cyTopHeight
);
1177 if(!MSSTYLES_GetNextInteger(lpCur
, lpEnd
, &lpCur
, &pMargins
->cyBottomHeight
)) {
1178 TRACE("Could not parse margins property\n");
1179 return E_PROP_ID_UNSUPPORTED
;