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