[UXTHEME] Remove unused variable.
[reactos.git] / reactos / dll / win32 / uxtheme / msstyles.c
1 /*
2 * Win32 5.1 msstyles theme format
3 *
4 * Copyright (C) 2003 Kevin Koltzau
5 *
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.
10 *
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.
15 *
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
19 */
20
21 #include "uxthemep.h"
22
23 #include <wine/unicode.h>
24
25 /***********************************************************************
26 * Defines and global variables
27 */
28
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);
32
33 extern int alphaBlendMode;
34
35 #define MSSTYLES_VERSION 0x0003
36
37 static const WCHAR szThemesIniResource[] = {
38 't','h','e','m','e','s','_','i','n','i','\0'
39 };
40
41 /***********************************************************************/
42
43 /**********************************************************************
44 * MSSTYLES_OpenThemeFile
45 *
46 * Load and validate a theme
47 *
48 * PARAMS
49 * lpThemeFile Path to theme file to load
50 * pszColorName Color name wanted, can be NULL
51 * pszSizeName Size name wanted, can be NULL
52 *
53 * NOTES
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.
57 */
58 HRESULT MSSTYLES_OpenThemeFile(LPCWSTR lpThemeFile, LPCWSTR pszColorName, LPCWSTR pszSizeName, PTHEME_FILE *tf)
59 {
60 HMODULE hTheme;
61 HRSRC hrsc;
62 HRESULT hr = S_OK;
63 static const WCHAR szPackThemVersionResource[] = {
64 'P','A','C','K','T','H','E','M','_','V','E','R','S','I','O','N', '\0'
65 };
66 static const WCHAR szColorNamesResource[] = {
67 'C','O','L','O','R','N','A','M','E','S','\0'
68 };
69 static const WCHAR szSizeNamesResource[] = {
70 'S','I','Z','E','N','A','M','E','S','\0'
71 };
72
73 WORD version;
74 DWORD versize;
75 LPWSTR pszColors;
76 LPWSTR pszSelectedColor = NULL;
77 LPWSTR pszSizes;
78 LPWSTR pszSelectedSize = NULL;
79 LPWSTR tmp;
80
81 if (!gbThemeHooksActive)
82 return E_FAIL;
83
84 TRACE("Opening %s\n", debugstr_w(lpThemeFile));
85
86 hTheme = LoadLibraryExW(lpThemeFile, NULL, LOAD_LIBRARY_AS_DATAFILE);
87
88 /* Validate that this is really a theme */
89 if(!hTheme) {
90 hr = HRESULT_FROM_WIN32(GetLastError());
91 goto invalid_theme;
92 }
93 if(!(hrsc = FindResourceW(hTheme, MAKEINTRESOURCEW(1), szPackThemVersionResource))) {
94 TRACE("No version resource found\n");
95 hr = HRESULT_FROM_WIN32(ERROR_BAD_FORMAT);
96 goto invalid_theme;
97 }
98 if((versize = SizeofResource(hTheme, hrsc)) != 2)
99 {
100 TRACE("Version resource found, but wrong size: %d\n", versize);
101 hr = HRESULT_FROM_WIN32(ERROR_BAD_FORMAT);
102 goto invalid_theme;
103 }
104 version = *(WORD*)LoadResource(hTheme, hrsc);
105 if(version != MSSTYLES_VERSION)
106 {
107 TRACE("Version of theme file is unsupported: 0x%04x\n", version);
108 hr = HRESULT_FROM_WIN32(ERROR_BAD_FORMAT);
109 goto invalid_theme;
110 }
111
112 if(!(hrsc = FindResourceW(hTheme, MAKEINTRESOURCEW(1), szColorNamesResource))) {
113 TRACE("Color names resource not found\n");
114 hr = HRESULT_FROM_WIN32(ERROR_BAD_FORMAT);
115 goto invalid_theme;
116 }
117 pszColors = LoadResource(hTheme, hrsc);
118
119 if(!(hrsc = FindResourceW(hTheme, MAKEINTRESOURCEW(1), szSizeNamesResource))) {
120 TRACE("Size names resource not found\n");
121 hr = HRESULT_FROM_WIN32(ERROR_BAD_FORMAT);
122 goto invalid_theme;
123 }
124 pszSizes = LoadResource(hTheme, hrsc);
125
126 /* Validate requested color against what's available from the theme */
127 if(pszColorName) {
128 tmp = pszColors;
129 while(*tmp) {
130 if(!lstrcmpiW(pszColorName, tmp)) {
131 pszSelectedColor = tmp;
132 break;
133 }
134 tmp += lstrlenW(tmp)+1;
135 }
136 }
137 else
138 pszSelectedColor = pszColors; /* Use the default color */
139
140 /* Validate requested size against what's available from the theme */
141 if(pszSizeName) {
142 tmp = pszSizes;
143 while(*tmp) {
144 if(!lstrcmpiW(pszSizeName, tmp)) {
145 pszSelectedSize = tmp;
146 break;
147 }
148 tmp += lstrlenW(tmp)+1;
149 }
150 }
151 else
152 pszSelectedSize = pszSizes; /* Use the default size */
153
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;
158 goto invalid_theme;
159 }
160
161 *tf = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(THEME_FILE));
162 (*tf)->hTheme = hTheme;
163
164 GetFullPathNameW(lpThemeFile, MAX_PATH, (*tf)->szThemeFile, NULL);
165
166 (*tf)->pszAvailColors = pszColors;
167 (*tf)->pszAvailSizes = pszSizes;
168 (*tf)->pszSelectedColor = pszSelectedColor;
169 (*tf)->pszSelectedSize = pszSelectedSize;
170 (*tf)->dwRefCount = 1;
171
172 TRACE("Theme %p refcount: %d\n", *tf, (*tf)->dwRefCount);
173
174 return S_OK;
175
176 invalid_theme:
177 if(hTheme) FreeLibrary(hTheme);
178 return hr;
179 }
180
181 /***********************************************************************
182 * MSSTYLES_CloseThemeFile
183 *
184 * Close theme file and free resources
185 */
186 void MSSTYLES_CloseThemeFile(PTHEME_FILE tf)
187 {
188 if(tf) {
189
190 tf->dwRefCount--;
191 TRACE("Theme %p refcount: %d\n", tf, tf->dwRefCount);
192
193 if(!tf->dwRefCount) {
194 if(tf->hTheme) FreeLibrary(tf->hTheme);
195 if(tf->classes) {
196 while(tf->classes) {
197 PTHEME_CLASS pcls = tf->classes;
198 tf->classes = pcls->next;
199 while(pcls->partstate) {
200 PTHEME_PARTSTATE ps = pcls->partstate;
201
202 while(ps->properties) {
203 PTHEME_PROPERTY prop = ps->properties;
204 ps->properties = prop->next;
205 HeapFree(GetProcessHeap(), 0, prop);
206 }
207
208 pcls->partstate = ps->next;
209 HeapFree(GetProcessHeap(), 0, ps);
210 }
211 HeapFree(GetProcessHeap(), 0, pcls);
212 }
213 }
214 while (tf->images)
215 {
216 PTHEME_IMAGE img = tf->images;
217 tf->images = img->next;
218 DeleteObject (img->image);
219 HeapFree (GetProcessHeap(), 0, img);
220 }
221 HeapFree(GetProcessHeap(), 0, tf);
222 }
223 }
224 }
225
226 /***********************************************************************
227 * MSSTYLES_ReferenceTheme
228 *
229 * Increase the reference count of the theme file
230 */
231 HRESULT MSSTYLES_ReferenceTheme(PTHEME_FILE tf)
232 {
233 tf->dwRefCount++;
234 TRACE("Theme %p refcount: %d\n", tf, tf->dwRefCount);
235 return S_OK;
236 }
237
238 /***********************************************************************
239 * MSSTYLES_GetThemeIni
240 *
241 * Retrieves themes.ini from a theme
242 */
243 PUXINI_FILE MSSTYLES_GetThemeIni(PTHEME_FILE tf)
244 {
245 return UXINI_LoadINI(tf->hTheme, szThemesIniResource);
246 }
247
248 /***********************************************************************
249 * MSSTYLES_GetActiveThemeIni
250 *
251 * Retrieve the ini file for the selected color/style
252 */
253 static PUXINI_FILE MSSTYLES_GetActiveThemeIni(PTHEME_FILE tf)
254 {
255 static const WCHAR szFileResNamesResource[] = {
256 'F','I','L','E','R','E','S','N','A','M','E','S','\0'
257 };
258 DWORD dwColorCount = 0;
259 DWORD dwSizeCount = 0;
260 DWORD dwColorNum = 0;
261 DWORD dwSizeNum = 0;
262 DWORD i;
263 DWORD dwResourceIndex;
264 LPWSTR tmp;
265 HRSRC hrsc;
266
267 /* Count the number of available colors & styles, and determine the index number
268 of the color/style we are interested in
269 */
270 tmp = tf->pszAvailColors;
271 while(*tmp) {
272 if(!lstrcmpiW(tf->pszSelectedColor, tmp))
273 dwColorNum = dwColorCount;
274 tmp += lstrlenW(tmp)+1;
275 dwColorCount++;
276 }
277 tmp = tf->pszAvailSizes;
278 while(*tmp) {
279 if(!lstrcmpiW(tf->pszSelectedSize, tmp))
280 dwSizeNum = dwSizeCount;
281 tmp += lstrlenW(tmp)+1;
282 dwSizeCount++;
283 }
284
285 if(!(hrsc = FindResourceW(tf->hTheme, MAKEINTRESOURCEW(1), szFileResNamesResource))) {
286 TRACE("FILERESNAMES map not found\n");
287 return NULL;
288 }
289 tmp = LoadResource(tf->hTheme, hrsc);
290 dwResourceIndex = (dwSizeCount * dwColorNum) + dwSizeNum;
291 for(i=0; i < dwResourceIndex; i++) {
292 tmp += lstrlenW(tmp)+1;
293 }
294 return UXINI_LoadINI(tf->hTheme, tmp);
295 }
296
297
298 /***********************************************************************
299 * MSSTYLES_ParseIniSectionName
300 *
301 * Parse an ini section name into its component parts
302 * Valid formats are:
303 * [classname]
304 * [classname(state)]
305 * [classname.part]
306 * [classname.part(state)]
307 * [application::classname]
308 * [application::classname(state)]
309 * [application::classname.part]
310 * [application::classname.part(state)]
311 *
312 * PARAMS
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
319 */
320 static BOOL MSSTYLES_ParseIniSectionName(LPCWSTR lpSection, DWORD dwLen, LPWSTR szAppName, LPWSTR szClassName, int *iPartId, int *iStateId)
321 {
322 WCHAR sec[255];
323 WCHAR part[60] = {'\0'};
324 WCHAR state[60] = {'\0'};
325 LPWSTR tmp;
326 LPWSTR comp;
327 lstrcpynW(sec, lpSection, min(dwLen+1, sizeof(sec)/sizeof(sec[0])));
328
329 *szAppName = 0;
330 *szClassName = 0;
331 *iPartId = 0;
332 *iStateId = 0;
333 comp = sec;
334 /* Get the application name */
335 tmp = strchrW(comp, ':');
336 if(tmp) {
337 *tmp++ = 0;
338 tmp++;
339 lstrcpynW(szAppName, comp, MAX_THEME_APP_NAME);
340 comp = tmp;
341 }
342
343 tmp = strchrW(comp, '.');
344 if(tmp) {
345 *tmp++ = 0;
346 lstrcpynW(szClassName, comp, MAX_THEME_CLASS_NAME);
347 comp = tmp;
348 /* now get the part & state */
349 tmp = strchrW(comp, '(');
350 if(tmp) {
351 *tmp++ = 0;
352 lstrcpynW(part, comp, sizeof(part)/sizeof(part[0]));
353 comp = tmp;
354 /* now get the state */
355 tmp = strchrW(comp, ')');
356 if (!tmp)
357 return FALSE;
358 *tmp = 0;
359 lstrcpynW(state, comp, sizeof(state)/sizeof(state[0]));
360 }
361 else {
362 lstrcpynW(part, comp, sizeof(part)/sizeof(part[0]));
363 }
364 }
365 else {
366 tmp = strchrW(comp, '(');
367 if(tmp) {
368 *tmp++ = 0;
369 lstrcpynW(szClassName, comp, MAX_THEME_CLASS_NAME);
370 comp = tmp;
371 /* now get the state */
372 tmp = strchrW(comp, ')');
373 if (!tmp)
374 return FALSE;
375 *tmp = 0;
376 lstrcpynW(state, comp, sizeof(state)/sizeof(state[0]));
377 }
378 else {
379 lstrcpynW(szClassName, comp, MAX_THEME_CLASS_NAME);
380 }
381 }
382 if(!*szClassName) return FALSE;
383 return MSSTYLES_LookupPartState(szClassName, part[0]?part:NULL, state[0]?state:NULL, iPartId, iStateId);
384 }
385
386 /***********************************************************************
387 * MSSTYLES_FindClass
388 *
389 * Find a class
390 *
391 * PARAMS
392 * tf Theme file
393 * pszAppName App name to find
394 * pszClassName Class name to find
395 *
396 * RETURNS
397 * The class found, or NULL
398 */
399 static PTHEME_CLASS MSSTYLES_FindClass(PTHEME_FILE tf, LPCWSTR pszAppName, LPCWSTR pszClassName)
400 {
401 PTHEME_CLASS cur = tf->classes;
402 while(cur) {
403 if(!pszAppName) {
404 if(!*cur->szAppName && !lstrcmpiW(pszClassName, cur->szClassName))
405 return cur;
406 }
407 else {
408 if(!lstrcmpiW(pszAppName, cur->szAppName) && !lstrcmpiW(pszClassName, cur->szClassName))
409 return cur;
410 }
411 cur = cur->next;
412 }
413 return NULL;
414 }
415
416 /***********************************************************************
417 * MSSTYLES_AddClass
418 *
419 * Add a class to a theme file
420 *
421 * PARAMS
422 * tf Theme file
423 * pszAppName App name to add
424 * pszClassName Class name to add
425 *
426 * RETURNS
427 * The class added, or a class previously added with the same name
428 */
429 static PTHEME_CLASS MSSTYLES_AddClass(PTHEME_FILE tf, LPCWSTR pszAppName, LPCWSTR pszClassName)
430 {
431 PTHEME_CLASS cur = MSSTYLES_FindClass(tf, pszAppName, pszClassName);
432 if(cur) return cur;
433
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;
441 tf->classes = cur;
442 return cur;
443 }
444
445 /***********************************************************************
446 * MSSTYLES_FindPartState
447 *
448 * Find a part/state
449 *
450 * PARAMS
451 * tc Class to search
452 * iPartId Part ID to find
453 * iStateId State ID to find
454 * tcNext Receives the next class in the override chain
455 *
456 * RETURNS
457 * The part/state found, or NULL
458 */
459 PTHEME_PARTSTATE MSSTYLES_FindPartState(PTHEME_CLASS tc, int iPartId, int iStateId, PTHEME_CLASS *tcNext)
460 {
461 PTHEME_PARTSTATE cur = tc->partstate;
462 while(cur) {
463 if(cur->iPartId == iPartId && cur->iStateId == iStateId) {
464 if(tcNext) *tcNext = tc->overrides;
465 return cur;
466 }
467 cur = cur->next;
468 }
469 if(tc->overrides) return MSSTYLES_FindPartState(tc->overrides, iPartId, iStateId, tcNext);
470 return NULL;
471 }
472
473 /***********************************************************************
474 * MSSTYLES_AddPartState
475 *
476 * Add a part/state to a class
477 *
478 * PARAMS
479 * tc Theme class
480 * iPartId Part ID to add
481 * iStateId State ID to add
482 *
483 * RETURNS
484 * The part/state added, or a part/state previously added with the same IDs
485 */
486 static PTHEME_PARTSTATE MSSTYLES_AddPartState(PTHEME_CLASS tc, int iPartId, int iStateId)
487 {
488 PTHEME_PARTSTATE cur = MSSTYLES_FindPartState(tc, iPartId, iStateId, NULL);
489 if(cur) return cur;
490
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;
496 tc->partstate = cur;
497 return cur;
498 }
499
500 /***********************************************************************
501 * MSSTYLES_LFindProperty
502 *
503 * Find a property within a property list
504 *
505 * PARAMS
506 * tp property list to scan
507 * iPropertyPrimitive Type of value expected
508 * iPropertyId ID of the required value
509 *
510 * RETURNS
511 * The property found, or NULL
512 */
513 static PTHEME_PROPERTY MSSTYLES_LFindProperty(PTHEME_PROPERTY tp, int iPropertyPrimitive, int iPropertyId)
514 {
515 PTHEME_PROPERTY cur = tp;
516 while(cur) {
517 if(cur->iPropertyId == iPropertyId) {
518 if(cur->iPrimitiveType == iPropertyPrimitive) {
519 return cur;
520 }
521 else {
522 if(!iPropertyPrimitive)
523 return cur;
524 return NULL;
525 }
526 }
527 cur = cur->next;
528 }
529 return NULL;
530 }
531
532 /***********************************************************************
533 * MSSTYLES_PSFindProperty
534 *
535 * Find a value within a part/state
536 *
537 * PARAMS
538 * ps Part/state to search
539 * iPropertyPrimitive Type of value expected
540 * iPropertyId ID of the required value
541 *
542 * RETURNS
543 * The property found, or NULL
544 */
545 static inline PTHEME_PROPERTY MSSTYLES_PSFindProperty(PTHEME_PARTSTATE ps, int iPropertyPrimitive, int iPropertyId)
546 {
547 return MSSTYLES_LFindProperty(ps->properties, iPropertyPrimitive, iPropertyId);
548 }
549
550 /***********************************************************************
551 * MSSTYLES_FindMetric
552 *
553 * Find a metric property for a theme file
554 *
555 * PARAMS
556 * tf Theme file
557 * iPropertyPrimitive Type of value expected
558 * iPropertyId ID of the required value
559 *
560 * RETURNS
561 * The property found, or NULL
562 */
563 PTHEME_PROPERTY MSSTYLES_FindMetric(PTHEME_FILE tf, int iPropertyPrimitive, int iPropertyId)
564 {
565 return MSSTYLES_LFindProperty(tf->metrics, iPropertyPrimitive, iPropertyId);
566 }
567
568 /***********************************************************************
569 * MSSTYLES_AddProperty
570 *
571 * Add a property to a part/state
572 *
573 * PARAMS
574 * ps 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
579 *
580 * RETURNS
581 * The property added, or a property previously added with the same IDs
582 */
583 static PTHEME_PROPERTY MSSTYLES_AddProperty(PTHEME_PARTSTATE ps, int iPropertyPrimitive, int iPropertyId, LPCWSTR lpValue, DWORD dwValueLen, BOOL isGlobal)
584 {
585 PTHEME_PROPERTY cur = MSSTYLES_PSFindProperty(ps, iPropertyPrimitive, iPropertyId);
586 /* Should duplicate properties overwrite the original, or be ignored? */
587 if(cur) return cur;
588
589 cur = HeapAlloc(GetProcessHeap(), 0, sizeof(THEME_PROPERTY));
590 cur->iPrimitiveType = iPropertyPrimitive;
591 cur->iPropertyId = iPropertyId;
592 cur->lpValue = lpValue;
593 cur->dwValueLen = dwValueLen;
594
595 if(ps->iStateId)
596 cur->origin = PO_STATE;
597 else if(ps->iPartId)
598 cur->origin = PO_PART;
599 else if(isGlobal)
600 cur->origin = PO_GLOBAL;
601 else
602 cur->origin = PO_CLASS;
603
604 cur->next = ps->properties;
605 ps->properties = cur;
606 return cur;
607 }
608
609 /***********************************************************************
610 * MSSTYLES_AddMetric
611 *
612 * Add a property to a part/state
613 *
614 * PARAMS
615 * tf Theme file
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
620 *
621 * RETURNS
622 * The property added, or a property previously added with the same IDs
623 */
624 static PTHEME_PROPERTY MSSTYLES_AddMetric(PTHEME_FILE tf, int iPropertyPrimitive, int iPropertyId, LPCWSTR lpValue, DWORD dwValueLen)
625 {
626 PTHEME_PROPERTY cur = MSSTYLES_FindMetric(tf, iPropertyPrimitive, iPropertyId);
627 /* Should duplicate properties overwrite the original, or be ignored? */
628 if(cur) return cur;
629
630 cur = HeapAlloc(GetProcessHeap(), 0, sizeof(THEME_PROPERTY));
631 cur->iPrimitiveType = iPropertyPrimitive;
632 cur->iPropertyId = iPropertyId;
633 cur->lpValue = lpValue;
634 cur->dwValueLen = dwValueLen;
635
636 cur->origin = PO_GLOBAL;
637
638 cur->next = tf->metrics;
639 tf->metrics = cur;
640 return cur;
641 }
642
643 /***********************************************************************
644 * MSSTYLES_ParseThemeIni
645 *
646 * Parse the theme ini for the selected color/style
647 *
648 * PARAMS
649 * tf Theme to parse
650 */
651 void MSSTYLES_ParseThemeIni(PTHEME_FILE tf)
652 {
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'};
655 PTHEME_CLASS cls;
656 PTHEME_CLASS globals;
657 PTHEME_PARTSTATE ps;
658 PUXINI_FILE ini;
659 WCHAR szAppName[MAX_THEME_APP_NAME];
660 WCHAR szClassName[MAX_THEME_CLASS_NAME];
661 WCHAR szPropertyName[MAX_THEME_VALUE_NAME];
662 int iPartId;
663 int iStateId;
664 int iPropertyPrimitive;
665 int iPropertyId;
666 DWORD dwLen;
667 LPCWSTR lpName;
668 DWORD dwValueLen;
669 LPCWSTR lpValue;
670
671 if(tf->classes)
672 return;
673
674 ini = MSSTYLES_GetActiveThemeIni(tf);
675
676 while((lpName=UXINI_GetNextSection(ini, &dwLen)))
677 {
678 if(CompareStringW(LOCALE_SYSTEM_DEFAULT, NORM_IGNORECASE, lpName, dwLen, szSysMetrics, -1) == CSTR_EQUAL)
679 {
680 while((lpName=UXINI_GetNextValue(ini, &dwLen, &lpValue, &dwValueLen)))
681 {
682 lstrcpynW(szPropertyName, lpName, min(dwLen+1, sizeof(szPropertyName)/sizeof(szPropertyName[0])));
683 if(MSSTYLES_LookupProperty(szPropertyName, &iPropertyPrimitive, &iPropertyId))
684 {
685 /* Catch all metrics, including colors */
686 MSSTYLES_AddMetric(tf, iPropertyPrimitive, iPropertyId, lpValue, dwValueLen);
687 }
688 else
689 {
690 TRACE("Unknown system metric %s\n", debugstr_w(szPropertyName));
691 }
692 }
693 continue;
694 }
695
696 if(MSSTYLES_ParseIniSectionName(lpName, dwLen, szAppName, szClassName, &iPartId, &iStateId))
697 {
698 BOOL isGlobal = FALSE;
699 if(!lstrcmpiW(szClassName, szGlobals))
700 {
701 isGlobal = TRUE;
702 }
703 cls = MSSTYLES_AddClass(tf, szAppName, szClassName);
704 ps = MSSTYLES_AddPartState(cls, iPartId, iStateId);
705
706 while((lpName=UXINI_GetNextValue(ini, &dwLen, &lpValue, &dwValueLen)))
707 {
708 lstrcpynW(szPropertyName, lpName, min(dwLen+1, sizeof(szPropertyName)/sizeof(szPropertyName[0])));
709 if(MSSTYLES_LookupProperty(szPropertyName, &iPropertyPrimitive, &iPropertyId))
710 {
711 MSSTYLES_AddProperty(ps, iPropertyPrimitive, iPropertyId, lpValue, dwValueLen, isGlobal);
712 }
713 else
714 {
715 TRACE("Unknown property %s\n", debugstr_w(szPropertyName));
716 }
717 }
718 }
719 }
720
721 /* App/Class combos override values defined by the base class, map these overrides */
722 globals = MSSTYLES_FindClass(tf, NULL, szGlobals);
723 cls = tf->classes;
724 while(cls)
725 {
726 if(*cls->szAppName)
727 {
728 cls->overrides = MSSTYLES_FindClass(tf, NULL, cls->szClassName);
729 if(!cls->overrides)
730 {
731 TRACE("No overrides found for app %s class %s\n", debugstr_w(cls->szAppName), debugstr_w(cls->szClassName));
732 }
733 else
734 {
735 cls->overrides = globals;
736 }
737 }
738 else
739 {
740 /* Everything overrides globals..except globals */
741 if(cls != globals)
742 cls->overrides = globals;
743 }
744 cls = cls->next;
745 }
746 UXINI_CloseINI(ini);
747
748 if(!tf->classes) {
749 ERR("Failed to parse theme ini\n");
750 }
751 }
752
753 /***********************************************************************
754 * MSSTYLES_OpenThemeClass
755 *
756 * Open a theme class, uses the current active theme
757 *
758 * PARAMS
759 * pszAppName Application name, for theme styles specific
760 * to a particular application
761 * pszClassList List of requested classes, semicolon delimited
762 */
763 PTHEME_CLASS MSSTYLES_OpenThemeClass(PTHEME_FILE tf, LPCWSTR pszAppName, LPCWSTR pszClassList)
764 {
765 PTHEME_CLASS cls = NULL;
766 WCHAR szClassName[MAX_THEME_CLASS_NAME];
767 LPCWSTR start;
768 LPCWSTR end;
769 DWORD len;
770
771 if(!tf->classes) {
772 return NULL;
773 }
774
775 start = pszClassList;
776 while((end = strchrW(start, ';'))) {
777 len = end-start;
778 lstrcpynW(szClassName, start, min(len+1, sizeof(szClassName)/sizeof(szClassName[0])));
779 start = end+1;
780 cls = MSSTYLES_FindClass(tf, pszAppName, szClassName);
781 if(cls) break;
782 }
783 if(!cls && *start) {
784 lstrcpynW(szClassName, start, sizeof(szClassName)/sizeof(szClassName[0]));
785 cls = MSSTYLES_FindClass(tf, pszAppName, szClassName);
786 }
787 if(cls) {
788 TRACE("Opened app %s, class %s from list %s\n", debugstr_w(cls->szAppName), debugstr_w(cls->szClassName), debugstr_w(pszClassList));
789 cls->tf = tf;
790 cls->tf->dwRefCount++;
791 TRACE("Theme %p refcount: %d\n", tf, tf->dwRefCount);
792 }
793 return cls;
794 }
795
796 /***********************************************************************
797 * MSSTYLES_CloseThemeClass
798 *
799 * Close a theme class
800 *
801 * PARAMS
802 * tc Theme class to close
803 *
804 * NOTES
805 * The MSSTYLES_CloseThemeFile decreases the refcount of the owning
806 * theme file and cleans it up, if needed.
807 */
808 HRESULT MSSTYLES_CloseThemeClass(PTHEME_CLASS tc)
809 {
810 MSSTYLES_CloseThemeFile (tc->tf);
811 return S_OK;
812 }
813
814 /***********************************************************************
815 * MSSTYLES_FindProperty
816 *
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.
820 */
821 PTHEME_PROPERTY MSSTYLES_FindProperty(PTHEME_CLASS tc, int iPartId, int iStateId, int iPropertyPrimitive, int iPropertyId)
822 {
823 PTHEME_CLASS next = tc;
824 PTHEME_PARTSTATE ps;
825 PTHEME_PROPERTY tp;
826
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))) {
831 return tp;
832 }
833 }
834 /* If that fails, and we didn't already try it, search for just part */
835 if(iStateId != 0)
836 iStateId = 0;
837 /* As a last ditch attempt..go for just class */
838 else if(iPartId != 0)
839 iPartId = 0;
840 else
841 return NULL;
842
843 if((tp = MSSTYLES_FindProperty(tc, iPartId, iStateId, iPropertyPrimitive, iPropertyId)))
844 return tp;
845 return NULL;
846 }
847
848 /* Prepare a bitmap to be used for alpha blending */
849 static BOOL prepare_alpha (HBITMAP bmp, BOOL* hasAlpha)
850 {
851 DIBSECTION dib;
852 int n;
853 BYTE* p;
854
855 *hasAlpha = FALSE;
856
857 if (!bmp || GetObjectW( bmp, sizeof(dib), &dib ) != sizeof(dib))
858 return FALSE;
859
860 if(dib.dsBm.bmBitsPixel != 32)
861 /* nothing to do */
862 return TRUE;
863
864 *hasAlpha = TRUE;
865 p = dib.dsBm.bmBits;
866 n = dib.dsBmih.biHeight * dib.dsBmih.biWidth;
867 /* AlphaBlend() wants premultiplied alpha, so do that now */
868 while (n-- > 0)
869 {
870 int a = p[3]+1;
871 p[0] = (p[0] * a) >> 8;
872 p[1] = (p[1] * a) >> 8;
873 p[2] = (p[2] * a) >> 8;
874 p += 4;
875 }
876
877 return TRUE;
878 }
879
880 HBITMAP MSSTYLES_LoadBitmap (PTHEME_CLASS tc, LPCWSTR lpFilename, BOOL* hasAlpha)
881 {
882 WCHAR szFile[MAX_PATH];
883 LPWSTR tmp;
884 PTHEME_IMAGE img;
885 lstrcpynW(szFile, lpFilename, sizeof(szFile)/sizeof(szFile[0]));
886 tmp = szFile;
887 do {
888 if(*tmp == '\\') *tmp = '_';
889 if(*tmp == '/') *tmp = '_';
890 if(*tmp == '.') *tmp = '_';
891 } while(*tmp++);
892
893 /* Try to locate in list of loaded images */
894 img = tc->tf->images;
895 while (img)
896 {
897 if (lstrcmpiW (szFile, img->name) == 0)
898 {
899 TRACE ("found %p %s: %p\n", img, debugstr_w (img->name), img->image);
900 *hasAlpha = img->hasAlpha;
901 return img->image;
902 }
903 img = img->next;
904 }
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);
915 return img->image;
916 }
917
918 static BOOL MSSTYLES_GetNextInteger(LPCWSTR lpStringStart, LPCWSTR lpStringEnd, LPCWSTR *lpValEnd, int *value)
919 {
920 LPCWSTR cur = lpStringStart;
921 int total = 0;
922 BOOL gotNeg = FALSE;
923
924 while(cur < lpStringEnd && (*cur < '0' || *cur > '9' || *cur == '-')) cur++;
925 if(cur >= lpStringEnd) {
926 return FALSE;
927 }
928 if(*cur == '-') {
929 cur++;
930 gotNeg = TRUE;
931 }
932 while(cur < lpStringEnd && (*cur >= '0' && *cur <= '9')) {
933 total = total * 10 + (*cur - '0');
934 cur++;
935 }
936 if(gotNeg) total = -total;
937 *value = total;
938 if(lpValEnd) *lpValEnd = cur;
939 return TRUE;
940 }
941
942 static BOOL MSSTYLES_GetNextToken(LPCWSTR lpStringStart, LPCWSTR lpStringEnd, LPCWSTR *lpValEnd, LPWSTR lpBuff, DWORD buffSize) {
943 LPCWSTR cur = lpStringStart;
944 LPCWSTR start;
945 LPCWSTR end;
946
947 while(cur < lpStringEnd && (isspace(*cur) || *cur == ',')) cur++;
948 if(cur >= lpStringEnd) {
949 return FALSE;
950 }
951 start = cur;
952 while(cur < lpStringEnd && *cur != ',') cur++;
953 end = cur;
954 while(isspace(*end)) end--;
955
956 lstrcpynW(lpBuff, start, min(buffSize, end-start+1));
957
958 if(lpValEnd) *lpValEnd = cur;
959 return TRUE;
960 }
961
962 /***********************************************************************
963 * MSSTYLES_GetPropertyBool
964 *
965 * Retrieve a color value for a property
966 */
967 HRESULT MSSTYLES_GetPropertyBool(PTHEME_PROPERTY tp, BOOL *pfVal)
968 {
969 *pfVal = FALSE;
970 if(*tp->lpValue == 't' || *tp->lpValue == 'T')
971 *pfVal = TRUE;
972 return S_OK;
973 }
974
975 /***********************************************************************
976 * MSSTYLES_GetPropertyColor
977 *
978 * Retrieve a color value for a property
979 */
980 HRESULT MSSTYLES_GetPropertyColor(PTHEME_PROPERTY tp, COLORREF *pColor)
981 {
982 LPCWSTR lpEnd;
983 LPCWSTR lpCur;
984 int red, green, blue;
985
986 lpCur = tp->lpValue;
987 lpEnd = tp->lpValue + tp->dwValueLen;
988
989 if(!MSSTYLES_GetNextInteger(lpCur, lpEnd, &lpCur, &red)) {
990 TRACE("Could not parse color property\n");
991 return E_PROP_ID_UNSUPPORTED;
992 }
993 if(!MSSTYLES_GetNextInteger(lpCur, lpEnd, &lpCur, &green)) {
994 TRACE("Could not parse color property\n");
995 return E_PROP_ID_UNSUPPORTED;
996 }
997 if(!MSSTYLES_GetNextInteger(lpCur, lpEnd, &lpCur, &blue)) {
998 TRACE("Could not parse color property\n");
999 return E_PROP_ID_UNSUPPORTED;
1000 }
1001 *pColor = RGB(red,green,blue);
1002 return S_OK;
1003 }
1004
1005 /***********************************************************************
1006 * MSSTYLES_GetPropertyColor
1007 *
1008 * Retrieve a color value for a property
1009 */
1010 static HRESULT MSSTYLES_GetFont (LPCWSTR lpCur, LPCWSTR lpEnd,
1011 LPCWSTR *lpValEnd, LOGFONTW* pFont)
1012 {
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'};
1017 int pointSize;
1018 WCHAR attr[32];
1019
1020 if(!MSSTYLES_GetNextToken(lpCur, lpEnd, &lpCur, pFont->lfFaceName, LF_FACESIZE)) {
1021 TRACE("Property is there, but failed to get face name\n");
1022 *lpValEnd = lpCur;
1023 return E_PROP_ID_UNSUPPORTED;
1024 }
1025 if(!MSSTYLES_GetNextInteger(lpCur, lpEnd, &lpCur, &pointSize)) {
1026 TRACE("Property is there, but failed to get point size\n");
1027 *lpValEnd = lpCur;
1028 return E_PROP_ID_UNSUPPORTED;
1029 }
1030 if(pointSize > 0)
1031 {
1032 HDC hdc = GetDC(0);
1033 pointSize = -MulDiv(pointSize, GetDeviceCaps(hdc, LOGPIXELSY), 72);
1034 ReleaseDC(0, hdc);
1035 }
1036
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;
1045 }
1046 *lpValEnd = lpCur;
1047 return S_OK;
1048 }
1049
1050 HRESULT MSSTYLES_GetPropertyFont(PTHEME_PROPERTY tp, HDC hdc, LOGFONTW *pFont)
1051 {
1052 LPCWSTR lpCur = tp->lpValue;
1053 LPCWSTR lpEnd = tp->lpValue + tp->dwValueLen;
1054 HRESULT hr;
1055
1056 ZeroMemory(pFont, sizeof(LOGFONTW));
1057 hr = MSSTYLES_GetFont (lpCur, lpEnd, &lpCur, pFont);
1058
1059 return hr;
1060 }
1061
1062 /***********************************************************************
1063 * MSSTYLES_GetPropertyInt
1064 *
1065 * Retrieve an int value for a property
1066 */
1067 HRESULT MSSTYLES_GetPropertyInt(PTHEME_PROPERTY tp, int *piVal)
1068 {
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;
1072 }
1073 return S_OK;
1074 }
1075
1076 /***********************************************************************
1077 * MSSTYLES_GetPropertyIntList
1078 *
1079 * Retrieve an int list value for a property
1080 */
1081 HRESULT MSSTYLES_GetPropertyIntList(PTHEME_PROPERTY tp, INTLIST *pIntList)
1082 {
1083 int i;
1084 LPCWSTR lpCur = tp->lpValue;
1085 LPCWSTR lpEnd = tp->lpValue + tp->dwValueLen;
1086
1087 for(i=0; i < MAX_INTLIST_COUNT; i++) {
1088 if(!MSSTYLES_GetNextInteger(lpCur, lpEnd, &lpCur, &pIntList->iValues[i]))
1089 break;
1090 }
1091 pIntList->iValueCount = i;
1092 return S_OK;
1093 }
1094
1095 /***********************************************************************
1096 * MSSTYLES_GetPropertyPosition
1097 *
1098 * Retrieve a position value for a property
1099 */
1100 HRESULT MSSTYLES_GetPropertyPosition(PTHEME_PROPERTY tp, POINT *pPoint)
1101 {
1102 int x,y;
1103 LPCWSTR lpCur = tp->lpValue;
1104 LPCWSTR lpEnd = tp->lpValue + tp->dwValueLen;
1105
1106 if(!MSSTYLES_GetNextInteger(lpCur, lpEnd, &lpCur, &x)) {
1107 TRACE("Could not parse position property\n");
1108 return E_PROP_ID_UNSUPPORTED;
1109 }
1110 if(!MSSTYLES_GetNextInteger(lpCur, lpEnd, &lpCur, &y)) {
1111 TRACE("Could not parse position property\n");
1112 return E_PROP_ID_UNSUPPORTED;
1113 }
1114 pPoint->x = x;
1115 pPoint->y = y;
1116 return S_OK;
1117 }
1118
1119 /***********************************************************************
1120 * MSSTYLES_GetPropertyString
1121 *
1122 * Retrieve a string value for a property
1123 */
1124 HRESULT MSSTYLES_GetPropertyString(PTHEME_PROPERTY tp, LPWSTR pszBuff, int cchMaxBuffChars)
1125 {
1126 lstrcpynW(pszBuff, tp->lpValue, min(tp->dwValueLen+1, cchMaxBuffChars));
1127 return S_OK;
1128 }
1129
1130 /***********************************************************************
1131 * MSSTYLES_GetPropertyRect
1132 *
1133 * Retrieve a rect value for a property
1134 */
1135 HRESULT MSSTYLES_GetPropertyRect(PTHEME_PROPERTY tp, RECT *pRect)
1136 {
1137 LPCWSTR lpCur = tp->lpValue;
1138 LPCWSTR lpEnd = tp->lpValue + tp->dwValueLen;
1139
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;
1146 }
1147 return S_OK;
1148 }
1149
1150 /***********************************************************************
1151 * MSSTYLES_GetPropertyMargins
1152 *
1153 * Retrieve a margins value for a property
1154 */
1155 HRESULT MSSTYLES_GetPropertyMargins(PTHEME_PROPERTY tp, RECT *prc, MARGINS *pMargins)
1156 {
1157 LPCWSTR lpCur = tp->lpValue;
1158 LPCWSTR lpEnd = tp->lpValue + tp->dwValueLen;
1159
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;
1166 }
1167 return S_OK;
1168 }