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
55extern const char *winGetBaseDir(void);
56
57/* From winprefslex.l, the real parser */
58extern int parse_file(FILE * fp);
59
60/* Currently in use command ID, incremented each new menu item created */
61static int g_cmdid = STARTMENUID;
62
63/*
64 * Creates or appends a menu from a MENUPARSED structure
65 */
66static HMENU
67MakeMenu(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 */
143static wBOOL CALLBACK
144ReloadEnumWindowsProc(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 */
204static void
205ReloadPrefs(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 */
274void
275HandleCustomWM_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 */
300Bool
301HandleCustomWM_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 */
405void
406SetupSysMenu(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 */
455void
456SetupRootMenu(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 */
469HICON
470winOverrideDefaultIcon(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 */
489HICON
490winTaskbarIcon(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 */
524HICON
525LoadImageComma(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 */
613HICON
614winOverrideIcon(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 */
644int
645winIconIsOverride(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 */
663static int
664winPrefsLoadPreferences(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 */
705void
706LoadPreferences(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 */
789unsigned long
790winOverrideStyle(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