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