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