2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
24 * (c) Copyright 1989, 1990, 1991, 1992, 1993, 1994 OPEN SOFTWARE FOUNDATION, INC.
32 static char rcsid[] = "$XConsortium: WmResParse.c /main/9 1996/11/01 10:17:34 drk $"
36 * (c) Copyright 1987, 1988, 1989, 1990, 1993, 1994 Hewlett-Packard Company
37 * (c) Copyright 1993, 1994 International Business Machines Corp.
38 * (c) Copyright 1993, 1994 Sun Microsystems, Inc.
39 * (c) Copyright 1993, 1994 Novell, Inc.
42 * (c) Copyright 1987, 1988 DIGITAL EQUIPMENT CORPORATION */
44 * (c) Copyright 1988 MASSACHUSETTS INSTITUTE OF TECHNOLOGY */
51 #include "WmResNames.h"
53 #include <Dt/UserMsg.h>
54 #include <Dt/Connect.h>
62 #include "WmResource.h"
64 #include <Xm/VirtKeysP.h>
66 #include <X11/cursorfont.h>
67 #include <X11/keysym.h>
68 #include <X11/Xatom.h>
77 #ifdef MOTIF_ONE_DOT_ONE
81 #include <Xm/XmP.h> /* for XmeGetHomeDirName */
87 /* maximum string lengths */
89 #define MAX_KEYSYM_STRLEN 100
90 #define MAX_EVENTTYPE_STRLEN 20
91 #define MAX_MODIFIER_STRLEN 20
92 #define MAX_CONTEXT_STRLEN 20
93 #define MAX_GROUP_STRLEN 20
95 #define min(a,b) ((a)>(b) ? (b) : (a))
97 #define MAXLINE (MAXWMPATH+1)
101 #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
102 # define PARSE_MENU_ITEMS(pSD, mSpec) ParseMenuItems(pSD, mSpec)
104 # define PARSE_MENU_ITEMS(pSD, mSpec) ParseMenuItems(pSD)
105 #endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
108 * include extern functions
110 #include "WmResParse.h"
112 #include "WmWrkspace.h"
115 #include "WmFunction.h"
119 #ifdef MOTIF_ONE_DOT_ONE
120 extern char *getenv ();
124 # ifdef X_NOT_STDC_ENV
127 # define HOME_DT_WMRC "/.dt/dtwmrc"
128 # define LANG_DT_WMRC "/dtwmrc"
129 # define SYS_DT_WMRC CDE_CONFIGURATION_TOP "/sys.dtwmrc"
130 #endif /* PANELIST */
133 * Global Variables And Tables:
135 static char cfileName[MAXWMPATH+1];
137 #ifndef NO_MESSAGE_CATALOG
138 char * pWarningStringFile;
139 char * pWarningStringLine;
141 char pWarningStringFile[] = "%s: %s on line %d of configuration file %s\n";
142 char pWarningStringLine[] = "%s: %s on line %d of specification string\n";
144 #define cfileP (wmGD.pWmPB->pFile)
145 #define parseP (wmGD.pWmPB->pchNext)
146 #define line (wmGD.pWmPB->pchLine)
147 #define linec (wmGD.pWmPB->lineNumber)
149 static FILE *cfileP = NULL; /* fopen'ed configuration file or NULL */
150 static unsigned char line[MAXLINE+1]; /* line buffer */
151 static int linec = 0; /* line counter for parser */
152 static unsigned char *parseP = NULL; /* pointer to parse string */
161 static MaskTableEntry modifierStrings[] = {
164 {"ctrl", ControlMask},
165 {"shift", ShiftMask},
174 {NULL, (unsigned int)NULL},
182 unsigned int eventType;
183 Boolean (*parseProc)();
184 unsigned int closure;
188 #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
190 # define CCI_USE_DEFAULT_NAME_TAG "DEFAULT_NAME"
192 String CCIEntryModifierNames[] = {
203 NONE, /* internal only. */
204 INLINE, /* not supported. */
207 DELIMIT_INLINE, /* not supported. */
212 typedef struct _CCIFuncArg {
213 CCIEntryModifier mod;
216 #endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
218 #ifdef MOTIF_ONE_DOT_ONE
219 void GetHomeDirName(String fileName);
222 static String GetNetworkFileName (char *pchFile);
224 #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
225 static MenuItem *MakeSeparatorTemplate (int);
226 static void ParseMenuItemName (unsigned char **linePP, MenuItem *menuItem);
227 static Boolean ParseClientCommand (unsigned char **linePP, MenuSpec *menuSpec,
228 MenuItem *menuItem, unsigned char *string,
229 Boolean *use_separators);
230 static void FixMenuItem (MenuSpec *menuSpec, MenuItem *menuItem);
231 static Boolean GetCCIModifier (String modString, CCIEntryModifier *mod);
232 static Boolean ParseWmFuncCCIArgs (unsigned char **linePP,
233 WmFunction wmFunction, String *pArgs);
234 #endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
235 FILE *FopenConfigFile (void);
236 void SaveMenuAccelerators (WmScreenData *pSD, MenuSpec *newMenuSpec);
237 static void ParseMenuSet (WmScreenData *pSD, unsigned char *lineP);
238 MenuItem *ParseMwmMenuStr (WmScreenData *pSD, unsigned char *menuStr);
239 static MenuItem *ParseMenuItems (WmScreenData *pSD
240 #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
242 #endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
244 static Boolean ParseWmLabel (WmScreenData *pSD, MenuItem *menuItem,
245 unsigned char *string);
246 static void ParseWmMnemonic (unsigned char **linePP, MenuItem *menuItem);
247 static Boolean ParseWmAccelerator (unsigned char **linePP, MenuItem *menuItem);
248 int ParseWmFunction (unsigned char **linePP, unsigned int res_spec,
249 WmFunction *pWmFunction);
251 static Boolean ParseWmFuncMaybeStrArg (unsigned char **linePP,
252 WmFunction wmFunction, String *pArgs);
253 #endif /* PANELIST */
254 static Boolean ParseWmFuncNoArg (unsigned char **linePP, WmFunction wmFunction,
257 static Boolean ParseWmFuncStrArg (unsigned char **linePP,
258 WmFunction wmFunction, String *pArgs);
259 #endif /* PANELIST */
260 void FreeMenuItem (MenuItem *menuItem);
261 static Boolean ParseWmFuncGrpArg (unsigned char **linePP,
262 WmFunction wmFunction, GroupArg *pGroup);
263 static Boolean ParseWmFuncNbrArg (unsigned char **linePP,
264 WmFunction wmFunction,
265 unsigned long *pNumber);
266 void ParseButtonStr (WmScreenData *pSD, unsigned char *buttonStr);
267 static void ParseButtonSet (WmScreenData *pSD, unsigned char *lineP);
268 static Boolean ParseContext (unsigned char **linePP, Context *context,
269 Context *subContext);
271 ParseKeyStr (WmScreenData *pSD, unsigned char *keyStr);
272 static void ParseKeySet (WmScreenData *pSD, unsigned char *lineP);
273 Boolean ParseBtnEvent (unsigned char **linePP,
274 unsigned int *eventType,
275 unsigned int *button,
278 Boolean ParseKeyEvent (unsigned char **linePP, unsigned int *eventType,
279 KeyCode *keyCode, unsigned int *state);
280 static Boolean ParseEvent (unsigned char **linePP, EventTableEntry *table,
281 unsigned int *eventType, unsigned int *detail,
282 unsigned int *state, Boolean *fClick);
283 static Boolean ParseModifiers(unsigned char **linePP, unsigned int *state);
284 static Boolean LookupModifier (unsigned char *name, unsigned int *valueP);
285 static Boolean ParseEventType (unsigned char **linePP, EventTableEntry *table,
286 unsigned int *eventType, Cardinal *ix);
287 static Boolean ParseImmed (unsigned char **linePP, unsigned int closure,
288 unsigned int *detail);
289 static Boolean ParseKeySym (unsigned char **linePP, unsigned int closure,
290 unsigned int *detail);
291 static unsigned int StrToNum(unsigned char *str);
292 static unsigned int StrToHex(unsigned char *str);
293 static unsigned int StrToOct(unsigned char *str);
294 void ScanAlphanumeric (unsigned char **linePP);
295 void ScanWhitespace(unsigned char **linePP);
296 void ToLower (unsigned char *string);
298 PWarning (char *message);
299 static void ProcessAccelText (unsigned char *startP, unsigned char *endP,
300 unsigned char *destP);
301 void ProcessCommandLine (int argc, char *argv[]);
302 static void ParseScreensArgument (int argc, char *argv[], int *pArgnum,
303 unsigned char *lineP);
304 void ProcessMotifBindings (void);
306 static void ParseIncludeSet (WmScreenData *pSD, unsigned char *lineP);
307 static void ConfigStackInit (char *pchFileName);
308 static FILE *ConfigStackPush (unsigned char *pchFileName);
309 static void ConfigStackPop (void);
310 Boolean ParseWmFuncActionArg (unsigned char **linePP,
311 WmFunction wmFunction, String *pArgs);
312 static void PreprocessConfigFile (void);
313 #endif /* PANELIST */
315 static EventTableEntry buttonEvents[] = {
317 {"btn1down", ButtonPress, ParseImmed, SELECT_BUTTON, FALSE},
318 {"btn1up", ButtonRelease, ParseImmed, SELECT_BUTTON, FALSE},
319 {"btn1click", ButtonRelease, ParseImmed, SELECT_BUTTON, TRUE},
320 {"btn1click2", ButtonPress, ParseImmed, SELECT_BUTTON, TRUE},
321 {"btn2down", ButtonPress, ParseImmed, DMANIP_BUTTON, FALSE},
322 {"btn2up", ButtonRelease, ParseImmed, DMANIP_BUTTON, FALSE},
323 {"btn2click", ButtonRelease, ParseImmed, DMANIP_BUTTON, TRUE},
324 {"btn2click2", ButtonPress, ParseImmed, DMANIP_BUTTON, TRUE},
325 {"btn3down", ButtonPress, ParseImmed, BMENU_BUTTON, FALSE},
326 {"btn3up", ButtonRelease, ParseImmed, BMENU_BUTTON, FALSE},
327 {"btn3click", ButtonRelease, ParseImmed, BMENU_BUTTON, TRUE},
328 {"btn3click2", ButtonPress, ParseImmed, BMENU_BUTTON, TRUE},
329 {"btn4down", ButtonPress, ParseImmed, Button4, FALSE},
330 {"btn4up", ButtonRelease, ParseImmed, Button4, FALSE},
331 {"btn4click", ButtonRelease, ParseImmed, Button4, TRUE},
332 {"btn4click2", ButtonPress, ParseImmed, Button4, TRUE},
333 {"btn5down", ButtonPress, ParseImmed, Button5, FALSE},
334 {"btn5up", ButtonRelease, ParseImmed, Button5, FALSE},
335 {"btn5click", ButtonRelease, ParseImmed, Button5, TRUE},
336 {"btn5click2", ButtonPress, ParseImmed, Button5, TRUE},
337 { NULL, (unsigned int)NULL, (Boolean(*)())NULL, (unsigned int)NULL, (Boolean)NULL}
341 static EventTableEntry keyEvents[] = {
343 {"key", KeyPress, ParseKeySym, 0, FALSE},
344 { NULL, (unsigned int)NULL, (Boolean(*)())NULL, (unsigned int)NULL, (Boolean)NULL}
348 typedef struct _ConfigFileStackEntry {
352 char *wmgdConfigFile;
354 DtWmpParseBuf *pWmPB;
355 struct _ConfigFileStackEntry *pIncluder;
357 } ConfigFileStackEntry;
359 static ConfigFileStackEntry *pConfigStack = NULL;
360 static ConfigFileStackEntry *pConfigStackTop = NULL;
362 #endif /* PANELIST */
364 unsigned int buttonModifierMasks[] = {
374 * FUNCTION PARSER TABLE (function names must be in alphabetic order)
379 Context greyedContext;
380 unsigned int resource;
382 WmFunction wmFunction;
383 Boolean (*parseProc)();
384 } FunctionTableEntry;
388 * NOTE: New functions MUST be added in ALPHABETICAL order. A binary search
389 * is used to find the correct function name.
392 FunctionTableEntry functionTable[] = {
399 ParseWmFuncActionArg},
406 #endif /* PANELIST */
413 #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
419 #endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
420 {"f.circle_down", F_SUBCONTEXT_IB_IICON|F_SUBCONTEXT_IB_WICON,
425 {"f.circle_up", F_SUBCONTEXT_IB_IICON|F_SUBCONTEXT_IB_WICON,
431 {"f.create_workspace", 0,
436 {"f.delete_workspace", 0,
447 {"f.focus_color", F_SUBCONTEXT_IB_IICON|F_SUBCONTEXT_IB_WICON,
452 {"f.focus_key", F_SUBCONTEXT_IB_IICON|F_SUBCONTEXT_IB_WICON,
458 {"f.goto_workspace", 0,
469 ParseWmFuncStrArg}, /* [helpvolume && helptopic] */
474 ParseWmFuncNoArg}, /* for now */
476 #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
482 #endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
483 {"f.kill", F_CONTEXT_ROOT,
488 {"f.lower", F_SUBCONTEXT_IB_IICON|F_SUBCONTEXT_IB_WICON,
492 ParseWmFuncMaybeStrArg},
494 {"f.marquee_selection",
495 F_CONTEXT_WINDOW|F_CONTEXT_ICON|F_SUBCONTEXT_IB_IICON,
501 {"f.maximize", F_CONTEXT_ROOT|F_CONTEXT_MAXIMIZE|
502 F_SUBCONTEXT_IB_WICON,
512 {"f.minimize", F_CONTEXT_ICON|F_CONTEXT_ROOT|F_SUBCONTEXT_IB_IICON,
517 {"f.move", F_CONTEXT_ROOT,
533 {"f.next_workspace", 0,
539 {"f.nop", F_CONTEXT_ROOT|F_CONTEXT_ICON|F_CONTEXT_WINDOW|
540 F_SUBCONTEXT_IB_WICON | F_SUBCONTEXT_IB_IICON,
545 {"f.normalize", F_CONTEXT_ROOT|F_CONTEXT_NORMAL|F_SUBCONTEXT_IB_WICON,
551 {"f.normalize_and_raise",
552 F_CONTEXT_ROOT|F_CONTEXT_NORMAL,
555 F_Normalize_And_Raise,
556 ParseWmFuncMaybeStrArg},
558 {"f.normalize_and_raise",
559 F_CONTEXT_ROOT|F_CONTEXT_NORMAL,
562 F_Normalize_And_Raise,
564 #endif /* PANELIST */
566 {"f.occupy_all", F_CONTEXT_ICONBOX|F_CONTEXT_ROOT,
569 F_AddToAllWorkspaces,
582 #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
588 #endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
605 {"f.prev_workspace", 0,
611 {"f.quit_mwm", F_CONTEXT_ICON|F_CONTEXT_WINDOW,
616 {"f.raise", F_SUBCONTEXT_IB_IICON|F_SUBCONTEXT_IB_WICON,
620 ParseWmFuncMaybeStrArg},
621 {"f.raise_lower", F_CONTEXT_ROOT |
622 F_SUBCONTEXT_IB_IICON|F_SUBCONTEXT_IB_WICON,
632 {"f.refresh_win", F_CONTEXT_ICON|F_CONTEXT_ROOT,
638 {"f.remove", F_CONTEXT_ROOT,
644 {"f.resize", F_CONTEXT_ICON|F_CONTEXT_ROOT|
645 F_SUBCONTEXT_IB_IICON|F_SUBCONTEXT_IB_WICON,
651 {"f.restart", F_CONTEXT_ICON|F_CONTEXT_WINDOW,
657 {"f.restart", F_CONTEXT_ICON|F_CONTEXT_WINDOW,
663 {"f.restore", F_CONTEXT_ROOT|F_CONTEXT_NORMAL|F_SUBCONTEXT_IB_WICON,
668 {"f.restore_and_raise",
669 F_CONTEXT_ROOT|F_CONTEXT_NORMAL,
679 {"f.send_msg", F_CONTEXT_ROOT,
689 {"f.set_behavior", 0,
706 #if defined(PANELIST)
707 {"f.toggle_frontpanel", 0,
710 F_Toggle_Front_Panel,
718 #endif /* PANELIST */
722 {"f.workspace_presence",F_CONTEXT_ICON|F_CONTEXT_ROOT|F_CONTEXT_ICONBOX|
723 F_SUBCONTEXT_IB_IICON|F_SUBCONTEXT_IB_WICON,
725 {"f.workspace_presence", F_CONTEXT_ROOT|F_CONTEXT_ICONBOX|
726 F_SUBCONTEXT_IB_WICON,
729 F_Workspace_Presence,
732 #if defined(DEBUG) && defined(WSM)
742 * NOTE: New functions MUST be added in ALPHABETICAL order. A binary search
743 * is used to find the correct function name.
746 #define WMFUNCTIONTABLESIZE (sizeof(functionTable)/sizeof(functionTable[0]))
749 * Be sure to update these define, whenever adding/deleting a function.
752 # if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
753 # define F_CCI_INDEX 2
754 # endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
759 # if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
760 # define F_CCI_INDEX 1
761 # define F_EXEC_INDEX 4
762 # define F_NOP_INDEX 16
764 # define F_EXEC_INDEX 3
765 # define F_NOP_INDEX 14
766 # endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
770 /******************************<->*************************************
772 * void GetFunctionTableValues (int *execIndex, int *nopIndex,
777 * This routine dynamically computes the size of the functionTable[],
778 * and the indices for key functions, such as f.exec, f.action, and
783 * We are setting the values of F_EXEC_INDEX, F_ACTION_INDEX,
784 * and F_NOP_INDEX on a global level. The addresses
785 * for same are passed in.
792 * This routine calls smaller routines for efficiency sake.
794 ******************************<->***********************************/
796 GetFunctionTableValues (int *execIndex, int *nopIndex,
800 GetExecIndex (WMFUNCTIONTABLESIZE, execIndex);
802 GetActionIndex (WMFUNCTIONTABLESIZE, actionIndex);
804 GetNopIndex (WMFUNCTIONTABLESIZE, nopIndex);
806 } /* END OF FUNCTION GetFunctionTableValues */
810 /******************************<->*************************************
827 ******************************<->***********************************/
830 GetExecIndex (int tableSize, int *execIndex)
834 for (i = 0; i < (tableSize); i++)
836 if (!(strcmp ("f.exec", functionTable[i].funcName)))
846 } /* END OF FUNCTION GetExecIndex */
849 /******************************<->*************************************
866 ******************************<->***********************************/
870 GetActionIndex (int tableSize, int *actionIndex)
874 for (i = 0; i < (tableSize); i++)
876 if (!(strcmp ("f.action", functionTable[i].funcName)))
886 } /* END OF FUNCTION GetActionIndex */
890 /******************************<->*************************************
907 ******************************<->***********************************/
909 GetNopIndex (int tableSize, int *nopIndex)
913 for (i = 0; i < (tableSize); i++)
915 if (!(strcmp ("f.nop", functionTable[i].funcName)))
925 } /* END OF FUNCTION GetNopIndex */
930 /*************************************<->*************************************
953 *************************************<->***********************************/
955 WmDtGetHelpArgs(char *args,
956 unsigned char* volume,
957 unsigned char* topic,
960 unsigned char *string;
961 unsigned char *lineP;
965 parseP = (unsigned char*) args;
967 if(GetNextLine () != NULL)
971 if ((string = GetSmartSMString (&lineP)) != NULL)
973 *argsCount = *argsCount + 1;
974 strcpy ((char*)topic, (char*)string);
977 if ((string = GetSmartSMString (&lineP)) != NULL)
979 *argsCount = *argsCount + 1;
980 strcpy ((char*)volume, (char *)string);
984 } /* END OF FUNCTION WmDtGetHelpArgs */
990 /******************************<->*************************************
993 * ParseDtSessionHints (pSD, property)
998 * This function parses a DtSessionHints string and returns a list of
999 * DtSessionItems array. The string should have the syntax:
1006 * line = (global) line buffer
1007 * pSD->rootWindow = default root window of display
1019 *************************************<->***********************************/
1022 ParseDtSessionHints (WmScreenData *pSD, unsigned char *property)
1029 ParseSessionItems (pSD);
1031 } /* END OF FUNCTION ParseDtSessionHints */
1034 /*************************************<->*************************************
1036 * FindDtSessionMatch(commandArgc, commandArgv, pCD, pSD, pWorkSpaceList,
1041 * Try to find a match for this client in the session hints.
1042 * Set up client-session data.
1047 * commandArgc - argument count
1048 * commandArgv - WM_COMMAND argument vector
1049 * pCD - pointer to client data
1050 * pSD - pointer to screen data
1051 * pWorkspaceList - pointer to a list of workspaces (to be returned)
1052 * clientMachine - string for -host option in session hints
1056 * *pCD - client data (may be modified)
1057 * FindDtSessionMatch - returns True if a match for this client
1058 * was found in the session hints.
1059 * *pWorkspaceList - list of workspaces this client should be put
1060 * into. (needs to be freed)
1065 * Various pieces of client state (in pCD) are reset when a match
1068 * The caller must free *pWorkspaceList when done.
1070 *************************************<->***********************************/
1071 Boolean FindDtSessionMatch(int commandArgc, char **commandArgv,
1072 ClientData *pCD, WmScreenData *pSD,
1073 char **pWorkSpaceList, char *clientMachine)
1079 SessionGeom *sessionGeom;
1082 for (count = 0; count < pSD->totalSessionItems; count++)
1084 if (!pSD->pDtSessionItems[count].processed &&
1085 pSD->pDtSessionItems[count].commandArgc == commandArgc)
1087 if ((clientMachine) &&
1088 (pSD->pDtSessionItems[count].clientMachine) &&
1089 (strcmp(clientMachine,
1090 pSD->pDtSessionItems[count].clientMachine)))
1093 * This item has clientMachine string but the
1094 * clientMachine does not match.
1098 for (argNum = 0; argNum < commandArgc ; argNum++)
1100 if(strcmp(commandArgv[argNum],
1101 pSD->pDtSessionItems[count].commandArgv[argNum]))
1105 * One mismatch and we quit looking at this item.
1106 * Decrement argNum so a mismatch on the last item
1107 * will not look like a match below when comparing
1108 * argNum == commandArgc
1114 if (argNum == commandArgc)
1117 * Made it through all strings so this is a match
1120 pSD->pDtSessionItems[count].processed = True;
1121 pSD->remainingSessionItems --;
1122 pCD->clientFlags |= SM_LAUNCHED;
1125 * Free strings malloc'd for commandArgv for this item
1128 for (relCount = 0; relCount < commandArgc; relCount++)
1130 XtFree(pSD->pDtSessionItems[count].commandArgv[relCount]);
1132 XtFree((char *)pSD->pDtSessionItems[count].commandArgv);
1134 if(pSD->pDtSessionItems[count].clientState)
1137 pSD->pDtSessionItems[count].clientState;
1138 pCD->clientFlags |= SM_CLIENT_STATE;
1141 if(pSD->pDtSessionItems[count].sessionGeom)
1143 sessionGeom = pSD->pDtSessionItems[count].sessionGeom;
1144 if (sessionGeom->flags & XValue)
1146 pCD->clientX = sessionGeom->clientX;
1147 pCD->clientFlags |= SM_X;
1149 if (sessionGeom->flags & YValue)
1151 pCD->clientY = sessionGeom->clientY;
1152 pCD->clientFlags |= SM_Y;
1154 if (sessionGeom->flags & WidthValue)
1156 pCD->clientWidth = sessionGeom->clientWidth;
1157 pCD->clientFlags |= SM_WIDTH;
1159 if (sessionGeom->flags & HeightValue)
1161 pCD->clientHeight = sessionGeom->clientHeight;
1162 pCD->clientFlags |= SM_HEIGHT;
1166 * Free SessionGeom malloc'd space for this item
1169 XtFree((char *)pSD->pDtSessionItems[count].sessionGeom);
1172 if(pSD->pDtSessionItems[count].clientMachine)
1175 * Free clientMachine malloc'd space for this item
1179 pSD->pDtSessionItems[count].clientMachine);
1180 pSD->pDtSessionItems[count].clientMachine = NULL;
1184 if(pSD->pDtSessionItems[count].workspaces)
1187 * The caller is responsible for freeing this
1190 *pWorkSpaceList = pSD->pDtSessionItems[count].workspaces;
1194 if(pSD->remainingSessionItems == 0)
1197 * Free the whole pSD->pDtSessionHints structure
1199 XtFree((char *)pSD->pDtSessionItems);
1205 } /* not processed and argc's are the same */
1211 } /* END OF FUNCTION FindDtSessionMatch */
1217 /*************************************<->*************************************
1220 * ParseSessionItems (pSD)
1225 * Parse session items
1230 * pSD = pointer to screen data
1231 * cfileP = (global) file pointer to NULL
1232 * line = (global) line buffer
1233 * linec = (global) line count
1234 * parseP = (global) parse string pointer if cfileP == NULL
1235 * pSD->rootWindow = default root window of display
1240 * linec = (global) line count incremented
1241 * parseP = (global) parse string pointer if cfileP == NULL
1248 *************************************<->***********************************/
1251 ParseSessionItems (WmScreenData *pSD)
1253 unsigned char *string;
1254 unsigned char *lineP;
1259 * Parse property string
1264 if(GetNextLine () != NULL)
1266 pSD->totalSessionItems = atoi((char *)line);
1267 pSD->remainingSessionItems = pSD->totalSessionItems;
1271 if((pSD->totalSessionItems < 1) ||
1272 !GetSessionHintsInfo(pSD, pSD->totalSessionItems))
1275 * No items or couldn't allocate space
1282 while ((count < pSD->totalSessionItems) && (GetNextLine () != NULL))
1286 while ((string = GetSmartSMString (&lineP)) != NULL)
1288 if (!strcmp((char *)string, "-geometry"))
1291 * Parse geometry if it is present
1293 string = GetSmartSMString(&lineP);
1294 ParseSessionGeometry (pSD, count, string);
1297 else if (!strcmp((char *)string, "-state"))
1300 * Parse the state if it is present
1302 string = GetSmartSMString(&lineP);
1303 ParseSessionClientState (pSD, count, string);
1306 else if (!strcmp((char *)string, "-workspaces"))
1309 * Parse the workspaces string if it is present
1311 string = GetSmartSMString(&lineP);
1312 ParseSessionWorkspaces (pSD, count, string);
1315 else if (!strcmp((char *)string, "-cmd"))
1318 * Parse the command string if it is present
1320 string = GetSmartSMString(&lineP);
1321 ParseSessionCommand (pSD, count, &string);
1324 else if (!strcmp((char *)string, "-host"))
1327 * Parse the host string if it is present
1329 string = GetSmartSMString(&lineP);
1330 ParseSessionHost (pSD, count, string);
1333 } /* while GetSmartSMString */
1337 } /* while GetNextLine */
1341 } /* END OF FUNCTION ParseSessionItems */
1345 /*************************************<->*************************************
1347 * ParseSessionClientState (pSD, count, string);
1358 *************************************<->***********************************/
1359 void ParseSessionClientState (WmScreenData *pSD, int count,
1360 unsigned char *string)
1366 if(!strcmp((char *)string, "NormalState"))
1368 pSD->pDtSessionItems[count].clientState = NORMAL_STATE;
1370 else if(!strcmp((char *)string, "IconicState"))
1372 pSD->pDtSessionItems[count].clientState = MINIMIZED_STATE;
1376 } /* END OF FUNCTION ParseSessionClientState */
1379 /*************************************<->*************************************
1381 * ParseSessionGeometry (pSD, count, string)
1392 *************************************<->***********************************/
1393 void ParseSessionGeometry (WmScreenData *pSD, int count,
1394 unsigned char *string)
1397 SessionGeom *pTmpSessionGeom;
1399 int X, Y, width, height;
1400 X = Y = width = height = 0;
1406 mask = XParseGeometry((char *)string, &X, &Y, (unsigned int *)&width,
1407 (unsigned int *)&height);
1411 * Allocate space for the geometry structure
1414 if ((pTmpSessionGeom =
1415 (SessionGeom *)XtMalloc (sizeof (SessionGeom))) == NULL)
1417 Warning (((char *)GETMESSAGE(60, 1, "Insufficient memory for session geometry item")));
1422 pTmpSessionGeom->flags = mask;
1423 pTmpSessionGeom->clientX = X;
1424 pTmpSessionGeom->clientY = Y;
1425 pTmpSessionGeom->clientWidth = width;
1426 pTmpSessionGeom->clientHeight = height;
1428 pSD->pDtSessionItems[count].sessionGeom = pTmpSessionGeom;
1431 } /* END OF FUNCTION ParseSessionGeometry */
1434 /*************************************<->*************************************
1437 * ParseSessionWorkspaces (pSD, count, string)
1448 *************************************<->***********************************/
1449 void ParseSessionWorkspaces (WmScreenData *pSD, int count,
1450 unsigned char *string)
1455 * Allocate space for the workspaces string
1458 if ((pSD->pDtSessionItems[count].workspaces =
1459 (String)XtMalloc ((unsigned int) (strlen((char *)string) + 1))) == NULL)
1461 Warning (((char *)GETMESSAGE(60, 2, "Insufficient memory for workspaces list in sesssion item")));
1466 strcpy(pSD->pDtSessionItems[count].workspaces, (char *)string);
1468 } /* END OF FUNCTION ParseSessionWorkspaces */
1472 /*************************************<->*************************************
1475 * ParseSessionCommand (pSD, count, string)
1486 *************************************<->***********************************/
1487 void ParseSessionCommand (WmScreenData *pSD, int count,
1488 unsigned char **commandString)
1492 unsigned char **argv;
1496 unsigned char *string;
1498 argv = (unsigned char **) XtMalloc (ARG_AMT * sizeof(char *));
1499 iSizeArgv = ARG_AMT;
1501 while ((string = GetSmartSMString (commandString)) != NULL)
1504 * Get pointers to strings in command line and count them
1506 argv[argc] = string;
1509 if (argc >= iSizeArgv)
1511 iSizeArgv += ARG_AMT;
1512 argv = (unsigned char **)
1513 XtRealloc ((char *)argv, (iSizeArgv * sizeof(char *)));
1516 if ((pSD->pDtSessionItems[count].commandArgv =
1517 (char **)XtMalloc ((argc) * sizeof(char * ))) == NULL)
1520 * Allocate space for saved argv
1523 Warning (((char *)GETMESSAGE(60, 3, "Insufficient memory for commandArgv array")));
1527 pSD->pDtSessionItems[count].commandArgc = argc;
1528 for (xindex = 0; xindex < argc ; xindex++)
1530 if ((pSD->pDtSessionItems[count].commandArgv[xindex] =
1532 ((unsigned int) (strlen((char *)argv[xindex]) + 1))) == NULL)
1535 * Allocate space for the next command segment.
1537 Warning (((char *)GETMESSAGE(60, 4, "Insufficient memory for commandArgv item")));
1541 strcpy(pSD->pDtSessionItems[count].commandArgv[xindex],
1542 (char *)argv[xindex]);
1547 XtFree ((char *) argv);
1549 } /* END OF FUNCTION ParseSessionCommand */
1553 /*************************************<->*************************************
1556 * ParseSessionHost (pSD, count, string)
1567 *************************************<->***********************************/
1568 void ParseSessionHost (WmScreenData *pSD, int count,
1569 unsigned char *string)
1574 * Allocate space for the workspaces string
1577 if ((pSD->pDtSessionItems[count].clientMachine =
1578 (String)XtMalloc ((unsigned int) (strlen((char *)string) + 1))) ==
1581 Warning (((char *)GETMESSAGE(60, 38,
1582 "Insufficient memory for host name in sesssion item")));
1586 strcpy(pSD->pDtSessionItems[count].clientMachine, (char *)string);
1588 } /* END OF FUNCTION ParseSessionHost */
1592 /*************************************<->*************************************
1594 * GetSessionHintsInfo (pSD, numItems)
1605 *************************************<->***********************************/
1606 Boolean GetSessionHintsInfo (WmScreenData *pSD, long numItems)
1610 if ((pSD->pDtSessionItems =
1611 (DtSessionItem *)XtMalloc (numItems * sizeof (DtSessionItem)))
1614 Warning (((char *)GETMESSAGE(60, 5, "Insufficient memory for Dt Session Hints")));
1618 memset ((char *)pSD->pDtSessionItems, NULL,
1619 numItems * sizeof (DtSessionItem));
1624 } /* END OF FUNCTION GetSessionHintsInfo */
1629 /*************************************<->*************************************
1631 * PeekAhead (currentChar, currentLev)
1636 * Returns a new level value if this is a new nesting level of quoted string
1637 * Otherwise it returns a zero
1642 * currentChar = current position in the string
1643 * currentLev = current level of nesting
1648 * Returns either a new level of nesting or zero if the character is copied in
1654 *************************************<->***********************************/
1655 unsigned int PeekAhead(unsigned char *currentChar,
1656 unsigned int currentLev)
1660 Boolean done = False;
1661 unsigned int tmpLev = 1;
1662 #ifndef NO_MULTIBYTE
1665 while (((chlen = mblen ((char *)currentChar, MB_CUR_MAX)) > 0) &&
1666 (chlen == 1) && ((*currentChar == '"') || (*currentChar == '\\'))
1671 if(((chlen = mblen ((char *)currentChar, MB_CUR_MAX)) > 0) && (chlen == 1) &&
1672 ((*currentChar == '"') || (*currentChar == '\\')))
1675 if(*currentChar == '"')
1686 while((*currentChar != NULL) && (done == False) &&
1687 ((*currentChar == '"') || (*currentChar == '\\')))
1690 if((*currentChar != NULL) &&
1691 ((*currentChar == '"') || (*currentChar == '\\')))
1694 if(*currentChar == '"')
1704 #endif /*NO_MULTIBYTE*/
1707 * Figure out if this is truly a new level of nesting - else ignore it
1708 * This section probably could do some error checking and return -1
1709 * If so, change type of routine from unsigned int to int
1719 } /* END OF FUNCTION PeekAhead */
1726 #ifdef MOTIF_ONE_DOT_ONE
1727 /*************************************<->*************************************
1729 * GetHomeDirName (fileName)
1733 * This function finds the "HOME" directory
1747 *************************************<->***********************************/
1748 void GetHomeDirName(String fileName)
1754 if((ptr = getenv("HOME")) == NULL)
1756 if((ptr = getenv("USER")) != NULL)
1775 strcpy(fileName, ptr);
1780 /*************************************<->*************************************
1782 * SyncModifierStrings (fileName)
1786 * This function updates modifierStrings table so that Mwm uses the correct
1787 * modifier to keysym mapping. Specifically, fix up the Alt and Meta bindings.
1800 *************************************<->***********************************/
1801 void SyncModifierStrings(void)
1803 XModifierKeymap *map;
1806 map = XGetModifierMapping (DISPLAY);
1808 for (i = 0; i < 8; i++)
1810 for (j = 0; j < map->max_keypermod; j++)
1812 if (map->modifiermap[k])
1814 KeySym ks = XKeycodeToKeysym(DISPLAY, map->modifiermap[k], 0);
1815 char *nm = XKeysymToString(ks);
1817 /* Compare, ignoring the trailing '_L' or '_R' in keysym */
1818 if (nm && !strncmp("Alt", nm, 3))
1820 modifierStrings[ALT_INDEX].mask = (1<<i);
1822 else if (nm && !strncmp("Meta", nm, 4))
1824 modifierStrings[META_INDEX].mask = (1<<i);
1831 XFreeModifiermap(map);
1836 /*************************************<->*************************************
1843 * This function reads the mwm resource description file and processes the
1844 * resources that are described.
1849 * wmGD.bitmapDirectory = bitmapDirectory resource value
1850 * pSD->buttonBindings = buttonBindings resource value
1851 * wmGD.configFile = configuration file resource value
1852 * pSD->keyBindings = keyBindings resource value
1853 * wmGD.rootWindow = default root window of display
1854 * HOME = environment variable for home directory
1855 * functionTable = window manager function parse table
1860 * wmGD.buttonSpecs = list of button binding specifications
1861 * wmGD.keySpecs = list of key binding specification
1862 * wmGD.menuSpecs = list of menu specifications
1863 * *wmGD.acceleratorMenuSpecs = initialized array of (MenuSpec *)
1864 * wmGD.acceleratorMenuCount = 0
1869 * If there are more than MAXLINE characters on a line the excess characters
1872 *************************************<->***********************************/
1873 #define MENU_SPEC "menu"
1874 #define BUTTON_SPEC "buttons"
1875 #define KEY_SPEC "keys"
1877 #define FRONT_PANEL_SPEC DTWM_FP_PANEL_OLD
1878 #define DROP_EFFECTS_SPEC DTWM_FP_DROP_EFFECTS
1879 #define PANEL_SPEC DTWM_FP_PANEL
1880 #define BOX_SPEC DTWM_FP_BOX
1881 #define CONTROL_SPEC DTWM_FP_CONTROL
1882 #define INCLUDE_SPEC DTWM_FP_INCLUDE
1883 #define ANIMATION_SPEC DTWM_FP_ANIMATION
1884 #define SWITCH_SPEC DTWM_FP_SWITCH
1886 void ProcessWmFile (WmScreenData *pSD, Boolean bNested)
1888 #else /* PANELIST */
1889 void ProcessWmFile (WmScreenData *pSD)
1890 #endif /* PANELIST */
1892 unsigned char *lineP;
1893 unsigned char *string;
1897 static Boolean conversionInProgress = False;
1903 #endif /* PANELIST */
1906 * Initialize global data values that are set based on data in
1907 * the mwm resource description file.
1910 pSD->buttonSpecs = NULL;
1911 pSD->keySpecs = NULL;
1912 pSD->menuSpecs = NULL;
1915 /**** hhhhhhhhhhhh ******/
1916 GetFunctionTableValues (&F_EXEC_INDEX, &F_NOP_INDEX, &F_ACTION_INDEX);
1919 * Find and parse the default system menu string, if it exists.
1924 if (((parseP = (unsigned char *) builtinSystemMenu) != NULL) &&
1925 (GetNextLine () != NULL))
1928 ParseMenuSet (pSD, lineP);
1932 if (((parseP = (unsigned char *) builtinRootMenu) != NULL) &&
1933 (GetNextLine () != NULL))
1936 ParseMenuSet (pSD, lineP);
1939 if (wmGD.useFrontPanel && !wmGD.dtSD &&
1940 (XDefaultScreen (wmGD.display) == pSD->screen))
1942 wmGD.dtSD = pSD; /* only one per display */
1944 #endif /* PANELIST */
1947 * Find and associate a stream with the window manager resource
1951 if ((cfileP = FopenConfigFile ()) == NULL)
1953 if (!wmGD.useStandardBehavior)
1954 Warning (((char *)GETMESSAGE(60, 6, "Cannot open configuration file")));
1959 } /* end if (!bNested) */
1960 #endif /* PANELIST */
1962 * Parse the information in the configuration file.
1963 * If there are more than MAXLINE characters on a line the excess are
1968 while ((GetNextLine () != NULL)) /* not EOF nor read error */
1971 if ((*line == '!') || (string = GetString (&lineP)) == NULL)
1972 /* empty or comment line */
1978 if (!strcmp ((char *)string, MENU_SPEC))
1980 ParseMenuSet (pSD, lineP);
1982 else if (!strcmp ((char *) string, BUTTON_SPEC))
1984 ParseButtonSet (pSD, lineP);
1986 else if (!strcmp ((char *) string, KEY_SPEC))
1988 ParseKeySet (pSD, lineP);
1991 else if (!strcmp ((char *)string, INCLUDE_SPEC))
1993 ParseIncludeSet (pSD, lineP);
1995 #endif /* PANELIST */
2001 * Create and initialize the pSD->acceleratorMenuSpecs array.
2002 * This assumes we create pointers to MenuSpecs within ProcessWmFile().
2003 * Set pSD->acceleratorMenuCount to 0.
2006 /* count the number of menu specifications */
2008 menuSpec = pSD->menuSpecs;
2012 menuSpec = menuSpec->nextMenuSpec;
2015 /* allocate the array and initialize to zeros */
2016 pSD->acceleratorMenuSpecs = NULL;
2019 pSD->acceleratorMenuSpecs =
2020 (MenuSpec **) XtCalloc (n, sizeof (MenuSpec *));
2021 if (pSD->acceleratorMenuSpecs == NULL)
2023 Warning (((char *)GETMESSAGE(60, 7, "Insufficient memory for menu accelerators")));
2026 pSD->acceleratorMenuCount = 0;
2027 } /* END OF FUNCTION ProcessWmFile */
2029 /**** This function stolen from Xt/Intrinsic.c ****/
2030 /* The implementation of this routine is operating system dependent */
2032 static char *ExtractLocaleName(lang)
2036 #ifdef hpux /* hpux-specific parsing of the locale string */
2037 #define MAXLOCALE 64 /* buffer size of locale name */
2042 static char buf[MAXLOCALE];
2044 /* If lang has a substring ":<category>;", extract <category>
2045 * from the first such occurrence as the locale name.
2049 if (start = strchr (lang, ':')) {
2051 if (end = strchr (start, ';')) {
2053 strncpy(buf, start, len);
2054 *(buf + len) = '\0';
2064 #define RC_CONFIG_SUBDIR "/config/"
2065 #define RC_DEFAULT_CONFIG_SUBDIR "/config/C"
2068 /*************************************<->*************************************
2070 * FopenConfigFile ()
2075 * This function searches for, opens, and associates a stream with the mwm
2076 * resource description file,
2081 * wmGD.configFile = configuration file resource value.
2082 * HOME = environment variable for home directory
2087 * Return = If successful, a pointer to the FILE structure associated with
2088 * the configuration file. Otherwise, NULL.
2095 *************************************<->***********************************/
2096 FILE *FopenConfigFile (void)
2102 #ifndef MOTIF_ONE_DOT_ONE
2103 char *homeDir = XmeGetHomeDirName();
2106 Boolean stackPushed;
2107 #endif /* PANELIST */
2110 * Get the LANG environment variable
2111 * make copy since another call to getenv will blast the value.
2113 LANGp = setlocale(LC_CTYPE, NULL);
2116 * setlocale not guaranteed to return $LANG -- extract
2119 LANGp = ExtractLocaleName (LANGp);
2121 if ((LANGp == NULL) || (strlen(LANGp) == 0))
2127 if ((LANG = (char *) XtMalloc(strlen(LANGp) +1)) == NULL)
2129 PWarning (((char *)GETMESSAGE(60, 41, "Insufficient memory to get LANG environment variable.")));
2133 strcpy(LANG, LANGp);
2138 * To get a name for the file first look at the value of the configFile
2139 * resource. Interpret "~/.." as relative to the user's home directory.
2140 * Use the LANG variable if set and .mwmrc is in $HOME/$LANG/.mwmrc
2144 if (pConfigStackTop && pConfigStackTop->tempName)
2146 fileP = fopen (pConfigStackTop->tempName, "r");
2149 stackPushed = (pConfigStackTop && (pConfigStackTop != pConfigStack));
2151 cfileName[0] = '\0';
2152 #endif /* PANELIST */
2153 if ((wmGD.configFile != NULL) && (wmGD.configFile[0] != '\0'))
2154 /* pointer to nonNULL string */
2156 if ((wmGD.configFile[0] == '~') && (wmGD.configFile[1] == '/'))
2157 /* handle "~/..." */
2159 #ifdef MOTIF_ONE_DOT_ONE
2160 GetHomeDirName(cfileName);
2162 strcpy (cfileName, homeDir);
2166 strncat(cfileName, "/", MAXWMPATH-strlen(cfileName));
2167 strncat(cfileName, LANG, MAXWMPATH-strlen(cfileName));
2169 strncat(cfileName, &(wmGD.configFile[1]), MAXWMPATH-strlen(cfileName));
2170 if ((fileP = fopen (cfileName, "r")) != NULL)
2178 #endif /* PANELIST */
2183 * Just try $HOME/.mwmrc
2185 #ifdef MOTIF_ONE_DOT_ONE
2186 GetHomeDirName(cfileName);
2188 strcpy (cfileName, homeDir);
2190 strncat(cfileName, &(wmGD.configFile[1]),
2191 MAXWMPATH-strlen(cfileName));
2192 if ((fileP = fopen (cfileName, "r")) != NULL)
2200 #endif /* PANELIST */
2207 /* relative to current directory or absolute */
2212 pch = (char *) GetNetworkFileName (wmGD.configFile);
2214 if ((fileP = fopen (pch, "r")) != NULL)
2216 strncpy (cfileName, pch, MAXWMPATH);
2220 if ((fileP == NULL) && !stackPushed)
2222 #endif /* PANELIST */
2223 if ((fileP = fopen (wmGD.configFile, "r")) != NULL)
2233 else if ((fileP == NULL) && stackPushed)
2235 strcpy (cfileName, wmGD.configFile);
2237 #endif /* PANELIST */
2241 if ((fileP == NULL) && !stackPushed)
2243 #endif /* PANELIST */
2246 * The configFile resource didn't do it for us.
2247 * First try HOME_MWMRC, then try SYS_MWMRC .
2250 #define HOME_MWMRC "/.mwmrc"
2251 #define SLASH_MWMRC "/system.mwmrc"
2253 #ifdef MOTIF_ONE_DOT_ONE
2254 GetHomeDirName(cfileName);
2256 strcpy (cfileName, homeDir);
2264 * Looking for $HOME/$LANG/.mwmrc
2265 * --or--if $LANG is NULL
2266 * Looking for $HOME/.mwmrc
2271 strncat(cfileName, "/", MAXWMPATH-strlen(cfileName));
2272 strncat(cfileName, LANG, MAXWMPATH-strlen(cfileName));
2274 strncat(cfileName, HOME_MWMRC, MAXWMPATH - strlen(cfileName));
2280 * Looking for $HOME/.dt/$LANG/dtwmrc
2282 * --or--if $LANG is NULL--
2284 * Looking for $HOME/.dt/dtwmrc
2287 strncat(cfileName, "/.dt/", MAXWMPATH-strlen(cfileName));
2291 strncat(cfileName, LANG, MAXWMPATH-strlen(cfileName));
2293 strncat(cfileName, LANG_DT_WMRC, MAXWMPATH - strlen(cfileName));
2298 strncat(cfileName, "/", MAXWMPATH-strlen(cfileName));
2299 strncat(cfileName, LANG, MAXWMPATH-strlen(cfileName));
2301 strncat(cfileName, HOME_MWMRC, MAXWMPATH - strlen(cfileName));
2303 if ((fileP = fopen (cfileName, "r")) != NULL)
2311 #endif /* PANELIST */
2316 * Just try $HOME/.mwmrc
2318 #ifdef MOTIF_ONE_DOT_ONE
2319 GetHomeDirName(cfileName);
2321 strcpy (cfileName, homeDir);
2327 * Just try $HOME/.mwmrc
2329 strncat(cfileName, HOME_MWMRC, MAXWMPATH - strlen(cfileName));
2334 * Just try $HOME/.dt/dtwmrc
2336 strncat(cfileName, HOME_DT_WMRC, MAXWMPATH - strlen(cfileName));
2339 strncat(cfileName, HOME_MWMRC, MAXWMPATH - strlen(cfileName));
2341 if ((fileP = fopen (cfileName, "r")) != NULL)
2349 #endif /* PANELIST */
2355 #define DTLIBDIR CDE_INSTALLATION_TOP
2356 #define DTADMINDIR CDE_CONFIGURATION_TOP
2357 #define SLASH_DT_WMRC "/sys.dtwmrc"
2359 if ((fileP == NULL) && !stackPushed)
2362 * No home-based config file. Try the admin directory.
2364 strcpy(cfileName, DTADMINDIR);
2365 strncat(cfileName, RC_CONFIG_SUBDIR, MAXWMPATH-strlen(cfileName));
2366 strncat(cfileName, LANG, MAXWMPATH-strlen(cfileName));
2367 strncat(cfileName, SLASH_DT_WMRC, MAXWMPATH - strlen(cfileName));
2369 if (((fileP = fopen (cfileName, "r")) == NULL) && LANG && *LANG)
2371 /* Try it with no LANG */
2372 strcpy(cfileName, DTADMINDIR);
2373 strncat(cfileName, RC_CONFIG_SUBDIR, MAXWMPATH-strlen(cfileName));
2374 strncat(cfileName, SLASH_DT_WMRC, MAXWMPATH - strlen(cfileName));
2377 if ((fileP = fopen (cfileName, "r")) != NULL)
2384 if ((fileP == NULL) && !stackPushed)
2386 #endif /* PANELIST */
2389 #define LIBDIR "/usr/lib/X11"
2396 strcpy(cfileName, LIBDIR);
2397 strncat(cfileName, "/", MAXWMPATH-strlen(cfileName));
2398 strncat(cfileName, LANG, MAXWMPATH-strlen(cfileName));
2399 strncat(cfileName, SLASH_MWMRC, MAXWMPATH - strlen(cfileName));
2403 strcpy(cfileName, DTLIBDIR);
2404 strncat(cfileName, RC_CONFIG_SUBDIR, MAXWMPATH-strlen(cfileName));
2405 strncat(cfileName, LANG, MAXWMPATH-strlen(cfileName));
2406 strncat(cfileName, SLASH_DT_WMRC, MAXWMPATH - strlen(cfileName));
2410 * Try /$LANG/system.mwmrc within the install tree
2412 strcpy(cfileName, LIBDIR);
2413 strncat(cfileName, "/", MAXWMPATH-strlen(cfileName));
2414 strncat(cfileName, LANG, MAXWMPATH-strlen(cfileName));
2415 strncat(cfileName, SLASH_MWMRC, MAXWMPATH - strlen(cfileName));
2417 if ((fileP = fopen (cfileName, "r")) != NULL)
2423 #endif /* PANELIST */
2428 if ((fileP == NULL) && !stackPushed)
2430 #endif /* PANELIST */
2434 strcpy(cfileName, LIBDIR);
2435 strncat(cfileName, SLASH_MWMRC, MAXWMPATH - strlen(cfileName));
2437 fileP = fopen (cfileName, "r");
2438 #else /* PANELIST */
2439 return (fopen (cfileName, "r"));
2440 #endif /* PANELIST */
2444 strcpy(cfileName, DTLIBDIR);
2445 strncat(cfileName, RC_DEFAULT_CONFIG_SUBDIR,
2446 MAXWMPATH - strlen(cfileName));
2447 strncat(cfileName, SLASH_DT_WMRC, MAXWMPATH - strlen(cfileName));
2449 fileP = fopen (cfileName, "r");
2450 #else /* PANELIST */
2451 return (fopen (cfileName, "r"));
2452 #endif /* PANELIST */
2456 * Try /system.mwmrc within the install tree
2458 strcpy(cfileName, LIBDIR);
2459 strncat(cfileName, SLASH_MWMRC, MAXWMPATH - strlen(cfileName));
2467 strcpy(cfileName, cfileName);
2468 fileP = fopen (cfileName, "r");
2469 #else /* PANELIST */
2470 return (fopen (cfileName, "r"));
2471 #endif /* PANELIST */
2482 * handle "<host>:<path>" form of file name
2484 pch = (char *) GetNetworkFileName (cfileName);
2485 if ((fileP = fopen (cfileName, "r")) != NULL)
2487 strncpy (cfileName, pch, MAXWMPATH);
2492 * Either not "<host>:<path>" form or there was a
2493 * problem up above. This is the last attempt to
2498 fileP = fopen (cfileName, "r");
2504 ConfigStackInit (cfileName);
2507 if (wmGD.cppCommand && *wmGD.cppCommand)
2510 * Run the file through the C-preprocessor
2512 PreprocessConfigFile ();
2513 if (pConfigStackTop->cppName)
2515 /* open the result */
2516 fileP = fopen (pConfigStackTop->cppName, "r");
2526 #endif /* PANELIST */
2528 } /* END OF FUNCTION FopenConfigFile */
2531 /*************************************<->*************************************
2533 * SaveMenuAccelerators (pSD, newMenuSpec)
2538 * This function saves the MenuSpec pointer in pSD->acceleratorMenuSpecs.
2543 * newMenuSpec = pointer to MenuSpec to be saved.
2544 * pSD->acceleratorMenuSpecs =
2545 * pSD->acceleratorMenuCount =
2550 * pSD->acceleratorMenuSpecs = possibly updated
2551 * pSD->acceleratorMenuCount = possibly updated
2556 * We assume only MenuSpecs created within ProcessWmFile() are to be saved.
2557 * Otherwise, we may cause override the limits of pSD->acceleratorMenuSpecs.
2559 *************************************<->***********************************/
2561 void SaveMenuAccelerators (WmScreenData *pSD, MenuSpec *newMenuSpec)
2563 MenuSpec **pMenuSpec;
2565 pMenuSpec = pSD->acceleratorMenuSpecs;
2567 if (pMenuSpec == NULL)
2570 while ((*pMenuSpec != NULL) && (*pMenuSpec != newMenuSpec))
2575 if (*pMenuSpec == NULL)
2577 *pMenuSpec = newMenuSpec;
2578 pSD->acceleratorMenuCount++;
2581 } /* END OF FUNCTION SaveMenuAccelerators */
2584 /*************************************<->*************************************
2586 * ParseMenuSet (pSD, lineP)
2591 * Menu pane specification found. Parse the following syntax:
2594 * Menu menu_pane_name
2596 * label [mnemonic] [accelerator] function
2597 * label [mnemonic] [accelerator] function
2599 * label [mnemonic] [accelerator] function
2605 * cfileP = (global) file pointer to fopened configuration file or NULL
2606 * lineP = pointer to menu name in line buffer
2607 * line = (global) line buffer
2608 * linec = (global) line count
2609 * parseP = (global) parse string pointer if cfileP == NULL
2610 * pSD->rootWindow = default root window of display
2611 * wmGD.bitmapDirectory = bitmapDirectory resource value
2612 * HOME = environment variable for home directory
2617 * linec = (global) line count incremented
2618 * parseP = (global) parse string pointer if cfileP == NULL
2619 * pSD->menuSpecs = list of menu specifications
2624 * Skips unnamed menu specifications.
2625 * This means custom menu specifications can be distinguished by NULL name.
2627 *************************************<->***********************************/
2629 static void ParseMenuSet (WmScreenData *pSD, unsigned char *lineP)
2631 unsigned char *string;
2635 * If menu name is NULL then skip this pane specification.
2638 if ((string = GetString (&lineP)) == NULL)
2644 * Allocate space for the menu specification structure.
2647 if ((menuSpec = (MenuSpec *)XtMalloc (sizeof (MenuSpec))) == NULL)
2649 PWarning (((char *)GETMESSAGE(60, 9, "Insufficient memory for menu")));
2652 menuSpec->currentContext = 0;
2653 menuSpec->menuWidget = NULL;
2654 menuSpec->whichButton = SELECT_BUTTON; /* Button1 selection default */
2655 menuSpec->menuItems = NULL;
2656 menuSpec->accelContext = 0;
2657 menuSpec->accelKeySpecs = NULL;
2658 #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
2659 menuSpec->exclusions = NULL;
2660 menuSpec->clientLocal = FALSE;
2661 #endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
2662 menuSpec->nextMenuSpec = NULL;
2665 * Allocate and fill space for the menu name.
2668 if ((menuSpec->name =
2669 (String)XtMalloc ((unsigned int) (strlen ((char *)string) + 1)))
2672 PWarning (((char *)GETMESSAGE(60, 10, "Insufficient memory for menu")));
2673 XtFree ((char *)menuSpec);
2676 strcpy (menuSpec->name, (char *)string);
2679 * Add the empty structure to the head of the menu specification list.
2682 menuSpec->nextMenuSpec = pSD->menuSpecs;
2683 pSD->menuSpecs = menuSpec;
2686 * Require leading '{' on the next line.
2689 while ((GetNextLine () != NULL)) /* not EOF nor read error */
2692 ScanWhitespace(&lineP);
2694 if ((lineP == NULL) || (*line == '!') || (*lineP == '\0') || (*lineP == '#'))
2695 /* ignore empty or comment line */
2707 PWarning (((char *)GETMESSAGE(60, 11, "Expected '{' after menu name")));
2712 * Found leading "{" or EOF.
2713 * Parse menu item specifications until "}" or EOF found.
2716 menuSpec->menuItems = PARSE_MENU_ITEMS (pSD, menuSpec);
2718 } /* END OF FUNCTION ParseMenuSet */
2721 /*************************************<->*************************************
2724 * ParseMwmMenuStr (pSD, menuStr)
2729 * This function parses a WMW_MENU string and returns a list of
2730 * MenuItems structures. The string should have the syntax:
2732 * label [mnemonic] [accelerator] function
2733 * label [mnemonic] [accelerator] function
2735 * label [mnemonic] [accelerator] function
2740 * line = (global) line buffer
2741 * pSD->rootWindow = default root window of display
2742 * wmGD.bitmapDirectory = bitmapDirectory resource value
2743 * HOME = environment variable for home directory
2744 * functionTable = window manager function parse table
2749 * Return = list of MenuItem structures or NULL
2756 *************************************<->***********************************/
2758 MenuItem *ParseMwmMenuStr (WmScreenData *pSD, unsigned char *menuStr)
2765 return (PARSE_MENU_ITEMS (pSD, NULL));
2767 } /* END OF FUNCTION ParseMwmMenuStr */
2770 /*************************************<->*************************************
2773 * ParseMenuItems (pSD, menuSpec)
2778 * Parse menu item specifications:
2780 * label [mnemonic] [accelerator] function
2781 * label [mnemonic] [accelerator] function
2783 * label [mnemonic] [accelerator] function
2789 * pSD = pointer to screen data
2790 * cfileP = (global) file pointer to fopened configuration file or NULL
2791 * line = (global) line buffer
2792 * linec = (global) line count
2793 * parseP = (global) parse string pointer if cfileP == NULL
2794 * pSD->rootWindow = default root window of display
2795 * wmGD.bitmapDirectory = bitmapDirectory resource value
2796 * HOME = environment variable for home directory
2801 * linec = (global) line count incremented
2802 * parseP = (global) parse string pointer if cfileP == NULL
2803 * Return = list of MenuItem structures or NULL
2810 *************************************<->***********************************/
2812 static MenuItem *ParseMenuItems (WmScreenData *pSD
2813 #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
2814 , MenuSpec *menuSpec
2815 #endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
2818 unsigned char *string;
2819 unsigned char *lineP;
2820 MenuItem *firstMenuItem;
2821 MenuItem *lastMenuItem;
2824 #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
2825 Boolean use_separators = False;
2826 #endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
2829 * Parse "label [mnemonic] [accelerator] function" or
2830 * "<client command>[.<client command>]*"
2831 * lines until "}" or EOF found.
2834 firstMenuItem = lastMenuItem = NULL;
2835 while ((GetNextLine () != NULL))
2838 if ((*line == '!') || (*line == '#') || (string = GetString (&lineP)) == NULL)
2839 /* ignore empty or comment lines */
2843 if (*string == '}') /* finished with menu set. */
2849 * Allocate space for the menu item structure.
2852 if ((menuItem = (MenuItem *)XtMalloc (sizeof (MenuItem))) == NULL)
2854 PWarning (((char *)GETMESSAGE(60, 12, "Insufficient memory for menu item")));
2857 menuItem->nextMenuItem = NULL;
2858 menuItem->wmFunction = (WmFunction)NULL;
2859 menuItem->wmFuncArgs = NULL;
2860 #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
2861 menuItem->clientCommandName = NULL;
2862 menuItem->clientCommandID = 0;
2863 #endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
2865 #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
2867 * Is this a simple menu item label or is it a
2868 * client command specification.
2871 if (IsClientCommand((String) string))
2873 if (!ParseClientCommand(&lineP, menuSpec, menuItem, string,
2876 XtFree ((char *)menuItem);
2880 for (ix = 0; ix < WMFUNCTIONTABLESIZE - 1; ++ix)
2881 if (functionTable[ix].wmFunction == F_InvokeCommand)
2884 if (ix == WMFUNCTIONTABLESIZE - 1)
2887 menuItem->wmFunction = F_Nop;
2889 else menuItem->wmFunction = F_InvokeCommand;
2891 else /* It must be a menu item label */
2892 #endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
2895 * Parse the menu item label.
2897 if (!ParseWmLabel (pSD, menuItem, string))
2899 XtFree ((char *)menuItem);
2905 * Parse any menu function mnemonic.
2908 ParseWmMnemonic (&lineP, menuItem);
2911 * Parse any menu function accelerator.
2914 if (!ParseWmAccelerator (&lineP, menuItem))
2916 XtFree ((char *)menuItem);
2920 * Parse the menu function name if this is not a client
2921 * command. If it is a client command, then the wmFunction
2922 * field should already be set, as well as the ix variable,
2923 * but we do want to search for a menu item name that occupies
2924 * the same place as the function does for normal menu items.
2926 #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
2927 if (menuItem->wmFunction != NULL)
2928 ParseMenuItemName(&lineP, menuItem);
2930 #endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
2931 ix = ParseWmFunction (&lineP, CRS_MENU, &menuItem->wmFunction);
2934 * Determine context sensitivity and applicability mask.
2937 menuItem->greyedContext = functionTable[ix].greyedContext;
2938 menuItem->mgtMask = functionTable[ix].mgtMask;
2940 if ((menuItem->wmFunction == F_Toggle_Front_Panel) &&
2941 ((wmGD.useFrontPanel == False) ||
2942 (wmGD.dtSD != pSD)))
2945 * disallow this function if there's no front
2946 * panel on this screen.
2948 menuItem->greyedContext |= (F_CONTEXT_ALL |
2949 F_SUBCONTEXT_IB_WICON |
2950 F_SUBCONTEXT_IB_IICON);
2952 #endif /* PANELIST */
2955 * Apply the function argument parser.
2957 if (!(*(functionTable [ix].parseProc))
2958 (&lineP, menuItem->wmFunction, &menuItem->wmFuncArgs))
2960 FreeMenuItem (menuItem);
2961 continue; /* skip this menu item */
2964 #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
2966 * If we're working on the f.cci function, this will fix-up
2967 * the menuItem entries so that it appears that we read-in
2968 * an old-style client-command entry. Eventually, the cci
2969 * handling should be changed to make use of the wmFuncArgs.
2970 * Note that if DEFAULT_NAME was specified as the label, it
2971 * is first set to NULL.
2972 * FixMenuItem needs menuSpec since this is when the EXCLUDE
2975 if (ix == F_CCI_INDEX)
2977 CCIEntryModifier mod = ((CCIFuncArg *)menuItem->wmFuncArgs)->mod;
2979 /* first fix the label if needed. */
2980 if (!strcmp(menuItem->label, CCI_USE_DEFAULT_NAME_TAG))
2982 XtFree(menuItem->label);
2983 menuItem->label = NULL;
2986 FixMenuItem(menuSpec, menuItem);
2988 if (mod == DELIMIT || mod == DELIMIT_CASCADE || mod == DELIMIT_INLINE)
2989 use_separators = True;
2993 * If this menu item is supposed to be wrapped in separators,
2994 * then create a separator template before the menu item
2998 MenuItem *separator = MakeSeparatorTemplate(TOP_SEPARATOR);
2999 if (lastMenuItem != NULL) lastMenuItem->nextMenuItem = separator;
3000 else firstMenuItem = separator;
3001 lastMenuItem = separator;
3003 #endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
3006 * Add this item to the menu specification.
3009 if (lastMenuItem != NULL) /* not first */
3011 lastMenuItem->nextMenuItem = menuItem;
3015 firstMenuItem = menuItem;
3017 lastMenuItem = menuItem;
3019 #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
3020 /* If this menu item is supposed to be wrapped in separators
3021 * then create a separator template after the menu item
3025 MenuItem *separator = MakeSeparatorTemplate(BOTTOM_SEPARATOR);
3026 if (lastMenuItem != NULL) lastMenuItem->nextMenuItem = separator;
3027 else firstMenuItem = separator;
3028 lastMenuItem = separator;
3031 use_separators = FALSE;
3032 #endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
3035 return (firstMenuItem);
3037 } /* END OF FUNCTION ParseMenuItems */
3041 #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
3042 /*************************************<->*************************************
3044 * StoreExclusion (menuSpec, string)
3049 * Store the exclusion string in the menuspec. The list of exclusion
3050 * strings are used to determine whether an insertion should be disallowed.
3055 * menuSpec = the menu specification structure
3056 * string = exclusion client command string
3066 *************************************<->***********************************/
3068 static void StoreExclusion (MenuSpec *menuSpec, String string)
3070 MenuExclusion *exclusion;
3072 exclusion = (MenuExclusion *)XtMalloc(sizeof(MenuExclusion));
3073 exclusion->command_string = XtNewString(string);
3075 /* We don't care what order the exclusions are in so stick it
3076 at the head of the list because it is easier. */
3077 exclusion->nextExclusion = menuSpec->exclusions;
3078 menuSpec->exclusions = exclusion;
3082 /*************************************<->*************************************
3084 * IsClientCommand (string)
3089 * Determine whether the string is a client command by the prefix
3095 * string = possible client command string
3100 * Return = (Boolean) TRUE iff the string is a client command.
3101 * Otherwise, FALSE is returned.
3106 * This function simply checks what the first two or three characters of
3107 * the string are. If they match the beginning of a client command
3108 * specification, then TRUE is returned. This function does no go on to
3109 * parse the rest of the specification. The legal client command beginning
3112 * characters: meaning:
3113 * -----------------------------------------------
3114 * < simple client command beginning
3115 * ->< forced cascade menu
3116 * =< client command with separators
3117 * ~< exclusion operator
3121 * There is no leading whitespace on the string
3123 *************************************<->***********************************/
3125 Boolean IsClientCommand (String string)
3127 if ((mblen ((char *)string, MB_CUR_MAX) == 1 && *string == '<') ||
3128 (strncmp(string, "-><", 3) == 0) ||
3129 (strncmp(string, "=<", 2) == 0) ||
3130 (strncmp(string, "=><", 3) == 0) ||
3131 (strncmp(string, "~<", 2) == 0))
3138 /*************************************<->*************************************
3140 * ParseClientCommand (linePP, menuSpec, menuitem, string, use_separators)
3145 * Parse the string and whatever is left of the line to verify whether
3146 * correct syntax was used for a client command. Store the client command
3147 * string in the menuitem, unless it is an exclusion. If it is an
3148 * exclusion, then store the exclusion string in the menuSpec and return
3149 * FALSE to indicate that the menuitem is no longer needed.
3154 * linePP = pointer to current line buffer pointer.
3155 * menuItem = pointer to MenuItem structure
3156 * string = first token of client command
3161 * Return = (Boolean) TRUE iff the line is a valid client command
3162 * that can used to match insertions.
3163 * Otherwise, FALSE is returned meaning that the client
3164 * command had incorrect syntax or it was an exclusion, in
3165 * which case any useful information was stored in the
3171 * This function parses the entire line to determine if correct
3172 * syntax was used for the client command. We assume at this point
3173 * that the line is a client command. We are just syntax checking.
3174 * If the syntax is correct, the client command is stored in the
3175 * menuitem structure, in the "label" field.
3177 * Valid syntax for a client command (single quoted characters are
3180 * modifier = { '->' | '=' | '~' }
3181 * reference = '<' { name | '*' } '>'
3182 * command = [ modifier ] reference [ { modifier | '.' } reference ]*
3183 * name = alpha-numeric string, white space allowed
3187 * There is no leading whitespace on the string argument
3189 *************************************<->***********************************/
3191 enum { PRS_NO_STATE, PRS_BEGIN, PRS_MODIFIER, PRS_REFERENCE,
3192 PRS_SEPARATOR, PRS_END, PRS_ERROR, PRS_MAX_STATES };
3194 /* This table lists for each parse state, the legal states that can
3195 be moved to. Each list must end with a PRS_NO_STATE value to
3196 terminate the list. */
3197 static int cmd_parse_table[PRS_END][PRS_END] =
3199 /* PRS_NO_STATE */ { PRS_NO_STATE },
3200 /* PRS_BEGIN */ { PRS_MODIFIER, PRS_REFERENCE, PRS_NO_STATE },
3201 /* PRS_MODIFIER */ { PRS_REFERENCE, PRS_NO_STATE },
3202 /* PRS_REFERENCE */ { PRS_SEPARATOR, PRS_END, PRS_NO_STATE },
3203 /* PRS_SEPARATOR */ { PRS_REFERENCE, PRS_NO_STATE },
3206 static Boolean ParseClientCommand (unsigned char **linePP, MenuSpec *menuSpec,
3207 MenuItem *menuItem, unsigned char *string,
3208 Boolean *use_separators)
3210 int token, linelen, i;
3211 int state = PRS_BEGIN;
3212 String stream, unchanged_stream, exclusion_text;
3213 Boolean return_val = FALSE;
3214 Boolean exclusion = FALSE; /* this will be set to TRUE if the client
3215 command was parsed to be an exclusion
3218 /* Construct one input stream out of the string and the linePP that
3220 linelen = strlen((char *)string) + strlen((char *)*linePP) + 1;
3221 if ((unchanged_stream = stream = (String)
3222 XtMalloc((unsigned int)(sizeof(unsigned char) * linelen))) == NULL)
3224 PWarning (((char *)GETMESSAGE(60, 42,
3225 "Insufficient memory for menu item label")));
3228 strcpy(stream, (char *) string);
3229 strcat(stream, " ");
3230 strcat(stream, (char *) *linePP);
3234 token = PRS_NO_STATE;
3235 while (token == PRS_NO_STATE)
3237 if (mblen ((char *)stream, MB_CUR_MAX) > 1) {
3246 /* We've reached the end of the stream. Return the
3251 /* This should be a cascade-force modifier */
3253 if (mblen ((char *)stream, MB_CUR_MAX) > 1) {
3259 ++stream; token = PRS_MODIFIER;
3261 else token = PRS_ERROR;
3264 /* This is either a separators modifier or
3265 a combination separators and cascade-force
3268 if (mblen ((char *)stream, MB_CUR_MAX) > 1) {
3272 if (*stream == '>') ++stream;
3273 token = PRS_MODIFIER;
3274 *use_separators = TRUE;
3277 /* This is a exclude-command modifier */
3278 ++stream; token = PRS_MODIFIER;
3280 /* Setup a pointer to the text following the ~ so
3281 we can do matching later for exclusions. */
3282 exclusion_text = stream;
3285 /* Skip the open bracket */
3288 /* This should be the beginning of a reference. First
3289 skip any leading whitespace. */
3290 if (mblen ((char *)stream, MB_CUR_MAX) > 1) {
3294 while (mblen ((char *)stream, MB_CUR_MAX) == 1 &&
3295 (*stream == ' ' || *stream == '\t'))
3298 if (mblen ((char *)stream, MB_CUR_MAX) > 1) {
3302 /* Now check for a reference name wild card or a
3303 full reference name */
3308 while (mblen ((char *)stream, MB_CUR_MAX) == 1 &&
3309 (isalnum(*stream) || *stream == ' ' ||
3310 *stream == '\t' || *stream == '_' ))
3314 if (mblen ((char *)stream, MB_CUR_MAX) > 1) {
3319 /* Now skip past any trailing white space */
3320 while (mblen ((char *)stream, MB_CUR_MAX) == 1 &&
3321 (*stream == ' ' || *stream == '\t'))
3324 if (mblen ((char *)stream, MB_CUR_MAX) > 1) {
3328 /* At this point, we should be looking at the close
3332 token = PRS_REFERENCE;
3335 else token = PRS_ERROR;
3338 /* This is a reference separator */
3339 ++stream; token = PRS_SEPARATOR;
3343 /* The only place white space is allowed as at the
3344 beginning of the line, after all the client command
3345 text and within the delimiters of a REFERENCE. We
3346 are guaranteed not to have whitespace at the
3347 beginning of the line by the time this function is
3348 called. Also, the REFERENCE parsing above handles
3349 all white space internal to the client command. Therefore,
3350 since we are seeing white space, we must be at the
3351 end of the client command. */
3357 } /* end switch (*stream) */
3358 } /* end while (token == PRS_NO_STATE) */
3360 /* If we got an error then just return an error */
3361 if (token == PRS_ERROR)
3363 return_val = FALSE; break;
3366 /* Check whether the token we got is a valid transition */
3367 for (i = 0; cmd_parse_table[state][i] != PRS_NO_STATE; ++i)
3369 if (token == cmd_parse_table[state][i])
3371 /* It is a valid transition, so break out of the loop */
3376 /* If i is not indexing the NO_STATE value in the parse_table,
3377 then the parse succeeded. Check if the new state is PRS_END.
3378 If so then we are done. If the state isn't the same as the
3379 current token, then we hit a parse error. */
3380 if (cmd_parse_table[state][i] != PRS_NO_STATE)
3382 if (token == PRS_END)
3395 /* The transition was valid so make the transition by
3396 setting the state to be the current token. */
3399 } /* end for (;;) */
3401 /* If the return_val is TRUE, then the parse succeeded and we
3402 want to save the string we parsed into the label field of
3404 if (return_val == TRUE)
3406 /* NULL terminate the string */
3409 /* Check whether this client command was an exclusion. If not,
3410 then store the client command string in the menu item. */
3411 if (exclusion == TRUE)
3413 /* Since the command was an exclusion, store the command
3414 string in the menuSpec and change the return value to
3416 StoreExclusion(menuSpec, exclusion_text);
3421 menuItem->label = XtNewString(unchanged_stream);
3422 menuItem->labelType = XmSTRING;
3426 /* Free the string we allocated and return. */
3427 XtFree((char *)unchanged_stream);
3431 #endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
3434 /*************************************<->*************************************
3436 * ParseWmLabel (pSD, menuItem, string)
3441 * Parse a menu label string.
3446 * pSD = pointer to screen data
3447 * menuItem = pointer to MenuItem structure
3448 * string = label string
3454 * menuItem->labelType
3455 * menuItem->labelBitmapCache
3456 * Return = boolean, FALSE iff insufficient memory
3461 * We have two label types: XmSTRING and XmPIXMAP
3462 * We allocate and fill the label field with string and set the type to
3463 * XmSTRING. If string = "@<bitmap_file>", and <bitmap_file> contains a
3464 * with which to build a label image we save the bitmap in the MenuItem
3465 * structure and set the type to XmPIXMAP.
3467 *************************************<->***********************************/
3469 static Boolean ParseWmLabel (WmScreenData *pSD, MenuItem *menuItem,
3470 unsigned char *string)
3474 * Allocate the label field and copy string.
3477 if ((menuItem->label = (String)
3478 XtMalloc ((unsigned int)(strlen ((char *)string) + 1))) == NULL)
3480 PWarning (((char *)GETMESSAGE(60, 13, "Insufficient memory for menu item")));
3484 strcpy (menuItem->label, (char *)string);
3485 menuItem->labelType = XmSTRING;
3489 * Here: string = "@<bitmap file>"
3490 * Try to find the label bitmap in the bitmap cache or read the label
3494 string++; /* skip "@" */
3496 if ((menuItem->labelBitmapIndex = GetBitmapIndex (pSD,
3497 (char *)string, True)) >= 0)
3499 if ((menuItem->labelBitmapIndex = GetBitmapIndex (pSD,
3500 (char *)string)) >= 0)
3503 menuItem->labelType = XmPIXMAP;
3508 } /* END OF FUNCTION ParseWmLabel */
3512 /*************************************<->*************************************
3514 * ParseWmMnemonic (linePP, menuItem)
3519 * Parse an optional menu function mnemonic.
3524 * linePP = pointer to current line buffer pointer.
3525 * menuItem = pointer to MenuItem structure
3530 * linePP = pointer to revised line buffer pointer.
3531 * menuItem->mnemonic = valid mnemonic character or NULL.
3538 *************************************<->***********************************/
3540 static void ParseWmMnemonic (unsigned char **linePP, MenuItem *menuItem)
3542 unsigned char *lineP = *linePP;
3543 unsigned char *mnemonic;
3546 * Skip leading white space.
3548 ScanWhitespace (&lineP);
3549 menuItem->mnemonic = (KeySym)NULL;
3553 * We have a mnemonic specification.
3554 * Get the next string (we only use the first character).
3555 * If no string exists, the labelType is not XmSTRING, or does not contain
3556 * the first character, then skip the string and return.
3557 * Otherwise, accept the first character as a mnemonic.
3562 mnemonic = GetString(&lineP);
3564 #ifndef NO_MULTIBYTE
3565 if (menuItem->labelType == XmSTRING &&
3567 (ks = XStringToKeysym((char *)mnemonic)) != NoSymbol &&
3568 strchr(menuItem->label, (char)(ks & 0xff)) != NULL)
3570 menuItem->mnemonic = ks;
3573 if ((mnemonic != NULL) &&
3574 (*mnemonic != '\0') &&
3575 (menuItem->labelType == XmSTRING) &&
3576 (strchr (menuItem->label, *mnemonic) != NULL))
3577 /* valid mnemonic */
3579 menuItem->mnemonic = *mnemonic;
3584 PWarning (((char *)GETMESSAGE(60, 14, "Invalid mnemonic specification")));
3588 *linePP = lineP; /* consume any string */
3590 } /* END OF FUNCTION ParseWmMnemonic */
3593 /*************************************<->*************************************
3595 * ParseWmAccelerator (linePP, menuItem)
3600 * Parse an optional menu function accelerator.
3605 * linePP = pointer to current line buffer pointer.
3606 * menuItem = pointer to MenuItem structure
3611 * linePP = pointer to revised line buffer pointer.
3612 * menuItem->accelText = pointer to an accelerator string or NULL.
3619 *************************************<->***********************************/
3621 static Boolean ParseWmAccelerator (unsigned char **linePP, MenuItem *menuItem)
3623 unsigned char *lineP;
3625 unsigned int eventType;
3630 menuItem->accelState = 0;
3631 menuItem->accelKeyCode = 0;
3632 menuItem->accelText = NULL;
3636 * If linePP contains NULL, then abort.
3638 if (*linePP == (unsigned char *) NULL) return(FALSE);
3641 * Skip leading white space.
3643 ScanWhitespace (linePP);
3647 * If the second character is not ".", and an accelerator specification
3648 * exists, then process and save the specification string.
3651 if ((*lineP != '\0') && /* something follows */
3652 (*lineP != '!') && /* skip if we have the ! WmFunction */
3653 #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
3654 /* skip label name for client command */
3655 ((*lineP != '"') || (menuItem->wmFunction != F_InvokeCommand)) &&
3656 #endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
3658 (*(lineP+1) != '.')) /* skip if we have f.xxx WmFunction */
3660 if (ParseKeyEvent(&lineP, &eventType, &keycode, &state))
3662 if ((string = (String) XtMalloc
3663 ((unsigned int) (lineP - *linePP + 1))) == NULL)
3665 PWarning (((char *)GETMESSAGE(60, 15, "Insufficient memory for accelerator specification")));
3670 * Save the accelerator state and keycode.
3671 * Process and save the accelerator text.
3674 ProcessAccelText (*linePP, lineP, (unsigned char *) string);
3675 menuItem->accelState = state;
3676 menuItem->accelKeyCode = keycode;
3677 menuItem->accelText = string;
3682 PWarning (((char *)GETMESSAGE(60, 16, "Invalid accelerator specification")));
3686 *linePP = lineP; /* consume the specification */
3691 } /* END OF FUNCTION ParseWmAccelerator */
3694 #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
3695 /*************************************<->*************************************
3697 * ParseMenuItemName (linePP, menuItem)
3702 * Parse a user defined client command menu item
3707 * linePP = pointer to current line buffer pointer.
3708 * menuItem = pointer to MenuItem structure
3713 * menuItem->label will have menu item name appended to it
3717 * This function attempts to find a menu item label string at the end
3718 * of the client command specification line. A menu item label string
3719 * must be delimited by double quotes. If found, the label string is
3720 * appended to the menuItem->label field, after being reallocated to
3721 * accommodate the new space requirement.
3723 *************************************<->***********************************/
3725 static void ParseMenuItemName (unsigned char **linePP, MenuItem *menuItem)
3727 unsigned char *lineP, *endquote;
3730 /* Skip past any whitespace */
3731 ScanWhitespace (linePP);
3734 /* Look for a double quote */
3735 if (mblen ((char *)lineP, MB_CUR_MAX) == 1 && *lineP == '"')
3737 /* Move past the first quote. */
3742 /* Search for closing quote */
3743 while (*endquote != '\0' &&
3744 (chlen = mblen ((char *)endquote, MB_CUR_MAX)) > 0 &&
3745 (chlen > 1 || *endquote != '"'))
3747 /* If we ran off the end of the line, then just abort. Bad
3749 if ((chlen == 1 && *endquote == '\n') || *endquote == '\0') return;
3752 if (chlen < 0) return; /* invalid character */
3754 /* Well, we have a valid menu item name. Store it in the
3755 client command name field. Don't include the double quotes. */
3756 menuItem->clientCommandName =
3757 XtMalloc(sizeof(char) * (endquote - lineP) + 1);
3758 strncpy(menuItem->clientCommandName, (char *) lineP,
3760 menuItem->clientCommandName[strlen(menuItem->clientCommandName)+1] = '\0';
3764 /* If there was no double quote, then just advance to the end
3766 while (*lineP != '\0' &&
3767 ((chlen = mblen ((char *)lineP, MB_CUR_MAX)) > 1 ||
3769 lineP += chlen > 0 ? chlen : 1;
3773 #endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
3776 /*************************************<->*************************************
3779 * ParseWmFunction (linePP, res_spec, pWmFunction)
3784 * Parse a button, key, or menu function name and return its function table
3790 * linePP = pointer to current line buffer pointer.
3791 * res_spec = resource specification type (key, button, or menu).
3792 * pWmFunction = pointer to window manager function destination.
3793 * functionTable = window manager function parse table
3798 * linePP = pointer to revised line buffer pointer.
3799 * pWmFunction = pointer to parsed window manager function.
3800 * Return = function table index of parsed function.
3805 * Uses F_Nop if the function name or resource type is invalid.
3807 *************************************<->***********************************/
3809 int ParseWmFunction (unsigned char **linePP, unsigned int res_spec,
3810 WmFunction *pWmFunction)
3812 unsigned char *lineP = *linePP;
3813 unsigned char *string;
3814 register int low, mid, high, cmp;
3817 * Skip leading white space.
3819 ScanWhitespace (&lineP);
3822 * Have function string (may be NULL or a comment).
3823 * Handle the special case of '!'
3829 *pWmFunction = F_Exec;
3830 return (F_EXEC_INDEX);
3834 * Identify the function corresponding to the specified name.
3835 * Try binary search of the window manager function parse table.
3836 * Assume f.nop if the function and resource type cannot be matched.
3837 * This handles NULL and comment strings, bad function names, and functions
3838 * in inappropriate resource sets.
3840 string = GetString (&lineP);
3847 high = WMFUNCTIONTABLESIZE - 1;
3851 mid = (low + high)/2;
3852 cmp = strcmp (functionTable[mid].funcName, (char *)string);
3856 * Function name match
3857 * Require proper resource type for the function.
3860 if (res_spec & functionTable[mid].resource)
3862 *pWmFunction = functionTable[mid].wmFunction;
3866 /* invalid resource: use F_Nop */
3871 * Function name mismatch
3885 * Not found: assume f.nop
3887 *pWmFunction = F_Nop;
3888 return (F_NOP_INDEX);
3890 } /* END OF FUNCTION ParseWmFunction */
3893 /*************************************<->*************************************
3895 * ParseWmFuncMaybeStrArg (linePP, wmFunction, pArgs)
3900 * Parses a window manager function with a null or string argument.
3905 * linePP = pointer to current line buffer pointer.
3906 * wmFunction = function (not used).
3907 * pArgs = pointer to argument destination.
3912 * linePP = pointer to revised line buffer pointer.
3913 * pArgs = pointer to parsed argument string.
3914 * Return = FALSE iff insufficient memory
3919 * Only used to parse arguments for F_Lower, F_Raise, and F_Raise_Lower.
3920 * If it is used for any other function, be sure to change FreeMenuItem ()
3923 *************************************<->***********************************/
3928 Boolean ParseWmFuncMaybeStrArg (unsigned char **linePP,
3929 WmFunction wmFunction, String *pArgs)
3931 unsigned char *string = *linePP;
3934 ScanWhitespace (&string);
3939 return (ParseWmFuncStrArg (linePP, wmFunction, pArgs));
3944 else if (*lineP == '"' && *(lineP+1) == '-')
3947 strcpy ((char *) (lineP+1), (char *) (lineP+2));
3948 return (ParseWmFuncStrArg (linePP, wmFunction, pArgs));
3951 #endif /* PANELIST */
3952 if ((len = strlen ((char *)string)) != 0)
3954 if ((*pArgs = (String)XtMalloc (len + 1)) == NULL)
3956 PWarning (((char *)GETMESSAGE(60, 17, "Insufficient memory")));
3959 strcpy (*pArgs, (char *)string);
3963 /* Do ParseWmFuncNoArg () */
3969 } /* END OF FUNCTION ParseWmFuncMaybeStrArg */
3972 /*************************************<->*************************************
3974 * ParseWmFuncNoArg (linePP, wmFunction, pArgs)
3979 * Parses a window manager function null argument.
3984 * linePP = pointer to current line buffer pointer.
3985 * wmFunction = function (not used).
3986 * pArgs = pointer to argument destination.
3991 * linePP = unchanged
4000 *************************************<->***********************************/
4002 static Boolean ParseWmFuncNoArg (unsigned char **linePP, WmFunction wmFunction,
4009 } /* END OF FUNCTION ParseWmFuncNoArg */
4012 /*************************************<->*************************************
4014 * ParseWmFuncStrArg (linePP, wmFunction, pArgs)
4019 * Parses a window manager function string argument.
4024 * linePP = pointer to current line buffer pointer.
4025 * wmFunction = function for which the argument string is intended.
4026 * pArgs = pointer to argument string destination.
4031 * linePP = pointer to revised line buffer pointer.
4032 * pArgs = pointer to parsed argument string.
4033 * Return = FALSE iff insufficient memory
4038 * Insures that an argument for F_Exec() ends in '&' .
4039 * Only used to parse arguments for F_Exec, F_Menu, F_Lower, F_Raise,
4040 * F_Raise_Lower, and F_Screen. If it is used for any other function, be
4041 * sure to change FreeMenuItem () accordingly.
4043 *************************************<->***********************************/
4048 Boolean ParseWmFuncStrArg (unsigned char **linePP,
4049 WmFunction wmFunction, String *pArgs)
4051 unsigned char *string;
4053 #ifndef NO_MULTIBYTE
4061 if ((string = GetString (linePP)) != NULL)
4062 /* nonNULL string argument */
4064 len = strlen ((char *)string);
4065 if ((*pArgs = (String)XtMalloc (len + 2)) == NULL)
4067 PWarning (((char *)GETMESSAGE(60, 17, "Insufficient memory")));
4070 strcpy (*pArgs, (char *)string);
4073 * Insure that an argument for F_Exec ends in '&' .
4076 #ifndef NO_MULTIBYTE
4077 if ((wmFunction == F_Exec))
4082 ((len = mblen(p, MB_CUR_MAX)) > 0))
4084 mbtowc(&last, p, MB_CUR_MAX);
4089 mbtowc(&wdelim, &delim, MB_CUR_MAX);
4090 if (lastlen == 1 && last != wdelim)
4097 if ((wmFunction == F_Exec) && ((*pArgs)[len - 1] != '&'))
4099 (*pArgs)[len] = '&';
4100 (*pArgs)[len + 1] = '\0';
4105 /* NULL string argument */
4112 } /* END OF FUNCTION ParseWmFuncStrArg */
4115 /*************************************<->*************************************
4117 * FreeMenuItem (menuItem)
4122 * This procedure destroys a MenuItem structure.
4127 * menuItem = to be destroyed.
4137 * Assumes that ParseWmFuncStrArg () has parsed a menu item's function
4138 * argument only for F_Exec, F_Menu, F_Lower, F_Raise, F_Raise_Lower, and
4139 * F_Screen. If it is used for other functions, be sure to include them here!
4141 *************************************<->***********************************/
4143 void FreeMenuItem (MenuItem *menuItem)
4145 if (menuItem->label != NULL)
4147 XtFree ((char *)menuItem->label);
4150 if (menuItem->accelText != NULL)
4152 XtFree ((char *)menuItem->accelText);
4156 * If menuItem->wmFuncArgs is nonNULL, we assume that it is a string that
4157 * was malloc'ed in ParseWmFuncStrArg () and we free it now.
4159 if ((menuItem->wmFuncArgs != NULL) &&
4160 ((menuItem->wmFunction == F_Exec) ||
4161 (menuItem->wmFunction == F_Menu) ||
4162 (menuItem->wmFunction == F_Lower) ||
4163 (menuItem->wmFunction == F_Raise) ||
4164 (menuItem->wmFunction == F_Raise_Lower) ||
4165 (menuItem->wmFunction == F_Screen)))
4167 XtFree ((char *)menuItem->wmFuncArgs);
4170 XtFree ((char *)menuItem);
4172 } /* END OF FUNCTION FreeMenuItem */
4176 /*************************************<->*************************************
4178 * ParseWmFuncGrpArg (linePP, wmFunction, pGroup)
4183 * Parses a window manager function group argument.
4188 * linePP = pointer to current line buffer pointer.
4189 * wmFunction = function for which the group argument is intended.
4190 * pGroup = pointer to group argument destination.
4195 * linePP = pointer to revised line buffer pointer.
4196 * pGroup = pointer to parsed group argument.
4197 * Return = FALSE iff invalid group argument.
4202 * The only valid nonNULL arguments are "icon", "window", and "transient".
4204 *************************************<->***********************************/
4206 static Boolean ParseWmFuncGrpArg (unsigned char **linePP,
4207 WmFunction wmFunction, GroupArg *pGroup)
4209 unsigned char *lineP = *linePP;
4210 unsigned char *startP;
4211 unsigned char grpStr[MAX_GROUP_STRLEN+1];
4216 * Parse groups while each is followed by "|".
4223 * Skip whitespace and find next group string.
4226 ScanWhitespace (&lineP);
4228 ScanAlphanumeric (&lineP);
4229 if (startP == lineP)
4230 /* Group missing => use default or complain */
4234 PWarning (((char *)GETMESSAGE(60, 18, "Missing group specification")));
4239 *pGroup = F_GROUP_DEFAULT;
4245 * Found a group string; compare it with valid groups.
4248 len = min (lineP - startP, MAX_GROUP_STRLEN);
4249 (void) strncpy ((char *)grpStr, (char *)startP, len);
4253 if (!strcmp ("icon", (char *)grpStr))
4255 *pGroup |= F_GROUP_ICON;
4257 else if (!strcmp ("window", (char *)grpStr))
4259 *pGroup |= F_GROUP_WINDOW;
4261 else if (!strcmp ("transient", (char *)grpStr))
4263 *pGroup |= F_GROUP_TRANSIENT;
4266 /* Unknown group name */
4268 PWarning (((char *)GETMESSAGE(60, 19, "Invalid group specification")));
4273 * Continue processing until the line is exhausted.
4277 ScanWhitespace (&lineP);
4279 if (lineP == NULL || *lineP == '\0')
4283 else if (*lineP == '|')
4292 } /* END OF FUNCTION ParseWmFuncGrpArg */
4296 /*************************************<->*************************************
4298 * ParseWmFuncNbrArg (linePP, wmFunction, pNumber)
4303 * Parses a window manager function number argument.
4308 * linePP = pointer to current line buffer pointer.
4309 * wmFunction = function
4310 * pNumber = pointer to number argument destination.
4315 * linePP = pointer to revised line buffer pointer.
4316 * pNumber = pointer to parsed number argument.
4317 * Return = FALSE iff invalid number argument.
4324 *************************************<->***********************************/
4326 static Boolean ParseWmFuncNbrArg (unsigned char **linePP,
4327 WmFunction wmFunction,
4328 unsigned long *pNumber)
4332 val = StrToNum (GetString (linePP));
4335 PWarning (((char *)GETMESSAGE(60, 20, "Invalid number specification")));
4343 } /* END OF FUNCTION ParseWmFuncNbrArg */
4346 #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
4347 /*************************************<->*************************************
4349 * ParseWmFuncCCIArgs (linePP, wmFunction, pArgs)
4354 * Parses a Client-Command entry's arguments.
4359 * linePP = pointer to current line buffer pointer.
4360 * wmFunction = function for which the argument string is intended.
4361 * pArgs = pointer to argument string destination.
4366 * linePP = pointer to revised line buffer pointer.
4367 * pArgs = pointer to parsed argument string.
4368 * Return = FALSE iff insufficient memory
4375 *************************************<->***********************************/
4377 static Boolean ParseWmFuncCCIArgs (unsigned char **linePP,
4378 WmFunction wmFunction, String *pArgs)
4384 * modifier cci_entry_list
4388 * cci_entry . cci_entry
4394 * any combination of alpha and '_'
4397 CCIEntryModifier mod;
4399 unsigned char *string;
4402 cciArg = XtNew(CCIFuncArg);
4404 if ((string = GetString(linePP)) == NULL)
4406 /* Error - no data for f.cci command. cci_entry_list is required. */
4407 fprintf(stderr, "Incorrect format for f.cci command.\n");
4412 /* check if no modifier was specified. */
4413 if (string[0] == '<')
4416 cciArg->cciEntry = XtNewString((char*)string);
4420 if (! GetCCIModifier((String)string, &mod))
4423 cciArg->cciEntry = XtNewString("");
4429 if ((string = GetString(linePP)) == NULL)
4431 /* Found a modifier, but there's no cci_entry_list. */
4432 fprintf(stderr, "Incorrect format for f.cci command.\n");
4437 cciArg->cciEntry = XtNewString((char*)string);
4442 *pArgs = (String)cciArg;
4446 } /* END OF FUNCTION ParseWmFuncCCIArgs */
4447 #endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
4450 /*************************************<->*************************************
4457 * This function parses a button set specification string:
4461 * button context function
4462 * button context function
4464 * button context function
4471 * pSD->buttonBindings = buttonBindings resource value
4472 * functionTable = window manager function parse table
4477 * pSD->buttonSpecs = list of button binding specifications.
4482 * The button set specification name must match pSD->buttonBindings.
4484 *************************************<->***********************************/
4486 void ParseButtonStr (WmScreenData *pSD, unsigned char *buttonStr)
4488 unsigned char *lineP;
4492 if (((parseP = buttonStr) != NULL) && (GetNextLine () != NULL))
4495 ParseButtonSet (pSD, lineP);
4498 } /* END OF FUNCTION ParseButtonStr */
4501 /*************************************<->*************************************
4503 * ParseButtonSet (pSD, lineP)
4508 * Button set specification found. Parse the following syntax:
4511 * Buttons bindings_name
4513 * button context function
4514 * button context function
4516 * button context function
4522 * cfileP = (global) file pointer to fopened configuration file or NULL
4523 * line = (global) line buffer
4524 * lineP = pointer to current character in line buffer
4525 * pSD->buttonBindings = buttonBindings resource value
4530 * lineP = pointer to current character in line buffer
4531 * pSD->buttonSpecs = list of button binding specifications.
4536 * Skips unnamed button binding set and sets with names that don't match
4537 * the buttonBindings resource.
4538 * Skips bad button binding specifications.
4540 *************************************<->***********************************/
4542 static void ParseButtonSet (WmScreenData *pSD, unsigned char *lineP)
4544 unsigned char *string;
4545 ButtonSpec *buttonSpec;
4546 ButtonSpec *lastButtonSpec;
4550 * Parse the button set bindings from the configuration file.
4551 * If either the button set name or buttonBindings resource is NULL or
4552 * they don't match, then skip this button specification.
4555 if (((string = GetString (&lineP)) == NULL) ||
4556 (pSD->buttonBindings == NULL) ||
4557 strcmp ((char *)string, pSD->buttonBindings))
4563 * Require leading '{' on the next line.
4565 while ((GetNextLine () != NULL)) /* not EOF nor read error */
4568 ScanWhitespace(&lineP);
4570 if ((lineP == NULL) || (*line == '!') || (*lineP == '\0') || (*lineP == '#'))
4571 /* ignore empty or comment line */
4583 PWarning (((char *)GETMESSAGE(60, 21, "Expected '{' after button set name")));
4588 * Found leading "{" or EOF.
4589 * Prepare to accumulate button bindings by finding the end of
4590 * the button specification list.
4591 * lastButtonSpec will be NULL only if no prior bindings exist.
4594 lastButtonSpec = pSD->buttonSpecs;
4595 if (lastButtonSpec != NULL)
4597 while (lastButtonSpec->nextButtonSpec != NULL)
4599 lastButtonSpec = (lastButtonSpec->nextButtonSpec);
4604 * Parse "button context function" until "}" or EOF found.
4605 * Skips bad button binding specifications.
4608 while ((GetNextLine () != NULL)) /* not EOF nor read error */
4611 ScanWhitespace(&lineP);
4612 if ((lineP == NULL) || (*line == '!') || (*lineP == '\0') || (*lineP == '#'))
4613 /* ignore empty or comment lines */
4617 if (*lineP == '}') /* finished with button set */
4623 * Allocate space for the button binding specification.
4625 if ((buttonSpec = (ButtonSpec *)XtMalloc (sizeof (ButtonSpec))) == NULL)
4627 PWarning (((char *)GETMESSAGE(60, 22, "Insufficient memory for button specification")));
4630 buttonSpec->wmFunction = (WmFunction)NULL;
4631 buttonSpec->wmFuncArgs = NULL;
4632 buttonSpec->nextButtonSpec = NULL;
4635 * Parse the button specification "button".
4638 if (!ParseBtnEvent(&lineP,
4639 &buttonSpec->eventType,
4640 &buttonSpec->button,
4642 &buttonSpec->click))
4644 PWarning (((char *)GETMESSAGE(60, 23, "Invalid button specification")));
4645 XtFree ((char *)buttonSpec);
4646 continue; /* skip this button specification */
4651 * Parse the button context.
4653 if (!ParseContext(&lineP, &buttonSpec->context,
4654 &buttonSpec->subContext))
4656 PWarning (((char *)GETMESSAGE(60, 24, "Invalid button context")));
4657 XtFree ((char *)buttonSpec);
4658 continue; /* skip this button specification */
4662 * Parse the button function and any arguments.
4665 ix = ParseWmFunction (&lineP, CRS_BUTTON, &buttonSpec->wmFunction);
4668 * remove any subContexts that don't apply to this function
4671 if ((functionTable[ix].greyedContext & F_SUBCONTEXT_IB_IICON) &&
4672 (buttonSpec->subContext & F_SUBCONTEXT_IB_IICON))
4674 buttonSpec->subContext &= ~F_SUBCONTEXT_IB_IICON;
4677 if ((functionTable[ix].greyedContext & F_SUBCONTEXT_IB_WICON) &&
4678 (buttonSpec->subContext & F_SUBCONTEXT_IB_WICON))
4680 buttonSpec->subContext &= ~F_SUBCONTEXT_IB_WICON;
4684 * Map Button3 menus to BMenu virtual button
4686 if (buttonSpec->button == Button3 &&
4687 (buttonSpec->wmFunction == F_Menu ||
4688 buttonSpec->wmFunction == F_Post_SMenu)) {
4690 buttonSpec->button = wmGD.bMenuButton;
4694 * Apply the function argument parser.
4696 if (!(*(functionTable [ix].parseProc))
4697 (&lineP, buttonSpec->wmFunction, &buttonSpec->wmFuncArgs))
4699 XtFree ((char *)buttonSpec);
4700 continue; /* skip this button specification */
4704 * Add the button specification to the button specification list.
4706 if (lastButtonSpec != NULL)
4707 /* a prior specification exists */
4709 lastButtonSpec->nextButtonSpec = buttonSpec;
4713 pSD->buttonSpecs = buttonSpec;
4715 lastButtonSpec = buttonSpec;
4718 } /* END OF FUNCTION ParseButtonSet */
4722 /*************************************<->*************************************
4724 * ParseContext (linePP, context, subContext)
4729 * Parses a general context string.
4734 * linePP = pointer to current line buffer pointer.
4738 * linePP = pointer to revised line buffer pointer.
4739 * context = context field value
4740 * subContext = subContext field value
4741 * Return = (Boolean) true iff valid context string
4748 *************************************<->***********************************/
4750 static Boolean ParseContext (unsigned char **linePP, Context *context,
4751 Context *subContext)
4753 unsigned char *lineP = *linePP;
4754 unsigned char *startP;
4755 unsigned char ctxStr[MAX_CONTEXT_STRLEN+1];
4759 * Parse contexts while each is followed by "|".
4767 * Skip whitespace and find next context string.
4769 ScanWhitespace (&lineP);
4771 ScanAlphanumeric (&lineP);
4772 if (startP == lineP)
4773 /* ERROR: Context missing */
4779 * Found nonNULL string; compare it with valid contexts.
4782 len = min(lineP - startP, MAX_CONTEXT_STRLEN);
4783 (void) strncpy ((char *)ctxStr, (char *)startP, len);
4787 if (!strcmp ("root", (char *)ctxStr))
4789 *context |= F_CONTEXT_ROOT;
4790 *subContext |= F_SUBCONTEXT_R_ALL;
4792 else if (!strcmp ("icon", (char *)ctxStr))
4794 *context |= (F_CONTEXT_ICON |
4796 F_SUBCONTEXT_IB_IICON |
4797 F_SUBCONTEXT_IB_WICON );
4798 *subContext |= (F_SUBCONTEXT_I_ALL |
4799 F_SUBCONTEXT_IB_IICON |
4800 F_SUBCONTEXT_IB_WICON );
4802 else if (!strcmp ("window", (char *)ctxStr))
4804 *context |= F_CONTEXT_WINDOW;
4805 *subContext |= F_SUBCONTEXT_W_ALL;
4807 else if (!strcmp ("frame", (char *)ctxStr))
4809 *context |= F_CONTEXT_WINDOW;
4810 *subContext |= F_SUBCONTEXT_W_FRAME;
4812 else if (!strcmp ("title", (char *)ctxStr))
4814 *context |= F_CONTEXT_WINDOW;
4815 *subContext |= F_SUBCONTEXT_W_TITLE;
4817 else if (!strcmp ("border", (char *)ctxStr))
4819 *context |= F_CONTEXT_WINDOW;
4820 *subContext |= F_SUBCONTEXT_W_BORDER;
4822 else if (!strcmp ("app", (char *)ctxStr))
4824 *context |= F_CONTEXT_WINDOW;
4825 *subContext |= F_SUBCONTEXT_W_APP;
4828 else if (!strcmp ("ifkey", (char *)ctxStr))
4830 *context |= F_CONTEXT_IFKEY;
4834 /* Unknown context name */
4839 /* continue only if followed by '|' */
4840 ScanWhitespace (&lineP);
4851 } /* END OF FUNCTION ParseContext */
4854 /*************************************<->*************************************
4861 * This function parses a key set specification string:
4865 * key context function
4866 * key context function
4868 * key context function
4874 * pSD->keyBindings = keyBindings resource value
4875 * functionTable = window manager function parse table
4880 * pSD->keySpecs = list of key binding specification
4885 * The key set specification name must match pSD->keyBindings.
4887 *************************************<->***********************************/
4890 ParseKeyStr (WmScreenData *pSD, unsigned char *keyStr)
4892 unsigned char *lineP;
4896 if (((parseP = keyStr) != NULL) && (GetNextLine () != NULL))
4899 ParseKeySet (pSD, lineP);
4902 } /* END OF FUNCTION ParseKeyStr */
4906 /*************************************<->*************************************
4908 * ParseKeySet (pSD, lineP)
4913 * Key set specification found. Parse the following syntax:
4916 * Keys bindings_name
4918 * key context function
4919 * key context function
4921 * key context function
4927 * cfileP = (global) file pointer to fopened configuration file or NULL
4928 * line = (global) line buffer
4929 * lineP = pointer to current character in line buffer
4930 * pSD->keyBindings = keyBindings resource value
4935 * lineP = pointer to current character in line buffer
4936 * pSD->keySpecs = list of key binding specifications.
4941 * Skips unnamed key binding set and sets with names that don't match the
4942 * keyBindings resource.
4943 * Skips bad key binding specifications.
4945 *************************************<->***********************************/
4947 static void ParseKeySet (WmScreenData *pSD, unsigned char *lineP)
4949 unsigned char *string;
4951 KeySpec *lastKeySpec;
4952 unsigned int eventType;
4959 * Parse the key set bindings from the configuration file.
4960 * If either the key set name or keyBindings resource is NULL or they
4961 * don't match then skip this key specification.
4964 if (((string = GetString (&lineP)) == NULL) ||
4965 (pSD->keyBindings == NULL) ||
4966 strcmp ((char *)string, pSD->keyBindings))
4972 * Require leading '{' on next line.
4974 while ((GetNextLine () != NULL)) /* not EOF nor read error */
4977 ScanWhitespace(&lineP);
4979 if ((lineP == NULL) || (*line == '!') || (*lineP == '\0') || (*lineP == '#'))
4980 /* ignore empty or comment line */
4992 PWarning (((char *)GETMESSAGE(60, 25, "Expected '{' after key set name")));
4997 * Found leading "{" or EOF.
4998 * Prepare to accumulate key bindings by finding the end of
4999 * the key specification list.
5000 * lastKeySpec will be NULL only if no prior bindings exist.
5003 lastKeySpec = pSD->keySpecs;
5004 if (lastKeySpec != NULL)
5006 while (lastKeySpec->nextKeySpec != NULL)
5008 lastKeySpec = (lastKeySpec->nextKeySpec);
5013 * Parse "key context function" until "}" or EOF found.
5014 * Skip bad key bindings.
5017 while ((GetNextLine () != NULL)) /* not EOF nor read error */
5020 ScanWhitespace (&lineP);
5021 if ((lineP == NULL) || (*line == '!') || (*lineP == '\0') || (*lineP == '#'))
5022 /* ignore empty or comment lines */
5026 if (*lineP == '}') /* finished with key set */
5032 * Allocate space for the key specification.
5034 if ((keySpec = (KeySpec *)XtMalloc (sizeof (KeySpec))) == NULL)
5036 PWarning (((char *)GETMESSAGE(60, 26, "Insufficient memory for key specification")));
5040 keySpec->wmFunction = (WmFunction)NULL;
5041 keySpec->wmFuncArgs = NULL;
5042 keySpec->nextKeySpec = NULL;
5045 * Parse the key specification.
5050 if (!ParseKeyEvent(&lineP,
5058 PWarning (((char *)GETMESSAGE(60, 27, "Invalid key specification")));
5059 XtFree ((char *)keySpec);
5060 continue; /* skip this key specification */
5065 * Parse the key context.
5066 * Here lineP points to the candidate context string.
5069 if (!ParseContext(&lineP, &keySpec->context,
5070 &keySpec->subContext))
5074 PWarning (((char *)GETMESSAGE(60, 27, "Invalid key specification")));
5076 PWarning (((char *)GETMESSAGE(60, 28, "Invalid key context")));
5077 XtFree ((char *)keySpec);
5078 continue; /* skip this key specification */
5084 * Don't print an error message if this is a "hardware
5085 * available" binding.
5087 if (!(keySpec->context & F_CONTEXT_IFKEY))
5088 PWarning (((char *)GETMESSAGE(60, 27, "Invalid key specification")));
5089 XtFree ((char *)keySpec);
5090 continue; /* skip this key specification */
5094 * This flag is only used for parsing, clear it so the
5095 * rest of the program doesn't see it.
5097 keySpec->context &= ~F_CONTEXT_IFKEY;
5102 * Parse the key function and any arguments.
5105 ix = ParseWmFunction (&lineP, CRS_KEY, &keySpec->wmFunction);
5108 * remove any subContexts that don't apply to this function
5110 if ((functionTable[ix].greyedContext & F_SUBCONTEXT_IB_IICON) &&
5111 (keySpec->subContext & F_SUBCONTEXT_IB_IICON))
5113 keySpec->subContext &= ~F_SUBCONTEXT_IB_IICON;
5116 if ((functionTable[ix].greyedContext & F_SUBCONTEXT_IB_WICON) &&
5117 (keySpec->subContext & F_SUBCONTEXT_IB_WICON))
5119 keySpec->subContext &= ~F_SUBCONTEXT_IB_WICON;
5123 * Apply the function argument parser.
5125 if (!(*(functionTable [ix].parseProc))
5126 (&lineP, keySpec->wmFunction, &keySpec->wmFuncArgs))
5128 XtFree ((char *)keySpec);
5129 continue; /* skip this key specification */
5133 * Add the key specification to the key specification list.
5135 if (lastKeySpec != NULL)
5136 /* a prior specification exists */
5138 lastKeySpec->nextKeySpec = keySpec;
5142 pSD->keySpecs = keySpec;
5144 lastKeySpec = keySpec;
5147 } /* END OF FUNCTION ParseKeySet */
5151 /*************************************<->*************************************
5158 * Returns the next line from an fopened configuration file or a newline-
5159 * embedded configuration string.
5164 * cfileP = (global) file pointer to fopened configuration file or NULL
5165 * line = (global) line buffer
5166 * linec = (global) line count
5167 * parseP = (global) parse string pointer if cfileP == NULL
5172 * line = (global) next line
5173 * linec = (global) line count incremented
5174 * parseP = (global) parse string pointer incremented
5175 * Return = line or NULL if file or string is exhausted.
5180 * If there are more than MAXLINE characters on a line in the file cfileP the
5181 * excess are truncated.
5182 * Assumes the line buffer is long enough for any parse string line.
5184 *************************************<->***********************************/
5189 register unsigned char *string;
5192 #ifndef NO_MULTIBYTE
5201 /* read fopened file */
5203 if ((string = (unsigned char *)
5204 fgets ((char *)line, MAXLINE, cfileP)) != NULL)
5206 #ifndef NO_MULTIBYTE
5210 ((len = mblen((char *)string, MB_CUR_MAX)) > 0))
5212 mbtowc(&last, (char *)string, MB_CUR_MAX);
5217 mbtowc(&wdelim, &delim, MB_CUR_MAX);
5218 if (lastlen == 1 && last == wdelim)
5222 if (!fgets((char *)string, MAXLINE - (string - line), cfileP))
5227 ((len = mblen((char *)string, MB_CUR_MAX)) > 0))
5229 mbtowc(&last, (char *)string, MB_CUR_MAX);
5235 while (lastlen == 1 && last == wdelim);
5239 len = strlen((char *)string) - 2;
5240 if ((len > 0) && string[len] == '\\')
5243 string = &string[len];
5244 if (fgets((char *)string,
5245 MAXLINE - (string-line), cfileP) == NULL)
5247 len = strlen((char *)string) - 2;
5249 } while ((len >= 0) && string[len] == '\\');
5255 else if ((parseP != NULL) && (*parseP != '\0'))
5256 /* read parse string */
5259 #ifndef NO_MULTIBYTE
5260 while ((*parseP != '\0') &&
5261 ((chlen = mblen ((char *)parseP, MB_CUR_MAX)) > 0) &&
5263 /* copy all but NULL and newlines to line buffer */
5267 *(string++) = *(parseP++);
5271 while ((*parseP != '\0') && (*parseP != '\n'))
5272 /* copy all but end-of-line and newlines to line buffer */
5274 *(string++) = *(parseP++);
5278 if (*parseP == '\n')
5291 } /* END OF FUNCTION GetNextLine */
5297 /*************************************<->*************************************
5299 * GetStringC (linePP, SmBehavior)
5304 * Returns the next quoted or whitespace-terminated nonquoted string in the
5306 * Additional functionality added to GetString in that anything in a
5307 * quoted string is considered sacred and nothing will be stripped from
5308 * the middle of a quoted string.
5313 * linePP = pointer to current line buffer pointer.
5314 * SmBehavior = flag that enables parsing session manager hints
5320 * linePP = pointer to revised line buffer pointer.
5326 * May alter the line buffer contents.
5327 * Handles quoted strings and characters, removing trailing whitespace from
5329 * Returns NULL string if the line is empty or is a comment.
5330 * Code stolen from dtmwm.
5332 *************************************<->***********************************/
5334 /*************************************<->*************************************
5336 * GetString (linePP)
5341 * Returns the next quoted or whitespace-terminated nonquoted string in the
5347 * linePP = pointer to current line buffer pointer.
5352 * linePP = pointer to revised line buffer pointer.
5358 * May alter the line buffer contents.
5359 * Handles quoted strings and characters, removing trailing whitespace from
5361 * Returns NULL string if the line is empty or is a comment.
5363 *************************************<->***********************************/
5367 unsigned char *GetStringC (unsigned char **linePP, Boolean SmBehavior)
5369 unsigned char *GetString (unsigned char **linePP)
5372 unsigned char *lineP = *linePP;
5373 unsigned char *endP;
5374 unsigned char *curP;
5375 unsigned char *lnwsP;
5377 unsigned int level = 0, checkLev, i, quoteLevel[10];
5379 #ifndef NO_MULTIBYTE
5382 /* get rid of leading white space */
5383 ScanWhitespace (&lineP);
5386 * Return NULL if line is empty, a comment, or invalid.
5391 ((chlen = mblen ((char *)lineP, MB_CUR_MAX)) < 1) ||
5392 ((chlen == 1) && ((*lineP == '!') ||
5393 ((!SmBehavior) && (*lineP == '#'))))
5398 ((chlen = mblen ((char *)lineP, MB_CUR_MAX)) < 1) ||
5399 ((chlen > 0) && ((*lineP == '!') || (*lineP == '#')))
5407 if ((chlen == 1) && (*lineP == '"'))
5411 quoteLevel[level] = 1;
5414 * Start beyond double quote and find the end of the quoted string.
5415 * '\' quotes the next character.
5416 * Otherwise, matching double quote or NULL terminates the string.
5418 * We use lnwsP to point to the last non-whitespace character in the
5419 * quoted string. When we have found the end of the quoted string,
5420 * increment lnwsP and if lnwsP < endP, write NULL into *lnwsP.
5421 * This removes any trailing whitespace without overwriting the
5422 * matching quote, needed later. If the quoted string was all
5423 * whitespace, then this will write a NULL at the beginning of the
5424 * string that will be returned -- OK.
5426 lnwsP = lineP++; /* lnwsP points to first '"' */
5427 curP = endP = lineP; /* other pointers point beyond */
5429 while ((*endP = *curP) &&
5430 ((chlen = mblen ((char *)curP, MB_CUR_MAX)) > 0) &&
5431 ((chlen > 1) || (*curP != '"')))
5432 /* Haven't found matching quote yet.
5433 * First byte of next character has been copied to endP.
5437 if ((chlen == 1) && (*endP == '\\') &&
5438 ((chlen = mblen ((char *)curP, MB_CUR_MAX)) > 0))
5440 * copy first byte of quoted nonNULL character down.
5441 * point curP to next byte
5448 * Check to see if this is a quoted quote - if it is
5449 * strip off a level - if not - it's sacred leave it alone
5451 checkLev = PeekAhead((curP - 1), quoteLevel[level]);
5454 if(quoteLevel[level] <= checkLev)
5461 quoteLevel[level] = checkLev;
5464 for(i = 0;i < (checkLev - 2);i++)
5466 *endP++ = *curP++;curP++;
5481 /* Singlebyte character: character copy finished. */
5483 if (isspace (*endP))
5484 /* whitespace character: leave lnwsP unchanged. */
5489 /* non-whitespace character: point lnwsP to it. */
5495 /* Multibyte (nonwhitespace) character: point lnwsP to it.
5496 * Finish character byte copy.
5509 /* get rid of leading white space */
5510 ScanWhitespace (&lineP);
5513 /* Return NULL if line is empty, whitespace, or begins with a comment. */
5514 if ((lineP == NULL || *lineP == '\0') ||
5515 (!SmBehavior && (*lineP == '#')))
5517 /* Return NULL if line is empty, whitespace, or begins with a comment. */
5518 if ((lineP == NULL) || (*lineP == '\0') || (*lineP == '#'))
5529 quoteLevel[level] = 1;
5532 * Start beyond double quote and find the end of the quoted string.
5533 * '\' quotes the next character.
5534 * Otherwise, matching double quote or NULL terminates the string.
5536 * We use lnwsP to point to the last non-whitespace character in the
5537 * quoted string. When we have found the end of the quoted string,
5538 * increment lnwsP and if lnwsP < endP, write NULL into *lnwsP.
5539 * This removes any trailing whitespace without overwriting the
5540 * matching quote, needed later. If the quoted string was all
5541 * whitespace, then this will write a NULL at the beginning of the
5542 * string that will be returned -- OK.
5544 lnwsP = lineP++; /* lnwsP points to first '"' */
5545 curP = endP = lineP; /* other pointers point beyond */
5547 while ((*endP = *curP) && (*endP != '"'))
5548 /* haven't found matching quote yet */
5550 /* point curP to next character */
5552 if ((*endP == '\\') && (*curP != '\0'))
5553 /* shift quoted nonNULL character down and curP ahead */
5559 * Check to see if this is a quoted quote - if it is
5560 * strip off a level - if not - it's sacred leave it alone
5562 checkLev = PeekAhead((curP - 1), quoteLevel[level]);
5565 if(quoteLevel[level] <= checkLev)
5572 quoteLevel[level] = checkLev;
5575 for(i = 0;i < (checkLev - 2);i++)
5577 *endP++ = *curP++;curP++;
5590 if (isspace (*endP))
5591 /* whitespace character: leave lnwsP unchanged. */
5596 /* non-whitespace character: point lnwsP to it. */
5604 * Found matching quote or NULL.
5605 * NULL out any trailing whitespace.
5616 /* Unquoted string */
5619 * Find the end of the nonquoted string.
5620 * '\' quotes the next character.
5621 * Otherwise, whitespace, end-of-line, or '#' terminates the string.
5623 curP = endP = lineP;
5625 #ifndef NO_MULTIBYTE
5627 while ((*endP = *curP) &&
5628 ((chlen = mblen ((char *)curP, MB_CUR_MAX)) > 0) &&
5629 ((chlen > 1) || (!isspace (*curP) &&
5630 (SmBehavior || (*curP != '#')))))
5632 while ((*endP = *curP) &&
5633 ((chlen = mblen ((char *)curP, MB_CUR_MAX)) > 0) &&
5634 ((chlen > 1) || (!isspace (*curP) && (*curP != '#'))))
5636 /* Haven't found whitespace or '#' yet.
5637 * First byte of next character has been copied to endP.
5641 if ((chlen == 1) && (*endP == '\\') &&
5642 ((chlen = mblen ((char *)curP, MB_CUR_MAX)) > 0))
5644 * copy first byte of quoted nonNULL character down.
5645 * point curP to next byte
5652 /* Multibyte character: finish character copy. */
5662 while ((*endP = *curP) && !isspace (*endP) &&
5663 (SmBehavior || (*endP != '#')))
5665 while ((*endP = *curP) && !isspace (*endP) && (*endP != '#'))
5668 /* point curP to next character */
5670 if ((*endP == '\\') && (*curP != '\0'))
5671 /* shift quoted nonNULL character down and curP ahead */
5681 * Three cases for *endP:
5682 * '#' --> write NULL over # and point to NULL
5684 * matching quote -> write end-of-line over char and point beyond
5685 * NULL -> point to NULL
5689 if (!SmBehavior && (*endP == '#'))
5694 *endP = '\0'; /* write '\0' over '#' */
5695 *linePP = endP; /* point to '\0' */
5697 else if (*endP != '\0')
5699 *endP = '\0'; /* write NULL over terminator */
5700 *linePP = ++curP; /* point beyond terminator */
5706 return ((unsigned char *)lineP);
5708 } /* END OF FUNCTION GetString */
5709 #endif /* PANELIST */
5713 /*************************************<->*************************************
5715 * ParseBtnEvent (linePP, eventType, button, state, fClick)
5720 * Parse a button event specification.
5725 * linePP = pointer to current line buffer pointer
5726 * buttonEvents = (global) button event parse table
5727 * modifierStrings = (global) modifier string/mask table
5732 * linePP = pointer to revised line buffer pointer.
5733 * eventType = type of event
5734 * button = parsed button number
5735 * state = composite modifier mask
5736 * fClick = is click?
5738 * Return = (Boolean) true iff valid button event specification
5745 *************************************<->***********************************/
5747 Boolean ParseBtnEvent (unsigned char **linePP,
5748 unsigned int *eventType,
5749 unsigned int *button,
5750 unsigned int *state,
5753 if (!ParseEvent (linePP, buttonEvents, eventType, button, state, fClick))
5759 * The following is a fix for an X11 deficiency in regards to
5760 * modifiers in grabs.
5762 if (*eventType == ButtonRelease)
5764 /* the button that is going up will always be in the modifiers... */
5765 *state |= buttonModifierMasks[*button];
5770 } /* END OF FUNCTION ParseBtnEvent */
5774 /*************************************<->*************************************
5776 * ParseKeyEvent (linePP, eventType, keyCode, state)
5781 * Parse a key event specification.
5786 * linePP = pointer to current line buffer pointer
5787 * keyEvents = (global) key event parse table
5788 * modifierStrings = (global) modifier string/mask table
5793 * linePP = pointer to revised line buffer pointer.
5794 * eventType = type of event
5795 * keyCode = parsed KeyCode
5796 * state = composite modifier mask
5798 * Return = (Boolean) true iff valid key event specification
5805 *************************************<->***********************************/
5807 Boolean ParseKeyEvent (unsigned char **linePP, unsigned int *eventType,
5808 KeyCode *keyCode, unsigned int *state)
5813 unsigned int keySym = 0;
5815 if (!ParseEvent (linePP, keyEvents, eventType, &keySym, state, &fClick))
5821 * Here keySym is a KeySym. Convert it to a KeyCode.
5822 * KeyCode will be set to 0 if keySym is not defined for any KeyCode
5826 *keyCode = XKeysymToKeycode(DISPLAY, (KeySym) keySym);
5830 if (keySym == XK_F9)
5834 else if (keySym == XK_F10)
5838 else if (keySym == XK_F11)
5842 else if (keySym == XK_F12)
5846 *keyCode = XKeysymToKeycode(DISPLAY, (KeySym) keySym);
5849 return (*keyCode != 0);
5851 } /* END OF FUNCTION ParseKeyEvent */
5854 /*************************************<->*************************************
5856 * ParseEvent (linePP, table, eventType, detail, state, fClick)
5861 * Parse an event specification.
5866 * linePP = pointer to current line buffer pointer.
5867 * table = event parse table
5868 * modifierStrings = (global) modifier string/mask table
5873 * linePP = pointer to revised line buffer pointer.
5874 * eventType = type of event
5875 * detail = dependent upon parse table detail procedure and closure
5876 * state = composite modifier mask
5877 * fClick = click flag
5879 * Return = (Boolean) true iff valid event specification
5885 *************************************<->***********************************/
5887 static Boolean ParseEvent (unsigned char **linePP, EventTableEntry *table,
5888 unsigned int *eventType, unsigned int *detail,
5889 unsigned int *state, Boolean *fClick)
5891 unsigned char *lineP = *linePP;
5895 /* Parse the modifiers */
5896 if (!ParseModifiers (&lineP, state) || *lineP != '<')
5900 lineP++; /* skip '<' */
5902 /* Parse the event type */
5903 if (!ParseEventType (&lineP, table, eventType, &ix) || *lineP != '>')
5907 lineP++; /* skip '>' */
5910 * Compute detail and fClick.
5911 * Status will be False for a invalid KeySym name.
5913 status = (*(table[ix].parseProc))(&lineP, table[ix].closure, detail);
5914 *fClick = table[ix].fClick;
5922 } /* END OF FUNCTION ParseEvent */
5926 /*************************************<->*************************************
5928 * ParseModifiers(linePP, state)
5933 * Parses a modifier specification.
5938 * linePP = pointer to current line buffer pointer.
5939 * modifierStrings = (global) modifier string/mask table
5944 * linePP = pointer to revised line buffer pointer.
5945 * state = composite modifier mask
5946 * Return = (Boolean) true iff valid modifier name
5951 * If successful, will be followed by NULL or '<'.
5953 *************************************<->***********************************/
5955 static Boolean ParseModifiers(unsigned char **linePP, unsigned int *state)
5957 unsigned char *lineP = *linePP;
5958 unsigned char *startP;
5959 unsigned char modStr[MAX_MODIFIER_STRLEN+1];
5961 unsigned int maskBit;
5967 * Parse modifiers until the event specifier is encountered.
5970 ScanWhitespace (&lineP);
5971 while ((*lineP != '\0') && (*lineP != '<'))
5984 ScanAlphanumeric (&lineP);
5985 if (startP == lineP)
5986 /* ERROR: Modifier or '<' missing */
5990 len = min(lineP - startP, MAX_MODIFIER_STRLEN);
5991 (void) strncpy ((char *)modStr, (char *)startP, len);
5994 if (!LookupModifier (modStr, &maskBit))
5995 /* Unknown modifier name */
6008 ScanWhitespace(&lineP);
6012 return (TRUE); /* must have '<' or NULL following */
6014 } /* END OF FUNCTION ParseModifiers */
6017 /*************************************<->*************************************
6019 * LookupModifier (name, valueP)
6024 * Return the modifier mask for the provided modifier name.
6029 * name = modifier string
6030 * modifierStrings = modifier string/mask table
6035 * valueP = modifier mask
6036 * Return = (Boolean) true iff valid modifier name
6043 *************************************<->***********************************/
6045 static Boolean LookupModifier (unsigned char *name, unsigned int *valueP)
6052 for (i=0; modifierStrings[i].name != NULL; i++)
6054 if (!strcmp (modifierStrings[i].name, (char *)name))
6056 *valueP = modifierStrings[i].mask;
6064 } /* END OF FUNCTION LookupModifier */
6067 #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
6068 /*************************************<->*************************************
6070 * GetCCIModifier (modString, mod)
6075 * Return the cci modifier corresponding to the specified string
6080 * modString = cci modifier string; may be null
6085 * mod = cci modifier.
6086 * Return = (Boolean) true iff valid modifier string
6093 *************************************<->***********************************/
6095 static Boolean GetCCIModifier (String modString, CCIEntryModifier *mod)
6100 if (modString != NULL)
6102 ToLower ((unsigned char *)modString);
6103 for (i=NONE; i<=EXCLUDE; i++)
6105 if (!strcmp (CCIEntryModifierNames[i], modString))
6115 } /* END OF FUNCTION GetCCIModifier */
6118 /*************************************<->*************************************
6120 * FixMenuItem (menuSpec, menuItem)
6125 * Fix-up the menuItem so that it appears an old-style cci command was
6126 * read from the .mwmrc file
6131 * menuItem = the menu item structure
6132 * menuSpec = the menu specification structure
6137 * menuItem = the fixed-up menuitem
6138 * menuSpec = the fixed-up menu specification structure if EXCLUDE found
6144 *************************************<->***********************************/
6146 static void FixMenuItem (MenuSpec *menuSpec, MenuItem *menuItem)
6152 if (menuItem == NULL)
6155 cciArg = (CCIFuncArg *)menuItem->wmFuncArgs;
6157 menuItem->clientCommandName = menuItem->label;
6158 menuItem->label = cciArg->cciEntry;
6161 * Fix-up the label to handle the modifier.
6164 switch (cciArg->mod)
6174 tmp = (String) XtMalloc(strlen(menuItem->label) + 3);
6175 sprintf(tmp, "->%s", menuItem->label);
6176 XtFree(menuItem->label);
6177 menuItem->label = tmp;
6182 tmp = (String) XtMalloc(strlen(menuItem->label) + 2);
6183 sprintf(tmp, "=%s", menuItem->label);
6184 XtFree(menuItem->label);
6185 menuItem->label = tmp;
6188 case DELIMIT_INLINE:
6191 case DELIMIT_CASCADE:
6193 tmp = (String) XtMalloc(strlen(menuItem->label) + 3);
6194 sprintf(tmp, "=>%s", menuItem->label);
6195 XtFree(menuItem->label);
6196 menuItem->label = tmp;
6201 StoreExclusion(menuSpec, menuItem->label);
6203 tmp = (String) XtMalloc(strlen(menuItem->label) + 2);
6204 sprintf(tmp, "~%s", menuItem->label);
6205 XtFree(menuItem->label);
6206 menuItem->label = tmp;
6210 #endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */
6213 /*************************************<->*************************************
6215 * ParseEventType(linePP, table, eventType, ix)
6220 * Parses the event type string.
6225 * linePP = pointer to current line buffer pointer.
6226 * table = event parse table
6231 * linePP = pointer to revised line buffer pointer.
6232 * eventType = type of event
6233 * ix = table index for matched event
6235 * Return = (Boolean) true iff valid event
6242 *************************************<->***********************************/
6244 static Boolean ParseEventType (unsigned char **linePP, EventTableEntry *table,
6245 unsigned int *eventType, Cardinal *ix)
6247 unsigned char *lineP = *linePP;
6248 unsigned char *startP = *linePP;
6249 unsigned char eventTypeStr[MAX_EVENTTYPE_STRLEN+1];
6252 /* Parse out the event string */
6253 ScanAlphanumeric (&lineP);
6256 * Attempt to match the parsed event against our supported event set.
6259 if (startP != lineP)
6261 len = min (lineP - startP, MAX_EVENTTYPE_STRLEN);
6262 (void) strncpy ((char *)eventTypeStr, (char *)startP, len);
6263 eventTypeStr[len] = '\0';
6264 ToLower (eventTypeStr);
6266 for (len = 0; table[len].event != NULL; len++)
6267 if (!strcmp (table[len].event, (char *)eventTypeStr))
6270 *eventType = table[*ix].eventType;
6276 /* Unknown event specified */
6279 } /* END OF FUNCTION ParseEventType */
6282 /*************************************<->*************************************
6284 * ParseImmed (linePP, closure, detail)
6289 * Button event detail procedure.
6295 * closure = table entry
6300 * detail = pointer to closure
6309 *************************************<->***********************************/
6311 static Boolean ParseImmed (unsigned char **linePP, unsigned int closure,
6312 unsigned int *detail)
6317 } /* END OF FUNCTION ParseImmed */
6320 /*************************************<->*************************************
6322 * ParseKeySym (linePP, closure, detail)
6327 * Key event detail procedure. Parses a KeySym string.
6332 * linePP = pointer to current line buffer pointer
6334 * closure = not used.
6339 * linePP = pointer to revised line buffer pointer
6340 * detail = pointer to parsed KeySym
6342 * Return = (Boolean) true iff valid KeySym string
6349 *************************************<->***********************************/
6351 static Boolean ParseKeySym (unsigned char **linePP, unsigned int closure,
6352 unsigned int *detail)
6354 unsigned char *lineP = *linePP;
6355 unsigned char *startP;
6356 char keySymName[MAX_KEYSYM_STRLEN+1];
6358 #ifndef NO_MULTIBYTE
6362 ScanWhitespace (&lineP);
6365 #ifndef NO_MULTIBYTE
6367 ((chlen = mblen ((char *)lineP, MB_CUR_MAX)) > 0) &&
6369 (!isspace (*lineP) && *lineP != ',' && *lineP != ':')))
6371 /* Skip next character */
6375 while (*lineP && !isspace (*lineP) && *lineP != ',' && *lineP != ':' )
6377 /* Skip next character */
6382 len = min (lineP - startP, MAX_KEYSYM_STRLEN);
6383 (void) strncpy (keySymName, (char *)startP, len);
6384 keySymName[len] = '\0';
6386 #ifndef NO_MULTIBYTE
6387 if ((*detail = XStringToKeysym(keySymName)) == NoSymbol &&
6388 (mblen (keySymName, MB_CUR_MAX) == 1))
6390 if ((*detail = XStringToKeysym(keySymName)) == NoSymbol)
6393 if (!isdigit (keySymName[0]) ||
6394 ((*detail = StrToNum ((unsigned char *)&keySymName[0])) == -1))
6403 } /* END OF FUNCTION ParseKeySym */
6407 /*************************************<->*************************************
6414 * Converts a string to an unsigned hexadecimal, decimal, or octal integer.
6419 * str = character string
6424 * Return = unsigned integer
6431 *************************************<->***********************************/
6433 static unsigned int StrToNum(unsigned char *str)
6436 unsigned int val = 0;
6441 if (*str == 'x' || *str == 'X')
6443 return (StrToHex(++str));
6445 return (StrToOct(str));
6448 while ((c = *str) != '\0')
6450 if ('0' <= c && c <= '9')
6463 } /* END OF FUNCTION StrToNum */
6467 /*************************************<->*************************************
6486 *************************************<->***********************************/
6488 static unsigned int StrToHex(unsigned char *str)
6491 unsigned int val = 0;
6493 while ((c = *str) != '\0')
6495 if ('0' <= c && c <= '9')
6499 else if ('a' <= c && c <= 'f')
6501 val = val*16+c-'a'+10;
6503 else if ('A' <= c && c <= 'F')
6505 val = val*16+c-'A'+10;
6516 } /* END OF FUNCTION StrToHex */
6520 /*************************************<->*************************************
6539 *************************************<->***********************************/
6541 static unsigned int StrToOct(unsigned char *str)
6544 unsigned int val = 0;
6546 while ((c = *str) != '\0')
6548 if ('0' <= c && c <= '7')
6561 } /* END OF FUNCTION StrToOct */
6565 /*************************************<->*************************************
6567 * ScanAlphanumeric (linePP)
6572 * Scan string until a non-alphanumeric character is encountered.
6577 * linePP = nonNULL pointer to current line buffer pointer
6582 * linePP = nonNULL pointer to revised line buffer pointer
6587 * Assumes linePP is nonNULL
6589 *************************************<->***********************************/
6591 void ScanAlphanumeric (unsigned char **linePP)
6593 #ifndef NO_MULTIBYTE
6597 ((chlen = mblen ((char *) *linePP, MB_CUR_MAX)) > 0) &&
6598 ((chlen > 1) || isalnum (**linePP)))
6603 while (*linePP && isalnum (**linePP))
6609 } /* END OF FUNCTION ScanAlphanumeric */
6614 /*************************************<->*************************************
6616 * ScanWhitespace(linePP)
6621 * Scan the string, skipping over all white space characters.
6626 * linePP = nonNULL pointer to current line buffer pointer
6631 * linePP = nonNULL pointer to revised line buffer pointer
6636 * Assumes linePP is nonNULL
6638 *************************************<->***********************************/
6640 void ScanWhitespace(unsigned char **linePP)
6642 #ifndef NO_MULTIBYTE
6643 while (*linePP && (mblen ((char *)*linePP, MB_CUR_MAX) == 1) && isspace (**linePP))
6645 while (*linePP && isspace (**linePP))
6651 } /* END OF FUNCTION ScanWhitespace */
6652 #endif /* not WSM */
6656 /*************************************<->*************************************
6663 * Lower all characters in a string.
6668 * string = NULL-terminated character string or NULL
6673 * string = NULL-terminated lower case character string or NULL
6680 *************************************<->***********************************/
6682 void ToLower (unsigned char *string)
6684 unsigned char *pch = string;
6685 #ifndef NO_MULTIBYTE
6688 while (*pch && ((chlen = mblen ((char *)pch, MB_CUR_MAX)) > 0))
6690 if ((chlen == 1) && (isupper (*pch)))
6692 *pch = tolower(*pch);
6697 while (*pch != '\0')
6701 *pch = tolower(*pch);
6707 } /* END OF FUNCTION ToLower */
6711 /*************************************<->*************************************
6713 * PWarning (message)
6718 * This function lists a resource description parse message to stderr.
6723 * message = pointer to a message string
6724 * cfileP = (global) file pointer to fopened configuration file or NULL
6725 * linec = (global) line counter
6727 *************************************<->***********************************/
6730 PWarning (char *message)
6734 char pch[MAXWMPATH+1];
6738 sMessage = XtNewString ((String) message);
6741 if (pConfigStackTop->fileName)
6743 pchFile = pConfigStackTop->fileName;
6747 pchFile = wmGD.configFile;
6750 sprintf (pch, pWarningStringFile,
6751 GETMESSAGE(20,1,"Workspace Manager"),
6752 sMessage, linec, pchFile);
6756 sprintf (pch, pWarningStringLine,
6757 GETMESSAGE(20,1,"Workspace Manager"),
6760 _DtSimpleError (wmGD.mwmName, DtIgnore, NULL, pch, NULL);
6765 fprintf (stderr, ((char *)GETMESSAGE(60, 33, "%s: %s on line %d of configuration file %s\n")),
6766 wmGD.mwmName, message, linec,
6767 wmGD.configFile ? wmGD.configFile : cfileName);
6771 fprintf (stderr, ((char *)GETMESSAGE(60, 34, "%s: %s on line %d of specification string\n")),
6772 wmGD.mwmName, message, linec);
6778 } /* END OF FUNCTION PWarning */
6782 * Key substitution table entry
6785 typedef struct _keySubs
6787 unsigned char * pchFrom;
6789 unsigned char * pchTo;
6793 /*************************************<->*************************************
6795 * InitKeySubs (ppKeySubs, pNumKeySubs)
6800 * Initialize key label substitutions used in acclerator text
6805 * ppKeySubs = ptr to key substitution table ptr
6806 * pNumKeySubs = ptr to number of key substitutions
6811 * *ppKeySubs = ptr to key substitution table
6812 * *pNumKeySubs = number of substitutions found
6816 * *ppKeySubs is allocated with XtMalloc in a complicated way.
6817 * If this ever needs to be freed, a function to free it needs to
6820 *************************************<->***********************************/
6822 static void InitKeySubs (
6829 unsigned char *pch0;
6830 unsigned char *pch1;
6832 #ifndef NO_MULTIBYTE
6836 pch0 = (unsigned char *)GETMESSAGE(60, 40, "");
6838 if ((pch0 == NULL) || (*pch0 == '\0'))
6848 while (*pch0 != '\0')
6850 ScanWhitespace (&pch0);
6851 if (*pch0 == '\0') break;
6854 * allocate space for next key sub
6858 pKSret = (KeySub *) XtMalloc (1*sizeof(KeySub));
6862 pKSret = (KeySub *) XtRealloc ((char *)pKSret,
6863 (numKS+1)*sizeof(KeySub));
6865 pKS = &pKSret[numKS];
6867 /* get "from" string */
6869 #ifndef NO_MULTIBYTE
6870 while (*pch1 && ((chlen = mblen ((char *)pch1, MB_CUR_MAX)) > 0))
6872 if ((chlen == 1) && (*pch1 == ' '))
6878 #else /* NO_MULTIBYTE */
6879 while (*pch1 && (*pch1 != ' ')) pch1++;
6880 #endif /* NO_MULTIBYTE */
6881 pKS->lenFrom = pch1 - pch0;
6882 if (pKS->lenFrom < 1)
6889 pKS->pchFrom = (unsigned char *) XtMalloc (1+pKS->lenFrom);
6890 memcpy (pKS->pchFrom, pch0, pKS->lenFrom);
6891 pKS->pchFrom[pKS->lenFrom] = '\0';
6893 /* get "to" string */
6894 ScanWhitespace (&pch1);
6897 #ifndef NO_MULTIBYTE
6898 while (*pch1 && ((chlen = mblen ((char *)pch1, MB_CUR_MAX)) > 0))
6900 if ((chlen == 1) && (*pch1 == ' '))
6906 #else /* NO_MULTIBYTE */
6907 while (*pch1 && (*pch1 != ' ')) pch1++;
6908 #endif /* NO_MULTIBYTE */
6914 * Invalid format, "from" string with no "to" string.
6918 pKS->pchTo = (unsigned char *) XtMalloc (1+len);
6919 memcpy (pKS->pchTo, pch0, len);
6920 pKS->pchTo[len] = '\0';
6922 /* advance cursor */
6925 /* got one, bump the counter */
6929 *ppKeySubs = pKSret;
6930 *pNumKeySubs = numKS;
6935 /*************************************<->*************************************
6937 * ProcessAccelText (startP, endP, destP)
6942 * Process accelerator text and copy into string.
6947 * startP = pointer to start of valid accelerator specification
6948 * endP = pointer past end of accelerator specification
6949 * destP = pointer to destination buffer
6954 * Destination buffer has processed accelerator text.
6960 *************************************<->***********************************/
6962 static void ProcessAccelText (unsigned char *startP, unsigned char *endP,
6963 unsigned char *destP)
6965 #ifndef NO_MULTIBYTE
6969 static Boolean bAccelInit = False;
6970 static KeySub *pKeySub;
6971 static int numKeySubs;
6972 unsigned char * pchFirst;
6973 unsigned char * pchSub;
6979 InitKeySubs (&pKeySub, &numKeySubs);
6988 ScanWhitespace (&startP);
6990 while (*startP != '<')
6994 *destP++ = *startP++;
7000 #ifndef NO_MULTIBYTE
7002 (((chlen = mblen ((char *)startP, MB_CUR_MAX)) > 1)
7003 || isalnum (*startP)))
7011 *destP++ = *startP++;
7016 while (isalnum (*startP))
7021 *destP++ = *startP++;
7026 /* find substitution */
7030 for (i=0; i<numKeySubs; i++)
7032 if ((pKeySub[i].lenFrom == startP-pchFirst) &&
7033 (!strncasecmp ((char *)pKeySub[i].pchFrom, (char *)pchFirst,
7034 pKeySub[i].lenFrom)))
7036 pchSub = pKeySub[i].pchTo;
7037 lenSub = strlen((char *)pchSub);
7043 if ((pchSub != NULL) && (lenSub > 0))
7045 memcpy (destP, pchSub, lenSub);
7050 memcpy (destP, pchFirst, startP-pchFirst);
7051 destP += startP-pchFirst;
7056 ScanWhitespace (&startP);
7060 * Skip the key event type.
7062 startP++; /* skip '<' */
7063 while (*startP != '>')
7065 #ifndef NO_MULTIBYTE
7066 startP += mblen ((char *)startP, MB_CUR_MAX);
7071 startP++; /* skip '>' */
7074 * Copy the KeySym string.
7077 ScanWhitespace (&startP);
7078 while (startP != endP)
7080 *destP++ = *startP++;
7084 } /* END OF FUNCTION ProcessAccelText */
7088 /*************************************<->*************************************
7090 * ProcessCommandLine (argc, argv)
7095 * This function looks for and processes mwm options in the command line
7099 * argc = argument count.
7100 * argv = argument vector.
7105 * Changes global data to based on command line options recognized
7108 *************************************<->***********************************/
7109 #define SCREENS_OPT "-screens"
7110 #define MULTI_SCREEN_OPT "-multiscreen"
7112 void ProcessCommandLine (int argc, char *argv[])
7114 unsigned char *string;
7116 unsigned char *lineP;
7118 for (argnum = 1; argnum < argc; argnum++)
7120 lineP = (unsigned char *) argv[argnum];
7121 if ((string = GetString (&lineP)) == NULL)
7122 /* empty or comment line */
7126 if (!strcmp((char *)string, MULTI_SCREEN_OPT))
7128 wmGD.multiScreen = True;
7129 wmGD.numScreens = ScreenCount (DISPLAY);
7131 else if (!strcmp((char *)string, SCREENS_OPT))
7133 argnum++; /* skip to next arg */
7134 ParseScreensArgument (argc, argv, &argnum, lineP);
7138 } /* END OF FUNCTION ProcessCommandLine */
7141 /*************************************<->*************************************
7143 * ParseScreensArgument (argc, argv, pArgnum, lineP)
7148 * This function processes the ``-screens'' command line argument
7152 * argc = argument count.
7153 * argv = argument vector.
7154 * pArgnum = pointer to argument number where processing left off
7155 * lineP = pointer into argv[*pArgnum] where processing left off
7160 * Changes global data to based on command line options recognized
7161 * + wmGD.screenNames
7163 * Assumes default screenNames are already in place
7165 *************************************<->***********************************/
7167 static void ParseScreensArgument (int argc, char *argv[], int *pArgnum,
7168 unsigned char *lineP)
7170 unsigned char *string;
7175 for (; (*pArgnum < argc) && (sNum < ScreenCount(DISPLAY));
7176 (*pArgnum)++, sNum++)
7178 lineP = (unsigned char *)argv[*pArgnum];
7179 if (*argv[*pArgnum] == '"')
7182 * if Quote, use GetString to strip it
7184 if ((string = GetString (&lineP)) == NULL)
7185 /* empty or comment line */
7192 string = (unsigned char *)argv[*pArgnum];
7195 /* another option, end of screens names */
7200 if (!(wmGD.screenNames[sNum] = (unsigned char *)
7201 XtRealloc ((char*)wmGD.screenNames[sNum],
7202 1 + strlen((char *)string))))
7204 Warning (((char *)GETMESSAGE(60, 31, "Insufficient memory for screen names")));
7205 ExitWM(WM_ERROR_EXIT_VALUE);
7209 strcpy((char *)wmGD.screenNames[sNum], (char *)string);
7217 * remaining screens (if any) get first name specified
7221 lastLen = 1 + strlen((char *)wmGD.screenNames[0]);
7222 for (; sNum < ScreenCount(DISPLAY); sNum++)
7224 if (!(wmGD.screenNames[sNum] = (unsigned char *)
7225 XtRealloc ((char*)wmGD.screenNames[sNum], lastLen)))
7227 Warning (((char *)GETMESSAGE(60, 32, "Insufficient memory for screen names")));
7228 ExitWM(WM_ERROR_EXIT_VALUE);
7232 strcpy((char *)wmGD.screenNames[sNum],
7233 (char *)wmGD.screenNames[0]);
7238 } /* END OF FUNCTION ParseScreensArgument */
7241 /*************************************<->*************************************
7243 * ProcessMotifBindings ()
7248 * This function is used retrieve the motif input bindings
7249 * and put them into a property on the root window.
7252 *************************************<->***********************************/
7253 void ProcessMotifBindings (void)
7255 char fileName[MAXWMPATH+1];
7256 char *bindings = NULL;
7257 #ifndef MOTIF_ONE_DOT_ONE
7258 char *homeDir = XmeGetHomeDirName();
7264 * Look in the user's home directory for .motifbind
7267 #ifdef MOTIF_ONE_DOT_ONE
7268 GetHomeDirName(fileName);
7270 strcpy (fileName, homeDir);
7272 strncat(fileName, "/", MAXWMPATH-strlen(fileName));
7273 strncat(fileName, MOTIF_BINDINGS_FILE, MAXWMPATH-strlen(fileName));
7275 #ifdef MOTIF_ONE_DOT_ONE
7276 if ((fileP = fopen (fileName, "r")) != NULL)
7278 unsigned char buffer[MBBSIZ];
7280 Boolean first = True;
7281 int mode = PropModeReplace;
7285 * Get the atom for the property.
7287 wmGD.xa_MOTIF_BINDINGS =
7288 XInternAtom (DISPLAY, _XA_MOTIF_BINDINGS, False);
7291 * The property goes on the root window of screen zero
7293 propWindow = RootWindow(DISPLAY, 0);
7296 * Copy file contents to property on root window of screen 0.
7298 while ( (count=fread((char *) &buffer[0], 1, MBBSIZ, fileP)) > 0)
7300 XChangeProperty (DISPLAY, propWindow, wmGD.xa_MOTIF_BINDINGS,
7307 mode = PropModeAppend;
7313 XDeleteProperty (DISPLAY, RootWindow (DISPLAY, 0),
7314 XInternAtom (DISPLAY, "_MOTIF_BINDINGS", False));
7315 XDeleteProperty (DISPLAY, RootWindow (DISPLAY, 0),
7316 XInternAtom (DISPLAY, "_MOTIF_DEFAULT_BINDINGS", False));
7318 /* FIXME: unexported openmotif procedures */
7319 extern Boolean _XmVirtKeysLoadFileBindings(Display *dsp, String *binding);
7320 extern void _XmVirtKeysLoadFallbackBindings(Display *dsp, String *binding);
7321 if (_XmVirtKeysLoadFileBindings (fileName, &bindings) == True) {
7322 XChangeProperty (DISPLAY, RootWindow(DISPLAY, 0),
7323 XInternAtom (DISPLAY, "_MOTIF_BINDINGS", False),
7324 XA_STRING, 8, PropModeReplace,
7325 (unsigned char *)bindings, strlen(bindings));
7328 _XmVirtKeysLoadFallbackBindings (DISPLAY, &bindings);
7332 } /* END OF FUNCTION ProcessMotifBindings */
7336 /*************************************<->*************************************
7339 * ParseWmFunctionArg (linePP, ix, wmFunc, ppArg, sClientName)
7344 * Parse the function arguments for a window manager function.
7349 * linePP = pointer to line buffer pointer (contains string arg).
7350 * ix = window manager function index (returned by ParseWmFunction)
7351 * pWmFunction = pointer to window manager function destination.
7352 * ppArg = ptr to argument pointer.
7353 * sClientName = string name of client
7358 * *ppArg = arg to pass to window manager function when invoking.
7359 * Return = true on succes, false on some kind of parse error
7364 * functionTable (window manager function table) is indexed with ix
7365 * to get parsing info.
7367 * This function may malloc memory for the returned arg.
7369 * The sClientName is needed for starting some hpterm-based push_recall
7370 * clients. It needs to be passed into the action so the hpterm gets
7371 * named appropriately.
7373 *************************************<->***********************************/
7376 ParseWmFunctionArg (
7377 unsigned char **linePP,
7384 unsigned char *lineP = *linePP;
7385 Boolean bValidArg = True;
7386 unsigned char *str = NULL;
7389 * If this is (possibly) a string argument, put it
7390 * in quotes so that it will be parsed properly.
7392 if ((functionTable[ix].parseProc == ParseWmFuncStrArg) ||
7393 (functionTable[ix].parseProc == ParseWmFuncMaybeStrArg))
7395 if (lineP && *lineP != '"')
7398 * not in quotes, repackage it, escaping the appropriate
7401 str = _DtWmParseMakeQuotedString (lineP);
7410 * Apply the function argument parser.
7412 if ((functionTable[ix].wmFunction != wmFunc) ||
7413 !(*(functionTable [ix].parseProc)) (&lineP, wmFunc, ppArg))
7419 * Add the exec parms if this is an f.action
7421 if ((wmFunc == F_Action) && ppArg && *ppArg)
7423 WmActionArg *pAP = (WmActionArg *) *ppArg;
7427 * allocate more than enough string space to copy
7428 * strings and intervening spaces.
7430 if (sClientName && *sClientName)
7432 /* length of: "name=" + sClientName + NULL */
7433 totLen += 5 + strlen(sClientName) + 1;
7435 if (sTitle && *sTitle)
7437 /* length of: "," + "title=" + sTitle + NULL */
7438 totLen += 1 + 6 + strlen(sTitle) + 1;
7443 pAP->szExecParms = (String) XtMalloc (totLen);
7444 /* start with empty string */
7445 pAP->szExecParms[0] = '\0';
7447 if (sClientName && *sClientName)
7449 strcat (pAP->szExecParms, "name=");
7450 strcat (pAP->szExecParms, sClientName);
7452 if (sTitle && *sTitle)
7454 if (pAP->szExecParms[0] != '\0')
7456 strcat (pAP->szExecParms, ",");
7458 strcat (pAP->szExecParms, "title=");
7459 strcat (pAP->szExecParms, sTitle);
7466 XtFree ((char *) str);
7471 } /* END OF FUNCTION ParseWmFunctionArg */
7474 /*************************************<->*************************************
7476 * SystemCmd (pchCmd)
7481 * This function fiddles with our signal handling and calls the
7482 * system() function to invoke a unix command.
7487 * pchCmd = string with the command we want to exec.
7495 * The system() command is touchy about the SIGCLD behavior. Restore
7496 * the default SIGCLD handler during the time we run system().
7498 *************************************<->***********************************/
7501 SystemCmd (char *pchCmd)
7503 struct sigaction sa;
7504 struct sigaction osa;
7506 (void) sigemptyset(&sa.sa_mask);
7508 sa.sa_handler = SIG_DFL;
7510 (void) sigaction (SIGCHLD, &sa, &osa);
7514 (void) sigaction (SIGCHLD, &osa, (struct sigaction *) 0);
7519 /*************************************<->*************************************
7521 * DeleteTempConfigFileIfAny ()
7526 * This function deletes the temporary config file used to process
7527 * old dtwmrc syntax.
7541 *************************************<->***********************************/
7544 DeleteTempConfigFileIfAny (void)
7546 char pchCmd[MAXWMPATH+1];
7548 if (pConfigStackTop->tempName)
7550 strcpy (pchCmd, "/bin/rm ");
7551 strcat (pchCmd, pConfigStackTop->tempName);
7553 XtFree ((char *) pConfigStackTop->tempName);
7554 pConfigStackTop->tempName = NULL;
7556 if (pConfigStackTop->cppName)
7558 strcpy (pchCmd, "/bin/rm ");
7559 strcat (pchCmd, pConfigStackTop->cppName);
7561 XtFree ((char *) pConfigStackTop->cppName);
7562 pConfigStackTop->cppName = NULL;
7567 /*************************************<->*************************************
7569 * ParseIncludeSet (pSD, lineP)
7578 * cfileP = (global) file pointer to fopened configuration file or NULL
7579 * lineP = pointer to line buffer
7580 * line = (global) line buffer
7581 * linec = (global) line count
7582 * parseP = (global) parse string pointer if cfileP == NULL
7583 * pSD->rootWindow = default root window of display
7587 * linec = (global) line count incremented
7588 * parseP = (global) parse string pointer if cfileP == NULL
7594 *************************************<->***********************************/
7596 static void ParseIncludeSet (WmScreenData *pSD, unsigned char *lineP)
7598 unsigned char *string;
7599 unsigned char *pchName;
7602 * Require leading '{' on the next line.
7605 while ((GetNextLine () != NULL)) /* not EOF nor read error */
7608 ScanWhitespace(&lineP);
7610 if ((lineP == NULL) || (*line == '!') || (*lineP == '\0') || (*lineP == '#'))
7611 /* ignore empty or comment line */
7623 PWarning (((char *)GETMESSAGE(60, 37, "Expected '{'")));
7628 * Found leading "{" or EOF.
7629 * Parse include files until "}" or EOF found.
7631 while ((GetNextLine () != NULL))
7634 if ((*line == '!') || (string = GetString (&lineP)) == NULL)
7635 /* ignore empty or comment lines */
7639 if (*string == '}') /* finished with set. */
7643 pchName = _DtWmParseFilenameExpand (string);
7644 if (pchName && ConfigStackPush (pchName))
7646 ProcessWmFile (pSD, True /* nested */);
7648 XtFree ((char *) pchName);
7657 /*************************************<->*************************************
7659 * ConfigStackInit (pchFileName)
7664 * Initializes the config file processing stack
7668 * pchFileName = name of new file to start parsing
7677 *************************************<->***********************************/
7679 static void ConfigStackInit (char *pchFileName)
7682 pConfigStack = XtNew (ConfigFileStackEntry);
7686 pConfigStackTop = pConfigStack;
7687 pConfigStackTop->fileName = XtNewString (pchFileName);
7688 pConfigStackTop->tempName = NULL;
7689 pConfigStackTop->cppName = NULL;
7690 pConfigStackTop->offset = 0;
7691 pConfigStackTop->pWmPB = wmGD.pWmPB;
7692 pConfigStackTop->wmgdConfigFile = wmGD.configFile;
7693 pConfigStackTop->pIncluder = NULL;
7698 sprintf ((char *)wmGD.tmpBuffer,
7699 (char *)GETMESSAGE(60,36,"Insufficient memory to process included file: %s"),
7701 Warning ((char *)wmGD.tmpBuffer);
7706 /*************************************<->*************************************
7708 * ConfigStackPush (pchFileName)
7713 * Open an included config file
7717 * pchFileName = name of new file to start parsing
7718 * wmGD.pWmPB = global parse buffer (pickle this)
7722 * wmGD.pWmPB = global parse buffer (new one for new file)
7723 * return = FILE * to open file or NULL
7729 *************************************<->***********************************/
7732 ConfigStackPush (unsigned char *pchFileName)
7734 ConfigFileStackEntry *pEntry;
7735 FILE *pNewFile = NULL;
7737 pEntry = XtNew (ConfigFileStackEntry);
7740 /* save off state of current config file */
7741 pConfigStackTop->offset = ftell (cfileP);
7742 pConfigStackTop->pWmPB = wmGD.pWmPB;
7745 /* set up state of new config file */
7746 pEntry->fileName = XtNewString ((char *)pchFileName);
7747 pEntry->tempName = NULL;
7748 pEntry->cppName = NULL;
7749 pEntry->wmgdConfigFile = (String) pEntry->fileName;
7751 /* set globals for new config file */
7752 wmGD.pWmPB = _DtWmParseNewBuf ();
7753 wmGD.configFile = pEntry->wmgdConfigFile;
7755 /* put new entry onto stack */
7756 pEntry->pIncluder = pConfigStackTop;
7757 pConfigStackTop = pEntry;
7760 pNewFile = cfileP = FopenConfigFile();
7764 /* file open failed! back out */
7770 sprintf ((char *)wmGD.tmpBuffer,
7771 (char *)GETMESSAGE(60,36,"Insufficient memory to process included file: %s"),
7773 Warning ((char *)wmGD.tmpBuffer);
7781 /*************************************<->*************************************
7792 * pchFileName = name of new file to start parsing
7793 * wmGD.pWmPB = global parse buffer (pickle this)
7797 * wmGD.pWmPB = global parse buffer (new one for new file)
7802 * assumes cfileP is closed already
7804 *************************************<->***********************************/
7806 static void ConfigStackPop (void)
7808 Boolean error = False;
7809 ConfigFileStackEntry *pPrev;
7810 char pchCmd[MAXWMPATH+1];
7812 if (pConfigStackTop != pConfigStack)
7814 pPrev = pConfigStackTop->pIncluder;
7816 _DtWmParseDestroyBuf (wmGD.pWmPB);
7817 if (pConfigStackTop->tempName)
7819 XtFree (pConfigStackTop->tempName);
7821 if (pConfigStackTop->cppName)
7823 strcpy (pchCmd, "/bin/rm ");
7824 strcat (pchCmd, pConfigStackTop->cppName);
7826 XtFree ((char *) pConfigStackTop->cppName);
7827 pConfigStackTop->cppName = NULL;
7829 if (pConfigStackTop->fileName)
7831 XtFree (pConfigStackTop->fileName);
7834 wmGD.pWmPB = pPrev->pWmPB;
7835 wmGD.configFile = pPrev->wmgdConfigFile;
7836 if (pPrev->tempName)
7838 cfileP = fopen (pPrev->tempName, "r");
7840 else if (pPrev->cppName)
7842 cfileP = fopen (pPrev->cppName, "r");
7846 cfileP = fopen (pPrev->fileName, "r");
7850 fseek (cfileP, pPrev->offset, 0);
7854 char msg[MAXWMPATH+1];
7856 sprintf(msg, ((char *)GETMESSAGE(60, 39,
7857 "Could not reopen configuration file %s")),
7862 XtFree ((char *)pConfigStackTop);
7863 pConfigStackTop = pPrev;
7868 /*************************************<->*************************************
7870 * ParseWmFuncActionArg (linePP, wmFunction, pArgs)
7875 * Parses a window manager f.action argument
7880 * linePP = pointer to current line buffer pointer.
7881 * wmFunction = function for which the argument string is intended.
7882 * pArgs = pointer to argument destination.
7887 * linePP = pointer to revised line buffer pointer.
7888 * pArgs = pointer to parsed argument.
7889 * Return = FALSE iff insufficient memory
7895 *************************************<->***********************************/
7897 Boolean ParseWmFuncActionArg (unsigned char **linePP,
7898 WmFunction wmFunction, String *pArgs)
7900 #define WM_ACTION_ARG_INCREMENT 5
7901 #define WM_ACTION_ARG_PAD 256
7902 unsigned char *string;
7907 pAP = XtNew (WmActionArg);
7908 if (pAP && (string = GetString (linePP)) != NULL)
7910 /* Got action name */
7911 pAP->actionName = XtNewString ((char *) string);
7913 /* Get action arguments, if any */
7914 if (pAP->aap = (DtActionArg *)
7915 XtMalloc (WM_ACTION_ARG_INCREMENT * sizeof (DtActionArg)))
7917 iArgSz = WM_ACTION_ARG_INCREMENT;
7920 while ((string = GetString (linePP)) != NULL)
7922 if (pAP->aap[pAP->numArgs].u.file.name = (char *)
7923 XtMalloc(1 + strlen((char *)string)))
7925 pAP->aap[pAP->numArgs].argClass = DtACTION_FILE;
7927 /* format the action argument */
7928 pch = pAP->aap[pAP->numArgs].u.file.name;
7931 * Expand environment variable
7933 if (string[0] == '$')
7935 string = (unsigned char *) getenv ((char *)&string[1]);
7943 * Make sure there's room for the new
7947 XtRealloc (pch, (1+strlen((char *)string)));
7948 pAP->aap[pAP->numArgs].u.file.name = pch;
7952 /* !!! No host name processing is done!!! */
7954 strcpy (pch, (char *)string);
7957 if (pAP->numArgs == iArgSz)
7959 /* need to increase our array space */
7960 iArgSz += WM_ACTION_ARG_INCREMENT;
7961 pAP->aap = (DtActionArg *)
7962 XtRealloc((char *)pAP->aap,
7963 (iArgSz * sizeof (DtActionArg)));
7966 break; /* out of memory */
7972 break; /* out of memory */
7977 pAP->szExecParms = NULL;
7978 *pArgs = (String) pAP;
7981 /* NULL string argument */
7988 } /* END OF FUNCTION ParseWmFuncActionArg */
7991 #endif /* PANELIST */
7994 /*************************************<->*************************************
7996 * PreprocessConfigFile (pSD)
8001 * This function runs the configuration file through the C
8007 * pSD = ptr to screen data
8016 *************************************<->***********************************/
8019 PreprocessConfigFile (void)
8021 #define CPP_NAME_SIZE ((L_tmpnam)+1)
8022 char pchCmd[MAXWMPATH+1];
8024 if (wmGD.cppCommand && *wmGD.cppCommand)
8027 * Generate a temp file name.
8029 pConfigStackTop->cppName = XtMalloc (CPP_NAME_SIZE * sizeof(char));
8030 if (pConfigStackTop->cppName)
8032 (void) tmpnam (pConfigStackTop->cppName);
8035 * Build up the command line.
8037 strcpy (pchCmd, wmGD.cppCommand);
8038 strcat (pchCmd, " ");
8039 strcat (pchCmd, pConfigStackTop->fileName);
8040 strcat (pchCmd, " ");
8041 strcat (pchCmd, pConfigStackTop->cppName);
8044 * Run the config file through the converter program
8045 * and send the output to a temp file.
8053 /*************************************<->*************************************
8055 * GetNetworkFileName (char *pchFile)
8060 * This function returns a local representation for a network
8066 * pchFile - pointer to file name of form [<host>:]<path>
8070 * String - ptr to allocated string of local file name. If input
8071 * is not a network file, the a copy of pchFile is returned.
8076 * returned file name should be freed with XtFree().
8078 *************************************<->***********************************/
8081 GetNetworkFileName (char *pchFile)
8088 char *pchName = NULL;
8091 String sReturn = NULL;
8096 pch = strchr (pchFile, ':');
8101 * Expand special chars and find matching file.
8103 pchTok = (char **)shellscan (pchFile, &count, 0);
8105 if ((count == 1) || (count == 2))
8107 /* one match found */
8108 host_part = pchTok[0];
8112 /* several matches found, pick one */
8113 host_part = pchTok[1];
8120 if (host_part != NULL)
8122 pch = strchr (host_part, ':');
8126 * copy the string so we don't munge data
8129 host_part = sName = XtNewString ((String) host_part);
8130 pch = strchr (sName, ':');
8133 * separate the host and file parts of the
8142 * The colon went away. Hmm...
8144 file_part = host_part;
8148 if ((mblen(file_part, MB_CUR_MAX) == 1) &&
8149 (mblen(file_part+1, MB_CUR_MAX) == 1) &&
8150 (*file_part == '~') &&
8151 (*(file_part+1) == '/'))
8154 * Replace '~' with $HOME
8156 homeDir = XmeGetHomeDirName();
8157 len = strlen (host_part) + 1 +
8158 strlen (homeDir) + strlen (file_part) + 1;
8159 pch = (char *) XtMalloc (len);
8160 strcpy (pch, sName);
8162 pch += strlen (pch) + 1;
8163 strcpy (pch, homeDir);
8164 strcat (pch, file_part+1);
8173 * shellscan had a problem with the file name.
8174 * just operate on the name as-is.
8175 * temporarily replace ':' with a NULL
8177 host_part = sName = XtNewString ((String) pchFile);
8178 pch = strchr (sName, ':');
8180 host_part = pchFile;
8184 /* convert to canonical host/file name */
8186 tt_host_file_netfile (host_part, file_part);
8187 if (tt_pointer_error (netfile) == TT_OK)
8189 /* convert to local file name equivalent */
8190 pchName = tt_netfile_file (netfile);
8192 if (tt_pointer_error (pchName) == TT_OK)
8194 sReturn = XtNewString ((String) pchName);
8195 tt_free ((char *)pchName);
8202 XtFree ((char *)sName);
8206 if (sReturn == NULL)
8208 if ((mblen(pchFile, MB_CUR_MAX) == 1) &&
8209 (mblen(pchFile+1, MB_CUR_MAX) == 1) &&
8210 (*pchFile == '~') &&
8211 (*(pchFile+1) == '/'))
8214 * Replace '~' with $HOME
8216 homeDir = XmeGetHomeDirName();
8217 len = strlen (homeDir) + strlen (pchFile) + 1;
8218 sReturn = (char *) XtMalloc (len);
8219 strcpy (sReturn, homeDir);
8220 strcat (sReturn, pchFile+1);
8224 sReturn = XtNewString ((String) pchFile);
8230 /**************************** eof ***************************/
8234 #if ((!defined(WSM)) || defined(MWM_QATS_PROTOCOL))
8235 /*************************************<->*************************************
8237 * SetGreyedContextAndMgtMask (menuItem, wmFunction)
8242 * This function sets up the greyed context and management mask
8243 * for a menu item based on the menu function passed in.
8247 * menuItem = the menu item to be set up
8248 * wmFunction = the menu function to find in the function table
8249 * to determine how to set up the relevant fields
8253 * The menuItem will have its greyed context and management mask fields
8254 * set appropriately. If the given function cannot be found, the fields
8255 * will be set to the appropriate values as if the function were F_Nop.
8256 * Return = True if the function could be found. False otherwise.
8258 *************************************<->***********************************/
8260 Boolean SetGreyedContextAndMgtMask (MenuItem *menuItem,
8261 WmFunction wmFunction)
8265 for (ix = 0; ix < WMFUNCTIONTABLESIZE - 1; ++ix)
8267 if (functionTable[ix].wmFunction == wmFunction)
8269 /* Success! The function was found. Set up the
8270 values and get the heck out of here. */
8271 menuItem->greyedContext = functionTable[ix].greyedContext;
8272 menuItem->mgtMask = functionTable[ix].mgtMask;
8277 /* We couldn't find the given command in the function table.
8278 Set up the values as if the F_Nop function were found
8279 and return False. */
8280 menuItem->greyedContext = functionTable[F_NOP_INDEX].greyedContext;
8281 menuItem->mgtMask = functionTable[F_NOP_INDEX].mgtMask;
8287 /*************************************<->*************************************
8289 * MakeSeparatorTemplate ()
8301 *************************************<->***********************************/
8303 MenuItem *MakeSeparatorTemplate (int position)
8307 item = (MenuItem *)XtMalloc(sizeof(MenuItem));
8309 /* We use the labelType to determine where this separator is positioned
8310 relative to the client command(s) it is surrounding, i.e. TOP or
8312 item->labelType = position;
8313 /* Make it look like a client command: */
8314 item->label = XtNewString("<label-template>");
8315 item->labelBitmapIndex = -1;
8316 item->mnemonic = (KeySym) 0;
8317 item->accelState = 0;
8318 item->accelKeyCode = (KeyCode) NULL;
8319 item->accelText = (String) NULL;
8320 item->wmFunction = (WmFunction) F_Separator;
8321 item->wmFuncArgs = (String) NULL;
8322 item->greyedContext = 0;
8324 item->clientCommandName = (String) NULL;
8325 item->nextMenuItem = (MenuItem *) NULL;
8329 #endif /* !defined(WSM) || defined(MWM_QATS_PROTOCOL) */