winprefs.c revision 35c4bbdf
105b261ecSmrg/*
205b261ecSmrg * Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved.
36747b715Smrg * Copyright (C) Colin Harrison 2005-2008
405b261ecSmrg *
505b261ecSmrg * Permission is hereby granted, free of charge, to any person obtaining
605b261ecSmrg * a copy of this software and associated documentation files (the
705b261ecSmrg * "Software"), to deal in the Software without restriction, including
805b261ecSmrg * without limitation the rights to use, copy, modify, merge, publish,
905b261ecSmrg * distribute, sublicense, and/or sell copies of the Software, and to
1005b261ecSmrg * permit persons to whom the Software is furnished to do so, subject to
1105b261ecSmrg * the following conditions:
1205b261ecSmrg *
1305b261ecSmrg * The above copyright notice and this permission notice shall be
1405b261ecSmrg * included in all copies or substantial portions of the Software.
1505b261ecSmrg *
1605b261ecSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
1705b261ecSmrg * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1805b261ecSmrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
1905b261ecSmrg * NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR
2005b261ecSmrg * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
2105b261ecSmrg * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
2205b261ecSmrg * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2305b261ecSmrg *
2405b261ecSmrg * Except as contained in this notice, the name of the XFree86 Project
2505b261ecSmrg * shall not be used in advertising or otherwise to promote the sale, use
2605b261ecSmrg * or other dealings in this Software without prior written authorization
2705b261ecSmrg * from the XFree86 Project.
2805b261ecSmrg *
2905b261ecSmrg * Authors:     Earle F. Philhower, III
306747b715Smrg *              Colin Harrison
3105b261ecSmrg */
3205b261ecSmrg
3305b261ecSmrg#ifdef HAVE_XWIN_CONFIG_H
3405b261ecSmrg#include <xwin-config.h>
3505b261ecSmrg#endif
3605b261ecSmrg#include <stdio.h>
3705b261ecSmrg#include <stdlib.h>
3805b261ecSmrg#ifdef __CYGWIN__
3905b261ecSmrg#include <sys/resource.h>
4005b261ecSmrg#endif
4105b261ecSmrg#include "win.h"
4205b261ecSmrg
4305b261ecSmrg#include <X11/Xwindows.h>
4405b261ecSmrg#include <shellapi.h>
4505b261ecSmrg
4605b261ecSmrg#include "winprefs.h"
4735c4bbdfSmrg#include "windisplay.h"
4805b261ecSmrg#include "winmultiwindowclass.h"
4905b261ecSmrg
5005b261ecSmrg/* Where will the custom menu commands start counting from? */
5105b261ecSmrg#define STARTMENUID WM_USER
5205b261ecSmrg
5305b261ecSmrgextern const char *winGetBaseDir(void);
5405b261ecSmrg
5535c4bbdfSmrg/* From winprefslex.l, the real parser */
5635c4bbdfSmrgextern int parse_file(FILE * fp);
5705b261ecSmrg
5805b261ecSmrg/* Currently in use command ID, incremented each new menu item created */
5905b261ecSmrgstatic int g_cmdid = STARTMENUID;
6005b261ecSmrg
6105b261ecSmrg/* Local function to handle comma-ified icon names */
6235c4bbdfSmrgstatic HICON LoadImageComma(char *fname, int sx, int sy, int flags);
6305b261ecSmrg
6405b261ecSmrg/*
6505b261ecSmrg * Creates or appends a menu from a MENUPARSED structure
6605b261ecSmrg */
6705b261ecSmrgstatic HMENU
6835c4bbdfSmrgMakeMenu(char *name, HMENU editMenu, int editItem)
6905b261ecSmrg{
7035c4bbdfSmrg    int i;
7135c4bbdfSmrg    int item;
7235c4bbdfSmrg    MENUPARSED *m;
7335c4bbdfSmrg    HMENU hmenu, hsub;
7435c4bbdfSmrg
7535c4bbdfSmrg    for (i = 0; i < pref.menuItems; i++) {
7635c4bbdfSmrg        if (!strcmp(name, pref.menu[i].menuName))
7735c4bbdfSmrg            break;
7805b261ecSmrg    }
7935c4bbdfSmrg
8035c4bbdfSmrg    /* Didn't find a match, bummer */
8135c4bbdfSmrg    if (i == pref.menuItems) {
8235c4bbdfSmrg        ErrorF("MakeMenu: Can't find menu %s\n", name);
8335c4bbdfSmrg        return NULL;
8405b261ecSmrg    }
8505b261ecSmrg
8635c4bbdfSmrg    m = &(pref.menu[i]);
8735c4bbdfSmrg
8835c4bbdfSmrg    if (editMenu) {
8935c4bbdfSmrg        hmenu = editMenu;
9035c4bbdfSmrg        item = editItem;
9105b261ecSmrg    }
9235c4bbdfSmrg    else {
9335c4bbdfSmrg        hmenu = CreatePopupMenu();
9435c4bbdfSmrg        if (!hmenu) {
9535c4bbdfSmrg            ErrorF("MakeMenu: Unable to CreatePopupMenu() %s\n", name);
9635c4bbdfSmrg            return NULL;
9735c4bbdfSmrg        }
9835c4bbdfSmrg        item = 0;
9905b261ecSmrg    }
10005b261ecSmrg
10135c4bbdfSmrg    /* Add the menu items */
10235c4bbdfSmrg    for (i = 0; i < m->menuItems; i++) {
10335c4bbdfSmrg        /* Only assign IDs one time... */
10435c4bbdfSmrg        if (m->menuItem[i].commandID == 0)
10535c4bbdfSmrg            m->menuItem[i].commandID = g_cmdid++;
10635c4bbdfSmrg
10735c4bbdfSmrg        switch (m->menuItem[i].cmd) {
10835c4bbdfSmrg        case CMD_EXEC:
10935c4bbdfSmrg        case CMD_ALWAYSONTOP:
11035c4bbdfSmrg        case CMD_RELOAD:
11135c4bbdfSmrg            InsertMenu(hmenu,
11235c4bbdfSmrg                       item,
11335c4bbdfSmrg                       MF_BYPOSITION | MF_ENABLED | MF_STRING,
11435c4bbdfSmrg                       m->menuItem[i].commandID, m->menuItem[i].text);
11535c4bbdfSmrg            break;
11635c4bbdfSmrg
11735c4bbdfSmrg        case CMD_SEPARATOR:
11835c4bbdfSmrg            InsertMenu(hmenu, item, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
11935c4bbdfSmrg            break;
12035c4bbdfSmrg
12135c4bbdfSmrg        case CMD_MENU:
12235c4bbdfSmrg            /* Recursive! */
12335c4bbdfSmrg            hsub = MakeMenu(m->menuItem[i].param, 0, 0);
12435c4bbdfSmrg            if (hsub)
12535c4bbdfSmrg                InsertMenu(hmenu,
12635c4bbdfSmrg                           item,
12735c4bbdfSmrg                           MF_BYPOSITION | MF_POPUP | MF_ENABLED | MF_STRING,
12835c4bbdfSmrg                           (UINT_PTR) hsub, m->menuItem[i].text);
12935c4bbdfSmrg            break;
13035c4bbdfSmrg        }
13135c4bbdfSmrg
13235c4bbdfSmrg        /* If item==-1 (means to add at end of menu) don't increment) */
13335c4bbdfSmrg        if (item >= 0)
13435c4bbdfSmrg            item++;
13505b261ecSmrg    }
13605b261ecSmrg
13735c4bbdfSmrg    return hmenu;
13805b261ecSmrg}
13905b261ecSmrg
14005b261ecSmrg#ifdef XWIN_MULTIWINDOW
14105b261ecSmrg/*
14205b261ecSmrg * Callback routine that is executed once per window class.
14305b261ecSmrg * Removes or creates custom window settings depending on LPARAM
14405b261ecSmrg */
14505b261ecSmrgstatic wBOOL CALLBACK
14635c4bbdfSmrgReloadEnumWindowsProc(HWND hwnd, LPARAM lParam)
14705b261ecSmrg{
14835c4bbdfSmrg    HICON hicon;
14905b261ecSmrg
15035c4bbdfSmrg    if (!hwnd) {
15135c4bbdfSmrg        ErrorF("ReloadEnumWindowsProc: hwnd==NULL!\n");
15235c4bbdfSmrg        return FALSE;
15335c4bbdfSmrg    }
15435c4bbdfSmrg
15535c4bbdfSmrg    /* It's our baby, either clean or dirty it */
15635c4bbdfSmrg    if (lParam == FALSE) {
15735c4bbdfSmrg        /* Reset the window's icon to undefined. */
15835c4bbdfSmrg        hicon = (HICON) SendMessage(hwnd, WM_SETICON, ICON_BIG, 0);
15905b261ecSmrg
16035c4bbdfSmrg        /* If the old icon is generated on-the-fly, get rid of it, will regen */
16135c4bbdfSmrg        winDestroyIcon(hicon);
16205b261ecSmrg
16335c4bbdfSmrg        /* Same for the small icon */
16435c4bbdfSmrg        hicon = (HICON) SendMessage(hwnd, WM_SETICON, ICON_SMALL, 0);
16535c4bbdfSmrg        winDestroyIcon(hicon);
16605b261ecSmrg
16735c4bbdfSmrg        /* Remove any menu additions; bRevert=TRUE destroys any modified menus */
16835c4bbdfSmrg        GetSystemMenu(hwnd, TRUE);
1696747b715Smrg
17035c4bbdfSmrg        /* This window is now clean of our taint (but with undefined icons) */
17105b261ecSmrg    }
17235c4bbdfSmrg    else {
17335c4bbdfSmrg        /* Send a message to WM thread telling it re-evaluate the icon for this window */
17435c4bbdfSmrg        {
17535c4bbdfSmrg            winWMMessageRec wmMsg;
1766747b715Smrg
17735c4bbdfSmrg            WindowPtr pWin = GetProp(hwnd, WIN_WINDOW_PROP);
17805b261ecSmrg
17935c4bbdfSmrg            if (pWin) {
18035c4bbdfSmrg                winPrivWinPtr pWinPriv = winGetWindowPriv(pWin);
18135c4bbdfSmrg                winPrivScreenPtr s_pScreenPriv = pWinPriv->pScreenPriv;
18235c4bbdfSmrg
18335c4bbdfSmrg                wmMsg.msg = WM_WM_ICON_EVENT;
18435c4bbdfSmrg                wmMsg.hwndWindow = hwnd;
18535c4bbdfSmrg                wmMsg.iWindow = (Window) (INT_PTR) GetProp(hwnd, WIN_WID_PROP);
18635c4bbdfSmrg
18735c4bbdfSmrg                winSendMessageToWM(s_pScreenPriv->pWMInfo, &wmMsg);
18835c4bbdfSmrg            }
18935c4bbdfSmrg        }
19035c4bbdfSmrg
19135c4bbdfSmrg        /* Update the system menu for this window */
19235c4bbdfSmrg        SetupSysMenu(hwnd);
19335c4bbdfSmrg
19435c4bbdfSmrg        /* That was easy... */
19505b261ecSmrg    }
19605b261ecSmrg
19735c4bbdfSmrg    return TRUE;
19805b261ecSmrg}
19905b261ecSmrg#endif
20005b261ecSmrg
20105b261ecSmrg/*
20205b261ecSmrg * Removes any custom icons in classes, custom menus, etc.
20305b261ecSmrg * Frees all members in pref structure.
20405b261ecSmrg * Reloads the preferences file.
20505b261ecSmrg * Set custom icons and menus again.
20605b261ecSmrg */
20705b261ecSmrgstatic void
20835c4bbdfSmrgReloadPrefs(void)
20905b261ecSmrg{
21035c4bbdfSmrg    int i;
21105b261ecSmrg
21205b261ecSmrg#ifdef XWIN_MULTIWINDOW
21335c4bbdfSmrg    /* First, iterate over all windows, deleting their icons and custom menus.
21435c4bbdfSmrg     * This is really only needed because winDestroyIcon() will try to
21535c4bbdfSmrg     * destroy the old global icons, which will have changed.
21635c4bbdfSmrg     * It is probably better to set a windows USER_DATA to flag locally defined
21735c4bbdfSmrg     * icons, and use that to accurately know when to destroy old icons.
21835c4bbdfSmrg     */
21935c4bbdfSmrg    EnumThreadWindows(g_dwCurrentThreadID, ReloadEnumWindowsProc, FALSE);
22005b261ecSmrg#endif
22135c4bbdfSmrg
22235c4bbdfSmrg    /* Now, free/clear all info from our prefs structure */
22335c4bbdfSmrg    for (i = 0; i < pref.menuItems; i++)
22435c4bbdfSmrg        free(pref.menu[i].menuItem);
22535c4bbdfSmrg    free(pref.menu);
22635c4bbdfSmrg    pref.menu = NULL;
22735c4bbdfSmrg    pref.menuItems = 0;
22835c4bbdfSmrg
22935c4bbdfSmrg    pref.rootMenuName[0] = 0;
23035c4bbdfSmrg
23135c4bbdfSmrg    free(pref.sysMenu);
23235c4bbdfSmrg    pref.sysMenuItems = 0;
23335c4bbdfSmrg
23435c4bbdfSmrg    pref.defaultSysMenuName[0] = 0;
23535c4bbdfSmrg    pref.defaultSysMenuPos = 0;
23635c4bbdfSmrg
23735c4bbdfSmrg    pref.iconDirectory[0] = 0;
23835c4bbdfSmrg    pref.defaultIconName[0] = 0;
23935c4bbdfSmrg    pref.trayIconName[0] = 0;
24035c4bbdfSmrg
24135c4bbdfSmrg    for (i = 0; i < pref.iconItems; i++)
24235c4bbdfSmrg        if (pref.icon[i].hicon)
24335c4bbdfSmrg            DestroyIcon((HICON) pref.icon[i].hicon);
24435c4bbdfSmrg    free(pref.icon);
24535c4bbdfSmrg    pref.icon = NULL;
24635c4bbdfSmrg    pref.iconItems = 0;
24735c4bbdfSmrg
24835c4bbdfSmrg    /* Free global default X icon */
24935c4bbdfSmrg    if (g_hIconX)
25035c4bbdfSmrg        DestroyIcon(g_hIconX);
25135c4bbdfSmrg    if (g_hSmallIconX)
25235c4bbdfSmrg        DestroyIcon(g_hSmallIconX);
25335c4bbdfSmrg
25435c4bbdfSmrg    /* Reset the custom command IDs */
25535c4bbdfSmrg    g_cmdid = STARTMENUID;
25635c4bbdfSmrg
25735c4bbdfSmrg    /* Load the updated resource file */
25835c4bbdfSmrg    LoadPreferences();
25935c4bbdfSmrg
26035c4bbdfSmrg    g_hIconX = NULL;
26135c4bbdfSmrg    g_hSmallIconX = NULL;
26205b261ecSmrg
26305b261ecSmrg#ifdef XWIN_MULTIWINDOW
26435c4bbdfSmrg    winInitGlobalIcons();
26505b261ecSmrg#endif
26635c4bbdfSmrg
26705b261ecSmrg#ifdef XWIN_MULTIWINDOW
26835c4bbdfSmrg    /* Rebuild the icons and menus */
26935c4bbdfSmrg    EnumThreadWindows(g_dwCurrentThreadID, ReloadEnumWindowsProc, TRUE);
27005b261ecSmrg#endif
27105b261ecSmrg
27235c4bbdfSmrg    /* Whew, done */
27305b261ecSmrg}
27405b261ecSmrg
27505b261ecSmrg/*
27605b261ecSmrg * Check/uncheck the ALWAYSONTOP items in this menu
27705b261ecSmrg */
27805b261ecSmrgvoid
27935c4bbdfSmrgHandleCustomWM_INITMENU(HWND hwnd, HMENU hmenu)
28005b261ecSmrg{
28135c4bbdfSmrg    DWORD dwExStyle;
28235c4bbdfSmrg    int i, j;
28335c4bbdfSmrg
28435c4bbdfSmrg    if (!hwnd || !hmenu)
28535c4bbdfSmrg        return;
28635c4bbdfSmrg
28735c4bbdfSmrg    if (GetWindowLongPtr(hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST)
28835c4bbdfSmrg        dwExStyle = MF_BYCOMMAND | MF_CHECKED;
28935c4bbdfSmrg    else
29035c4bbdfSmrg        dwExStyle = MF_BYCOMMAND | MF_UNCHECKED;
29135c4bbdfSmrg
29235c4bbdfSmrg    for (i = 0; i < pref.menuItems; i++)
29335c4bbdfSmrg        for (j = 0; j < pref.menu[i].menuItems; j++)
29435c4bbdfSmrg            if (pref.menu[i].menuItem[j].cmd == CMD_ALWAYSONTOP)
29535c4bbdfSmrg                CheckMenuItem(hmenu, pref.menu[i].menuItem[j].commandID,
29635c4bbdfSmrg                              dwExStyle);
29735c4bbdfSmrg
29805b261ecSmrg}
29935c4bbdfSmrg
30005b261ecSmrg/*
30105b261ecSmrg * Searches for the custom WM_COMMAND command ID and performs action.
30205b261ecSmrg * Return TRUE if command is proccessed, FALSE otherwise.
30305b261ecSmrg */
30405b261ecSmrgBool
30535c4bbdfSmrgHandleCustomWM_COMMAND(HWND hwnd, int command)
30605b261ecSmrg{
30735c4bbdfSmrg    int i, j;
30835c4bbdfSmrg    MENUPARSED *m;
30935c4bbdfSmrg    DWORD dwExStyle;
31035c4bbdfSmrg
31135c4bbdfSmrg    if (!command)
31235c4bbdfSmrg        return FALSE;
31335c4bbdfSmrg
31435c4bbdfSmrg    for (i = 0; i < pref.menuItems; i++) {
31535c4bbdfSmrg        m = &(pref.menu[i]);
31635c4bbdfSmrg        for (j = 0; j < m->menuItems; j++) {
31735c4bbdfSmrg            if (command == m->menuItem[j].commandID) {
31835c4bbdfSmrg                /* Match! */
31935c4bbdfSmrg                switch (m->menuItem[j].cmd) {
32005b261ecSmrg#ifdef __CYGWIN__
32135c4bbdfSmrg                case CMD_EXEC:
32235c4bbdfSmrg                    if (fork() == 0) {
32335c4bbdfSmrg                        struct rlimit rl;
32435c4bbdfSmrg                        int fd;
32535c4bbdfSmrg
32635c4bbdfSmrg                        /* Close any open descriptors except for STD* */
32735c4bbdfSmrg                        getrlimit(RLIMIT_NOFILE, &rl);
32835c4bbdfSmrg                        for (fd = STDERR_FILENO + 1; fd < rl.rlim_cur; fd++)
32935c4bbdfSmrg                            close(fd);
33035c4bbdfSmrg
33135c4bbdfSmrg                        /* Disassociate any TTYs */
33235c4bbdfSmrg                        setsid();
33335c4bbdfSmrg
33435c4bbdfSmrg                        execl("/bin/sh",
33535c4bbdfSmrg                              "/bin/sh", "-c", m->menuItem[j].param, NULL);
33635c4bbdfSmrg                        exit(0);
33735c4bbdfSmrg                    }
33835c4bbdfSmrg                    else
33935c4bbdfSmrg                        return TRUE;
34035c4bbdfSmrg                    break;
34105b261ecSmrg#else
34235c4bbdfSmrg                case CMD_EXEC:
34335c4bbdfSmrg                {
34435c4bbdfSmrg                    /* Start process without console window */
34535c4bbdfSmrg                    STARTUPINFO start;
34635c4bbdfSmrg                    PROCESS_INFORMATION child;
34735c4bbdfSmrg
34835c4bbdfSmrg                    memset(&start, 0, sizeof(start));
34935c4bbdfSmrg                    start.cb = sizeof(start);
35035c4bbdfSmrg                    start.dwFlags = STARTF_USESHOWWINDOW;
35135c4bbdfSmrg                    start.wShowWindow = SW_HIDE;
35235c4bbdfSmrg
35335c4bbdfSmrg                    memset(&child, 0, sizeof(child));
35435c4bbdfSmrg
35535c4bbdfSmrg                    if (CreateProcess
35635c4bbdfSmrg                        (NULL, m->menuItem[j].param, NULL, NULL, FALSE, 0, NULL,
35735c4bbdfSmrg                         NULL, &start, &child)) {
35835c4bbdfSmrg                        CloseHandle(child.hThread);
35935c4bbdfSmrg                        CloseHandle(child.hProcess);
36035c4bbdfSmrg                    }
36135c4bbdfSmrg                    else
36235c4bbdfSmrg                        MessageBox(NULL, m->menuItem[j].param,
36335c4bbdfSmrg                                   "Mingrc Exec Command Error!",
36435c4bbdfSmrg                                   MB_OK | MB_ICONEXCLAMATION);
36535c4bbdfSmrg                }
36635c4bbdfSmrg                    return TRUE;
36705b261ecSmrg#endif
36835c4bbdfSmrg                case CMD_ALWAYSONTOP:
36935c4bbdfSmrg                    if (!hwnd)
37035c4bbdfSmrg                        return FALSE;
37135c4bbdfSmrg
37235c4bbdfSmrg                    /* Get extended window style */
37335c4bbdfSmrg                    dwExStyle = GetWindowLongPtr(hwnd, GWL_EXSTYLE);
37435c4bbdfSmrg
37535c4bbdfSmrg                    /* Handle topmost windows */
37635c4bbdfSmrg                    if (dwExStyle & WS_EX_TOPMOST)
37735c4bbdfSmrg                        SetWindowPos(hwnd,
37835c4bbdfSmrg                                     HWND_NOTOPMOST,
37935c4bbdfSmrg                                     0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
38035c4bbdfSmrg                    else
38135c4bbdfSmrg                        SetWindowPos(hwnd,
38235c4bbdfSmrg                                     HWND_TOPMOST,
38335c4bbdfSmrg                                     0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
38405b261ecSmrg#if XWIN_MULTIWINDOW
38535c4bbdfSmrg                    /* Reflect the changed Z order */
38635c4bbdfSmrg                    winReorderWindowsMultiWindow();
38705b261ecSmrg#endif
38835c4bbdfSmrg                    return TRUE;
38935c4bbdfSmrg
39035c4bbdfSmrg                case CMD_RELOAD:
39135c4bbdfSmrg                    ReloadPrefs();
39235c4bbdfSmrg                    return TRUE;
39335c4bbdfSmrg
39435c4bbdfSmrg                default:
39535c4bbdfSmrg                    return FALSE;
39635c4bbdfSmrg                }
39735c4bbdfSmrg            }                   /* match */
39835c4bbdfSmrg        }                       /* for j */
39935c4bbdfSmrg    }                           /* for i */
40005b261ecSmrg
40135c4bbdfSmrg    return FALSE;
40235c4bbdfSmrg}
40305b261ecSmrg
40405b261ecSmrg#ifdef XWIN_MULTIWINDOW
40505b261ecSmrg/*
40605b261ecSmrg * Add the default or a custom menu depending on the class match
40705b261ecSmrg */
40805b261ecSmrgvoid
40935c4bbdfSmrgSetupSysMenu(HWND hwnd)
41005b261ecSmrg{
41135c4bbdfSmrg    HMENU sys;
41235c4bbdfSmrg    int i;
41335c4bbdfSmrg    WindowPtr pWin;
41435c4bbdfSmrg    char *res_name, *res_class;
41535c4bbdfSmrg
41635c4bbdfSmrg    if (!hwnd)
41735c4bbdfSmrg        return;
41835c4bbdfSmrg
41935c4bbdfSmrg    pWin = GetProp(hwnd, WIN_WINDOW_PROP);
42035c4bbdfSmrg
42135c4bbdfSmrg    sys = GetSystemMenu(hwnd, FALSE);
42235c4bbdfSmrg    if (!sys)
42335c4bbdfSmrg        return;
42435c4bbdfSmrg
42535c4bbdfSmrg    if (pWin) {
42635c4bbdfSmrg        /* First see if there's a class match... */
42735c4bbdfSmrg        if (winMultiWindowGetClassHint(pWin, &res_name, &res_class)) {
42835c4bbdfSmrg            for (i = 0; i < pref.sysMenuItems; i++) {
42935c4bbdfSmrg                if (!strcmp(pref.sysMenu[i].match, res_name) ||
43035c4bbdfSmrg                    !strcmp(pref.sysMenu[i].match, res_class)) {
43135c4bbdfSmrg                    free(res_name);
43235c4bbdfSmrg                    free(res_class);
43335c4bbdfSmrg
43435c4bbdfSmrg                    MakeMenu(pref.sysMenu[i].menuName, sys,
43535c4bbdfSmrg                             pref.sysMenu[i].menuPos == AT_START ? 0 : -1);
43635c4bbdfSmrg                    return;
43735c4bbdfSmrg                }
43835c4bbdfSmrg            }
43935c4bbdfSmrg
44035c4bbdfSmrg            /* No match, just free alloc'd strings */
44135c4bbdfSmrg            free(res_name);
44235c4bbdfSmrg            free(res_class);
44335c4bbdfSmrg        }                       /* Found wm_class */
44435c4bbdfSmrg    }                           /* if pwin */
44535c4bbdfSmrg
44635c4bbdfSmrg    /* Fallback to system default */
44735c4bbdfSmrg    if (pref.defaultSysMenuName[0]) {
44835c4bbdfSmrg        if (pref.defaultSysMenuPos == AT_START)
44935c4bbdfSmrg            MakeMenu(pref.defaultSysMenuName, sys, 0);
45035c4bbdfSmrg        else
45135c4bbdfSmrg            MakeMenu(pref.defaultSysMenuName, sys, -1);
45205b261ecSmrg    }
45305b261ecSmrg}
45405b261ecSmrg#endif
45505b261ecSmrg
45605b261ecSmrg/*
45705b261ecSmrg * Possibly add a menu to the toolbar icon
45805b261ecSmrg */
45905b261ecSmrgvoid
46035c4bbdfSmrgSetupRootMenu(HMENU root)
46105b261ecSmrg{
46235c4bbdfSmrg    if (!root)
46335c4bbdfSmrg        return;
46405b261ecSmrg
46535c4bbdfSmrg    if (pref.rootMenuName[0]) {
46635c4bbdfSmrg        MakeMenu(pref.rootMenuName, root, 0);
46705b261ecSmrg    }
46805b261ecSmrg}
46905b261ecSmrg
47005b261ecSmrg/*
47105b261ecSmrg * Check for and return an overridden default ICON specified in the prefs
47205b261ecSmrg */
4736747b715SmrgHICON
47405b261ecSmrgwinOverrideDefaultIcon(int size)
47505b261ecSmrg{
47635c4bbdfSmrg    HICON hicon;
47735c4bbdfSmrg
47835c4bbdfSmrg    if (pref.defaultIconName[0]) {
47935c4bbdfSmrg        hicon = LoadImageComma(pref.defaultIconName, size, size, 0);
48035c4bbdfSmrg        if (hicon == NULL)
48135c4bbdfSmrg            ErrorF("winOverrideDefaultIcon: LoadImageComma(%s) failed\n",
48235c4bbdfSmrg                   pref.defaultIconName);
48335c4bbdfSmrg
48435c4bbdfSmrg        return hicon;
48505b261ecSmrg    }
48605b261ecSmrg
48735c4bbdfSmrg    return 0;
48805b261ecSmrg}
48905b261ecSmrg
49005b261ecSmrg/*
49105b261ecSmrg * Return the HICON to use in the taskbar notification area
49205b261ecSmrg */
4936747b715SmrgHICON
49405b261ecSmrgwinTaskbarIcon(void)
49505b261ecSmrg{
49635c4bbdfSmrg    HICON hicon;
49735c4bbdfSmrg
49835c4bbdfSmrg    hicon = 0;
49935c4bbdfSmrg    /* First try and load an overridden, if success then return it */
50035c4bbdfSmrg    if (pref.trayIconName[0]) {
50135c4bbdfSmrg        hicon = LoadImageComma(pref.trayIconName,
50235c4bbdfSmrg                               GetSystemMetrics(SM_CXSMICON),
50335c4bbdfSmrg                               GetSystemMetrics(SM_CYSMICON), 0);
50405b261ecSmrg    }
50505b261ecSmrg
50635c4bbdfSmrg    /* Otherwise return the default */
50735c4bbdfSmrg    if (!hicon)
50835c4bbdfSmrg        hicon = (HICON) LoadImage(g_hInstance,
50935c4bbdfSmrg                                  MAKEINTRESOURCE(IDI_XWIN),
51035c4bbdfSmrg                                  IMAGE_ICON,
51135c4bbdfSmrg                                  GetSystemMetrics(SM_CXSMICON),
51235c4bbdfSmrg                                  GetSystemMetrics(SM_CYSMICON), 0);
51305b261ecSmrg
51435c4bbdfSmrg    return hicon;
51505b261ecSmrg}
51605b261ecSmrg
51705b261ecSmrg/*
51805b261ecSmrg * Parse a filename to extract an icon:
51905b261ecSmrg *  If fname is exactly ",nnn" then extract icon from our resource
52005b261ecSmrg *  else if it is "file,nnn" then extract icon nnn from that file
52105b261ecSmrg *  else try to load it as an .ico file and if that fails return NULL
52205b261ecSmrg */
52305b261ecSmrgstatic HICON
52435c4bbdfSmrgLoadImageComma(char *fname, int sx, int sy, int flags)
52505b261ecSmrg{
52635c4bbdfSmrg    HICON hicon;
52735c4bbdfSmrg    int i;
52835c4bbdfSmrg    char file[PATH_MAX + NAME_MAX + 2];
52935c4bbdfSmrg
53035c4bbdfSmrg    /* Some input error checking */
53135c4bbdfSmrg    if (!fname || !fname[0])
53235c4bbdfSmrg        return NULL;
53335c4bbdfSmrg
53435c4bbdfSmrg    i = 0;
53535c4bbdfSmrg    hicon = NULL;
53635c4bbdfSmrg
53735c4bbdfSmrg    if (fname[0] == ',') {
53835c4bbdfSmrg        /* It's the XWIN.EXE resource they want */
53935c4bbdfSmrg        i = atoi(fname + 1);
54035c4bbdfSmrg        hicon = LoadImage(g_hInstance,
54135c4bbdfSmrg                          MAKEINTRESOURCE(i), IMAGE_ICON, sx, sy, flags);
54205b261ecSmrg    }
54335c4bbdfSmrg    else {
54435c4bbdfSmrg        file[0] = 0;
54535c4bbdfSmrg        /* Prepend path if not given a "X:\" filename */
54635c4bbdfSmrg        if (!(fname[0] && fname[1] == ':' && fname[2] == '\\')) {
54735c4bbdfSmrg            strcpy(file, pref.iconDirectory);
54835c4bbdfSmrg            if (pref.iconDirectory[0])
54935c4bbdfSmrg                if (fname[strlen(fname) - 1] != '\\')
55035c4bbdfSmrg                    strcat(file, "\\");
55135c4bbdfSmrg        }
55235c4bbdfSmrg        strcat(file, fname);
55335c4bbdfSmrg
55435c4bbdfSmrg        if (strrchr(file, ',')) {
55535c4bbdfSmrg            /* Specified as <fname>,<index> */
55635c4bbdfSmrg
55735c4bbdfSmrg            *(strrchr(file, ',')) = 0;  /* End string at comma */
55835c4bbdfSmrg            i = atoi(strrchr(fname, ',') + 1);
55935c4bbdfSmrg            hicon = ExtractIcon(g_hInstance, file, i);
56035c4bbdfSmrg        }
56135c4bbdfSmrg        else {
56235c4bbdfSmrg            /* Just an .ico file... */
56335c4bbdfSmrg
56435c4bbdfSmrg            hicon = (HICON) LoadImage(NULL,
56535c4bbdfSmrg                                      file,
56635c4bbdfSmrg                                      IMAGE_ICON,
56735c4bbdfSmrg                                      sx, sy, LR_LOADFROMFILE | flags);
56805b261ecSmrg        }
56905b261ecSmrg    }
57035c4bbdfSmrg    return hicon;
57105b261ecSmrg}
57205b261ecSmrg
57305b261ecSmrg/*
57405b261ecSmrg * Check for a match of the window class to one specified in the
57505b261ecSmrg * ICONS{} section in the prefs file, and load the icon from a file
57605b261ecSmrg */
5776747b715SmrgHICON
57835c4bbdfSmrgwinOverrideIcon(char *res_name, char *res_class, char *wmName)
57905b261ecSmrg{
58035c4bbdfSmrg    int i;
58135c4bbdfSmrg    HICON hicon;
58235c4bbdfSmrg
58335c4bbdfSmrg    for (i = 0; i < pref.iconItems; i++) {
58435c4bbdfSmrg        if ((res_name && !strcmp(pref.icon[i].match, res_name)) ||
58535c4bbdfSmrg            (res_class && !strcmp(pref.icon[i].match, res_class)) ||
58635c4bbdfSmrg            (wmName && strstr(wmName, pref.icon[i].match))) {
58735c4bbdfSmrg            if (pref.icon[i].hicon)
58835c4bbdfSmrg                return pref.icon[i].hicon;
58935c4bbdfSmrg
59035c4bbdfSmrg            hicon = LoadImageComma(pref.icon[i].iconFile, 0, 0, LR_DEFAULTSIZE);
59135c4bbdfSmrg            if (hicon == NULL)
59235c4bbdfSmrg                ErrorF("winOverrideIcon: LoadImageComma(%s) failed\n",
59335c4bbdfSmrg                       pref.icon[i].iconFile);
59435c4bbdfSmrg
59535c4bbdfSmrg            pref.icon[i].hicon = hicon;
59635c4bbdfSmrg            return hicon;
59735c4bbdfSmrg        }
59835c4bbdfSmrg    }
59905b261ecSmrg
60035c4bbdfSmrg    /* Didn't find the icon, fail gracefully */
60105b261ecSmrg    return 0;
60205b261ecSmrg}
60305b261ecSmrg
60405b261ecSmrg/*
60505b261ecSmrg * Should we free this icon or leave it in memory (is it part of our
60605b261ecSmrg * ICONS{} overrides)?
60705b261ecSmrg */
60805b261ecSmrgint
60935c4bbdfSmrgwinIconIsOverride(HICON hicon)
61005b261ecSmrg{
61135c4bbdfSmrg    int i;
61235c4bbdfSmrg
61335c4bbdfSmrg    if (!hicon)
61435c4bbdfSmrg        return 0;
61505b261ecSmrg
61635c4bbdfSmrg    for (i = 0; i < pref.iconItems; i++)
61735c4bbdfSmrg        if ((HICON) pref.icon[i].hicon == hicon)
61835c4bbdfSmrg            return 1;
61905b261ecSmrg
62005b261ecSmrg    return 0;
62105b261ecSmrg}
62205b261ecSmrg
62335c4bbdfSmrg/*
62435c4bbdfSmrg * Open and parse the XWinrc config file @path.
62535c4bbdfSmrg * If @path is NULL, use the built-in default.
62635c4bbdfSmrg */
62735c4bbdfSmrgstatic int
62835c4bbdfSmrgwinPrefsLoadPreferences(const char *path)
62935c4bbdfSmrg{
63035c4bbdfSmrg    FILE *prefFile = NULL;
63135c4bbdfSmrg
63235c4bbdfSmrg    if (path)
63335c4bbdfSmrg        prefFile = fopen(path, "r");
63435c4bbdfSmrg#ifdef __CYGWIN__
63535c4bbdfSmrg    else {
63635c4bbdfSmrg        char defaultPrefs[] =
63735c4bbdfSmrg            "MENU rmenu {\n"
63835c4bbdfSmrg            "  \"How to customize this menu\" EXEC \"xterm +tb -e man XWinrc\"\n"
63935c4bbdfSmrg            "  \"Launch xterm\" EXEC xterm\n"
64035c4bbdfSmrg            "  \"Load .XWinrc\" RELOAD\n"
64135c4bbdfSmrg            "  SEPARATOR\n" "}\n" "\n" "ROOTMENU rmenu\n";
64235c4bbdfSmrg
64335c4bbdfSmrg        path = "built-in default";
64435c4bbdfSmrg        prefFile = fmemopen(defaultPrefs, strlen(defaultPrefs), "r");
64535c4bbdfSmrg    }
64635c4bbdfSmrg#endif
64705b261ecSmrg
64835c4bbdfSmrg    if (!prefFile) {
64935c4bbdfSmrg        ErrorF("LoadPreferences: %s not found\n", path);
65035c4bbdfSmrg        return FALSE;
65135c4bbdfSmrg    }
65235c4bbdfSmrg
65335c4bbdfSmrg    ErrorF("LoadPreferences: Loading %s\n", path);
65435c4bbdfSmrg
65535c4bbdfSmrg    if ((parse_file(prefFile)) != 0) {
65635c4bbdfSmrg        ErrorF("LoadPreferences: %s is badly formed!\n", path);
65735c4bbdfSmrg        fclose(prefFile);
65835c4bbdfSmrg        return FALSE;
65935c4bbdfSmrg    }
66035c4bbdfSmrg
66135c4bbdfSmrg    fclose(prefFile);
66235c4bbdfSmrg    return TRUE;
66335c4bbdfSmrg}
66405b261ecSmrg
66505b261ecSmrg/*
6666747b715Smrg * Try and open ~/.XWinrc and system.XWinrc
66705b261ecSmrg * Load it into prefs structure for use by other functions
66805b261ecSmrg */
66905b261ecSmrgvoid
67035c4bbdfSmrgLoadPreferences(void)
67105b261ecSmrg{
67235c4bbdfSmrg    char *home;
67335c4bbdfSmrg    char fname[PATH_MAX + NAME_MAX + 2];
67435c4bbdfSmrg    char szDisplay[512];
67535c4bbdfSmrg    char *szEnvDisplay;
67635c4bbdfSmrg    int i, j;
67735c4bbdfSmrg    char param[PARAM_MAX + 1];
67835c4bbdfSmrg    char *srcParam, *dstParam;
67935c4bbdfSmrg    int parsed = FALSE;
68035c4bbdfSmrg
68135c4bbdfSmrg    /* First, clear all preference settings */
68235c4bbdfSmrg    memset(&pref, 0, sizeof(pref));
68335c4bbdfSmrg
68435c4bbdfSmrg    /* Now try and find a ~/.xwinrc file */
68535c4bbdfSmrg    home = getenv("HOME");
68635c4bbdfSmrg    if (home) {
68735c4bbdfSmrg        strcpy(fname, home);
68835c4bbdfSmrg        if (fname[strlen(fname) - 1] != '/')
68935c4bbdfSmrg            strcat(fname, "/");
69035c4bbdfSmrg        strcat(fname, ".XWinrc");
69135c4bbdfSmrg        parsed = winPrefsLoadPreferences(fname);
69205b261ecSmrg    }
69305b261ecSmrg
69435c4bbdfSmrg    /* No home file found, check system default */
69535c4bbdfSmrg    if (!parsed) {
69635c4bbdfSmrg        char buffer[MAX_PATH];
69735c4bbdfSmrg
69805b261ecSmrg#ifdef RELOCATE_PROJECTROOT
69935c4bbdfSmrg        snprintf(buffer, sizeof(buffer), "%s\\system.XWinrc", winGetBaseDir());
70005b261ecSmrg#else
70135c4bbdfSmrg        strncpy(buffer, SYSCONFDIR "/X11/system.XWinrc", sizeof(buffer));
70205b261ecSmrg#endif
70335c4bbdfSmrg        buffer[sizeof(buffer) - 1] = 0;
70435c4bbdfSmrg        parsed = winPrefsLoadPreferences(buffer);
70505b261ecSmrg    }
70605b261ecSmrg
70735c4bbdfSmrg    /* Neither user nor system configuration found, or were badly formed */
70835c4bbdfSmrg    if (!parsed) {
70935c4bbdfSmrg        ErrorF
71035c4bbdfSmrg            ("LoadPreferences: See \"man XWinrc\" to customize the XWin menu.\n");
71135c4bbdfSmrg        parsed = winPrefsLoadPreferences(NULL);
71205b261ecSmrg    }
71305b261ecSmrg
71435c4bbdfSmrg    /* Setup a DISPLAY environment variable, need to allocate on heap */
71535c4bbdfSmrg    /* because putenv doesn't copy the argument... */
71635c4bbdfSmrg    winGetDisplayName(szDisplay, 0);
71735c4bbdfSmrg    szEnvDisplay = (char *) (malloc(strlen(szDisplay) + strlen("DISPLAY=") + 1));
71835c4bbdfSmrg    if (szEnvDisplay) {
71935c4bbdfSmrg        snprintf(szEnvDisplay, 512, "DISPLAY=%s", szDisplay);
72035c4bbdfSmrg        putenv(szEnvDisplay);
72105b261ecSmrg    }
72205b261ecSmrg
72335c4bbdfSmrg    /* Replace any "%display%" in menu commands with display string */
72435c4bbdfSmrg    for (i = 0; i < pref.menuItems; i++) {
72535c4bbdfSmrg        for (j = 0; j < pref.menu[i].menuItems; j++) {
72635c4bbdfSmrg            if (pref.menu[i].menuItem[j].cmd == CMD_EXEC) {
72735c4bbdfSmrg                srcParam = pref.menu[i].menuItem[j].param;
72835c4bbdfSmrg                dstParam = param;
72935c4bbdfSmrg                while (*srcParam) {
73035c4bbdfSmrg                    if (!strncmp(srcParam, "%display%", 9)) {
73135c4bbdfSmrg                        memcpy(dstParam, szDisplay, strlen(szDisplay));
73235c4bbdfSmrg                        dstParam += strlen(szDisplay);
73335c4bbdfSmrg                        srcParam += 9;
73435c4bbdfSmrg                    }
73535c4bbdfSmrg                    else {
73635c4bbdfSmrg                        *dstParam = *srcParam;
73735c4bbdfSmrg                        dstParam++;
73835c4bbdfSmrg                        srcParam++;
73935c4bbdfSmrg                    }
74035c4bbdfSmrg                }
74135c4bbdfSmrg                *dstParam = 0;
74235c4bbdfSmrg                strcpy(pref.menu[i].menuItem[j].param, param);
74335c4bbdfSmrg            }                   /* cmd==cmd_exec */
74435c4bbdfSmrg        }                       /* for all menuitems */
74535c4bbdfSmrg    }                           /* for all menus */
74605b261ecSmrg
74705b261ecSmrg}
7486747b715Smrg
7496747b715Smrg/*
7506747b715Smrg * Check for a match of the window class to one specified in the
7516747b715Smrg * STYLES{} section in the prefs file, and return the style type
7526747b715Smrg */
7536747b715Smrgunsigned long
75435c4bbdfSmrgwinOverrideStyle(char *res_name, char *res_class, char *wmName)
7556747b715Smrg{
75635c4bbdfSmrg    int i;
75735c4bbdfSmrg
75835c4bbdfSmrg    for (i = 0; i < pref.styleItems; i++) {
75935c4bbdfSmrg        if ((res_name && !strcmp(pref.style[i].match, res_name)) ||
76035c4bbdfSmrg            (res_class && !strcmp(pref.style[i].match, res_class)) ||
76135c4bbdfSmrg            (wmName && strstr(wmName, pref.style[i].match))) {
76235c4bbdfSmrg            if (pref.style[i].type)
76335c4bbdfSmrg                return pref.style[i].type;
76435c4bbdfSmrg        }
76535c4bbdfSmrg    }
7666747b715Smrg
76735c4bbdfSmrg    /* Didn't find the style, fail gracefully */
7686747b715Smrg    return STYLE_NONE;
7696747b715Smrg}
770