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>
40ed6184dfSmrg#include <sys/cygwin.h>
4105b261ecSmrg#endif
4205b261ecSmrg#include "win.h"
4305b261ecSmrg
4405b261ecSmrg#include <X11/Xwindows.h>
4505b261ecSmrg#include <shellapi.h>
4605b261ecSmrg
4705b261ecSmrg#include "winprefs.h"
4835c4bbdfSmrg#include "windisplay.h"
4905b261ecSmrg#include "winmultiwindowclass.h"
501b5d61b8Smrg#include "winmultiwindowicons.h"
5105b261ecSmrg
5205b261ecSmrg/* Where will the custom menu commands start counting from? */
5305b261ecSmrg#define STARTMENUID WM_USER
5405b261ecSmrg
5505b261ecSmrgextern const char *winGetBaseDir(void);
5605b261ecSmrg
5735c4bbdfSmrg/* From winprefslex.l, the real parser */
5835c4bbdfSmrgextern int parse_file(FILE * fp);
5905b261ecSmrg
6005b261ecSmrg/* Currently in use command ID, incremented each new menu item created */
6105b261ecSmrgstatic int g_cmdid = STARTMENUID;
6205b261ecSmrg
6305b261ecSmrg/*
6405b261ecSmrg * Creates or appends a menu from a MENUPARSED structure
6505b261ecSmrg */
6605b261ecSmrgstatic HMENU
6735c4bbdfSmrgMakeMenu(char *name, HMENU editMenu, int editItem)
6805b261ecSmrg{
6935c4bbdfSmrg    int i;
7035c4bbdfSmrg    int item;
7135c4bbdfSmrg    MENUPARSED *m;
7235c4bbdfSmrg    HMENU hmenu, hsub;
7335c4bbdfSmrg
7435c4bbdfSmrg    for (i = 0; i < pref.menuItems; i++) {
7535c4bbdfSmrg        if (!strcmp(name, pref.menu[i].menuName))
7635c4bbdfSmrg            break;
7705b261ecSmrg    }
7835c4bbdfSmrg
7935c4bbdfSmrg    /* Didn't find a match, bummer */
8035c4bbdfSmrg    if (i == pref.menuItems) {
8135c4bbdfSmrg        ErrorF("MakeMenu: Can't find menu %s\n", name);
8235c4bbdfSmrg        return NULL;
8305b261ecSmrg    }
8405b261ecSmrg
8535c4bbdfSmrg    m = &(pref.menu[i]);
8635c4bbdfSmrg
8735c4bbdfSmrg    if (editMenu) {
8835c4bbdfSmrg        hmenu = editMenu;
8935c4bbdfSmrg        item = editItem;
9005b261ecSmrg    }
9135c4bbdfSmrg    else {
9235c4bbdfSmrg        hmenu = CreatePopupMenu();
9335c4bbdfSmrg        if (!hmenu) {
9435c4bbdfSmrg            ErrorF("MakeMenu: Unable to CreatePopupMenu() %s\n", name);
9535c4bbdfSmrg            return NULL;
9635c4bbdfSmrg        }
9735c4bbdfSmrg        item = 0;
9805b261ecSmrg    }
9905b261ecSmrg
10035c4bbdfSmrg    /* Add the menu items */
10135c4bbdfSmrg    for (i = 0; i < m->menuItems; i++) {
10235c4bbdfSmrg        /* Only assign IDs one time... */
10335c4bbdfSmrg        if (m->menuItem[i].commandID == 0)
10435c4bbdfSmrg            m->menuItem[i].commandID = g_cmdid++;
10535c4bbdfSmrg
10635c4bbdfSmrg        switch (m->menuItem[i].cmd) {
10735c4bbdfSmrg        case CMD_EXEC:
10835c4bbdfSmrg        case CMD_ALWAYSONTOP:
10935c4bbdfSmrg        case CMD_RELOAD:
11035c4bbdfSmrg            InsertMenu(hmenu,
11135c4bbdfSmrg                       item,
11235c4bbdfSmrg                       MF_BYPOSITION | MF_ENABLED | MF_STRING,
11335c4bbdfSmrg                       m->menuItem[i].commandID, m->menuItem[i].text);
11435c4bbdfSmrg            break;
11535c4bbdfSmrg
11635c4bbdfSmrg        case CMD_SEPARATOR:
11735c4bbdfSmrg            InsertMenu(hmenu, item, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
11835c4bbdfSmrg            break;
11935c4bbdfSmrg
12035c4bbdfSmrg        case CMD_MENU:
12135c4bbdfSmrg            /* Recursive! */
12235c4bbdfSmrg            hsub = MakeMenu(m->menuItem[i].param, 0, 0);
12335c4bbdfSmrg            if (hsub)
12435c4bbdfSmrg                InsertMenu(hmenu,
12535c4bbdfSmrg                           item,
12635c4bbdfSmrg                           MF_BYPOSITION | MF_POPUP | MF_ENABLED | MF_STRING,
12735c4bbdfSmrg                           (UINT_PTR) hsub, m->menuItem[i].text);
12835c4bbdfSmrg            break;
12935c4bbdfSmrg        }
13035c4bbdfSmrg
13135c4bbdfSmrg        /* If item==-1 (means to add at end of menu) don't increment) */
13235c4bbdfSmrg        if (item >= 0)
13335c4bbdfSmrg            item++;
13405b261ecSmrg    }
13505b261ecSmrg
13635c4bbdfSmrg    return hmenu;
13705b261ecSmrg}
13805b261ecSmrg
13905b261ecSmrg/*
14005b261ecSmrg * Callback routine that is executed once per window class.
14105b261ecSmrg * Removes or creates custom window settings depending on LPARAM
14205b261ecSmrg */
14305b261ecSmrgstatic wBOOL CALLBACK
14435c4bbdfSmrgReloadEnumWindowsProc(HWND hwnd, LPARAM lParam)
14505b261ecSmrg{
14635c4bbdfSmrg    HICON hicon;
14705b261ecSmrg
14835c4bbdfSmrg    if (!hwnd) {
14935c4bbdfSmrg        ErrorF("ReloadEnumWindowsProc: hwnd==NULL!\n");
15035c4bbdfSmrg        return FALSE;
15135c4bbdfSmrg    }
15235c4bbdfSmrg
15335c4bbdfSmrg    /* It's our baby, either clean or dirty it */
15435c4bbdfSmrg    if (lParam == FALSE) {
15535c4bbdfSmrg        /* Reset the window's icon to undefined. */
15635c4bbdfSmrg        hicon = (HICON) SendMessage(hwnd, WM_SETICON, ICON_BIG, 0);
15705b261ecSmrg
15835c4bbdfSmrg        /* If the old icon is generated on-the-fly, get rid of it, will regen */
15935c4bbdfSmrg        winDestroyIcon(hicon);
16005b261ecSmrg
16135c4bbdfSmrg        /* Same for the small icon */
16235c4bbdfSmrg        hicon = (HICON) SendMessage(hwnd, WM_SETICON, ICON_SMALL, 0);
16335c4bbdfSmrg        winDestroyIcon(hicon);
16405b261ecSmrg
16535c4bbdfSmrg        /* Remove any menu additions; bRevert=TRUE destroys any modified menus */
16635c4bbdfSmrg        GetSystemMenu(hwnd, TRUE);
1676747b715Smrg
16835c4bbdfSmrg        /* This window is now clean of our taint (but with undefined icons) */
16905b261ecSmrg    }
17035c4bbdfSmrg    else {
17135c4bbdfSmrg        /* Send a message to WM thread telling it re-evaluate the icon for this window */
17235c4bbdfSmrg        {
17335c4bbdfSmrg            winWMMessageRec wmMsg;
1746747b715Smrg
17535c4bbdfSmrg            WindowPtr pWin = GetProp(hwnd, WIN_WINDOW_PROP);
17605b261ecSmrg
17735c4bbdfSmrg            if (pWin) {
17835c4bbdfSmrg                winPrivWinPtr pWinPriv = winGetWindowPriv(pWin);
17935c4bbdfSmrg                winPrivScreenPtr s_pScreenPriv = pWinPriv->pScreenPriv;
18035c4bbdfSmrg
18135c4bbdfSmrg                wmMsg.msg = WM_WM_ICON_EVENT;
18235c4bbdfSmrg                wmMsg.hwndWindow = hwnd;
18335c4bbdfSmrg                wmMsg.iWindow = (Window) (INT_PTR) GetProp(hwnd, WIN_WID_PROP);
18435c4bbdfSmrg
18535c4bbdfSmrg                winSendMessageToWM(s_pScreenPriv->pWMInfo, &wmMsg);
18635c4bbdfSmrg            }
18735c4bbdfSmrg        }
18835c4bbdfSmrg
18935c4bbdfSmrg        /* Update the system menu for this window */
19035c4bbdfSmrg        SetupSysMenu(hwnd);
19135c4bbdfSmrg
19235c4bbdfSmrg        /* That was easy... */
19305b261ecSmrg    }
19405b261ecSmrg
19535c4bbdfSmrg    return TRUE;
19605b261ecSmrg}
19705b261ecSmrg
19805b261ecSmrg/*
19905b261ecSmrg * Removes any custom icons in classes, custom menus, etc.
20005b261ecSmrg * Frees all members in pref structure.
20105b261ecSmrg * Reloads the preferences file.
20205b261ecSmrg * Set custom icons and menus again.
20305b261ecSmrg */
20405b261ecSmrgstatic void
2051b5d61b8SmrgReloadPrefs(winPrivScreenPtr pScreenPriv)
20605b261ecSmrg{
20735c4bbdfSmrg    int i;
20805b261ecSmrg
2091b5d61b8Smrg    winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo;
2101b5d61b8Smrg
21135c4bbdfSmrg    /* First, iterate over all windows, deleting their icons and custom menus.
21235c4bbdfSmrg     * This is really only needed because winDestroyIcon() will try to
21335c4bbdfSmrg     * destroy the old global icons, which will have changed.
21435c4bbdfSmrg     * It is probably better to set a windows USER_DATA to flag locally defined
21535c4bbdfSmrg     * icons, and use that to accurately know when to destroy old icons.
21635c4bbdfSmrg     */
2171b5d61b8Smrg    if (pScreenInfo->fMultiWindow)
2181b5d61b8Smrg        EnumThreadWindows(g_dwCurrentThreadID, ReloadEnumWindowsProc, FALSE);
21935c4bbdfSmrg
22035c4bbdfSmrg    /* Now, free/clear all info from our prefs structure */
22135c4bbdfSmrg    for (i = 0; i < pref.menuItems; i++)
22235c4bbdfSmrg        free(pref.menu[i].menuItem);
22335c4bbdfSmrg    free(pref.menu);
22435c4bbdfSmrg    pref.menu = NULL;
22535c4bbdfSmrg    pref.menuItems = 0;
22635c4bbdfSmrg
22735c4bbdfSmrg    pref.rootMenuName[0] = 0;
22835c4bbdfSmrg
22935c4bbdfSmrg    free(pref.sysMenu);
23035c4bbdfSmrg    pref.sysMenuItems = 0;
23135c4bbdfSmrg
23235c4bbdfSmrg    pref.defaultSysMenuName[0] = 0;
23335c4bbdfSmrg    pref.defaultSysMenuPos = 0;
23435c4bbdfSmrg
23535c4bbdfSmrg    pref.iconDirectory[0] = 0;
23635c4bbdfSmrg    pref.defaultIconName[0] = 0;
23735c4bbdfSmrg    pref.trayIconName[0] = 0;
23835c4bbdfSmrg
23935c4bbdfSmrg    for (i = 0; i < pref.iconItems; i++)
24035c4bbdfSmrg        if (pref.icon[i].hicon)
24135c4bbdfSmrg            DestroyIcon((HICON) pref.icon[i].hicon);
24235c4bbdfSmrg    free(pref.icon);
24335c4bbdfSmrg    pref.icon = NULL;
24435c4bbdfSmrg    pref.iconItems = 0;
24535c4bbdfSmrg
24635c4bbdfSmrg    /* Free global default X icon */
24735c4bbdfSmrg    if (g_hIconX)
24835c4bbdfSmrg        DestroyIcon(g_hIconX);
24935c4bbdfSmrg    if (g_hSmallIconX)
25035c4bbdfSmrg        DestroyIcon(g_hSmallIconX);
25135c4bbdfSmrg
25235c4bbdfSmrg    /* Reset the custom command IDs */
25335c4bbdfSmrg    g_cmdid = STARTMENUID;
25435c4bbdfSmrg
25535c4bbdfSmrg    /* Load the updated resource file */
25635c4bbdfSmrg    LoadPreferences();
25735c4bbdfSmrg
25835c4bbdfSmrg    g_hIconX = NULL;
25935c4bbdfSmrg    g_hSmallIconX = NULL;
26005b261ecSmrg
2611b5d61b8Smrg    if (pScreenInfo->fMultiWindow) {
2621b5d61b8Smrg        winInitGlobalIcons();
26335c4bbdfSmrg
2641b5d61b8Smrg        /* Rebuild the icons and menus */
2651b5d61b8Smrg        EnumThreadWindows(g_dwCurrentThreadID, ReloadEnumWindowsProc, TRUE);
2661b5d61b8Smrg    }
26705b261ecSmrg
26835c4bbdfSmrg    /* Whew, done */
26905b261ecSmrg}
27005b261ecSmrg
27105b261ecSmrg/*
27205b261ecSmrg * Check/uncheck the ALWAYSONTOP items in this menu
27305b261ecSmrg */
27405b261ecSmrgvoid
27535c4bbdfSmrgHandleCustomWM_INITMENU(HWND hwnd, HMENU hmenu)
27605b261ecSmrg{
27735c4bbdfSmrg    DWORD dwExStyle;
27835c4bbdfSmrg    int i, j;
27935c4bbdfSmrg
28035c4bbdfSmrg    if (!hwnd || !hmenu)
28135c4bbdfSmrg        return;
28235c4bbdfSmrg
28335c4bbdfSmrg    if (GetWindowLongPtr(hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST)
28435c4bbdfSmrg        dwExStyle = MF_BYCOMMAND | MF_CHECKED;
28535c4bbdfSmrg    else
28635c4bbdfSmrg        dwExStyle = MF_BYCOMMAND | MF_UNCHECKED;
28735c4bbdfSmrg
28835c4bbdfSmrg    for (i = 0; i < pref.menuItems; i++)
28935c4bbdfSmrg        for (j = 0; j < pref.menu[i].menuItems; j++)
29035c4bbdfSmrg            if (pref.menu[i].menuItem[j].cmd == CMD_ALWAYSONTOP)
29135c4bbdfSmrg                CheckMenuItem(hmenu, pref.menu[i].menuItem[j].commandID,
29235c4bbdfSmrg                              dwExStyle);
29335c4bbdfSmrg
29405b261ecSmrg}
29535c4bbdfSmrg
29605b261ecSmrg/*
29705b261ecSmrg * Searches for the custom WM_COMMAND command ID and performs action.
298ed6184dfSmrg * Return TRUE if command is processed, FALSE otherwise.
29905b261ecSmrg */
30005b261ecSmrgBool
3011b5d61b8SmrgHandleCustomWM_COMMAND(HWND hwnd, WORD command, winPrivScreenPtr pScreenPriv)
30205b261ecSmrg{
30335c4bbdfSmrg    int i, j;
30435c4bbdfSmrg    MENUPARSED *m;
30535c4bbdfSmrg    DWORD dwExStyle;
30635c4bbdfSmrg
30735c4bbdfSmrg    if (!command)
30835c4bbdfSmrg        return FALSE;
30935c4bbdfSmrg
31035c4bbdfSmrg    for (i = 0; i < pref.menuItems; i++) {
31135c4bbdfSmrg        m = &(pref.menu[i]);
31235c4bbdfSmrg        for (j = 0; j < m->menuItems; j++) {
31335c4bbdfSmrg            if (command == m->menuItem[j].commandID) {
31435c4bbdfSmrg                /* Match! */
31535c4bbdfSmrg                switch (m->menuItem[j].cmd) {
31605b261ecSmrg#ifdef __CYGWIN__
31735c4bbdfSmrg                case CMD_EXEC:
31835c4bbdfSmrg                    if (fork() == 0) {
31935c4bbdfSmrg                        struct rlimit rl;
32035c4bbdfSmrg                        int fd;
32135c4bbdfSmrg
32235c4bbdfSmrg                        /* Close any open descriptors except for STD* */
32335c4bbdfSmrg                        getrlimit(RLIMIT_NOFILE, &rl);
32435c4bbdfSmrg                        for (fd = STDERR_FILENO + 1; fd < rl.rlim_cur; fd++)
32535c4bbdfSmrg                            close(fd);
32635c4bbdfSmrg
32735c4bbdfSmrg                        /* Disassociate any TTYs */
32835c4bbdfSmrg                        setsid();
32935c4bbdfSmrg
33035c4bbdfSmrg                        execl("/bin/sh",
33135c4bbdfSmrg                              "/bin/sh", "-c", m->menuItem[j].param, NULL);
33235c4bbdfSmrg                        exit(0);
33335c4bbdfSmrg                    }
33435c4bbdfSmrg                    else
33535c4bbdfSmrg                        return TRUE;
33635c4bbdfSmrg                    break;
33705b261ecSmrg#else
33835c4bbdfSmrg                case CMD_EXEC:
33935c4bbdfSmrg                {
34035c4bbdfSmrg                    /* Start process without console window */
34135c4bbdfSmrg                    STARTUPINFO start;
34235c4bbdfSmrg                    PROCESS_INFORMATION child;
34335c4bbdfSmrg
34435c4bbdfSmrg                    memset(&start, 0, sizeof(start));
34535c4bbdfSmrg                    start.cb = sizeof(start);
34635c4bbdfSmrg                    start.dwFlags = STARTF_USESHOWWINDOW;
34735c4bbdfSmrg                    start.wShowWindow = SW_HIDE;
34835c4bbdfSmrg
34935c4bbdfSmrg                    memset(&child, 0, sizeof(child));
35035c4bbdfSmrg
35135c4bbdfSmrg                    if (CreateProcess
35235c4bbdfSmrg                        (NULL, m->menuItem[j].param, NULL, NULL, FALSE, 0, NULL,
35335c4bbdfSmrg                         NULL, &start, &child)) {
35435c4bbdfSmrg                        CloseHandle(child.hThread);
35535c4bbdfSmrg                        CloseHandle(child.hProcess);
35635c4bbdfSmrg                    }
35735c4bbdfSmrg                    else
35835c4bbdfSmrg                        MessageBox(NULL, m->menuItem[j].param,
35935c4bbdfSmrg                                   "Mingrc Exec Command Error!",
36035c4bbdfSmrg                                   MB_OK | MB_ICONEXCLAMATION);
36135c4bbdfSmrg                }
36235c4bbdfSmrg                    return TRUE;
36305b261ecSmrg#endif
36435c4bbdfSmrg                case CMD_ALWAYSONTOP:
36535c4bbdfSmrg                    if (!hwnd)
36635c4bbdfSmrg                        return FALSE;
36735c4bbdfSmrg
36835c4bbdfSmrg                    /* Get extended window style */
36935c4bbdfSmrg                    dwExStyle = GetWindowLongPtr(hwnd, GWL_EXSTYLE);
37035c4bbdfSmrg
37135c4bbdfSmrg                    /* Handle topmost windows */
37235c4bbdfSmrg                    if (dwExStyle & WS_EX_TOPMOST)
37335c4bbdfSmrg                        SetWindowPos(hwnd,
37435c4bbdfSmrg                                     HWND_NOTOPMOST,
37535c4bbdfSmrg                                     0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
37635c4bbdfSmrg                    else
37735c4bbdfSmrg                        SetWindowPos(hwnd,
37835c4bbdfSmrg                                     HWND_TOPMOST,
37935c4bbdfSmrg                                     0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
3801b5d61b8Smrg                    {
3811b5d61b8Smrg                        winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo;
3821b5d61b8Smrg                        if (pScreenInfo->fMultiWindow)
3831b5d61b8Smrg                            /* Reflect the changed Z order */
3841b5d61b8Smrg                            winReorderWindowsMultiWindow();
3851b5d61b8Smrg                    }
38635c4bbdfSmrg                    return TRUE;
38735c4bbdfSmrg
38835c4bbdfSmrg                case CMD_RELOAD:
3891b5d61b8Smrg                    ReloadPrefs(pScreenPriv);
39035c4bbdfSmrg                    return TRUE;
39135c4bbdfSmrg
39235c4bbdfSmrg                default:
39335c4bbdfSmrg                    return FALSE;
39435c4bbdfSmrg                }
39535c4bbdfSmrg            }                   /* match */
39635c4bbdfSmrg        }                       /* for j */
39735c4bbdfSmrg    }                           /* for i */
39805b261ecSmrg
39935c4bbdfSmrg    return FALSE;
40035c4bbdfSmrg}
40105b261ecSmrg
40205b261ecSmrg/*
40305b261ecSmrg * Add the default or a custom menu depending on the class match
40405b261ecSmrg */
40505b261ecSmrgvoid
40635c4bbdfSmrgSetupSysMenu(HWND hwnd)
40705b261ecSmrg{
40835c4bbdfSmrg    HMENU sys;
40935c4bbdfSmrg    int i;
41035c4bbdfSmrg    WindowPtr pWin;
41135c4bbdfSmrg    char *res_name, *res_class;
41235c4bbdfSmrg
41335c4bbdfSmrg    if (!hwnd)
41435c4bbdfSmrg        return;
41535c4bbdfSmrg
41635c4bbdfSmrg    pWin = GetProp(hwnd, WIN_WINDOW_PROP);
41735c4bbdfSmrg
41835c4bbdfSmrg    sys = GetSystemMenu(hwnd, FALSE);
41935c4bbdfSmrg    if (!sys)
42035c4bbdfSmrg        return;
42135c4bbdfSmrg
42235c4bbdfSmrg    if (pWin) {
42335c4bbdfSmrg        /* First see if there's a class match... */
42435c4bbdfSmrg        if (winMultiWindowGetClassHint(pWin, &res_name, &res_class)) {
42535c4bbdfSmrg            for (i = 0; i < pref.sysMenuItems; i++) {
42635c4bbdfSmrg                if (!strcmp(pref.sysMenu[i].match, res_name) ||
42735c4bbdfSmrg                    !strcmp(pref.sysMenu[i].match, res_class)) {
42835c4bbdfSmrg                    free(res_name);
42935c4bbdfSmrg                    free(res_class);
43035c4bbdfSmrg
43135c4bbdfSmrg                    MakeMenu(pref.sysMenu[i].menuName, sys,
43235c4bbdfSmrg                             pref.sysMenu[i].menuPos == AT_START ? 0 : -1);
43335c4bbdfSmrg                    return;
43435c4bbdfSmrg                }
43535c4bbdfSmrg            }
43635c4bbdfSmrg
43735c4bbdfSmrg            /* No match, just free alloc'd strings */
43835c4bbdfSmrg            free(res_name);
43935c4bbdfSmrg            free(res_class);
44035c4bbdfSmrg        }                       /* Found wm_class */
44135c4bbdfSmrg    }                           /* if pwin */
44235c4bbdfSmrg
44335c4bbdfSmrg    /* Fallback to system default */
44435c4bbdfSmrg    if (pref.defaultSysMenuName[0]) {
44535c4bbdfSmrg        if (pref.defaultSysMenuPos == AT_START)
44635c4bbdfSmrg            MakeMenu(pref.defaultSysMenuName, sys, 0);
44735c4bbdfSmrg        else
44835c4bbdfSmrg            MakeMenu(pref.defaultSysMenuName, sys, -1);
44905b261ecSmrg    }
45005b261ecSmrg}
45105b261ecSmrg
45205b261ecSmrg/*
45305b261ecSmrg * Possibly add a menu to the toolbar icon
45405b261ecSmrg */
45505b261ecSmrgvoid
45635c4bbdfSmrgSetupRootMenu(HMENU root)
45705b261ecSmrg{
45835c4bbdfSmrg    if (!root)
45935c4bbdfSmrg        return;
46005b261ecSmrg
46135c4bbdfSmrg    if (pref.rootMenuName[0]) {
46235c4bbdfSmrg        MakeMenu(pref.rootMenuName, root, 0);
46305b261ecSmrg    }
46405b261ecSmrg}
46505b261ecSmrg
46605b261ecSmrg/*
46705b261ecSmrg * Check for and return an overridden default ICON specified in the prefs
46805b261ecSmrg */
4696747b715SmrgHICON
47005b261ecSmrgwinOverrideDefaultIcon(int size)
47105b261ecSmrg{
47235c4bbdfSmrg    HICON hicon;
47335c4bbdfSmrg
47435c4bbdfSmrg    if (pref.defaultIconName[0]) {
475ed6184dfSmrg        hicon = LoadImageComma(pref.defaultIconName, pref.iconDirectory, size, size, 0);
47635c4bbdfSmrg        if (hicon == NULL)
47735c4bbdfSmrg            ErrorF("winOverrideDefaultIcon: LoadImageComma(%s) failed\n",
47835c4bbdfSmrg                   pref.defaultIconName);
47935c4bbdfSmrg
48035c4bbdfSmrg        return hicon;
48105b261ecSmrg    }
48205b261ecSmrg
48335c4bbdfSmrg    return 0;
48405b261ecSmrg}
48505b261ecSmrg
48605b261ecSmrg/*
48705b261ecSmrg * Return the HICON to use in the taskbar notification area
48805b261ecSmrg */
4896747b715SmrgHICON
49005b261ecSmrgwinTaskbarIcon(void)
49105b261ecSmrg{
49235c4bbdfSmrg    HICON hicon;
49335c4bbdfSmrg
49435c4bbdfSmrg    hicon = 0;
49535c4bbdfSmrg    /* First try and load an overridden, if success then return it */
49635c4bbdfSmrg    if (pref.trayIconName[0]) {
497ed6184dfSmrg        hicon = LoadImageComma(pref.trayIconName, pref.iconDirectory,
49835c4bbdfSmrg                               GetSystemMetrics(SM_CXSMICON),
49935c4bbdfSmrg                               GetSystemMetrics(SM_CYSMICON), 0);
500ed6184dfSmrg        if (hicon == NULL)
501ed6184dfSmrg            ErrorF("winTaskbarIcon: LoadImageComma(%s) failed\n",
502ed6184dfSmrg                   pref.trayIconName);
50305b261ecSmrg    }
50405b261ecSmrg
50535c4bbdfSmrg    /* Otherwise return the default */
50635c4bbdfSmrg    if (!hicon)
50735c4bbdfSmrg        hicon = (HICON) LoadImage(g_hInstance,
50835c4bbdfSmrg                                  MAKEINTRESOURCE(IDI_XWIN),
50935c4bbdfSmrg                                  IMAGE_ICON,
51035c4bbdfSmrg                                  GetSystemMetrics(SM_CXSMICON),
51135c4bbdfSmrg                                  GetSystemMetrics(SM_CYSMICON), 0);
51205b261ecSmrg
51335c4bbdfSmrg    return hicon;
51405b261ecSmrg}
51505b261ecSmrg
51605b261ecSmrg/*
517ed6184dfSmrg * Handle comma-ified icon names
518ed6184dfSmrg *
51905b261ecSmrg * Parse a filename to extract an icon:
52005b261ecSmrg *  If fname is exactly ",nnn" then extract icon from our resource
52105b261ecSmrg *  else if it is "file,nnn" then extract icon nnn from that file
52205b261ecSmrg *  else try to load it as an .ico file and if that fails return NULL
52305b261ecSmrg */
524ed6184dfSmrgHICON
525ed6184dfSmrgLoadImageComma(char *fname, char *iconDirectory, int sx, int sy, int flags)
52605b261ecSmrg{
52735c4bbdfSmrg    HICON hicon;
52835c4bbdfSmrg    int i;
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 {
544ed6184dfSmrg        char *file = malloc(PATH_MAX + NAME_MAX + 2);
545ed6184dfSmrg        Bool convert = FALSE;
546ed6184dfSmrg
547ed6184dfSmrg        if (!file)
548ed6184dfSmrg            return NULL;
549ed6184dfSmrg
55035c4bbdfSmrg        file[0] = 0;
551ed6184dfSmrg
552ed6184dfSmrg        /* If fname starts 'X:\', it's an absolute Windows path, do nothing */
55335c4bbdfSmrg        if (!(fname[0] && fname[1] == ':' && fname[2] == '\\')) {
554ed6184dfSmrg#ifdef  __CYGWIN__
555ed6184dfSmrg            /* If fname starts with '/', it's an absolute cygwin path, we'll
556ed6184dfSmrg               need to convert it */
557ed6184dfSmrg            if (fname[0] == '/') {
558ed6184dfSmrg                convert = TRUE;
559ed6184dfSmrg            }
560ed6184dfSmrg            else
561ed6184dfSmrg#endif
562ed6184dfSmrg            if (iconDirectory) {
563ed6184dfSmrg                /* Otherwise, prepend the default icon directory, which
564ed6184dfSmrg                   currently must be in absolute Windows path form */
565ed6184dfSmrg                strcpy(file, iconDirectory);
566ed6184dfSmrg                if (iconDirectory[0])
567ed6184dfSmrg                    if (iconDirectory[strlen(iconDirectory) - 1] != '\\')
568ed6184dfSmrg                        strcat(file, "\\");
569ed6184dfSmrg            }
57035c4bbdfSmrg        }
57135c4bbdfSmrg        strcat(file, fname);
57235c4bbdfSmrg
573ed6184dfSmrg        /* Trim off any ',index' */
57435c4bbdfSmrg        if (strrchr(file, ',')) {
57535c4bbdfSmrg            *(strrchr(file, ',')) = 0;  /* End string at comma */
57635c4bbdfSmrg            i = atoi(strrchr(fname, ',') + 1);
57735c4bbdfSmrg        }
57835c4bbdfSmrg        else {
579ed6184dfSmrg            i = -1;
580ed6184dfSmrg        }
58135c4bbdfSmrg
582ed6184dfSmrg#ifdef  __CYGWIN__
583ed6184dfSmrg        /* Convert from Cygwin path to Windows path */
584ed6184dfSmrg        if (convert) {
585ed6184dfSmrg            char *converted_file = cygwin_create_path(CCP_POSIX_TO_WIN_A | CCP_ABSOLUTE, file);
586ed6184dfSmrg            if (converted_file) {
587ed6184dfSmrg                free(file);
588ed6184dfSmrg                file = converted_file;
589ed6184dfSmrg            }
590ed6184dfSmrg        }
591ed6184dfSmrg#endif
592ed6184dfSmrg
593ed6184dfSmrg        if (i >= 0) {
594ed6184dfSmrg            /* Specified as <fname>,<index> */
595ed6184dfSmrg            hicon = ExtractIcon(g_hInstance, file, i);
596ed6184dfSmrg        }
597ed6184dfSmrg        else {
598ed6184dfSmrg            /* Specified as just an .ico file */
59935c4bbdfSmrg            hicon = (HICON) LoadImage(NULL,
60035c4bbdfSmrg                                      file,
60135c4bbdfSmrg                                      IMAGE_ICON,
60235c4bbdfSmrg                                      sx, sy, LR_LOADFROMFILE | flags);
60305b261ecSmrg        }
604ed6184dfSmrg        free(file);
60505b261ecSmrg    }
60635c4bbdfSmrg    return hicon;
60705b261ecSmrg}
60805b261ecSmrg
60905b261ecSmrg/*
61005b261ecSmrg * Check for a match of the window class to one specified in the
61105b261ecSmrg * ICONS{} section in the prefs file, and load the icon from a file
61205b261ecSmrg */
6136747b715SmrgHICON
61435c4bbdfSmrgwinOverrideIcon(char *res_name, char *res_class, char *wmName)
61505b261ecSmrg{
61635c4bbdfSmrg    int i;
61735c4bbdfSmrg    HICON hicon;
61835c4bbdfSmrg
61935c4bbdfSmrg    for (i = 0; i < pref.iconItems; i++) {
62035c4bbdfSmrg        if ((res_name && !strcmp(pref.icon[i].match, res_name)) ||
62135c4bbdfSmrg            (res_class && !strcmp(pref.icon[i].match, res_class)) ||
62235c4bbdfSmrg            (wmName && strstr(wmName, pref.icon[i].match))) {
62335c4bbdfSmrg            if (pref.icon[i].hicon)
62435c4bbdfSmrg                return pref.icon[i].hicon;
62535c4bbdfSmrg
626ed6184dfSmrg            hicon = LoadImageComma(pref.icon[i].iconFile, pref.iconDirectory, 0, 0, LR_DEFAULTSIZE);
62735c4bbdfSmrg            if (hicon == NULL)
62835c4bbdfSmrg                ErrorF("winOverrideIcon: LoadImageComma(%s) failed\n",
62935c4bbdfSmrg                       pref.icon[i].iconFile);
63035c4bbdfSmrg
63135c4bbdfSmrg            pref.icon[i].hicon = hicon;
63235c4bbdfSmrg            return hicon;
63335c4bbdfSmrg        }
63435c4bbdfSmrg    }
63505b261ecSmrg
63635c4bbdfSmrg    /* Didn't find the icon, fail gracefully */
63705b261ecSmrg    return 0;
63805b261ecSmrg}
63905b261ecSmrg
64005b261ecSmrg/*
64105b261ecSmrg * Should we free this icon or leave it in memory (is it part of our
64205b261ecSmrg * ICONS{} overrides)?
64305b261ecSmrg */
64405b261ecSmrgint
64535c4bbdfSmrgwinIconIsOverride(HICON hicon)
64605b261ecSmrg{
64735c4bbdfSmrg    int i;
64835c4bbdfSmrg
64935c4bbdfSmrg    if (!hicon)
65035c4bbdfSmrg        return 0;
65105b261ecSmrg
65235c4bbdfSmrg    for (i = 0; i < pref.iconItems; i++)
65335c4bbdfSmrg        if ((HICON) pref.icon[i].hicon == hicon)
65435c4bbdfSmrg            return 1;
65505b261ecSmrg
65605b261ecSmrg    return 0;
65705b261ecSmrg}
65805b261ecSmrg
65935c4bbdfSmrg/*
66035c4bbdfSmrg * Open and parse the XWinrc config file @path.
66135c4bbdfSmrg * If @path is NULL, use the built-in default.
66235c4bbdfSmrg */
66335c4bbdfSmrgstatic int
66435c4bbdfSmrgwinPrefsLoadPreferences(const char *path)
66535c4bbdfSmrg{
66635c4bbdfSmrg    FILE *prefFile = NULL;
66735c4bbdfSmrg
66835c4bbdfSmrg    if (path)
66935c4bbdfSmrg        prefFile = fopen(path, "r");
67035c4bbdfSmrg#ifdef __CYGWIN__
67135c4bbdfSmrg    else {
67235c4bbdfSmrg        char defaultPrefs[] =
67335c4bbdfSmrg            "MENU rmenu {\n"
67435c4bbdfSmrg            "  \"How to customize this menu\" EXEC \"xterm +tb -e man XWinrc\"\n"
67535c4bbdfSmrg            "  \"Launch xterm\" EXEC xterm\n"
67635c4bbdfSmrg            "  \"Load .XWinrc\" RELOAD\n"
67735c4bbdfSmrg            "  SEPARATOR\n" "}\n" "\n" "ROOTMENU rmenu\n";
67835c4bbdfSmrg
67935c4bbdfSmrg        path = "built-in default";
68035c4bbdfSmrg        prefFile = fmemopen(defaultPrefs, strlen(defaultPrefs), "r");
68135c4bbdfSmrg    }
68235c4bbdfSmrg#endif
68305b261ecSmrg
68435c4bbdfSmrg    if (!prefFile) {
68535c4bbdfSmrg        ErrorF("LoadPreferences: %s not found\n", path);
68635c4bbdfSmrg        return FALSE;
68735c4bbdfSmrg    }
68835c4bbdfSmrg
68935c4bbdfSmrg    ErrorF("LoadPreferences: Loading %s\n", path);
69035c4bbdfSmrg
69135c4bbdfSmrg    if ((parse_file(prefFile)) != 0) {
69235c4bbdfSmrg        ErrorF("LoadPreferences: %s is badly formed!\n", path);
69335c4bbdfSmrg        fclose(prefFile);
69435c4bbdfSmrg        return FALSE;
69535c4bbdfSmrg    }
69635c4bbdfSmrg
69735c4bbdfSmrg    fclose(prefFile);
69835c4bbdfSmrg    return TRUE;
69935c4bbdfSmrg}
70005b261ecSmrg
70105b261ecSmrg/*
7026747b715Smrg * Try and open ~/.XWinrc and system.XWinrc
70305b261ecSmrg * Load it into prefs structure for use by other functions
70405b261ecSmrg */
70505b261ecSmrgvoid
70635c4bbdfSmrgLoadPreferences(void)
70705b261ecSmrg{
70835c4bbdfSmrg    char *home;
70935c4bbdfSmrg    char fname[PATH_MAX + NAME_MAX + 2];
71035c4bbdfSmrg    char szDisplay[512];
71135c4bbdfSmrg    char *szEnvDisplay;
71235c4bbdfSmrg    int i, j;
71335c4bbdfSmrg    char param[PARAM_MAX + 1];
71435c4bbdfSmrg    char *srcParam, *dstParam;
71535c4bbdfSmrg    int parsed = FALSE;
71635c4bbdfSmrg
71735c4bbdfSmrg    /* First, clear all preference settings */
71835c4bbdfSmrg    memset(&pref, 0, sizeof(pref));
71935c4bbdfSmrg
72035c4bbdfSmrg    /* Now try and find a ~/.xwinrc file */
72135c4bbdfSmrg    home = getenv("HOME");
72235c4bbdfSmrg    if (home) {
72335c4bbdfSmrg        strcpy(fname, home);
72435c4bbdfSmrg        if (fname[strlen(fname) - 1] != '/')
72535c4bbdfSmrg            strcat(fname, "/");
72635c4bbdfSmrg        strcat(fname, ".XWinrc");
72735c4bbdfSmrg        parsed = winPrefsLoadPreferences(fname);
72805b261ecSmrg    }
72905b261ecSmrg
73035c4bbdfSmrg    /* No home file found, check system default */
73135c4bbdfSmrg    if (!parsed) {
73235c4bbdfSmrg        char buffer[MAX_PATH];
73335c4bbdfSmrg
73405b261ecSmrg#ifdef RELOCATE_PROJECTROOT
73535c4bbdfSmrg        snprintf(buffer, sizeof(buffer), "%s\\system.XWinrc", winGetBaseDir());
73605b261ecSmrg#else
73735c4bbdfSmrg        strncpy(buffer, SYSCONFDIR "/X11/system.XWinrc", sizeof(buffer));
73805b261ecSmrg#endif
73935c4bbdfSmrg        buffer[sizeof(buffer) - 1] = 0;
74035c4bbdfSmrg        parsed = winPrefsLoadPreferences(buffer);
74105b261ecSmrg    }
74205b261ecSmrg
74335c4bbdfSmrg    /* Neither user nor system configuration found, or were badly formed */
74435c4bbdfSmrg    if (!parsed) {
74535c4bbdfSmrg        ErrorF
74635c4bbdfSmrg            ("LoadPreferences: See \"man XWinrc\" to customize the XWin menu.\n");
74735c4bbdfSmrg        parsed = winPrefsLoadPreferences(NULL);
74805b261ecSmrg    }
74905b261ecSmrg
75035c4bbdfSmrg    /* Setup a DISPLAY environment variable, need to allocate on heap */
75135c4bbdfSmrg    /* because putenv doesn't copy the argument... */
75235c4bbdfSmrg    winGetDisplayName(szDisplay, 0);
75335c4bbdfSmrg    szEnvDisplay = (char *) (malloc(strlen(szDisplay) + strlen("DISPLAY=") + 1));
75435c4bbdfSmrg    if (szEnvDisplay) {
75535c4bbdfSmrg        snprintf(szEnvDisplay, 512, "DISPLAY=%s", szDisplay);
75635c4bbdfSmrg        putenv(szEnvDisplay);
75705b261ecSmrg    }
75805b261ecSmrg
75935c4bbdfSmrg    /* Replace any "%display%" in menu commands with display string */
76035c4bbdfSmrg    for (i = 0; i < pref.menuItems; i++) {
76135c4bbdfSmrg        for (j = 0; j < pref.menu[i].menuItems; j++) {
76235c4bbdfSmrg            if (pref.menu[i].menuItem[j].cmd == CMD_EXEC) {
76335c4bbdfSmrg                srcParam = pref.menu[i].menuItem[j].param;
76435c4bbdfSmrg                dstParam = param;
76535c4bbdfSmrg                while (*srcParam) {
76635c4bbdfSmrg                    if (!strncmp(srcParam, "%display%", 9)) {
76735c4bbdfSmrg                        memcpy(dstParam, szDisplay, strlen(szDisplay));
76835c4bbdfSmrg                        dstParam += strlen(szDisplay);
76935c4bbdfSmrg                        srcParam += 9;
77035c4bbdfSmrg                    }
77135c4bbdfSmrg                    else {
77235c4bbdfSmrg                        *dstParam = *srcParam;
77335c4bbdfSmrg                        dstParam++;
77435c4bbdfSmrg                        srcParam++;
77535c4bbdfSmrg                    }
77635c4bbdfSmrg                }
77735c4bbdfSmrg                *dstParam = 0;
77835c4bbdfSmrg                strcpy(pref.menu[i].menuItem[j].param, param);
77935c4bbdfSmrg            }                   /* cmd==cmd_exec */
78035c4bbdfSmrg        }                       /* for all menuitems */
78135c4bbdfSmrg    }                           /* for all menus */
78205b261ecSmrg
78305b261ecSmrg}
7846747b715Smrg
7856747b715Smrg/*
7866747b715Smrg * Check for a match of the window class to one specified in the
7876747b715Smrg * STYLES{} section in the prefs file, and return the style type
7886747b715Smrg */
7896747b715Smrgunsigned long
79035c4bbdfSmrgwinOverrideStyle(char *res_name, char *res_class, char *wmName)
7916747b715Smrg{
79235c4bbdfSmrg    int i;
79335c4bbdfSmrg
79435c4bbdfSmrg    for (i = 0; i < pref.styleItems; i++) {
79535c4bbdfSmrg        if ((res_name && !strcmp(pref.style[i].match, res_name)) ||
79635c4bbdfSmrg            (res_class && !strcmp(pref.style[i].match, res_class)) ||
79735c4bbdfSmrg            (wmName && strstr(wmName, pref.style[i].match))) {
79835c4bbdfSmrg            if (pref.style[i].type)
79935c4bbdfSmrg                return pref.style[i].type;
80035c4bbdfSmrg        }
80135c4bbdfSmrg    }
8026747b715Smrg
80335c4bbdfSmrg    /* Didn't find the style, fail gracefully */
8046747b715Smrg    return STYLE_NONE;
8056747b715Smrg}
806