1/* 2 * Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved. 3 * Copyright (C) Colin Harrison 2005-2008 4 * 5 * Permission is hereby granted, free of charge, to any person obtaining 6 * a copy of this software and associated documentation files (the 7 * "Software"), to deal in the Software without restriction, including 8 * without limitation the rights to use, copy, modify, merge, publish, 9 * distribute, sublicense, and/or sell copies of the Software, and to 10 * permit persons to whom the Software is furnished to do so, subject to 11 * the following conditions: 12 * 13 * The above copyright notice and this permission notice shall be 14 * included in all copies or substantial portions of the Software. 15 * 16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 * NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR 20 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 21 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 22 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 * 24 * Except as contained in this notice, the name of the XFree86 Project 25 * shall not be used in advertising or otherwise to promote the sale, use 26 * or other dealings in this Software without prior written authorization 27 * from the XFree86 Project. 28 * 29 * Authors: Earle F. Philhower, III 30 * Colin Harrison 31 */ 32 33#ifdef HAVE_XWIN_CONFIG_H 34#include <xwin-config.h> 35#endif 36#include <stdio.h> 37#include <stdlib.h> 38#ifdef __CYGWIN__ 39#include <sys/resource.h> 40#endif 41#include "win.h" 42 43#include <X11/Xwindows.h> 44#include <shellapi.h> 45 46#include "winprefs.h" 47#include "winmultiwindowclass.h" 48 49/* Where will the custom menu commands start counting from? */ 50#define STARTMENUID WM_USER 51 52extern const char *winGetBaseDir(void); 53 54/* From winmultiwindowflex.l, the real parser */ 55extern void parse_file (FILE *fp); 56 57 58/* Currently in use command ID, incremented each new menu item created */ 59static int g_cmdid = STARTMENUID; 60 61 62/* Defined in DIX */ 63extern char *display; 64 65/* Local function to handle comma-ified icon names */ 66static HICON 67LoadImageComma (char *fname, int sx, int sy, int flags); 68 69 70/* 71 * Creates or appends a menu from a MENUPARSED structure 72 */ 73static HMENU 74MakeMenu (char *name, 75 HMENU editMenu, 76 int editItem) 77{ 78 int i; 79 int item; 80 MENUPARSED *m; 81 HMENU hmenu, hsub; 82 83 for (i=0; i<pref.menuItems; i++) 84 { 85 if (!strcmp(name, pref.menu[i].menuName)) 86 break; 87 } 88 89 /* Didn't find a match, bummer */ 90 if (i==pref.menuItems) 91 { 92 ErrorF("MakeMenu: Can't find menu %s\n", name); 93 return NULL; 94 } 95 96 m = &(pref.menu[i]); 97 98 if (editMenu) 99 { 100 hmenu = editMenu; 101 item = editItem; 102 } 103 else 104 { 105 hmenu = CreatePopupMenu(); 106 if (!hmenu) 107 { 108 ErrorF("MakeMenu: Unable to CreatePopupMenu() %s\n", name); 109 return NULL; 110 } 111 item = 0; 112 } 113 114 /* Add the menu items */ 115 for (i=0; i<m->menuItems; i++) 116 { 117 /* Only assign IDs one time... */ 118 if ( m->menuItem[i].commandID == 0 ) 119 m->menuItem[i].commandID = g_cmdid++; 120 121 switch (m->menuItem[i].cmd) 122 { 123 case CMD_EXEC: 124 case CMD_ALWAYSONTOP: 125 case CMD_RELOAD: 126 InsertMenu (hmenu, 127 item, 128 MF_BYPOSITION|MF_ENABLED|MF_STRING, 129 m->menuItem[i].commandID, 130 m->menuItem[i].text); 131 break; 132 133 case CMD_SEPARATOR: 134 InsertMenu (hmenu, 135 item, 136 MF_BYPOSITION|MF_SEPARATOR, 137 0, 138 NULL); 139 break; 140 141 case CMD_MENU: 142 /* Recursive! */ 143 hsub = MakeMenu (m->menuItem[i].param, 0, 0); 144 if (hsub) 145 InsertMenu (hmenu, 146 item, 147 MF_BYPOSITION|MF_POPUP|MF_ENABLED|MF_STRING, 148 (UINT_PTR)hsub, 149 m->menuItem[i].text); 150 break; 151 } 152 153 /* If item==-1 (means to add at end of menu) don't increment) */ 154 if (item>=0) 155 item++; 156 } 157 158 return hmenu; 159} 160 161 162#ifdef XWIN_MULTIWINDOW 163/* 164 * Callback routine that is executed once per window class. 165 * Removes or creates custom window settings depending on LPARAM 166 */ 167static wBOOL CALLBACK 168ReloadEnumWindowsProc (HWND hwnd, LPARAM lParam) 169{ 170 HICON hicon; 171 Window wid; 172 173 if (!hwnd) { 174 ErrorF("ReloadEnumWindowsProc: hwnd==NULL!\n"); 175 return FALSE; 176 } 177 178 /* It's our baby, either clean or dirty it */ 179 if (lParam==FALSE) 180 { 181 /* Reset the window's icon to undefined. */ 182 hicon = (HICON)SendMessage(hwnd, WM_SETICON, ICON_BIG, 0); 183 184 /* If the old icon is generated on-the-fly, get rid of it, will regen */ 185 winDestroyIcon (hicon); 186 187 /* Same for the small icon */ 188 hicon = (HICON)SendMessage(hwnd, WM_SETICON, ICON_SMALL, 0); 189 winDestroyIcon (hicon); 190 191 /* Remove any menu additions; bRevert=TRUE destroys any modified menus */ 192 GetSystemMenu (hwnd, TRUE); 193 194 /* This window is now clean of our taint (but with undefined icons) */ 195 } 196 else 197 { 198 /* winUpdateIcon() will set the icon default, dynamic, or from xwinrc */ 199 wid = (Window)GetProp (hwnd, WIN_WID_PROP); 200 if (wid) 201 winUpdateIcon (wid); 202 203 /* Update the system menu for this window */ 204 SetupSysMenu ((unsigned long)hwnd); 205 206 /* That was easy... */ 207 } 208 209 return TRUE; 210} 211#endif 212 213 214/* 215 * Removes any custom icons in classes, custom menus, etc. 216 * Frees all members in pref structure. 217 * Reloads the preferences file. 218 * Set custom icons and menus again. 219 */ 220static void 221ReloadPrefs (void) 222{ 223 int i; 224 225#ifdef XWIN_MULTIWINDOW 226 /* First, iterate over all windows, deleting their icons and custom menus. 227 * This is really only needed because winDestroyIcon() will try to 228 * destroy the old global icons, which will have changed. 229 * It is probably better to set a windows USER_DATA to flag locally defined 230 * icons, and use that to accurately know when to destroy old icons. 231 */ 232 EnumThreadWindows (g_dwCurrentThreadID, ReloadEnumWindowsProc, FALSE); 233#endif 234 235 /* Now, free/clear all info from our prefs structure */ 236 for (i=0; i<pref.menuItems; i++) 237 free (pref.menu[i].menuItem); 238 free (pref.menu); 239 pref.menu = NULL; 240 pref.menuItems = 0; 241 242 pref.rootMenuName[0] = 0; 243 244 free (pref.sysMenu); 245 pref.sysMenuItems = 0; 246 247 pref.defaultSysMenuName[0] = 0; 248 pref.defaultSysMenuPos = 0; 249 250 pref.iconDirectory[0] = 0; 251 pref.defaultIconName[0] = 0; 252 pref.trayIconName[0] = 0; 253 254 for (i=0; i<pref.iconItems; i++) 255 if (pref.icon[i].hicon) 256 DestroyIcon ((HICON)pref.icon[i].hicon); 257 free (pref.icon); 258 pref.icon = NULL; 259 pref.iconItems = 0; 260 261 /* Free global default X icon */ 262 if (g_hIconX) 263 DestroyIcon (g_hIconX); 264 if (g_hSmallIconX) 265 DestroyIcon (g_hSmallIconX); 266 267 /* Reset the custom command IDs */ 268 g_cmdid = STARTMENUID; 269 270 /* Load the updated resource file */ 271 LoadPreferences(); 272 273 g_hIconX = NULL; 274 g_hSmallIconX = NULL; 275 276#ifdef XWIN_MULTIWINDOW 277 winInitGlobalIcons(); 278#endif 279 280#ifdef XWIN_MULTIWINDOW 281 /* Rebuild the icons and menus */ 282 EnumThreadWindows (g_dwCurrentThreadID, ReloadEnumWindowsProc, TRUE); 283#endif 284 285 /* Whew, done */ 286} 287 288/* 289 * Check/uncheck the ALWAYSONTOP items in this menu 290 */ 291void 292HandleCustomWM_INITMENU(unsigned long hwndIn, 293 unsigned long hmenuIn) 294{ 295 HWND hwnd; 296 HMENU hmenu; 297 DWORD dwExStyle; 298 int i, j; 299 300 hwnd = (HWND)hwndIn; 301 hmenu = (HMENU)hmenuIn; 302 if (!hwnd || !hmenu) 303 return; 304 305 if (GetWindowLongPtr(hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST) 306 dwExStyle = MF_BYCOMMAND | MF_CHECKED; 307 else 308 dwExStyle = MF_BYCOMMAND | MF_UNCHECKED; 309 310 for (i=0; i<pref.menuItems; i++) 311 for (j=0; j<pref.menu[i].menuItems; j++) 312 if (pref.menu[i].menuItem[j].cmd==CMD_ALWAYSONTOP) 313 CheckMenuItem (hmenu, pref.menu[i].menuItem[j].commandID, dwExStyle ); 314 315} 316 317/* 318 * Searches for the custom WM_COMMAND command ID and performs action. 319 * Return TRUE if command is proccessed, FALSE otherwise. 320 */ 321Bool 322HandleCustomWM_COMMAND (unsigned long hwndIn, 323 int command) 324{ 325 HWND hwnd; 326 int i, j; 327 MENUPARSED *m; 328 DWORD dwExStyle; 329 330 hwnd = (HWND)hwndIn; 331 332 if (!command) 333 return FALSE; 334 335 for (i=0; i<pref.menuItems; i++) 336 { 337 m = &(pref.menu[i]); 338 for (j=0; j<m->menuItems; j++) 339 { 340 if (command==m->menuItem[j].commandID) 341 { 342 /* Match! */ 343 switch(m->menuItem[j].cmd) 344 { 345#ifdef __CYGWIN__ 346 case CMD_EXEC: 347 if (fork()==0) 348 { 349 struct rlimit rl; 350 unsigned long i; 351 352 /* Close any open descriptors except for STD* */ 353 getrlimit (RLIMIT_NOFILE, &rl); 354 for (i = STDERR_FILENO+1; i < rl.rlim_cur; i++) 355 close(i); 356 357 /* Disassociate any TTYs */ 358 setsid(); 359 360 execl ("/bin/sh", 361 "/bin/sh", 362 "-c", 363 m->menuItem[j].param, 364 NULL); 365 exit (0); 366 } 367 else 368 return TRUE; 369 break; 370#else 371 case CMD_EXEC: 372 { 373 /* Start process without console window */ 374 STARTUPINFO start; 375 PROCESS_INFORMATION child; 376 377 memset (&start, 0, sizeof (start)); 378 start.cb = sizeof (start); 379 start.dwFlags = STARTF_USESHOWWINDOW; 380 start.wShowWindow = SW_HIDE; 381 382 memset (&child, 0, sizeof (child)); 383 384 if (CreateProcess (NULL, m->menuItem[j].param, NULL, NULL, FALSE, 0, 385 NULL, NULL, &start, &child)) 386 { 387 CloseHandle (child.hThread); 388 CloseHandle (child.hProcess); 389 } 390 else 391 MessageBox(NULL, m->menuItem[j].param, "Mingrc Exec Command Error!", MB_OK | MB_ICONEXCLAMATION); 392 } 393 return TRUE; 394#endif 395 case CMD_ALWAYSONTOP: 396 if (!hwnd) 397 return FALSE; 398 399 /* Get extended window style */ 400 dwExStyle = GetWindowLongPtr(hwnd, GWL_EXSTYLE); 401 402 /* Handle topmost windows */ 403 if (dwExStyle & WS_EX_TOPMOST) 404 SetWindowPos (hwnd, 405 HWND_NOTOPMOST, 406 0, 0, 407 0, 0, 408 SWP_NOSIZE | SWP_NOMOVE); 409 else 410 SetWindowPos (hwnd, 411 HWND_TOPMOST, 412 0, 0, 413 0, 0, 414 SWP_NOSIZE | SWP_NOMOVE); 415#if XWIN_MULTIWINDOW 416 /* Reflect the changed Z order */ 417 winReorderWindowsMultiWindow (); 418#endif 419 return TRUE; 420 421 case CMD_RELOAD: 422 ReloadPrefs(); 423 return TRUE; 424 425 default: 426 return FALSE; 427 } 428 } /* match */ 429 } /* for j */ 430 } /* for i */ 431 432 return FALSE; 433} 434 435 436#ifdef XWIN_MULTIWINDOW 437/* 438 * Add the default or a custom menu depending on the class match 439 */ 440void 441SetupSysMenu (unsigned long hwndIn) 442{ 443 HWND hwnd; 444 HMENU sys; 445 int i; 446 WindowPtr pWin; 447 char *res_name, *res_class; 448 449 hwnd = (HWND)hwndIn; 450 if (!hwnd) 451 return; 452 453 pWin = GetProp (hwnd, WIN_WINDOW_PROP); 454 455 sys = GetSystemMenu (hwnd, FALSE); 456 if (!sys) 457 return; 458 459 if (pWin) 460 { 461 /* First see if there's a class match... */ 462 if (winMultiWindowGetClassHint (pWin, &res_name, &res_class)) 463 { 464 for (i=0; i<pref.sysMenuItems; i++) 465 { 466 if (!strcmp(pref.sysMenu[i].match, res_name) || 467 !strcmp(pref.sysMenu[i].match, res_class) ) 468 { 469 free(res_name); 470 free(res_class); 471 472 MakeMenu (pref.sysMenu[i].menuName, sys, 473 pref.sysMenu[i].menuPos==AT_START?0:-1); 474 return; 475 } 476 } 477 478 /* No match, just free alloc'd strings */ 479 free(res_name); 480 free(res_class); 481 } /* Found wm_class */ 482 } /* if pwin */ 483 484 /* Fallback to system default */ 485 if (pref.defaultSysMenuName[0]) 486 { 487 if (pref.defaultSysMenuPos==AT_START) 488 MakeMenu (pref.defaultSysMenuName, sys, 0); 489 else 490 MakeMenu (pref.defaultSysMenuName, sys, -1); 491 } 492} 493#endif 494 495 496/* 497 * Possibly add a menu to the toolbar icon 498 */ 499void 500SetupRootMenu (unsigned long hmenuRoot) 501{ 502 HMENU root; 503 504 root = (HMENU)hmenuRoot; 505 if (!root) 506 return; 507 508 if (pref.rootMenuName[0]) 509 { 510 MakeMenu(pref.rootMenuName, root, 0); 511 } 512} 513 514 515/* 516 * Check for and return an overridden default ICON specified in the prefs 517 */ 518HICON 519winOverrideDefaultIcon(int size) 520{ 521 HICON hicon; 522 523 if (pref.defaultIconName[0]) 524 { 525 hicon = LoadImageComma (pref.defaultIconName, size, size, 0); 526 if (hicon==NULL) 527 ErrorF ("winOverrideDefaultIcon: LoadImageComma(%s) failed\n", 528 pref.defaultIconName); 529 530 return hicon; 531 } 532 533 return 0; 534} 535 536 537/* 538 * Return the HICON to use in the taskbar notification area 539 */ 540HICON 541winTaskbarIcon(void) 542{ 543 HICON hicon; 544 545 hicon = 0; 546 /* First try and load an overridden, if success then return it */ 547 if (pref.trayIconName[0]) 548 { 549 hicon = LoadImageComma (pref.trayIconName, 550 GetSystemMetrics (SM_CXSMICON), 551 GetSystemMetrics (SM_CYSMICON), 552 0 ); 553 } 554 555 /* Otherwise return the default */ 556 if (!hicon) 557 hicon = (HICON) LoadImage (g_hInstance, 558 MAKEINTRESOURCE(IDI_XWIN), 559 IMAGE_ICON, 560 GetSystemMetrics (SM_CXSMICON), 561 GetSystemMetrics (SM_CYSMICON), 562 0); 563 564 return hicon; 565} 566 567 568/* 569 * Parse a filename to extract an icon: 570 * If fname is exactly ",nnn" then extract icon from our resource 571 * else if it is "file,nnn" then extract icon nnn from that file 572 * else try to load it as an .ico file and if that fails return NULL 573 */ 574static HICON 575LoadImageComma (char *fname, int sx, int sy, int flags) 576{ 577 HICON hicon; 578 int index; 579 char file[PATH_MAX+NAME_MAX+2]; 580 581 /* Some input error checking */ 582 if (!fname || !fname[0]) 583 return NULL; 584 585 index = 0; 586 hicon = NULL; 587 588 if (fname[0]==',') 589 { 590 /* It's the XWIN.EXE resource they want */ 591 index = atoi (fname+1); 592 hicon = LoadImage (g_hInstance, 593 MAKEINTRESOURCE(index), 594 IMAGE_ICON, 595 sx, 596 sy, 597 flags); 598 } 599 else 600 { 601 file[0] = 0; 602 /* Prepend path if not given a "X:\" filename */ 603 if ( !(fname[0] && fname[1]==':' && fname[2]=='\\') ) 604 { 605 strcpy (file, pref.iconDirectory); 606 if (pref.iconDirectory[0]) 607 if (fname[strlen(fname)-1]!='\\') 608 strcat (file, "\\"); 609 } 610 strcat (file, fname); 611 612 if (strrchr (file, ',')) 613 { 614 /* Specified as <fname>,<index> */ 615 616 *(strrchr (file, ',')) = 0; /* End string at comma */ 617 index = atoi (strrchr (fname, ',') + 1); 618 hicon = ExtractIcon (g_hInstance, file, index); 619 } 620 else 621 { 622 /* Just an .ico file... */ 623 624 hicon = (HICON)LoadImage (NULL, 625 file, 626 IMAGE_ICON, 627 sx, 628 sy, 629 LR_LOADFROMFILE|flags); 630 } 631 } 632 return hicon; 633} 634 635/* 636 * Check for a match of the window class to one specified in the 637 * ICONS{} section in the prefs file, and load the icon from a file 638 */ 639HICON 640winOverrideIcon (unsigned long longWin) 641{ 642 WindowPtr pWin = (WindowPtr) longWin; 643 char *res_name, *res_class; 644 int i; 645 HICON hicon; 646 char *wmName; 647 648 if (pWin==NULL) 649 return 0; 650 651 /* If we can't find the class, we can't override from default! */ 652 if (!winMultiWindowGetClassHint (pWin, &res_name, &res_class)) 653 return 0; 654 655 winMultiWindowGetWMName (pWin, &wmName); 656 657 for (i=0; i<pref.iconItems; i++) { 658 if (!strcmp(pref.icon[i].match, res_name) || 659 !strcmp(pref.icon[i].match, res_class) || 660 (wmName && strstr(wmName, pref.icon[i].match))) 661 { 662 free (res_name); 663 free (res_class); 664 free(wmName); 665 666 if (pref.icon[i].hicon) 667 return pref.icon[i].hicon; 668 669 hicon = LoadImageComma (pref.icon[i].iconFile, 0, 0, LR_DEFAULTSIZE); 670 if (hicon==NULL) 671 ErrorF ("winOverrideIcon: LoadImageComma(%s) failed\n", 672 pref.icon[i].iconFile); 673 674 pref.icon[i].hicon = hicon; 675 return hicon; 676 } 677 } 678 679 /* Didn't find the icon, fail gracefully */ 680 free (res_name); 681 free (res_class); 682 free(wmName); 683 684 return 0; 685} 686 687 688/* 689 * Should we free this icon or leave it in memory (is it part of our 690 * ICONS{} overrides)? 691 */ 692int 693winIconIsOverride(unsigned hiconIn) 694{ 695 HICON hicon; 696 int i; 697 698 hicon = (HICON)hiconIn; 699 700 if (!hicon) 701 return 0; 702 703 for (i=0; i<pref.iconItems; i++) 704 if ((HICON)pref.icon[i].hicon == hicon) 705 return 1; 706 707 return 0; 708} 709 710 711 712/* 713 * Try and open ~/.XWinrc and system.XWinrc 714 * Load it into prefs structure for use by other functions 715 */ 716void 717LoadPreferences (void) 718{ 719 char *home; 720 char fname[PATH_MAX+NAME_MAX+2]; 721 FILE *prefFile; 722 char szDisplay[512]; 723 char *szEnvDisplay; 724 int i, j; 725 char param[PARAM_MAX+1]; 726 char *srcParam, *dstParam; 727 728 /* First, clear all preference settings */ 729 memset (&pref, 0, sizeof(pref)); 730 prefFile = NULL; 731 732 /* Now try and find a ~/.xwinrc file */ 733 home = getenv ("HOME"); 734 if (home) 735 { 736 strcpy (fname, home); 737 if (fname[strlen(fname)-1]!='/') 738 strcat (fname, "/"); 739 strcat (fname, ".XWinrc"); 740 741 prefFile = fopen (fname, "r"); 742 if (prefFile) 743 ErrorF ("winPrefsLoadPreferences: %s\n", fname); 744 } 745 746 /* No home file found, check system default */ 747 if (!prefFile) 748 { 749 char buffer[MAX_PATH]; 750#ifdef RELOCATE_PROJECTROOT 751 snprintf(buffer, sizeof(buffer), "%s\\system.XWinrc", winGetBaseDir()); 752#else 753 strncpy(buffer, SYSCONFDIR"/X11/system.XWinrc", sizeof(buffer)); 754#endif 755 buffer[sizeof(buffer)-1] = 0; 756 prefFile = fopen (buffer, "r"); 757 if (prefFile) 758 ErrorF ("winPrefsLoadPreferences: %s\n", buffer); 759 } 760 761 /* If we could open it, then read the settings and close it */ 762 if (prefFile) 763 { 764 parse_file (prefFile); 765 fclose (prefFile); 766 } 767 768 /* Setup a DISPLAY environment variable, need to allocate on heap */ 769 /* because putenv doesn't copy the argument... */ 770 snprintf (szDisplay, 512, "DISPLAY=127.0.0.1:%s.0", display); 771 szEnvDisplay = (char *)(malloc (strlen(szDisplay)+1)); 772 if (szEnvDisplay) 773 { 774 strcpy (szEnvDisplay, szDisplay); 775 putenv (szEnvDisplay); 776 } 777 778 /* Replace any "%display%" in menu commands with display string */ 779 snprintf (szDisplay, 512, "127.0.0.1:%s.0", display); 780 for (i=0; i<pref.menuItems; i++) 781 { 782 for (j=0; j<pref.menu[i].menuItems; j++) 783 { 784 if (pref.menu[i].menuItem[j].cmd==CMD_EXEC) 785 { 786 srcParam = pref.menu[i].menuItem[j].param; 787 dstParam = param; 788 while (*srcParam) { 789 if (!strncmp(srcParam, "%display%", 9)) 790 { 791 memcpy (dstParam, szDisplay, strlen(szDisplay)); 792 dstParam += strlen(szDisplay); 793 srcParam += 9; 794 } 795 else 796 { 797 *dstParam = *srcParam; 798 dstParam++; 799 srcParam++; 800 } 801 } 802 *dstParam = 0; 803 strcpy (pref.menu[i].menuItem[j].param, param); 804 } /* cmd==cmd_exec */ 805 } /* for all menuitems */ 806 } /* for all menus */ 807 808} 809 810 811/* 812 * Check for a match of the window class to one specified in the 813 * STYLES{} section in the prefs file, and return the style type 814 */ 815unsigned long 816winOverrideStyle (unsigned long longpWin) 817{ 818 WindowPtr pWin = (WindowPtr) longpWin; 819 char *res_name, *res_class; 820 int i; 821 char *wmName; 822 823 if (pWin==NULL) 824 return STYLE_NONE; 825 826 /* If we can't find the class, we can't override from default! */ 827 if (!winMultiWindowGetClassHint (pWin, &res_name, &res_class)) 828 return STYLE_NONE; 829 830 winMultiWindowGetWMName (pWin, &wmName); 831 832 for (i=0; i<pref.styleItems; i++) { 833 if (!strcmp(pref.style[i].match, res_name) || 834 !strcmp(pref.style[i].match, res_class) || 835 (wmName && strstr(wmName, pref.style[i].match))) 836 { 837 free (res_name); 838 free (res_class); 839 free(wmName); 840 841 if (pref.style[i].type) 842 return pref.style[i].type; 843 } 844 } 845 846 /* Didn't find the style, fail gracefully */ 847 free (res_name); 848 free (res_class); 849 free(wmName); 850 851 return STYLE_NONE; 852} 853