808 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			808 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
|  * Copyright (C) 1994-2000 The XFree86 Project, Inc. All Rights Reserved.
 | |
|  * Copyright (C) Colin Harrison 2005-2008
 | |
|  *
 | |
|  * Permission is hereby granted, free of charge, to any person obtaining
 | |
|  * a copy of this software and associated documentation files (the
 | |
|  * "Software"), to deal in the Software without restriction, including
 | |
|  * without limitation the rights to use, copy, modify, merge, publish,
 | |
|  * distribute, sublicense, and/or sell copies of the Software, and to
 | |
|  * permit persons to whom the Software is furnished to do so, subject to
 | |
|  * the following conditions:
 | |
|  *
 | |
|  * The above copyright notice and this permission notice shall be
 | |
|  * included in all copies or substantial portions of the Software.
 | |
|  *
 | |
|  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 | |
|  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 | |
|  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 | |
|  * NONINFRINGEMENT. IN NO EVENT SHALL THE XFREE86 PROJECT BE LIABLE FOR
 | |
|  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
 | |
|  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 | |
|  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | |
|  *
 | |
|  * Except as contained in this notice, the name of the XFree86 Project
 | |
|  * shall not be used in advertising or otherwise to promote the sale, use
 | |
|  * or other dealings in this Software without prior written authorization
 | |
|  * from the XFree86 Project.
 | |
|  *
 | |
|  * Authors:     Earle F. Philhower, III
 | |
|  *              Colin Harrison
 | |
|  */
 | |
| 
 | |
| #ifdef HAVE_XWIN_CONFIG_H
 | |
| #include <xwin-config.h>
 | |
| #endif
 | |
| #include <stdio.h>
 | |
| #include <stdlib.h>
 | |
| #ifdef __CYGWIN__
 | |
| #include <sys/resource.h>
 | |
| #include <sys/cygwin.h>
 | |
| #endif
 | |
| #include "win.h"
 | |
| 
 | |
| #include <X11/Xwindows.h>
 | |
| #include <shellapi.h>
 | |
| 
 | |
| #include "winprefs.h"
 | |
| #include "windisplay.h"
 | |
| #include "winmultiwindowclass.h"
 | |
| #include "winmultiwindowicons.h"
 | |
| 
 | |
| /* Where will the custom menu commands start counting from? */
 | |
| #define STARTMENUID WM_USER
 | |
| 
 | |
| extern const char *winGetBaseDir(void);
 | |
| 
 | |
| /* From winprefslex.l, the real parser */
 | |
| extern int parse_file(FILE * fp);
 | |
| 
 | |
| /* Currently in use command ID, incremented each new menu item created */
 | |
| static int g_cmdid = STARTMENUID;
 | |
| 
 | |
| /*
 | |
|  * Creates or appends a menu from a MENUPARSED structure
 | |
|  */
 | |
| static HMENU
 | |
| MakeMenu(char *name, HMENU editMenu, int editItem)
 | |
| {
 | |
|     int i;
 | |
|     int item;
 | |
|     MENUPARSED *m;
 | |
|     HMENU hmenu, hsub;
 | |
| 
 | |
|     for (i = 0; i < pref.menuItems; i++) {
 | |
|         if (!strcmp(name, pref.menu[i].menuName))
 | |
|             break;
 | |
|     }
 | |
| 
 | |
|     /* Didn't find a match, bummer */
 | |
|     if (i == pref.menuItems) {
 | |
|         ErrorF("MakeMenu: Can't find menu %s\n", name);
 | |
|         return NULL;
 | |
|     }
 | |
| 
 | |
|     m = &(pref.menu[i]);
 | |
| 
 | |
|     if (editMenu) {
 | |
|         hmenu = editMenu;
 | |
|         item = editItem;
 | |
|     }
 | |
|     else {
 | |
|         hmenu = CreatePopupMenu();
 | |
|         if (!hmenu) {
 | |
|             ErrorF("MakeMenu: Unable to CreatePopupMenu() %s\n", name);
 | |
|             return NULL;
 | |
|         }
 | |
|         item = 0;
 | |
|     }
 | |
| 
 | |
|     /* Add the menu items */
 | |
|     for (i = 0; i < m->menuItems; i++) {
 | |
|         /* Only assign IDs one time... */
 | |
|         if (m->menuItem[i].commandID == 0)
 | |
|             m->menuItem[i].commandID = g_cmdid++;
 | |
| 
 | |
|         switch (m->menuItem[i].cmd) {
 | |
|         case CMD_EXEC:
 | |
|         case CMD_ALWAYSONTOP:
 | |
|         case CMD_RELOAD:
 | |
|             InsertMenu(hmenu,
 | |
|                        item,
 | |
|                        MF_BYPOSITION | MF_ENABLED | MF_STRING,
 | |
|                        m->menuItem[i].commandID, m->menuItem[i].text);
 | |
|             break;
 | |
| 
 | |
|         case CMD_SEPARATOR:
 | |
|             InsertMenu(hmenu, item, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
 | |
|             break;
 | |
| 
 | |
|         case CMD_MENU:
 | |
|             /* Recursive! */
 | |
|             hsub = MakeMenu(m->menuItem[i].param, 0, 0);
 | |
|             if (hsub)
 | |
|                 InsertMenu(hmenu,
 | |
|                            item,
 | |
|                            MF_BYPOSITION | MF_POPUP | MF_ENABLED | MF_STRING,
 | |
|                            (UINT_PTR) hsub, m->menuItem[i].text);
 | |
|             break;
 | |
|         }
 | |
| 
 | |
|         /* If item==-1 (means to add at end of menu) don't increment) */
 | |
|         if (item >= 0)
 | |
|             item++;
 | |
|     }
 | |
| 
 | |
|     return hmenu;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Callback routine that is executed once per window class.
 | |
|  * Removes or creates custom window settings depending on LPARAM
 | |
|  */
 | |
| static wBOOL CALLBACK
 | |
| ReloadEnumWindowsProc(HWND hwnd, LPARAM lParam)
 | |
| {
 | |
|     HICON hicon;
 | |
| 
 | |
|     if (!hwnd) {
 | |
|         ErrorF("ReloadEnumWindowsProc: hwnd==NULL!\n");
 | |
|         return FALSE;
 | |
|     }
 | |
| 
 | |
|     /* It's our baby, either clean or dirty it */
 | |
|     if (lParam == FALSE) {
 | |
|         /* Reset the window's icon to undefined. */
 | |
|         hicon = (HICON) SendMessage(hwnd, WM_SETICON, ICON_BIG, 0);
 | |
| 
 | |
|         /* If the old icon is generated on-the-fly, get rid of it, will regen */
 | |
|         winDestroyIcon(hicon);
 | |
| 
 | |
|         /* Same for the small icon */
 | |
|         hicon = (HICON) SendMessage(hwnd, WM_SETICON, ICON_SMALL, 0);
 | |
|         winDestroyIcon(hicon);
 | |
| 
 | |
|         /* Remove any menu additions; bRevert=TRUE destroys any modified menus */
 | |
|         GetSystemMenu(hwnd, TRUE);
 | |
| 
 | |
|         /* This window is now clean of our taint (but with undefined icons) */
 | |
|     }
 | |
|     else {
 | |
|         /* Send a message to WM thread telling it re-evaluate the icon for this window */
 | |
|         {
 | |
|             winWMMessageRec wmMsg;
 | |
| 
 | |
|             WindowPtr pWin = GetProp(hwnd, WIN_WINDOW_PROP);
 | |
| 
 | |
|             if (pWin) {
 | |
|                 winPrivWinPtr pWinPriv = winGetWindowPriv(pWin);
 | |
|                 winPrivScreenPtr s_pScreenPriv = pWinPriv->pScreenPriv;
 | |
| 
 | |
|                 wmMsg.msg = WM_WM_ICON_EVENT;
 | |
|                 wmMsg.hwndWindow = hwnd;
 | |
|                 wmMsg.iWindow = (Window) (INT_PTR) GetProp(hwnd, WIN_WID_PROP);
 | |
| 
 | |
|                 winSendMessageToWM(s_pScreenPriv->pWMInfo, &wmMsg);
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         /* Update the system menu for this window */
 | |
|         SetupSysMenu(hwnd);
 | |
| 
 | |
|         /* That was easy... */
 | |
|     }
 | |
| 
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Removes any custom icons in classes, custom menus, etc.
 | |
|  * Frees all members in pref structure.
 | |
|  * Reloads the preferences file.
 | |
|  * Set custom icons and menus again.
 | |
|  */
 | |
| static void
 | |
| ReloadPrefs(winPrivScreenPtr pScreenPriv)
 | |
| {
 | |
|     int i;
 | |
| 
 | |
|     winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo;
 | |
| 
 | |
|     /* First, iterate over all windows, deleting their icons and custom menus.
 | |
|      * This is really only needed because winDestroyIcon() will try to
 | |
|      * destroy the old global icons, which will have changed.
 | |
|      * It is probably better to set a windows USER_DATA to flag locally defined
 | |
|      * icons, and use that to accurately know when to destroy old icons.
 | |
|      */
 | |
|     if (pScreenInfo->fMultiWindow)
 | |
|         EnumThreadWindows(g_dwCurrentThreadID, ReloadEnumWindowsProc, FALSE);
 | |
| 
 | |
|     /* Now, free/clear all info from our prefs structure */
 | |
|     for (i = 0; i < pref.menuItems; i++)
 | |
|         free(pref.menu[i].menuItem);
 | |
|     free(pref.menu);
 | |
|     pref.menu = NULL;
 | |
|     pref.menuItems = 0;
 | |
| 
 | |
|     pref.rootMenuName[0] = 0;
 | |
| 
 | |
|     free(pref.sysMenu);
 | |
|     pref.sysMenuItems = 0;
 | |
| 
 | |
|     pref.defaultSysMenuName[0] = 0;
 | |
|     pref.defaultSysMenuPos = 0;
 | |
| 
 | |
|     pref.iconDirectory[0] = 0;
 | |
|     pref.defaultIconName[0] = 0;
 | |
|     pref.trayIconName[0] = 0;
 | |
| 
 | |
|     for (i = 0; i < pref.iconItems; i++)
 | |
|         if (pref.icon[i].hicon)
 | |
|             DestroyIcon((HICON) pref.icon[i].hicon);
 | |
|     free(pref.icon);
 | |
|     pref.icon = NULL;
 | |
|     pref.iconItems = 0;
 | |
| 
 | |
|     /* Free global default X icon */
 | |
|     if (g_hIconX)
 | |
|         DestroyIcon(g_hIconX);
 | |
|     if (g_hSmallIconX)
 | |
|         DestroyIcon(g_hSmallIconX);
 | |
| 
 | |
|     /* Reset the custom command IDs */
 | |
|     g_cmdid = STARTMENUID;
 | |
| 
 | |
|     /* Load the updated resource file */
 | |
|     LoadPreferences();
 | |
| 
 | |
|     g_hIconX = NULL;
 | |
|     g_hSmallIconX = NULL;
 | |
| 
 | |
|     if (pScreenInfo->fMultiWindow) {
 | |
|         winInitGlobalIcons();
 | |
| 
 | |
|         /* Rebuild the icons and menus */
 | |
|         EnumThreadWindows(g_dwCurrentThreadID, ReloadEnumWindowsProc, TRUE);
 | |
|     }
 | |
| 
 | |
|     /* Whew, done */
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Check/uncheck the ALWAYSONTOP items in this menu
 | |
|  */
 | |
| void
 | |
| HandleCustomWM_INITMENU(HWND hwnd, HMENU hmenu)
 | |
| {
 | |
|     DWORD dwExStyle;
 | |
|     int i, j;
 | |
| 
 | |
|     if (!hwnd || !hmenu)
 | |
|         return;
 | |
| 
 | |
|     if (GetWindowLongPtr(hwnd, GWL_EXSTYLE) & WS_EX_TOPMOST)
 | |
|         dwExStyle = MF_BYCOMMAND | MF_CHECKED;
 | |
|     else
 | |
|         dwExStyle = MF_BYCOMMAND | MF_UNCHECKED;
 | |
| 
 | |
|     for (i = 0; i < pref.menuItems; i++)
 | |
|         for (j = 0; j < pref.menu[i].menuItems; j++)
 | |
|             if (pref.menu[i].menuItem[j].cmd == CMD_ALWAYSONTOP)
 | |
|                 CheckMenuItem(hmenu, pref.menu[i].menuItem[j].commandID,
 | |
|                               dwExStyle);
 | |
| 
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Searches for the custom WM_COMMAND command ID and performs action.
 | |
|  * Return TRUE if command is processed, FALSE otherwise.
 | |
|  */
 | |
| Bool
 | |
| HandleCustomWM_COMMAND(HWND hwnd, WORD command, winPrivScreenPtr pScreenPriv)
 | |
| {
 | |
|     int i, j;
 | |
|     MENUPARSED *m;
 | |
|     DWORD dwExStyle;
 | |
| 
 | |
|     if (!command)
 | |
|         return FALSE;
 | |
| 
 | |
|     for (i = 0; i < pref.menuItems; i++) {
 | |
|         m = &(pref.menu[i]);
 | |
|         for (j = 0; j < m->menuItems; j++) {
 | |
|             if (command == m->menuItem[j].commandID) {
 | |
|                 /* Match! */
 | |
|                 switch (m->menuItem[j].cmd) {
 | |
| #ifdef __CYGWIN__
 | |
|                 case CMD_EXEC:
 | |
|                     if (fork() == 0) {
 | |
|                         struct rlimit rl;
 | |
|                         int fd;
 | |
| 
 | |
|                         /* Close any open descriptors except for STD* */
 | |
|                         getrlimit(RLIMIT_NOFILE, &rl);
 | |
|                         for (fd = STDERR_FILENO + 1; fd < rl.rlim_cur; fd++)
 | |
|                             close(fd);
 | |
| 
 | |
|                         /* Disassociate any TTYs */
 | |
|                         setsid();
 | |
| 
 | |
|                         execl("/bin/sh",
 | |
|                               "/bin/sh", "-c", m->menuItem[j].param, NULL);
 | |
|                         exit(0);
 | |
|                     }
 | |
|                     else
 | |
|                         return TRUE;
 | |
|                     break;
 | |
| #else
 | |
|                 case CMD_EXEC:
 | |
|                 {
 | |
|                     /* Start process without console window */
 | |
|                     STARTUPINFO start;
 | |
|                     PROCESS_INFORMATION child;
 | |
| 
 | |
|                     memset(&start, 0, sizeof(start));
 | |
|                     start.cb = sizeof(start);
 | |
|                     start.dwFlags = STARTF_USESHOWWINDOW;
 | |
|                     start.wShowWindow = SW_HIDE;
 | |
| 
 | |
|                     memset(&child, 0, sizeof(child));
 | |
| 
 | |
|                     if (CreateProcess
 | |
|                         (NULL, m->menuItem[j].param, NULL, NULL, FALSE, 0, NULL,
 | |
|                          NULL, &start, &child)) {
 | |
|                         CloseHandle(child.hThread);
 | |
|                         CloseHandle(child.hProcess);
 | |
|                     }
 | |
|                     else
 | |
|                         MessageBox(NULL, m->menuItem[j].param,
 | |
|                                    "Mingrc Exec Command Error!",
 | |
|                                    MB_OK | MB_ICONEXCLAMATION);
 | |
|                 }
 | |
|                     return TRUE;
 | |
| #endif
 | |
|                 case CMD_ALWAYSONTOP:
 | |
|                     if (!hwnd)
 | |
|                         return FALSE;
 | |
| 
 | |
|                     /* Get extended window style */
 | |
|                     dwExStyle = GetWindowLongPtr(hwnd, GWL_EXSTYLE);
 | |
| 
 | |
|                     /* Handle topmost windows */
 | |
|                     if (dwExStyle & WS_EX_TOPMOST)
 | |
|                         SetWindowPos(hwnd,
 | |
|                                      HWND_NOTOPMOST,
 | |
|                                      0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
 | |
|                     else
 | |
|                         SetWindowPos(hwnd,
 | |
|                                      HWND_TOPMOST,
 | |
|                                      0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE);
 | |
|                     {
 | |
|                         winScreenInfo *pScreenInfo = pScreenPriv->pScreenInfo;
 | |
|                         if (pScreenInfo->fMultiWindow)
 | |
|                             /* Reflect the changed Z order */
 | |
|                             winReorderWindowsMultiWindow();
 | |
|                     }
 | |
|                     return TRUE;
 | |
| 
 | |
|                 case CMD_RELOAD:
 | |
|                     ReloadPrefs(pScreenPriv);
 | |
|                     return TRUE;
 | |
| 
 | |
|                 default:
 | |
|                     return FALSE;
 | |
|                 }
 | |
|             }                   /* match */
 | |
|         }                       /* for j */
 | |
|     }                           /* for i */
 | |
| 
 | |
|     return FALSE;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Add the default or a custom menu depending on the class match
 | |
|  */
 | |
| void
 | |
| SetupSysMenu(HWND hwnd)
 | |
| {
 | |
|     HMENU sys;
 | |
|     int i;
 | |
|     WindowPtr pWin;
 | |
|     char *res_name, *res_class;
 | |
| 
 | |
|     if (!hwnd)
 | |
|         return;
 | |
| 
 | |
|     pWin = GetProp(hwnd, WIN_WINDOW_PROP);
 | |
| 
 | |
|     sys = GetSystemMenu(hwnd, FALSE);
 | |
|     if (!sys)
 | |
|         return;
 | |
| 
 | |
|     if (pWin) {
 | |
|         /* First see if there's a class match... */
 | |
|         if (winMultiWindowGetClassHint(pWin, &res_name, &res_class)) {
 | |
|             for (i = 0; i < pref.sysMenuItems; i++) {
 | |
|                 if (!strcmp(pref.sysMenu[i].match, res_name) ||
 | |
|                     !strcmp(pref.sysMenu[i].match, res_class)) {
 | |
|                     free(res_name);
 | |
|                     free(res_class);
 | |
| 
 | |
|                     MakeMenu(pref.sysMenu[i].menuName, sys,
 | |
|                              pref.sysMenu[i].menuPos == AT_START ? 0 : -1);
 | |
|                     return;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             /* No match, just free alloc'd strings */
 | |
|             free(res_name);
 | |
|             free(res_class);
 | |
|         }                       /* Found wm_class */
 | |
|     }                           /* if pwin */
 | |
| 
 | |
|     /* Fallback to system default */
 | |
|     if (pref.defaultSysMenuName[0]) {
 | |
|         if (pref.defaultSysMenuPos == AT_START)
 | |
|             MakeMenu(pref.defaultSysMenuName, sys, 0);
 | |
|         else
 | |
|             MakeMenu(pref.defaultSysMenuName, sys, -1);
 | |
|     }
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Possibly add a menu to the toolbar icon
 | |
|  */
 | |
| void
 | |
| SetupRootMenu(HMENU root)
 | |
| {
 | |
|     if (!root)
 | |
|         return;
 | |
| 
 | |
|     if (pref.rootMenuName[0]) {
 | |
|         MakeMenu(pref.rootMenuName, root, 0);
 | |
|     }
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Check for and return an overridden default ICON specified in the prefs
 | |
|  */
 | |
| HICON
 | |
| winOverrideDefaultIcon(int size)
 | |
| {
 | |
|     HICON hicon;
 | |
| 
 | |
|     if (pref.defaultIconName[0]) {
 | |
|         hicon = LoadImageComma(pref.defaultIconName, pref.iconDirectory, size, size, 0);
 | |
|         if (hicon == NULL)
 | |
|             ErrorF("winOverrideDefaultIcon: LoadImageComma(%s) failed\n",
 | |
|                    pref.defaultIconName);
 | |
| 
 | |
|         return hicon;
 | |
|     }
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Return the HICON to use in the taskbar notification area
 | |
|  */
 | |
| HICON
 | |
| winTaskbarIcon(void)
 | |
| {
 | |
|     HICON hicon;
 | |
| 
 | |
|     hicon = 0;
 | |
|     /* First try and load an overridden, if success then return it */
 | |
|     if (pref.trayIconName[0]) {
 | |
|         hicon = LoadImageComma(pref.trayIconName, pref.iconDirectory,
 | |
|                                GetSystemMetrics(SM_CXSMICON),
 | |
|                                GetSystemMetrics(SM_CYSMICON), 0);
 | |
|         if (hicon == NULL)
 | |
|             ErrorF("winTaskbarIcon: LoadImageComma(%s) failed\n",
 | |
|                    pref.trayIconName);
 | |
|     }
 | |
| 
 | |
|     /* Otherwise return the default */
 | |
|     if (!hicon)
 | |
|         hicon = (HICON) LoadImage(g_hInstance,
 | |
|                                   MAKEINTRESOURCE(IDI_XWIN),
 | |
|                                   IMAGE_ICON,
 | |
|                                   GetSystemMetrics(SM_CXSMICON),
 | |
|                                   GetSystemMetrics(SM_CYSMICON), 0);
 | |
| 
 | |
|     return hicon;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Handle comma-ified icon names
 | |
|  *
 | |
|  * Parse a filename to extract an icon:
 | |
|  *  If fname is exactly ",nnn" then extract icon from our resource
 | |
|  *  else if it is "file,nnn" then extract icon nnn from that file
 | |
|  *  else try to load it as an .ico file and if that fails return NULL
 | |
|  */
 | |
| HICON
 | |
| LoadImageComma(char *fname, char *iconDirectory, int sx, int sy, int flags)
 | |
| {
 | |
|     HICON hicon;
 | |
|     int i;
 | |
| 
 | |
|     /* Some input error checking */
 | |
|     if (!fname || !fname[0])
 | |
|         return NULL;
 | |
| 
 | |
|     i = 0;
 | |
|     hicon = NULL;
 | |
| 
 | |
|     if (fname[0] == ',') {
 | |
|         /* It's the XWIN.EXE resource they want */
 | |
|         i = atoi(fname + 1);
 | |
|         hicon = LoadImage(g_hInstance,
 | |
|                           MAKEINTRESOURCE(i), IMAGE_ICON, sx, sy, flags);
 | |
|     }
 | |
|     else {
 | |
|         char *file = calloc(1, PATH_MAX + NAME_MAX + 2);
 | |
| #ifdef  __CYGWIN__
 | |
|         Bool convert = FALSE;
 | |
| #endif
 | |
| 
 | |
|         if (!file)
 | |
|             return NULL;
 | |
| 
 | |
|         file[0] = 0;
 | |
| 
 | |
|         /* If fname starts 'X:\', it's an absolute Windows path, do nothing */
 | |
|         if (!(fname[0] && fname[1] == ':' && fname[2] == '\\')) {
 | |
| #ifdef  __CYGWIN__
 | |
|             /* If fname starts with '/', it's an absolute cygwin path, we'll
 | |
|                need to convert it */
 | |
|             if (fname[0] == '/') {
 | |
|                 convert = TRUE;
 | |
|             }
 | |
|             else
 | |
| #endif
 | |
|             if (iconDirectory) {
 | |
|                 /* Otherwise, prepend the default icon directory, which
 | |
|                    currently must be in absolute Windows path form */
 | |
|                 strcpy(file, iconDirectory);
 | |
|                 if (iconDirectory[0])
 | |
|                     if (iconDirectory[strlen(iconDirectory) - 1] != '\\')
 | |
|                         strcat(file, "\\");
 | |
|             }
 | |
|         }
 | |
|         strcat(file, fname);
 | |
| 
 | |
|         /* Trim off any ',index' */
 | |
|         if (strrchr(file, ',')) {
 | |
|             *(strrchr(file, ',')) = 0;  /* End string at comma */
 | |
|             i = atoi(strrchr(fname, ',') + 1);
 | |
|         }
 | |
|         else {
 | |
|             i = -1;
 | |
|         }
 | |
| 
 | |
| #ifdef  __CYGWIN__
 | |
|         /* Convert from Cygwin path to Windows path */
 | |
|         if (convert) {
 | |
|             char *converted_file = cygwin_create_path(CCP_POSIX_TO_WIN_A | CCP_ABSOLUTE, file);
 | |
|             if (converted_file) {
 | |
|                 free(file);
 | |
|                 file = converted_file;
 | |
|             }
 | |
|         }
 | |
| #endif
 | |
| 
 | |
|         if (i >= 0) {
 | |
|             /* Specified as <fname>,<index> */
 | |
|             hicon = ExtractIcon(g_hInstance, file, i);
 | |
|         }
 | |
|         else {
 | |
|             /* Specified as just an .ico file */
 | |
|             hicon = (HICON) LoadImage(NULL,
 | |
|                                       file,
 | |
|                                       IMAGE_ICON,
 | |
|                                       sx, sy, LR_LOADFROMFILE | flags);
 | |
|         }
 | |
|         free(file);
 | |
|     }
 | |
|     return hicon;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Check for a match of the window class to one specified in the
 | |
|  * ICONS{} section in the prefs file, and load the icon from a file
 | |
|  */
 | |
| HICON
 | |
| winOverrideIcon(char *res_name, char *res_class, char *wmName)
 | |
| {
 | |
|     int i;
 | |
|     HICON hicon;
 | |
| 
 | |
|     for (i = 0; i < pref.iconItems; i++) {
 | |
|         if ((res_name && !strcmp(pref.icon[i].match, res_name)) ||
 | |
|             (res_class && !strcmp(pref.icon[i].match, res_class)) ||
 | |
|             (wmName && strstr(wmName, pref.icon[i].match))) {
 | |
|             if (pref.icon[i].hicon)
 | |
|                 return pref.icon[i].hicon;
 | |
| 
 | |
|             hicon = LoadImageComma(pref.icon[i].iconFile, pref.iconDirectory, 0, 0, LR_DEFAULTSIZE);
 | |
|             if (hicon == NULL)
 | |
|                 ErrorF("winOverrideIcon: LoadImageComma(%s) failed\n",
 | |
|                        pref.icon[i].iconFile);
 | |
| 
 | |
|             pref.icon[i].hicon = hicon;
 | |
|             return hicon;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /* Didn't find the icon, fail gracefully */
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Should we free this icon or leave it in memory (is it part of our
 | |
|  * ICONS{} overrides)?
 | |
|  */
 | |
| int
 | |
| winIconIsOverride(HICON hicon)
 | |
| {
 | |
|     int i;
 | |
| 
 | |
|     if (!hicon)
 | |
|         return 0;
 | |
| 
 | |
|     for (i = 0; i < pref.iconItems; i++)
 | |
|         if ((HICON) pref.icon[i].hicon == hicon)
 | |
|             return 1;
 | |
| 
 | |
|     return 0;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Open and parse the XWinrc config file @path.
 | |
|  * If @path is NULL, use the built-in default.
 | |
|  */
 | |
| static int
 | |
| winPrefsLoadPreferences(const char *path)
 | |
| {
 | |
|     FILE *prefFile = NULL;
 | |
| 
 | |
|     if (path)
 | |
|         prefFile = fopen(path, "r");
 | |
| #ifdef __CYGWIN__
 | |
|     else {
 | |
|         char defaultPrefs[] =
 | |
|             "MENU rmenu {\n"
 | |
|             "  \"How to customize this menu\" EXEC \"xterm +tb -e man XWinrc\"\n"
 | |
|             "  \"Launch xterm\" EXEC xterm\n"
 | |
|             "  \"Load .XWinrc\" RELOAD\n"
 | |
|             "  SEPARATOR\n" "}\n" "\n" "ROOTMENU rmenu\n";
 | |
| 
 | |
|         path = "built-in default";
 | |
|         prefFile = fmemopen(defaultPrefs, strlen(defaultPrefs), "r");
 | |
|     }
 | |
| #endif
 | |
| 
 | |
|     if (!prefFile) {
 | |
|         ErrorF("LoadPreferences: %s not found\n", path);
 | |
|         return FALSE;
 | |
|     }
 | |
| 
 | |
|     ErrorF("LoadPreferences: Loading %s\n", path);
 | |
| 
 | |
|     if ((parse_file(prefFile)) != 0) {
 | |
|         ErrorF("LoadPreferences: %s is badly formed!\n", path);
 | |
|         fclose(prefFile);
 | |
|         return FALSE;
 | |
|     }
 | |
| 
 | |
|     fclose(prefFile);
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Try and open ~/.XWinrc and system.XWinrc
 | |
|  * Load it into prefs structure for use by other functions
 | |
|  */
 | |
| void
 | |
| LoadPreferences(void)
 | |
| {
 | |
|     char *home;
 | |
|     char fname[PATH_MAX + NAME_MAX + 2];
 | |
|     char szDisplay[512];
 | |
|     char *szEnvDisplay;
 | |
|     int i, j;
 | |
|     char param[PARAM_MAX + 1];
 | |
|     char *srcParam, *dstParam;
 | |
|     int parsed = FALSE;
 | |
| 
 | |
|     /* First, clear all preference settings */
 | |
|     memset(&pref, 0, sizeof(pref));
 | |
| 
 | |
|     /* Now try and find a ~/.xwinrc file */
 | |
|     home = getenv("HOME");
 | |
|     if (home) {
 | |
|         strcpy(fname, home);
 | |
|         if (fname[strlen(fname) - 1] != '/')
 | |
|             strcat(fname, "/");
 | |
|         strcat(fname, ".XWinrc");
 | |
|         parsed = winPrefsLoadPreferences(fname);
 | |
|     }
 | |
| 
 | |
|     /* No home file found, check system default */
 | |
|     if (!parsed) {
 | |
|         char buffer[MAX_PATH];
 | |
| 
 | |
| #ifdef RELOCATE_PROJECTROOT
 | |
|         snprintf(buffer, sizeof(buffer), "%s\\system.XWinrc", winGetBaseDir());
 | |
| #else
 | |
|         strncpy(buffer, SYSCONFDIR "/X11/system.XWinrc", sizeof(buffer));
 | |
| #endif
 | |
|         buffer[sizeof(buffer) - 1] = 0;
 | |
|         parsed = winPrefsLoadPreferences(buffer);
 | |
|     }
 | |
| 
 | |
|     /* Neither user nor system configuration found, or were badly formed */
 | |
|     if (!parsed) {
 | |
|         ErrorF
 | |
|             ("LoadPreferences: See \"man XWinrc\" to customize the XWin menu.\n");
 | |
|         parsed = winPrefsLoadPreferences(NULL);
 | |
|     }
 | |
| 
 | |
|     /* Setup a DISPLAY environment variable, need to allocate on heap */
 | |
|     /* because putenv doesn't copy the argument... */
 | |
|     winGetDisplayName(szDisplay, 0);
 | |
|     szEnvDisplay = calloc(1, strlen(szDisplay) + strlen("DISPLAY=") + 1);
 | |
|     if (szEnvDisplay) {
 | |
|         snprintf(szEnvDisplay, 512, "DISPLAY=%s", szDisplay);
 | |
|         putenv(szEnvDisplay);
 | |
|     }
 | |
| 
 | |
|     /* Replace any "%display%" in menu commands with display string */
 | |
|     for (i = 0; i < pref.menuItems; i++) {
 | |
|         for (j = 0; j < pref.menu[i].menuItems; j++) {
 | |
|             if (pref.menu[i].menuItem[j].cmd == CMD_EXEC) {
 | |
|                 srcParam = pref.menu[i].menuItem[j].param;
 | |
|                 dstParam = param;
 | |
|                 while (*srcParam) {
 | |
|                     if (!strncmp(srcParam, "%display%", 9)) {
 | |
|                         memcpy(dstParam, szDisplay, strlen(szDisplay));
 | |
|                         dstParam += strlen(szDisplay);
 | |
|                         srcParam += 9;
 | |
|                     }
 | |
|                     else {
 | |
|                         *dstParam = *srcParam;
 | |
|                         dstParam++;
 | |
|                         srcParam++;
 | |
|                     }
 | |
|                 }
 | |
|                 *dstParam = 0;
 | |
|                 strcpy(pref.menu[i].menuItem[j].param, param);
 | |
|             }                   /* cmd==cmd_exec */
 | |
|         }                       /* for all menuitems */
 | |
|     }                           /* for all menus */
 | |
| 
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Check for a match of the window class to one specified in the
 | |
|  * STYLES{} section in the prefs file, and return the style type
 | |
|  */
 | |
| unsigned long
 | |
| winOverrideStyle(char *res_name, char *res_class, char *wmName)
 | |
| {
 | |
|     int i;
 | |
| 
 | |
|     for (i = 0; i < pref.styleItems; i++) {
 | |
|         if ((res_name && !strcmp(pref.style[i].match, res_name)) ||
 | |
|             (res_class && !strcmp(pref.style[i].match, res_class)) ||
 | |
|             (wmName && strstr(wmName, pref.style[i].match))) {
 | |
|             if (pref.style[i].type)
 | |
|                 return pref.style[i].type;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     /* Didn't find the style, fail gracefully */
 | |
|     return STYLE_NONE;
 | |
| }
 |