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