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