1 static const char CVSID
[] = "$Id: userCmds.c,v 1.57 2009/06/23 21:03:13 lebert Exp $";
2 /*******************************************************************************
4 * userCmds.c -- Nirvana Editor shell and macro command dialogs *
6 * Copyright (C) 1999 Mark Edel *
8 * This is free software; you can redistribute it and/or modify it under the *
9 * terms of the GNU General Public License as published by the Free Software *
10 * Foundation; either version 2 of the License, or (at your option) any later *
11 * version. In addition, you may distribute version of this program linked to *
12 * Motif or Open Motif. See README for details. *
14 * This software is distributed in the hope that it will be useful, but WITHOUT *
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *
19 * You should have received a copy of the GNU General Public License along with *
20 * software; if not, write to the Free Software Foundation, Inc., 59 Temple *
21 * Place, Suite 330, Boston, MA 02111-1307 USA *
23 * Nirvana Text Editor *
26 * Written by Mark Edel *
28 *******************************************************************************/
31 #include "../config.h"
38 #include "preferences.h"
44 #include "interpret.h"
46 #include "../util/DialogF.h"
47 #include "../util/misc.h"
48 #include "../util/managedList.h"
55 #include "../util/VMSparam.h"
58 #include <sys/param.h>
63 #include <X11/keysym.h>
64 #include <X11/IntrinsicP.h>
68 #include <Xm/LabelG.h>
70 #include <Xm/ToggleB.h>
71 #include <Xm/SelectioB.h>
72 #include <Xm/RowColumn.h>
73 #include <Xm/CascadeB.h>
74 #include <Xm/MenuShell.h>
81 #define MENU_WIDGET(w) (XmGetPostedFromWidget(XtParent(w)))
83 #define MENU_WIDGET(w) (w)
86 extern void _XmDismissTearOff(Widget w
, XtPointer call
, XtPointer x
);
88 /* max. number of user programmable menu commands allowed per each of the
89 macro, shell, and background menus */
90 #define MAX_ITEMS_PER_MENU 400
92 /* indicates, that an unknown (i.e. not existing) language mode
93 is bound to an user menu item */
94 #define UNKNOWN_LANGUAGE_MODE -2
96 /* major divisions (in position units) in User Commands dialogs */
97 #define LEFT_MARGIN_POS 1
98 #define RIGHT_MARGIN_POS 99
100 #define SHELL_CMD_TOP 70
101 #define MACRO_CMD_TOP 40
103 /* types of current dialog and/or menu */
104 enum dialogTypes
{SHELL_CMDS
, MACRO_CMDS
, BG_MENU_CMDS
};
106 /* Structure representing a menu item for shell, macro and BG menus*/
109 unsigned int modifiers
;
120 /* Structure for widgets and flags associated with shell command,
121 macro command and BG command editing dialogs */
125 Widget nameTextW
, accTextW
, mneTextW
, cmdTextW
, saveFirstBtn
;
126 Widget loadAfterBtn
, selInpBtn
, winInpBtn
, eitherInpBtn
, noInpBtn
;
127 Widget repInpBtn
, sameOutBtn
, dlogOutBtn
, winOutBtn
, dlogShell
;
129 menuItemRec
**menuItemsList
;
133 /* Structure for keeping track of hierarchical sub-menus during user-menu
140 /* Structure holding hierarchical info about one sub-menu.
142 Suppose following user menu items:
144 b.) "subMenuA>menuItemA1"
145 c.) "subMenuA>menuItemA2"
146 d.) "subMenuA>subMenuB>menuItemB1"
147 e.) "subMenuA>subMenuB>menuItemB2"
149 Structure of this user menu is:
151 Main Menu Name Sub-Menu A Name Sub-Menu B Name
152 element nbr. element nbr. element nbr.
154 1 subMenuA --+-> 0 menuItemA1
156 +-> 2 subMenuB --+-> 0 menuItemB1
159 Above example holds 2 sub-menus:
160 1.) "subMenuA" (hierarchical ID = {1} means: element nbr. "1" of main menu)
161 2.) "subMenuA>subMenuB" (hierarchical ID = {1, 2} means: el. nbr. "2" of
162 "subMenuA", which itself is el. nbr. "0" of main menu) */
164 char *usmiName
; /* hierarchical name of sub-menu */
165 int *usmiId
; /* hierarchical ID of sub-menu */
166 int usmiIdLen
; /* length of hierarchical ID */
169 /* Holds info about sub-menu structure of an user menu */
171 int usmcNbrOfMainMenuItems
; /* number of main menu items */
172 int usmcNbrOfSubMenus
; /* number of sub-menus */
173 userSubMenuInfo
*usmcInfo
; /* list of sub-menu info */
176 /* Structure holding info about a single menu item.
177 According to above example there exist 5 user menu items:
178 a.) "menuItem1" (hierarchical ID = {0} means: element nbr. "0" of main menu)
179 b.) "menuItemA1" (hierarchical ID = {1, 0} means: el. nbr. "0" of
180 "subMenuA", which itself is el. nbr. "1" of main menu)
181 c.) "menuItemA2" (hierarchical ID = {1, 1})
182 d.) "menuItemB1" (hierarchical ID = {1, 2, 0})
183 e.) "menuItemB2" (hierarchical ID = {1, 2, 1})
186 char *umiName
; /* hierarchical name of menu item
187 (w.o. language mode info) */
188 int *umiId
; /* hierarchical ID of menu item */
189 int umiIdLen
; /* length of hierarchical ID */
190 Boolean umiIsDefault
; /* menu item is default one ("@*") */
191 int umiNbrOfLanguageModes
; /* number of language modes
192 applicable for this menu item */
193 int *umiLanguageMode
; /* list of applicable lang. modes */
194 int umiDefaultIndex
; /* array index of menu item to be
195 used as default, if no lang. mode
197 Boolean umiToBeManaged
; /* indicates, that menu item needs
201 /* Structure holding info about a selected user menu (shell, macro or
204 int sumType
; /* type of menu (shell, macro or
206 Widget sumMenuPane
; /* pane of main menu */
207 int sumNbrOfListItems
; /* number of menu items */
208 menuItemRec
**sumItemList
; /* list of menu items */
209 userMenuInfo
**sumInfoList
; /* list of infos about menu items */
210 userSubMenuCache
*sumSubMenus
; /* info about sub-menu structure */
211 UserMenuList
*sumMainMenuList
; /* cached info about main menu */
212 Boolean
*sumMenuCreated
; /* pointer to "menu created"
216 /* Descriptions of the current user programmed menu items for re-generating
217 menus and processing shell, macro, and background menu selections */
218 static menuItemRec
*ShellMenuItems
[MAX_ITEMS_PER_MENU
];
219 static userMenuInfo
*ShellMenuInfo
[MAX_ITEMS_PER_MENU
];
220 static userSubMenuCache ShellSubMenus
;
221 static int NShellMenuItems
= 0;
222 static menuItemRec
*MacroMenuItems
[MAX_ITEMS_PER_MENU
];
223 static userMenuInfo
*MacroMenuInfo
[MAX_ITEMS_PER_MENU
];
224 static userSubMenuCache MacroSubMenus
;
225 static int NMacroMenuItems
= 0;
226 static menuItemRec
*BGMenuItems
[MAX_ITEMS_PER_MENU
];
227 static userMenuInfo
*BGMenuInfo
[MAX_ITEMS_PER_MENU
];
228 static userSubMenuCache BGSubMenus
;
229 static int NBGMenuItems
= 0;
231 /* Top level shells of the user-defined menu editing dialogs */
232 static Widget ShellCmdDialog
= NULL
;
233 static Widget MacroCmdDialog
= NULL
;
234 static Widget BGMenuCmdDialog
= NULL
;
236 /* Paste learn/replay sequence buttons in user defined menu editing dialogs
237 (for dimming and undimming externally when replay macro is available) */
238 static Widget MacroPasteReplayBtn
= NULL
;
239 static Widget BGMenuPasteReplayBtn
= NULL
;
241 static void editMacroOrBGMenu(WindowInfo
*window
, int dialogType
);
242 static void dimSelDepItemsInMenu(Widget menuPane
, menuItemRec
**menuList
,
243 int nMenuItems
, int sensitive
);
244 static void rebuildMenuOfAllWindows(int menuType
);
245 static void rebuildMenu(WindowInfo
*window
, int menuType
);
246 static Widget
findInMenuTree(menuTreeItem
*menuTree
, int nTreeEntries
,
247 const char *hierName
);
248 static char *copySubstring(const char *string
, int length
);
249 static Widget
createUserMenuItem(Widget menuPane
, char *name
, menuItemRec
*f
,
250 int index
, XtCallbackProc cbRtn
, XtPointer cbArg
);
251 static Widget
createUserSubMenu(Widget parent
, char *label
, Widget
*menuItem
);
252 static void deleteMenuItems(Widget menuPane
);
253 static void selectUserMenu(WindowInfo
*window
, int menuType
, selectedUserMenu
*menu
);
254 static void updateMenu(WindowInfo
*window
, int menuType
);
255 static void manageTearOffMenu(Widget menuPane
);
256 static void resetManageMode(UserMenuList
*list
);
257 static void manageAllSubMenuWidgets(UserMenuListElement
*subMenu
);
258 static void unmanageAllSubMenuWidgets(UserMenuListElement
*subMenu
);
259 static void manageMenuWidgets(UserMenuList
*list
);
260 static void removeAccelFromMenuWidgets(UserMenuList
*menuList
);
261 static void assignAccelToMenuWidgets(UserMenuList
*menuList
, WindowInfo
*window
);
262 static void manageUserMenu(selectedUserMenu
*menu
, WindowInfo
*window
);
263 static void createMenuItems(WindowInfo
*window
, selectedUserMenu
*menu
);
264 static void okCB(Widget w
, XtPointer clientData
, XtPointer callData
);
265 static void applyCB(Widget w
, XtPointer clientData
, XtPointer callData
);
266 static void checkCB(Widget w
, XtPointer clientData
, XtPointer callData
);
267 static int checkMacro(userCmdDialog
*ucd
);
268 static int checkMacroText(char *macro
, Widget errorParent
, Widget errFocus
);
269 static int applyDialogChanges(userCmdDialog
*ucd
);
270 static void closeCB(Widget w
, XtPointer clientData
, XtPointer callData
);
271 static void pasteReplayCB(Widget w
, XtPointer clientData
, XtPointer callData
);
272 static void destroyCB(Widget w
, XtPointer clientData
, XtPointer callData
);
273 static void accKeyCB(Widget w
, XtPointer clientData
, XKeyEvent
*event
);
274 static void sameOutCB(Widget w
, XtPointer clientData
, XtPointer callData
);
275 static void shellMenuCB(Widget w
, WindowInfo
*window
, XtPointer callData
);
276 static void macroMenuCB(Widget w
, WindowInfo
*window
, XtPointer callData
);
277 static void bgMenuCB(Widget w
, WindowInfo
*window
, XtPointer callData
) ;
278 static void accFocusCB(Widget w
, XtPointer clientData
, XtPointer callData
);
279 static void accLoseFocusCB(Widget w
, XtPointer clientData
,
281 static void updateDialogFields(menuItemRec
*f
, userCmdDialog
*ucd
);
282 static menuItemRec
*readDialogFields(userCmdDialog
*ucd
, int silent
);
283 static menuItemRec
*copyMenuItemRec(menuItemRec
*item
);
284 static void freeMenuItemRec(menuItemRec
*item
);
285 static void *getDialogDataCB(void *oldItem
, int explicitRequest
, int *abort
,
287 static void setDialogDataCB(void *item
, void *cbArg
);
288 static void freeItemCB(void *item
);
289 static int dialogFieldsAreEmpty(userCmdDialog
*ucd
);
290 static void disableTextW(Widget textW
);
291 static char *writeMenuItemString(menuItemRec
**menuItems
, int nItems
,
293 static int loadMenuItemString(char *inString
, menuItemRec
**menuItems
,
294 int *nItems
, int listType
);
295 static void generateAcceleratorString(char *text
, unsigned int modifiers
,
297 static void genAccelEventName(char *text
, unsigned int modifiers
,
299 static int parseAcceleratorString(const char *string
, unsigned int *modifiers
,
301 static int parseError(const char *message
);
302 static char *copyMacroToEnd(char **inPtr
);
303 static void addTerminatingNewline(char **string
);
304 static void parseMenuItemList(menuItemRec
**itemList
, int nbrOfItems
,
305 userMenuInfo
**infoList
, userSubMenuCache
*subMenus
);
306 static int getSubMenuDepth(const char *menuName
);
307 static userMenuInfo
*parseMenuItemRec(menuItemRec
*item
);
308 static void parseMenuItemName(char *menuItemName
, userMenuInfo
*info
);
309 static void generateUserMenuId(userMenuInfo
*info
, userSubMenuCache
*subMenus
);
310 static userSubMenuInfo
*findSubMenuInfo(userSubMenuCache
*subMenus
,
311 const char *hierName
);
312 static char *stripLanguageMode(const char *menuItemName
);
313 static void setDefaultIndex(userMenuInfo
**infoList
, int nbrOfItems
,
315 static void applyLangModeToUserMenuInfo(userMenuInfo
**infoList
, int nbrOfItems
,
317 static int doesLanguageModeMatch(userMenuInfo
*info
, int languageMode
);
318 static void freeUserMenuInfoList(userMenuInfo
**infoList
, int nbrOfItems
);
319 static void freeUserMenuInfo(userMenuInfo
*info
);
320 static void allocSubMenuCache(userSubMenuCache
*subMenus
, int nbrOfItems
);
321 static void freeSubMenuCache(userSubMenuCache
*subMenus
);
322 static void allocUserMenuList(UserMenuList
*list
, int nbrOfItems
);
323 static void freeUserMenuList(UserMenuList
*list
);
324 static UserMenuListElement
*allocUserMenuListElement(Widget menuItem
, char *accKeys
);
325 static void freeUserMenuListElement(UserMenuListElement
*element
);
326 static UserMenuList
*allocUserSubMenuList(int nbrOfItems
);
327 static void freeUserSubMenuList(UserMenuList
*list
);
330 ** Present a dialog for editing the user specified commands in the shell menu
332 void EditShellMenu(WindowInfo
*window
)
334 Widget form
, accLabel
, inpLabel
, inpBox
, outBox
, outLabel
;
335 Widget nameLabel
, cmdLabel
, okBtn
, applyBtn
, closeBtn
;
341 /* if the dialog is already displayed, just pop it to the top and return */
342 if (ShellCmdDialog
!= NULL
) {
343 RaiseDialogWindow(ShellCmdDialog
);
347 /* Create a structure for keeping track of dialog state */
348 ucd
= (userCmdDialog
*)XtMalloc(sizeof(userCmdDialog
));
349 ucd
->window
= window
;
351 /* Set the dialog to operate on the Shell menu */
352 ucd
->menuItemsList
= (menuItemRec
**)XtMalloc(sizeof(menuItemRec
*) *
354 for (i
=0; i
<NShellMenuItems
; i
++)
355 ucd
->menuItemsList
[i
] = copyMenuItemRec(ShellMenuItems
[i
]);
356 ucd
->nMenuItems
= NShellMenuItems
;
357 ucd
->dialogType
= SHELL_CMDS
;
360 XtSetArg(args
[ac
], XmNdeleteResponse
, XmDO_NOTHING
); ac
++;
361 XtSetArg(args
[ac
], XmNiconName
, "NEdit Shell Menu"); ac
++;
362 XtSetArg(args
[ac
], XmNtitle
, "Shell Menu"); ac
++;
363 ucd
->dlogShell
= CreateWidget(TheAppShell
, "shellCommands",
364 topLevelShellWidgetClass
, args
, ac
);
365 AddSmallIcon(ucd
->dlogShell
);
366 form
= XtVaCreateManagedWidget("editShellCommands", xmFormWidgetClass
,
367 ucd
->dlogShell
, XmNautoUnmanage
, False
,
368 XmNresizePolicy
, XmRESIZE_NONE
, NULL
);
369 ShellCmdDialog
= ucd
->dlogShell
;
370 XtAddCallback(form
, XmNdestroyCallback
, destroyCB
, ucd
);
371 AddMotifCloseCallback(ucd
->dlogShell
, closeCB
, ucd
);
374 XtSetArg(args
[ac
], XmNtopAttachment
, XmATTACH_POSITION
); ac
++;
375 XtSetArg(args
[ac
], XmNtopPosition
, 2); ac
++;
376 XtSetArg(args
[ac
], XmNleftAttachment
, XmATTACH_POSITION
); ac
++;
377 XtSetArg(args
[ac
], XmNleftPosition
, LEFT_MARGIN_POS
); ac
++;
378 XtSetArg(args
[ac
], XmNrightAttachment
, XmATTACH_POSITION
); ac
++;
379 XtSetArg(args
[ac
], XmNrightPosition
, LIST_RIGHT
-1); ac
++;
380 XtSetArg(args
[ac
], XmNbottomAttachment
, XmATTACH_POSITION
); ac
++;
381 XtSetArg(args
[ac
], XmNbottomPosition
, SHELL_CMD_TOP
); ac
++;
382 ucd
->managedList
= CreateManagedList(form
, "list", args
, ac
,
383 (void **)ucd
->menuItemsList
, &ucd
->nMenuItems
, MAX_ITEMS_PER_MENU
,
384 20, getDialogDataCB
, ucd
, setDialogDataCB
, ucd
, freeItemCB
);
386 ucd
->loadAfterBtn
= XtVaCreateManagedWidget("loadAfterBtn",
387 xmToggleButtonWidgetClass
, form
,
388 XmNlabelString
, s1
=MKSTRING("Re-load file after executing command"),
390 XmNalignment
, XmALIGNMENT_BEGINNING
,
392 XmNleftAttachment
, XmATTACH_POSITION
,
393 XmNleftPosition
, LIST_RIGHT
,
394 XmNrightAttachment
, XmATTACH_POSITION
,
395 XmNrightPosition
, RIGHT_MARGIN_POS
,
396 XmNbottomAttachment
, XmATTACH_POSITION
,
397 XmNbottomPosition
, SHELL_CMD_TOP
, NULL
);
399 ucd
->saveFirstBtn
= XtVaCreateManagedWidget("saveFirstBtn",
400 xmToggleButtonWidgetClass
, form
,
401 XmNlabelString
, s1
=MKSTRING("Save file before executing command"),
403 XmNalignment
, XmALIGNMENT_BEGINNING
,
405 XmNleftAttachment
, XmATTACH_POSITION
,
406 XmNleftPosition
, LIST_RIGHT
,
407 XmNrightAttachment
, XmATTACH_POSITION
,
408 XmNrightPosition
, RIGHT_MARGIN_POS
,
409 XmNbottomAttachment
, XmATTACH_WIDGET
,
410 XmNbottomWidget
, ucd
->loadAfterBtn
, NULL
);
412 ucd
->repInpBtn
= XtVaCreateManagedWidget("repInpBtn",
413 xmToggleButtonWidgetClass
, form
,
414 XmNlabelString
, s1
=MKSTRING("Output replaces input"),
416 XmNalignment
, XmALIGNMENT_BEGINNING
,
418 XmNleftAttachment
, XmATTACH_POSITION
,
419 XmNleftPosition
, LIST_RIGHT
,
420 XmNrightAttachment
, XmATTACH_POSITION
,
421 XmNrightPosition
, RIGHT_MARGIN_POS
,
422 XmNbottomAttachment
, XmATTACH_WIDGET
,
423 XmNbottomWidget
, ucd
->saveFirstBtn
, NULL
);
425 outBox
= XtVaCreateManagedWidget("outBox", xmRowColumnWidgetClass
, form
,
426 XmNpacking
, XmPACK_TIGHT
,
427 XmNorientation
, XmHORIZONTAL
,
428 XmNradioBehavior
, True
,
429 XmNradioAlwaysOne
, True
,
430 XmNleftAttachment
, XmATTACH_POSITION
,
431 XmNleftPosition
, LIST_RIGHT
+ 2,
432 XmNrightAttachment
, XmATTACH_POSITION
,
433 XmNrightPosition
, RIGHT_MARGIN_POS
,
434 XmNbottomAttachment
, XmATTACH_WIDGET
,
435 XmNbottomWidget
, ucd
->repInpBtn
,
436 XmNbottomOffset
, 4, NULL
);
437 ucd
->sameOutBtn
= XtVaCreateManagedWidget("sameOutBtn",
438 xmToggleButtonWidgetClass
, outBox
,
439 XmNlabelString
, s1
=MKSTRING("same document"),
441 XmNalignment
, XmALIGNMENT_BEGINNING
,
445 XtAddCallback(ucd
->sameOutBtn
, XmNvalueChangedCallback
, sameOutCB
, ucd
);
446 ucd
->dlogOutBtn
= XtVaCreateManagedWidget("dlogOutBtn",
447 xmToggleButtonWidgetClass
, outBox
,
448 XmNlabelString
, s1
=MKSTRING("dialog"),
450 XmNalignment
, XmALIGNMENT_BEGINNING
,
452 XmNset
, False
, NULL
);
454 ucd
->winOutBtn
= XtVaCreateManagedWidget("winOutBtn", xmToggleButtonWidgetClass
,
456 XmNlabelString
, s1
=MKSTRING("new document"),
458 XmNalignment
, XmALIGNMENT_BEGINNING
,
460 XmNset
, False
, NULL
);
462 outLabel
= XtVaCreateManagedWidget("outLabel", xmLabelGadgetClass
, form
,
463 XmNlabelString
, s1
=MKSTRING("Command Output (stdout/stderr):"),
464 XmNalignment
, XmALIGNMENT_BEGINNING
,
466 XmNleftAttachment
, XmATTACH_POSITION
,
467 XmNleftPosition
, LIST_RIGHT
,
468 XmNrightAttachment
, XmATTACH_POSITION
,
469 XmNrightPosition
, RIGHT_MARGIN_POS
,
470 XmNbottomAttachment
, XmATTACH_WIDGET
,
471 XmNbottomWidget
, outBox
, NULL
);
474 inpBox
= XtVaCreateManagedWidget("inpBox", xmRowColumnWidgetClass
, form
,
475 XmNpacking
, XmPACK_TIGHT
,
476 XmNorientation
, XmHORIZONTAL
,
477 XmNradioBehavior
, True
,
478 XmNradioAlwaysOne
, True
,
479 XmNleftAttachment
, XmATTACH_POSITION
,
480 XmNleftPosition
, LIST_RIGHT
+ 2,
481 XmNrightAttachment
, XmATTACH_POSITION
,
482 XmNrightPosition
, RIGHT_MARGIN_POS
,
483 XmNbottomAttachment
, XmATTACH_WIDGET
,
484 XmNbottomWidget
, outLabel
, NULL
);
485 ucd
->selInpBtn
= XtVaCreateManagedWidget("selInpBtn", xmToggleButtonWidgetClass
,
487 XmNlabelString
, s1
=MKSTRING("selection"),
489 XmNalignment
, XmALIGNMENT_BEGINNING
,
493 ucd
->winInpBtn
= XtVaCreateManagedWidget("winInpBtn",
494 xmToggleButtonWidgetClass
, inpBox
,
495 XmNlabelString
, s1
=MKSTRING("document"),
497 XmNalignment
, XmALIGNMENT_BEGINNING
,
499 XmNset
, False
, NULL
);
501 ucd
->eitherInpBtn
= XtVaCreateManagedWidget("eitherInpBtn",
502 xmToggleButtonWidgetClass
, inpBox
,
503 XmNlabelString
, s1
=MKSTRING("either"),
505 XmNalignment
, XmALIGNMENT_BEGINNING
,
507 XmNset
, False
, NULL
);
509 ucd
->noInpBtn
= XtVaCreateManagedWidget("noInpBtn",
510 xmToggleButtonWidgetClass
, inpBox
,
511 XmNlabelString
, s1
=MKSTRING("none"),
513 XmNalignment
, XmALIGNMENT_BEGINNING
,
515 XmNset
, False
, NULL
);
517 inpLabel
= XtVaCreateManagedWidget("inpLabel", xmLabelGadgetClass
, form
,
518 XmNlabelString
, s1
=MKSTRING("Command Input (stdin):"),
519 XmNalignment
, XmALIGNMENT_BEGINNING
,
521 XmNleftAttachment
, XmATTACH_POSITION
,
522 XmNleftPosition
, LIST_RIGHT
,
523 XmNrightAttachment
, XmATTACH_POSITION
,
524 XmNrightPosition
, RIGHT_MARGIN_POS
,
525 XmNbottomAttachment
, XmATTACH_WIDGET
,
526 XmNbottomWidget
, inpBox
, NULL
);
529 ucd
->mneTextW
= XtVaCreateManagedWidget("mne", xmTextWidgetClass
, form
,
532 XmNleftAttachment
, XmATTACH_POSITION
,
533 XmNleftPosition
, RIGHT_MARGIN_POS
-10,
534 XmNrightAttachment
, XmATTACH_POSITION
,
535 XmNrightPosition
, RIGHT_MARGIN_POS
,
536 XmNbottomAttachment
, XmATTACH_WIDGET
,
537 XmNbottomWidget
, inpLabel
, NULL
);
538 RemapDeleteKey(ucd
->mneTextW
);
540 ucd
->accTextW
= XtVaCreateManagedWidget("acc", xmTextWidgetClass
, form
,
542 XmNmaxLength
, MAX_ACCEL_LEN
-1,
543 XmNcursorPositionVisible
, False
,
544 XmNleftAttachment
, XmATTACH_POSITION
,
545 XmNleftPosition
, LIST_RIGHT
,
546 XmNrightAttachment
, XmATTACH_POSITION
,
547 XmNrightPosition
, RIGHT_MARGIN_POS
-15,
548 XmNbottomAttachment
, XmATTACH_WIDGET
,
549 XmNbottomWidget
, inpLabel
, NULL
);
550 XtAddEventHandler(ucd
->accTextW
, KeyPressMask
, False
,
551 (XtEventHandler
)accKeyCB
, ucd
);
552 XtAddCallback(ucd
->accTextW
, XmNfocusCallback
, accFocusCB
, ucd
);
553 XtAddCallback(ucd
->accTextW
, XmNlosingFocusCallback
, accLoseFocusCB
, ucd
);
554 accLabel
= XtVaCreateManagedWidget("accLabel", xmLabelGadgetClass
, form
,
555 XmNlabelString
, s1
=MKSTRING("Accelerator"),
557 XmNuserData
, ucd
->accTextW
,
558 XmNalignment
, XmALIGNMENT_BEGINNING
,
560 XmNleftAttachment
, XmATTACH_POSITION
,
561 XmNleftPosition
, LIST_RIGHT
,
562 XmNrightAttachment
, XmATTACH_POSITION
,
563 XmNrightPosition
, LIST_RIGHT
+ 24,
564 XmNbottomAttachment
, XmATTACH_WIDGET
,
565 XmNbottomWidget
, ucd
->mneTextW
, NULL
);
568 XtVaCreateManagedWidget("mneLabel", xmLabelGadgetClass
, form
,
569 XmNlabelString
, s1
=MKSTRING("Mnemonic"),
571 XmNuserData
, ucd
->mneTextW
,
572 XmNalignment
, XmALIGNMENT_END
,
574 XmNleftAttachment
, XmATTACH_POSITION
,
575 XmNleftPosition
, LIST_RIGHT
+ 24,
576 XmNrightAttachment
, XmATTACH_POSITION
,
577 XmNrightPosition
, RIGHT_MARGIN_POS
,
578 XmNbottomAttachment
, XmATTACH_WIDGET
,
579 XmNbottomWidget
, ucd
->mneTextW
, NULL
);
582 ucd
->nameTextW
= XtVaCreateManagedWidget("name", xmTextWidgetClass
, form
,
583 XmNleftAttachment
, XmATTACH_POSITION
,
584 XmNleftPosition
, LIST_RIGHT
,
585 XmNrightAttachment
, XmATTACH_POSITION
,
586 XmNrightPosition
, RIGHT_MARGIN_POS
,
587 XmNbottomAttachment
, XmATTACH_WIDGET
,
588 XmNbottomWidget
, accLabel
, NULL
);
589 RemapDeleteKey(ucd
->nameTextW
);
591 nameLabel
= XtVaCreateManagedWidget("nameLabel", xmLabelGadgetClass
, form
,
592 XmNlabelString
, s1
=MKSTRING("Menu Entry"),
594 XmNuserData
, ucd
->nameTextW
,
595 XmNalignment
, XmALIGNMENT_BEGINNING
,
597 XmNleftAttachment
, XmATTACH_POSITION
,
598 XmNleftPosition
, LIST_RIGHT
,
599 XmNbottomAttachment
, XmATTACH_WIDGET
,
600 XmNbottomWidget
, ucd
->nameTextW
, NULL
);
603 XtVaCreateManagedWidget("nameNotes", xmLabelGadgetClass
, form
,
604 XmNlabelString
, s1
=MKSTRING("(> for sub-menu, @ language mode)"),
605 XmNalignment
, XmALIGNMENT_END
,
607 XmNleftAttachment
, XmATTACH_WIDGET
,
608 XmNleftWidget
, nameLabel
,
609 XmNrightAttachment
, XmATTACH_POSITION
,
610 XmNrightPosition
, RIGHT_MARGIN_POS
,
611 XmNbottomAttachment
, XmATTACH_WIDGET
,
612 XmNbottomWidget
, ucd
->nameTextW
, NULL
);
615 XtVaCreateManagedWidget("topLabel", xmLabelGadgetClass
, form
,
616 XmNlabelString
, s1
=MKSTRING(
617 "Select a shell menu item from the list at left.\n\
618 Select \"New\" to add a new command to the menu."),
619 XmNtopAttachment
, XmATTACH_POSITION
,
621 XmNleftAttachment
, XmATTACH_POSITION
,
622 XmNleftPosition
, LIST_RIGHT
,
623 XmNrightAttachment
, XmATTACH_POSITION
,
624 XmNrightPosition
, RIGHT_MARGIN_POS
,
625 XmNbottomAttachment
, XmATTACH_WIDGET
,
626 XmNbottomWidget
, nameLabel
, NULL
);
629 cmdLabel
= XtVaCreateManagedWidget("cmdLabel", xmLabelGadgetClass
, form
,
630 XmNlabelString
, s1
=MKSTRING("Shell Command to Execute"),
632 XmNalignment
, XmALIGNMENT_BEGINNING
,
634 XmNtopAttachment
, XmATTACH_POSITION
,
635 XmNtopPosition
, SHELL_CMD_TOP
,
636 XmNleftAttachment
, XmATTACH_POSITION
,
637 XmNleftPosition
, LEFT_MARGIN_POS
, NULL
);
639 XtVaCreateManagedWidget("cmdLabel", xmLabelGadgetClass
, form
,
640 XmNlabelString
, s1
=MKSTRING("(% expands to current filename, # to line number)"),
641 XmNalignment
, XmALIGNMENT_END
,
643 XmNtopAttachment
, XmATTACH_POSITION
,
644 XmNtopPosition
, SHELL_CMD_TOP
,
645 XmNleftAttachment
, XmATTACH_WIDGET
,
646 XmNleftWidget
, cmdLabel
,
647 XmNrightAttachment
, XmATTACH_POSITION
,
648 XmNrightPosition
, RIGHT_MARGIN_POS
, NULL
);
651 okBtn
= XtVaCreateManagedWidget("ok",xmPushButtonWidgetClass
,form
,
652 XmNlabelString
, s1
=MKSTRING("OK"),
653 XmNmarginWidth
, BUTTON_WIDTH_MARGIN
,
654 XmNleftAttachment
, XmATTACH_POSITION
,
656 XmNrightAttachment
, XmATTACH_POSITION
,
657 XmNrightPosition
, 29,
658 XmNbottomAttachment
, XmATTACH_POSITION
,
659 XmNbottomPosition
, 99, NULL
);
660 XtAddCallback(okBtn
, XmNactivateCallback
, okCB
, ucd
);
663 applyBtn
= XtVaCreateManagedWidget("apply",xmPushButtonWidgetClass
,form
,
664 XmNlabelString
, s1
=MKSTRING("Apply"),
666 XmNleftAttachment
, XmATTACH_POSITION
,
668 XmNrightAttachment
, XmATTACH_POSITION
,
669 XmNrightPosition
, 58,
670 XmNbottomAttachment
, XmATTACH_POSITION
,
671 XmNbottomPosition
, 99, NULL
);
672 XtAddCallback(applyBtn
, XmNactivateCallback
, applyCB
, ucd
);
675 closeBtn
= XtVaCreateManagedWidget("close",
676 xmPushButtonWidgetClass
, form
,
677 XmNlabelString
, s1
=MKSTRING("Close"),
678 XmNleftAttachment
, XmATTACH_POSITION
,
680 XmNrightAttachment
, XmATTACH_POSITION
,
681 XmNrightPosition
, 87,
682 XmNbottomAttachment
, XmATTACH_POSITION
,
683 XmNbottomPosition
, 99,
685 XtAddCallback(closeBtn
, XmNactivateCallback
, closeCB
, ucd
);
689 XtSetArg(args
[ac
], XmNeditMode
, XmMULTI_LINE_EDIT
); ac
++;
690 XtSetArg(args
[ac
], XmNscrollHorizontal
, False
); ac
++;
691 XtSetArg(args
[ac
], XmNwordWrap
, True
); ac
++;
692 XtSetArg(args
[ac
], XmNtopAttachment
, XmATTACH_WIDGET
); ac
++;
693 XtSetArg(args
[ac
], XmNtopWidget
, cmdLabel
); ac
++;
694 XtSetArg(args
[ac
], XmNleftAttachment
, XmATTACH_POSITION
); ac
++;
695 XtSetArg(args
[ac
], XmNleftPosition
, LEFT_MARGIN_POS
); ac
++;
696 XtSetArg(args
[ac
], XmNrightAttachment
, XmATTACH_POSITION
); ac
++;
697 XtSetArg(args
[ac
], XmNrightPosition
, RIGHT_MARGIN_POS
); ac
++;
698 XtSetArg(args
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
699 XtSetArg(args
[ac
], XmNbottomWidget
, okBtn
); ac
++;
700 XtSetArg(args
[ac
], XmNbottomOffset
, 5); ac
++;
701 ucd
->cmdTextW
= XmCreateScrolledText(form
, "name", args
, ac
);
702 AddMouseWheelSupport(ucd
->cmdTextW
);
703 XtManageChild(ucd
->cmdTextW
);
704 MakeSingleLineTextW(ucd
->cmdTextW
);
705 RemapDeleteKey(ucd
->cmdTextW
);
706 XtVaSetValues(cmdLabel
, XmNuserData
, ucd
->cmdTextW
, NULL
); /* for mnemonic */
708 /* Disable text input for the accelerator key widget, let the
709 event handler manage it instead */
710 disableTextW(ucd
->accTextW
);
712 /* initializs the dialog fields to match "New" list item */
713 updateDialogFields(NULL
, ucd
);
715 /* Set initial default button */
716 XtVaSetValues(form
, XmNdefaultButton
, okBtn
, NULL
);
717 XtVaSetValues(form
, XmNcancelButton
, closeBtn
, NULL
);
719 /* Handle mnemonic selection of buttons and focus to dialog */
720 AddDialogMnemonicHandler(form
, FALSE
);
722 /* realize all of the widgets in the new window */
723 RealizeWithoutForcingPosition(ucd
->dlogShell
);
727 ** Present a dialogs for editing the user specified commands in the Macro
728 ** and background menus
730 void EditMacroMenu(WindowInfo
*window
)
732 editMacroOrBGMenu(window
, MACRO_CMDS
);
734 void EditBGMenu(WindowInfo
*window
)
736 editMacroOrBGMenu(window
, BG_MENU_CMDS
);
739 static void editMacroOrBGMenu(WindowInfo
*window
, int dialogType
)
741 Widget form
, accLabel
, pasteReplayBtn
;
742 Widget nameLabel
, cmdLabel
, okBtn
, applyBtn
, closeBtn
;
749 /* if the dialog is already displayed, just pop it to the top and return */
750 if (dialogType
== MACRO_CMDS
&& MacroCmdDialog
!= NULL
) {
751 RaiseDialogWindow(MacroCmdDialog
);
754 if (dialogType
== BG_MENU_CMDS
&& BGMenuCmdDialog
!= NULL
) {
755 RaiseDialogWindow(BGMenuCmdDialog
);
759 /* Create a structure for keeping track of dialog state */
760 ucd
= (userCmdDialog
*)XtMalloc(sizeof(userCmdDialog
));
761 ucd
->window
= window
;
763 /* Set the dialog to operate on the Macro menu */
764 ucd
->menuItemsList
= (menuItemRec
**)XtMalloc(sizeof(menuItemRec
**) *
766 if (dialogType
== MACRO_CMDS
) {
767 for (i
=0; i
<NMacroMenuItems
; i
++)
768 ucd
->menuItemsList
[i
] = copyMenuItemRec(MacroMenuItems
[i
]);
769 ucd
->nMenuItems
= NMacroMenuItems
;
770 } else { /* BG_MENU_CMDS */
771 for (i
=0; i
<NBGMenuItems
; i
++)
772 ucd
->menuItemsList
[i
] = copyMenuItemRec(BGMenuItems
[i
]);
773 ucd
->nMenuItems
= NBGMenuItems
;
775 ucd
->dialogType
= dialogType
;
777 title
= dialogType
== MACRO_CMDS
? "Macro Commands" :
778 "Window Background Menu";
780 XtSetArg(args
[ac
], XmNdeleteResponse
, XmDO_NOTHING
); ac
++;
781 XtSetArg(args
[ac
], XmNiconName
, title
); ac
++;
782 XtSetArg(args
[ac
], XmNtitle
, title
); ac
++;
783 ucd
->dlogShell
= CreateWidget(TheAppShell
, "macros",
784 topLevelShellWidgetClass
, args
, ac
);
785 AddSmallIcon(ucd
->dlogShell
);
786 form
= XtVaCreateManagedWidget("editMacroCommands", xmFormWidgetClass
,
787 ucd
->dlogShell
, XmNautoUnmanage
, False
,
788 XmNresizePolicy
, XmRESIZE_NONE
, NULL
);
789 XtAddCallback(form
, XmNdestroyCallback
, destroyCB
, ucd
);
790 AddMotifCloseCallback(ucd
->dlogShell
, closeCB
, ucd
);
793 XtSetArg(args
[ac
], XmNtopAttachment
, XmATTACH_POSITION
); ac
++;
794 XtSetArg(args
[ac
], XmNtopPosition
, 2); ac
++;
795 XtSetArg(args
[ac
], XmNleftAttachment
, XmATTACH_POSITION
); ac
++;
796 XtSetArg(args
[ac
], XmNleftPosition
, LEFT_MARGIN_POS
); ac
++;
797 XtSetArg(args
[ac
], XmNrightAttachment
, XmATTACH_POSITION
); ac
++;
798 XtSetArg(args
[ac
], XmNrightPosition
, LIST_RIGHT
-1); ac
++;
799 XtSetArg(args
[ac
], XmNbottomAttachment
, XmATTACH_POSITION
); ac
++;
800 XtSetArg(args
[ac
], XmNbottomPosition
, MACRO_CMD_TOP
); ac
++;
801 ucd
->managedList
= CreateManagedList(form
, "list", args
, ac
,
802 (void **)ucd
->menuItemsList
, &ucd
->nMenuItems
, MAX_ITEMS_PER_MENU
, 20,
803 getDialogDataCB
, ucd
, setDialogDataCB
, ucd
, freeItemCB
);
805 ucd
->selInpBtn
= XtVaCreateManagedWidget("selInpBtn",
806 xmToggleButtonWidgetClass
, form
,
807 XmNlabelString
, s1
=MKSTRING("Requires Selection"),
809 XmNalignment
, XmALIGNMENT_BEGINNING
,
812 XmNleftAttachment
, XmATTACH_POSITION
,
813 XmNleftPosition
, LIST_RIGHT
,
814 XmNbottomAttachment
, XmATTACH_POSITION
,
815 XmNbottomPosition
, MACRO_CMD_TOP
, NULL
);
818 ucd
->mneTextW
= XtVaCreateManagedWidget("mne", xmTextWidgetClass
, form
,
821 XmNleftAttachment
, XmATTACH_POSITION
,
822 XmNleftPosition
, RIGHT_MARGIN_POS
-21-5,
823 XmNrightAttachment
, XmATTACH_POSITION
,
824 XmNrightPosition
, RIGHT_MARGIN_POS
-21,
825 XmNbottomAttachment
, XmATTACH_WIDGET
,
826 XmNbottomWidget
, ucd
->selInpBtn
,
827 XmNbottomOffset
, 5, NULL
);
828 RemapDeleteKey(ucd
->mneTextW
);
830 ucd
->accTextW
= XtVaCreateManagedWidget("acc", xmTextWidgetClass
, form
,
832 XmNmaxLength
, MAX_ACCEL_LEN
-1,
833 XmNcursorPositionVisible
, False
,
834 XmNleftAttachment
, XmATTACH_POSITION
,
835 XmNleftPosition
, LIST_RIGHT
,
836 XmNrightAttachment
, XmATTACH_POSITION
,
837 XmNrightPosition
, RIGHT_MARGIN_POS
-20-10,
838 XmNbottomAttachment
, XmATTACH_WIDGET
,
839 XmNbottomWidget
, ucd
->selInpBtn
,
840 XmNbottomOffset
, 5, NULL
);
841 XtAddEventHandler(ucd
->accTextW
, KeyPressMask
, False
,
842 (XtEventHandler
)accKeyCB
, ucd
);
843 XtAddCallback(ucd
->accTextW
, XmNfocusCallback
, accFocusCB
, ucd
);
844 XtAddCallback(ucd
->accTextW
, XmNlosingFocusCallback
, accLoseFocusCB
, ucd
);
846 accLabel
= XtVaCreateManagedWidget("accLabel", xmLabelGadgetClass
, form
,
847 XmNlabelString
, s1
=MKSTRING("Accelerator"),
849 XmNuserData
, ucd
->accTextW
,
850 XmNalignment
, XmALIGNMENT_BEGINNING
,
852 XmNleftAttachment
, XmATTACH_POSITION
,
853 XmNleftPosition
, LIST_RIGHT
,
854 XmNrightAttachment
, XmATTACH_POSITION
,
855 XmNrightPosition
, LIST_RIGHT
+ 22,
856 XmNbottomAttachment
, XmATTACH_WIDGET
,
857 XmNbottomWidget
, ucd
->mneTextW
, NULL
);
860 XtVaCreateManagedWidget("mneLabel", xmLabelGadgetClass
, form
,
861 XmNlabelString
, s1
=MKSTRING("Mnemonic"),
863 XmNuserData
, ucd
->mneTextW
,
864 XmNalignment
, XmALIGNMENT_END
,
866 XmNleftAttachment
, XmATTACH_POSITION
,
867 XmNleftPosition
, LIST_RIGHT
+ 22,
868 XmNrightAttachment
, XmATTACH_POSITION
,
869 XmNrightPosition
, RIGHT_MARGIN_POS
-21,
870 XmNbottomAttachment
, XmATTACH_WIDGET
,
871 XmNbottomWidget
, ucd
->mneTextW
, NULL
);
874 pasteReplayBtn
= XtVaCreateManagedWidget("pasteReplay",
875 xmPushButtonWidgetClass
, form
,
876 XmNlabelString
, s1
=MKSTRING("Paste Learn/\nReplay Macro"),
878 XmNsensitive
, GetReplayMacro() != NULL
,
879 XmNleftAttachment
, XmATTACH_POSITION
,
880 XmNleftPosition
, RIGHT_MARGIN_POS
-20,
881 XmNrightAttachment
, XmATTACH_POSITION
,
882 XmNrightPosition
, RIGHT_MARGIN_POS
,
883 XmNbottomAttachment
, XmATTACH_POSITION
,
884 XmNbottomPosition
, MACRO_CMD_TOP
, NULL
);
885 XtAddCallback(pasteReplayBtn
, XmNactivateCallback
,
889 ucd
->nameTextW
= XtVaCreateManagedWidget("name", xmTextWidgetClass
, form
,
890 XmNleftAttachment
, XmATTACH_POSITION
,
891 XmNleftPosition
, LIST_RIGHT
,
892 XmNrightAttachment
, XmATTACH_POSITION
,
893 XmNrightPosition
, RIGHT_MARGIN_POS
,
894 XmNbottomAttachment
, XmATTACH_WIDGET
,
895 XmNbottomWidget
, accLabel
, NULL
);
896 RemapDeleteKey(ucd
->nameTextW
);
898 nameLabel
= XtVaCreateManagedWidget("nameLabel", xmLabelGadgetClass
, form
,
899 XmNlabelString
, s1
=MKSTRING("Menu Entry"),
901 XmNuserData
, ucd
->nameTextW
,
902 XmNalignment
, XmALIGNMENT_BEGINNING
,
904 XmNleftAttachment
, XmATTACH_POSITION
,
905 XmNleftPosition
, LIST_RIGHT
,
906 XmNbottomAttachment
, XmATTACH_WIDGET
,
907 XmNbottomWidget
, ucd
->nameTextW
, NULL
);
910 XtVaCreateManagedWidget("nameNotes", xmLabelGadgetClass
, form
,
911 XmNlabelString
, s1
=MKSTRING("(> for sub-menu, @ language mode)"),
912 XmNalignment
, XmALIGNMENT_END
,
914 XmNleftAttachment
, XmATTACH_WIDGET
,
915 XmNleftWidget
, nameLabel
,
916 XmNrightAttachment
, XmATTACH_POSITION
,
917 XmNrightPosition
, RIGHT_MARGIN_POS
,
918 XmNbottomAttachment
, XmATTACH_WIDGET
,
919 XmNbottomWidget
, ucd
->nameTextW
, NULL
);
922 XtVaCreateManagedWidget("topLabel", xmLabelGadgetClass
, form
,
923 XmNlabelString
, s1
=MKSTRING(
924 "Select a macro menu item from the list at left.\n\
925 Select \"New\" to add a new command to the menu."),
926 XmNtopAttachment
, XmATTACH_POSITION
,
928 XmNleftAttachment
, XmATTACH_POSITION
,
929 XmNleftPosition
, LIST_RIGHT
,
930 XmNrightAttachment
, XmATTACH_POSITION
,
931 XmNrightPosition
, RIGHT_MARGIN_POS
,
932 XmNbottomAttachment
, XmATTACH_WIDGET
,
933 XmNbottomWidget
, nameLabel
, NULL
);
936 cmdLabel
= XtVaCreateManagedWidget("cmdLabel", xmLabelGadgetClass
, form
,
937 XmNlabelString
, s1
=MKSTRING("Macro Command to Execute"),
939 XmNalignment
, XmALIGNMENT_BEGINNING
,
941 XmNtopAttachment
, XmATTACH_POSITION
,
942 XmNtopPosition
, MACRO_CMD_TOP
,
943 XmNleftAttachment
, XmATTACH_POSITION
,
944 XmNleftPosition
, LEFT_MARGIN_POS
, NULL
);
947 okBtn
= XtVaCreateManagedWidget("ok",xmPushButtonWidgetClass
,form
,
948 XmNlabelString
, s1
=MKSTRING("OK"),
949 XmNmarginWidth
, BUTTON_WIDTH_MARGIN
,
950 XmNleftAttachment
, XmATTACH_POSITION
,
952 XmNrightAttachment
, XmATTACH_POSITION
,
953 XmNrightPosition
, 23,
954 XmNbottomAttachment
, XmATTACH_POSITION
,
955 XmNbottomPosition
, 99, NULL
);
956 XtAddCallback(okBtn
, XmNactivateCallback
, okCB
, ucd
);
959 applyBtn
= XtVaCreateManagedWidget("apply",xmPushButtonWidgetClass
,form
,
960 XmNlabelString
, s1
=MKSTRING("Apply"),
962 XmNleftAttachment
, XmATTACH_POSITION
,
964 XmNrightAttachment
, XmATTACH_POSITION
,
965 XmNrightPosition
, 46,
966 XmNbottomAttachment
, XmATTACH_POSITION
,
967 XmNbottomPosition
, 99, NULL
);
968 XtAddCallback(applyBtn
, XmNactivateCallback
, applyCB
, ucd
);
971 applyBtn
= XtVaCreateManagedWidget("check",xmPushButtonWidgetClass
,form
,
972 XmNlabelString
, s1
=MKSTRING("Check"),
974 XmNleftAttachment
, XmATTACH_POSITION
,
976 XmNrightAttachment
, XmATTACH_POSITION
,
977 XmNrightPosition
, 69,
978 XmNbottomAttachment
, XmATTACH_POSITION
,
979 XmNbottomPosition
, 99, NULL
);
980 XtAddCallback(applyBtn
, XmNactivateCallback
, checkCB
, ucd
);
983 closeBtn
= XtVaCreateManagedWidget("close",
984 xmPushButtonWidgetClass
, form
,
985 XmNlabelString
, s1
=MKSTRING("Close"),
986 XmNleftAttachment
, XmATTACH_POSITION
,
988 XmNrightAttachment
, XmATTACH_POSITION
,
989 XmNrightPosition
, 92,
990 XmNbottomAttachment
, XmATTACH_POSITION
,
991 XmNbottomPosition
, 99,
993 XtAddCallback(closeBtn
, XmNactivateCallback
, closeCB
, ucd
);
997 XtSetArg(args
[ac
], XmNeditMode
, XmMULTI_LINE_EDIT
); ac
++;
998 XtSetArg(args
[ac
], XmNtopAttachment
, XmATTACH_WIDGET
); ac
++;
999 XtSetArg(args
[ac
], XmNtopWidget
, cmdLabel
); ac
++;
1000 XtSetArg(args
[ac
], XmNleftAttachment
, XmATTACH_POSITION
); ac
++;
1001 XtSetArg(args
[ac
], XmNleftPosition
, LEFT_MARGIN_POS
); ac
++;
1002 XtSetArg(args
[ac
], XmNrightAttachment
, XmATTACH_POSITION
); ac
++;
1003 XtSetArg(args
[ac
], XmNrightPosition
, RIGHT_MARGIN_POS
); ac
++;
1004 XtSetArg(args
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
1005 XtSetArg(args
[ac
], XmNbottomWidget
, okBtn
); ac
++;
1006 XtSetArg(args
[ac
], XmNbottomOffset
, 5); ac
++;
1007 ucd
->cmdTextW
= XmCreateScrolledText(form
, "name", args
, ac
);
1008 AddMouseWheelSupport(ucd
->cmdTextW
);
1009 XtManageChild(ucd
->cmdTextW
);
1010 RemapDeleteKey(ucd
->cmdTextW
);
1011 XtVaSetValues(cmdLabel
, XmNuserData
, ucd
->cmdTextW
, NULL
); /* for mnemonic */
1013 /* Disable text input for the accelerator key widget, let the
1014 event handler manage it instead */
1015 disableTextW(ucd
->accTextW
);
1017 /* initializs the dialog fields to match "New" list item */
1018 updateDialogFields(NULL
, ucd
);
1020 /* Set initial default button */
1021 XtVaSetValues(form
, XmNdefaultButton
, okBtn
, NULL
);
1022 XtVaSetValues(form
, XmNcancelButton
, closeBtn
, NULL
);
1024 /* Handle mnemonic selection of buttons and focus to dialog */
1025 AddDialogMnemonicHandler(form
, FALSE
);
1027 /* Make widgets for top level shell and paste-replay buttons available
1028 to other functions */
1029 if (dialogType
== MACRO_CMDS
) {
1030 MacroCmdDialog
= ucd
->dlogShell
;
1031 MacroPasteReplayBtn
= pasteReplayBtn
;
1033 BGMenuCmdDialog
= ucd
->dlogShell
;
1034 BGMenuPasteReplayBtn
= pasteReplayBtn
;
1037 /* Realize all of the widgets in the new dialog */
1038 RealizeWithoutForcingPosition(ucd
->dlogShell
);
1042 ** Update the Shell, Macro, and Window Background menus of window
1043 ** "window" from the currently loaded command descriptions.
1045 void UpdateUserMenus(WindowInfo
*window
)
1047 if (!IsTopDocument(window
))
1050 /* update user menus, which are shared over all documents, only
1051 if language mode was changed */
1052 if (window
->userMenuCache
->umcLanguageMode
!= window
->languageMode
) {
1054 updateMenu(window
, SHELL_CMDS
);
1056 updateMenu(window
, MACRO_CMDS
);
1058 /* remember language mode assigned to shared user menus */
1059 window
->userMenuCache
->umcLanguageMode
= window
->languageMode
;
1062 /* update background menu, which is owned by a single document, only
1063 if language mode was changed */
1064 if (window
->userBGMenuCache
.ubmcLanguageMode
!= window
->languageMode
) {
1065 updateMenu(window
, BG_MENU_CMDS
);
1067 /* remember language mode assigned to background menu */
1068 window
->userBGMenuCache
.ubmcLanguageMode
= window
->languageMode
;
1073 ** Dim/undim buttons for pasting replay macros into macro and bg menu dialogs
1075 void DimPasteReplayBtns(int sensitive
)
1077 if (MacroCmdDialog
!= NULL
)
1078 XtSetSensitive(MacroPasteReplayBtn
, sensitive
);
1079 if (BGMenuCmdDialog
!= NULL
)
1080 XtSetSensitive(BGMenuPasteReplayBtn
, sensitive
);
1084 ** Dim/undim user programmable menu items which depend on there being
1085 ** a selection in their associated window.
1087 void DimSelectionDepUserMenuItems(WindowInfo
*window
, int sensitive
)
1089 if (!IsTopDocument(window
))
1093 dimSelDepItemsInMenu(window
->shellMenuPane
, ShellMenuItems
,
1094 NShellMenuItems
, sensitive
);
1096 dimSelDepItemsInMenu(window
->macroMenuPane
, MacroMenuItems
,
1097 NMacroMenuItems
, sensitive
);
1098 dimSelDepItemsInMenu(window
->bgMenuPane
, BGMenuItems
,
1099 NBGMenuItems
, sensitive
);
1102 static void dimSelDepItemsInMenu(Widget menuPane
, menuItemRec
**menuList
,
1103 int nMenuItems
, int sensitive
)
1111 XtVaGetValues(menuPane
, XmNchildren
, &items
, XmNnumChildren
, &nItems
, NULL
);
1112 for (n
=0; n
<(int)nItems
; n
++) {
1113 XtVaGetValues(items
[n
], XmNuserData
, &userData
, NULL
);
1114 if (userData
!= (XtPointer
)PERMANENT_MENU_ITEM
) {
1115 if (XtClass(items
[n
]) == xmCascadeButtonWidgetClass
) {
1116 XtVaGetValues(items
[n
], XmNsubMenuId
, &subMenu
, NULL
);
1117 dimSelDepItemsInMenu(subMenu
, menuList
, nMenuItems
, sensitive
);
1119 index
= (int)userData
- 10;
1120 if (index
<0 || index
>= nMenuItems
)
1122 if (menuList
[index
]->input
== FROM_SELECTION
)
1123 XtSetSensitive(items
[n
], sensitive
);
1130 ** Harmless kludge for making undo/redo menu items in background menu properly
1131 ** sensitive (even though they're programmable) along with real undo item
1134 void SetBGMenuUndoSensitivity(WindowInfo
*window
, int sensitive
)
1136 if (window
->bgMenuUndoItem
!= NULL
)
1137 SetSensitive(window
, window
->bgMenuUndoItem
, sensitive
);
1139 void SetBGMenuRedoSensitivity(WindowInfo
*window
, int sensitive
)
1141 if (window
->bgMenuRedoItem
!= NULL
)
1142 SetSensitive(window
, window
->bgMenuRedoItem
, sensitive
);
1146 ** Generate a text string for the preferences file describing the contents
1147 ** of the shell cmd list. This string is not exactly of the form that it
1148 ** can be read by LoadShellCmdsString, rather, it is what needs to be written
1149 ** to a resource file such that it will read back in that form.
1151 char *WriteShellCmdsString(void)
1153 return writeMenuItemString(ShellMenuItems
, NShellMenuItems
,
1158 ** Generate a text string for the preferences file describing the contents of
1159 ** the macro menu and background menu commands lists. These strings are not
1160 ** exactly of the form that it can be read by LoadMacroCmdsString, rather, it
1161 ** is what needs to be written to a resource file such that it will read back
1164 char *WriteMacroCmdsString(void)
1166 return writeMenuItemString(MacroMenuItems
, NMacroMenuItems
, MACRO_CMDS
);
1169 char *WriteBGMenuCmdsString(void)
1171 return writeMenuItemString(BGMenuItems
, NBGMenuItems
, BG_MENU_CMDS
);
1175 ** Read a string representing shell command menu items and add them to the
1176 ** internal list used for constructing shell menus
1178 int LoadShellCmdsString(char *inString
)
1180 return loadMenuItemString(inString
, ShellMenuItems
, &NShellMenuItems
,
1185 ** Read strings representing macro menu or background menu command menu items
1186 ** and add them to the internal lists used for constructing menus
1188 int LoadMacroCmdsString(char *inString
)
1190 return loadMenuItemString(inString
, MacroMenuItems
, &NMacroMenuItems
,
1194 int LoadBGMenuCmdsString(char *inString
)
1196 return loadMenuItemString(inString
, BGMenuItems
, &NBGMenuItems
,
1201 ** Cache user menus:
1202 ** Setup user menu info after read of macro, shell and background menu
1203 ** string (reason: language mode info from preference string is read *after*
1204 ** user menu preference string was read).
1206 void SetupUserMenuInfo(void)
1208 parseMenuItemList(ShellMenuItems
, NShellMenuItems
, ShellMenuInfo
, &ShellSubMenus
);
1209 parseMenuItemList(MacroMenuItems
, NMacroMenuItems
, MacroMenuInfo
, &MacroSubMenus
);
1210 parseMenuItemList(BGMenuItems
, NBGMenuItems
, BGMenuInfo
, &BGSubMenus
);
1214 ** Cache user menus:
1215 ** Update user menu info to take into account e.g. change of language modes
1216 ** (i.e. add / move / delete of language modes etc).
1218 void UpdateUserMenuInfo(void)
1220 freeUserMenuInfoList(ShellMenuInfo
, NShellMenuItems
);
1221 freeSubMenuCache(&ShellSubMenus
);
1222 parseMenuItemList(ShellMenuItems
, NShellMenuItems
, ShellMenuInfo
, &ShellSubMenus
);
1224 freeUserMenuInfoList(MacroMenuInfo
, NMacroMenuItems
);
1225 freeSubMenuCache(&MacroSubMenus
);
1226 parseMenuItemList(MacroMenuItems
, NMacroMenuItems
, MacroMenuInfo
, &MacroSubMenus
);
1228 freeUserMenuInfoList(BGMenuInfo
, NBGMenuItems
);
1229 freeSubMenuCache(&BGSubMenus
);
1230 parseMenuItemList(BGMenuItems
, NBGMenuItems
, BGMenuInfo
, &BGSubMenus
);
1234 ** Search through the shell menu and execute the first command with menu item
1235 ** name "itemName". Returns True on successs and False on failure.
1238 int DoNamedShellMenuCmd(WindowInfo
*window
, const char *itemName
, int fromMacro
)
1242 for (i
=0; i
<NShellMenuItems
; i
++) {
1243 if (!strcmp(ShellMenuItems
[i
]->name
, itemName
)) {
1244 if (ShellMenuItems
[i
]->output
== TO_SAME_WINDOW
&&
1245 CheckReadOnly(window
))
1247 DoShellMenuCmd(window
, ShellMenuItems
[i
]->cmd
,
1248 ShellMenuItems
[i
]->input
, ShellMenuItems
[i
]->output
,
1249 ShellMenuItems
[i
]->repInput
, ShellMenuItems
[i
]->saveFirst
,
1250 ShellMenuItems
[i
]->loadAfter
, fromMacro
);
1259 ** Search through the Macro or background menu and execute the first command
1260 ** with menu item name "itemName". Returns True on successs and False on
1263 int DoNamedMacroMenuCmd(WindowInfo
*window
, const char *itemName
)
1267 for (i
=0; i
<NMacroMenuItems
; i
++) {
1268 if (!strcmp(MacroMenuItems
[i
]->name
, itemName
)) {
1269 DoMacro(window
, MacroMenuItems
[i
]->cmd
, "macro menu command");
1276 int DoNamedBGMenuCmd(WindowInfo
*window
, const char *itemName
)
1280 for (i
=0; i
<NBGMenuItems
; i
++) {
1281 if (!strcmp(BGMenuItems
[i
]->name
, itemName
)) {
1282 DoMacro(window
, BGMenuItems
[i
]->cmd
, "background menu macro");
1290 ** Cache user menus:
1291 ** Rebuild all of the Shell, Macro, Background menus of given editor window.
1293 void RebuildAllMenus(WindowInfo
*window
)
1295 rebuildMenu(window
, SHELL_CMDS
);
1296 rebuildMenu(window
, MACRO_CMDS
);
1297 rebuildMenu(window
, BG_MENU_CMDS
);
1301 ** Cache user menus:
1302 ** Rebuild either Shell, Macro or Background menus of all editor windows.
1304 static void rebuildMenuOfAllWindows(int menuType
)
1308 for (w
=WindowList
; w
!=NULL
; w
=w
->next
)
1309 rebuildMenu(w
, menuType
);
1313 ** Rebuild either the Shell, Macro or Background menu of "window", depending
1314 ** on value of "menuType". Rebuild is realized by following main steps:
1315 ** - dismiss user (sub) menu tearoff.
1316 ** - delete all user defined menu widgets.
1317 ** - update user menu including (re)creation of menu widgets.
1319 static void rebuildMenu(WindowInfo
*window
, int menuType
)
1321 selectedUserMenu menu
;
1323 /* Background menu is always rebuild (exists once per document).
1324 Shell, macro (user) menu cache is rebuild only, if given window is
1325 currently displayed on top. */
1326 if (menuType
!= BG_MENU_CMDS
&& !IsTopDocument(window
))
1329 /* Fetch the appropriate menu data */
1330 selectUserMenu(window
, menuType
, &menu
);
1332 /* dismiss user menu tearoff, to workaround the quick
1333 but noticeable shrink-expand bug, most probably
1334 triggered by the rebuild of the user menus. In any
1335 case, the submenu tearoffs will later be dismissed
1336 too in order to prevent dangling tearoffs, so doing
1337 this also for the main user menu tearoffs shouldn't
1339 if (!XmIsMenuShell(XtParent(menu
.sumMenuPane
)))
1340 _XmDismissTearOff(XtParent(menu
.sumMenuPane
), NULL
, NULL
);
1342 /* destroy all widgets related to menu pane */
1343 deleteMenuItems(menu
.sumMenuPane
);
1345 /* remove cached user menu info */
1346 freeUserMenuList(menu
.sumMainMenuList
);
1347 *menu
.sumMenuCreated
= False
;
1349 /* re-create & cache user menu items */
1350 updateMenu(window
, menuType
);
1354 ** Fetch the appropriate menu info for given menu type
1356 static void selectUserMenu(WindowInfo
*window
, int menuType
, selectedUserMenu
*menu
)
1358 if (menuType
== SHELL_CMDS
) {
1359 menu
->sumMenuPane
= window
->shellMenuPane
;
1360 menu
->sumNbrOfListItems
= NShellMenuItems
;
1361 menu
->sumItemList
= ShellMenuItems
;
1362 menu
->sumInfoList
= ShellMenuInfo
;
1363 menu
->sumSubMenus
= &ShellSubMenus
;
1364 menu
->sumMainMenuList
= &window
->userMenuCache
->umcShellMenuList
;
1365 menu
->sumMenuCreated
= &window
->userMenuCache
->umcShellMenuCreated
;
1366 } else if (menuType
== MACRO_CMDS
) {
1367 menu
->sumMenuPane
= window
->macroMenuPane
;
1368 menu
->sumNbrOfListItems
= NMacroMenuItems
;
1369 menu
->sumItemList
= MacroMenuItems
;
1370 menu
->sumInfoList
= MacroMenuInfo
;
1371 menu
->sumSubMenus
= &MacroSubMenus
;
1372 menu
->sumMainMenuList
= &window
->userMenuCache
->umcMacroMenuList
;
1373 menu
->sumMenuCreated
= &window
->userMenuCache
->umcMacroMenuCreated
;
1374 } else { /* BG_MENU_CMDS */
1375 menu
->sumMenuPane
= window
->bgMenuPane
;
1376 menu
->sumNbrOfListItems
= NBGMenuItems
;
1377 menu
->sumItemList
= BGMenuItems
;
1378 menu
->sumInfoList
= BGMenuInfo
;
1379 menu
->sumSubMenus
= &BGSubMenus
;
1380 menu
->sumMainMenuList
= &window
->userBGMenuCache
.ubmcMenuList
;
1381 menu
->sumMenuCreated
= &window
->userBGMenuCache
.ubmcMenuCreated
;
1383 menu
->sumType
= menuType
;
1387 ** Updates either the Shell, Macro or Background menu of "window", depending
1388 ** on value of "menuType". Update is realized by following main steps:
1389 ** - set / reset "to be managed" flag of user menu info list items
1390 ** according to current selected language mode.
1391 ** - create *all* user menu items (widgets etc). related to given
1392 ** window & menu type, if not done before.
1393 ** - manage / unmanage user menu widgets according to "to be managed"
1394 ** indication of user menu info list items.
1396 static void updateMenu(WindowInfo
*window
, int menuType
)
1398 selectedUserMenu menu
;
1400 /* Fetch the appropriate menu data */
1401 selectUserMenu(window
, menuType
, &menu
);
1403 /* Set / reset "to be managed" flag of all info list items */
1404 applyLangModeToUserMenuInfo(menu
.sumInfoList
, menu
.sumNbrOfListItems
,
1405 window
->languageMode
);
1407 /* create user menu items, if not done before */
1408 if (!*menu
.sumMenuCreated
)
1409 createMenuItems(window
, &menu
);
1411 /* manage user menu items depending on current language mode */
1412 manageUserMenu(&menu
, window
);
1414 if (menuType
== BG_MENU_CMDS
) {
1415 /* Set the proper sensitivity of items which may be dimmed */
1416 SetBGMenuUndoSensitivity(window
, XtIsSensitive(window
->undoItem
));
1417 SetBGMenuRedoSensitivity(window
, XtIsSensitive(window
->redoItem
));
1420 DimSelectionDepUserMenuItems(window
, window
->buffer
->primary
.selected
);
1424 ** Manually adjust the dimension of the menuShell _before_
1425 ** re-managing the menu pane, to either expose hidden menu
1426 ** entries or remove empty space.
1428 static void manageTearOffMenu(Widget menuPane
)
1430 Dimension width
, height
, border
;
1432 /* somehow OM went into a long CPU cycling when we
1433 attempt to change the shell window dimension by
1434 setting the XmNwidth & XmNheight directly. Using
1435 XtResizeWidget() seem to fix it */
1436 XtVaGetValues(XtParent(menuPane
), XmNborderWidth
, &border
, NULL
);
1437 XtVaGetValues(menuPane
, XmNwidth
, &width
, XmNheight
, &height
, NULL
);
1438 XtResizeWidget(XtParent(menuPane
), width
, height
, border
);
1440 XtManageChild(menuPane
);
1444 ** Cache user menus:
1445 ** Reset manage mode of user menu items in window cache.
1447 static void resetManageMode(UserMenuList
*list
)
1450 UserMenuListElement
*element
;
1452 for (i
=0; i
<list
->umlNbrItems
; i
++) {
1453 element
= list
->umlItems
[i
];
1455 /* remember current manage mode before reset it to
1457 element
->umlePrevManageMode
= element
->umleManageMode
;
1458 element
->umleManageMode
= UMMM_UNMANAGE
;
1460 /* recursively reset manage mode of sub-menus */
1461 if (element
->umleSubMenuList
!= NULL
)
1462 resetManageMode(element
->umleSubMenuList
);
1467 ** Cache user menus:
1468 ** Manage all menu widgets of given user sub-menu list.
1470 static void manageAllSubMenuWidgets(UserMenuListElement
*subMenu
)
1473 UserMenuList
*subMenuList
;
1474 UserMenuListElement
*element
;
1475 WidgetList widgetList
;
1476 Cardinal nWidgetListItems
;
1478 /* if the sub-menu is torn off, unmanage the menu pane
1479 before updating it to prevent the tear-off menu
1480 from shrinking and expanding as the menu entries
1482 if (!XmIsMenuShell(XtParent(subMenu
->umleSubMenuPane
))) {
1483 XtUnmanageChild(subMenu
->umleSubMenuPane
);
1486 /* manage all children of sub-menu pane */
1487 XtVaGetValues(subMenu
->umleSubMenuPane
,
1488 XmNchildren
, &widgetList
,
1489 XmNnumChildren
, &nWidgetListItems
,
1491 XtManageChildren(widgetList
, nWidgetListItems
);
1493 /* scan, if an menu item of given sub-menu holds a nested
1495 subMenuList
= subMenu
->umleSubMenuList
;
1497 for (i
=0; i
<subMenuList
->umlNbrItems
; i
++) {
1498 element
= subMenuList
->umlItems
[i
];
1500 if (element
->umleSubMenuList
!= NULL
) {
1501 /* if element is a sub-menu, then continue managing
1502 all items of that sub-menu recursively */
1503 manageAllSubMenuWidgets(element
);
1507 /* manage sub-menu pane widget itself */
1508 XtManageChild(subMenu
->umleMenuItem
);
1510 /* if the sub-menu is torn off, then adjust & manage the menu */
1511 if (!XmIsMenuShell(XtParent(subMenu
->umleSubMenuPane
))) {
1512 manageTearOffMenu(subMenu
->umleSubMenuPane
);
1515 /* redisplay sub-menu tearoff window, if the sub-menu
1516 was torn off before */
1517 ShowHiddenTearOff(subMenu
->umleSubMenuPane
);
1521 ** Cache user menus:
1522 ** Unmanage all menu widgets of given user sub-menu list.
1524 static void unmanageAllSubMenuWidgets(UserMenuListElement
*subMenu
)
1528 UserMenuList
*subMenuList
;
1529 UserMenuListElement
*element
;
1530 WidgetList widgetList
;
1531 Cardinal nWidgetListItems
;
1533 /* if sub-menu is torn-off, then unmap its shell
1534 (so tearoff window isn't displayed anymore) */
1535 shell
= XtParent(subMenu
->umleSubMenuPane
);
1536 if (!XmIsMenuShell(shell
)) {
1537 XtUnmapWidget(shell
);
1540 /* unmanage all children of sub-menu pane */
1541 XtVaGetValues(subMenu
->umleSubMenuPane
,
1542 XmNchildren
, &widgetList
,
1543 XmNnumChildren
, &nWidgetListItems
,
1545 XtUnmanageChildren(widgetList
, nWidgetListItems
);
1547 /* scan, if an menu item of given sub-menu holds a nested
1549 subMenuList
= subMenu
->umleSubMenuList
;
1551 for (i
=0; i
<subMenuList
->umlNbrItems
; i
++) {
1552 element
= subMenuList
->umlItems
[i
];
1554 if (element
->umleSubMenuList
!= NULL
) {
1555 /* if element is a sub-menu, then continue unmanaging
1556 all items of that sub-menu recursively */
1557 unmanageAllSubMenuWidgets(element
);
1561 /* unmanage sub-menu pane widget itself */
1562 XtUnmanageChild(subMenu
->umleMenuItem
);
1566 ** Cache user menus:
1567 ** Manage / unmanage menu widgets according to given user menu list.
1569 static void manageMenuWidgets(UserMenuList
*list
)
1572 UserMenuListElement
*element
;
1574 /* (un)manage all elements of given user menu list */
1575 for (i
=0; i
<list
->umlNbrItems
; i
++) {
1576 element
= list
->umlItems
[i
];
1578 if (element
->umlePrevManageMode
!= element
->umleManageMode
||
1579 element
->umleManageMode
== UMMM_MANAGE
) {
1580 /* previous and current manage mode differ OR
1581 current manage mode indicates: element needs to be
1582 (un)managed individually */
1583 if (element
->umleManageMode
== UMMM_MANAGE_ALL
) {
1584 /* menu item represented by "element" is a sub-menu and
1585 needs to be completely managed */
1586 manageAllSubMenuWidgets(element
);
1587 } else if (element
->umleManageMode
== UMMM_MANAGE
) {
1588 if (element
->umlePrevManageMode
== UMMM_UNMANAGE
||
1589 element
->umlePrevManageMode
== UMMM_UNMANAGE_ALL
) {
1590 /* menu item represented by "element" was unmanaged
1591 before and needs to be managed now */
1592 XtManageChild(element
->umleMenuItem
);
1595 /* if element is a sub-menu, then continue (un)managing
1596 single elements of that sub-menu one by one */
1597 if (element
->umleSubMenuList
!= NULL
) {
1598 /* if the sub-menu is torn off, unmanage the menu pane
1599 before updating it to prevent the tear-off menu
1600 from shrinking and expanding as the menu entries
1602 if (!XmIsMenuShell(XtParent(element
->umleSubMenuPane
))) {
1603 XtUnmanageChild(element
->umleSubMenuPane
);
1606 /* (un)manage menu entries of sub-menu */
1607 manageMenuWidgets(element
->umleSubMenuList
);
1609 /* if the sub-menu is torn off, then adjust & manage the menu */
1610 if (!XmIsMenuShell(XtParent(element
->umleSubMenuPane
))) {
1611 manageTearOffMenu(element
->umleSubMenuPane
);
1614 /* if the sub-menu was torn off then redisplay it */
1615 ShowHiddenTearOff(element
->umleSubMenuPane
);
1617 } else if (element
->umleManageMode
== UMMM_UNMANAGE_ALL
){
1618 /* menu item represented by "element" is a sub-menu and
1619 needs to be completely unmanaged */
1620 unmanageAllSubMenuWidgets(element
);
1622 /* current mode is UMMM_UNMANAGE -> menu item represented
1623 by "element" is a single menu item and needs to be
1625 XtUnmanageChild(element
->umleMenuItem
);
1632 ** Cache user menus:
1633 ** Remove accelerators from all items of given user (sub-)menu list.
1635 static void removeAccelFromMenuWidgets(UserMenuList
*menuList
)
1638 UserMenuListElement
*element
;
1640 /* scan all elements of this (sub-)menu */
1641 for (i
=0; i
<menuList
->umlNbrItems
; i
++) {
1642 element
= menuList
->umlItems
[i
];
1644 if (element
->umleSubMenuList
!= NULL
) {
1645 /* if element is a sub-menu, then continue removing accelerators
1646 from all items of that sub-menu recursively */
1647 removeAccelFromMenuWidgets(element
->umleSubMenuList
);
1648 } else if (element
->umleAccKeys
!= NULL
&&
1649 element
->umleManageMode
== UMMM_UNMANAGE
&&
1650 element
->umlePrevManageMode
== UMMM_MANAGE
) {
1651 /* remove accelerator if one was bound */
1652 XtVaSetValues(element
->umleMenuItem
, XmNaccelerator
, NULL
, NULL
);
1658 ** Cache user menus:
1659 ** Assign accelerators to all managed items of given user (sub-)menu list.
1661 static void assignAccelToMenuWidgets(UserMenuList
*menuList
, WindowInfo
*window
)
1664 UserMenuListElement
*element
;
1666 /* scan all elements of this (sub-)menu */
1667 for (i
=0; i
<menuList
->umlNbrItems
; i
++) {
1668 element
= menuList
->umlItems
[i
];
1670 if (element
->umleSubMenuList
!= NULL
) {
1671 /* if element is a sub-menu, then continue assigning accelerators
1672 to all managed items of that sub-menu recursively */
1673 assignAccelToMenuWidgets(element
->umleSubMenuList
, window
);
1674 } else if (element
->umleAccKeys
!= NULL
&&
1675 element
->umleManageMode
== UMMM_MANAGE
&&
1676 element
->umlePrevManageMode
== UMMM_UNMANAGE
) {
1677 /* assign accelerator if applicable */
1678 XtVaSetValues(element
->umleMenuItem
, XmNaccelerator
,
1679 element
->umleAccKeys
, NULL
);
1680 if (!element
->umleAccLockPatchApplied
) {
1681 UpdateAccelLockPatch(window
->splitPane
, element
->umleMenuItem
);
1682 element
->umleAccLockPatchApplied
= True
;
1689 ** Cache user menus:
1690 ** (Un)Manage all items of selected user menu.
1692 static void manageUserMenu(selectedUserMenu
*menu
, WindowInfo
*window
)
1696 Boolean currentLEisSubMenu
;
1698 UserMenuList
*menuList
;
1699 UserMenuListElement
*currentLE
;
1700 UserMenuManageMode
*mode
;
1702 /* reset manage mode of all items of selected user menu in window cache */
1703 resetManageMode(menu
->sumMainMenuList
);
1705 /* set manage mode of all items of selected user menu in window cache
1706 according to the "to be managed" indication of the info list */
1707 for (n
=0; n
<menu
->sumNbrOfListItems
; n
++) {
1708 info
= menu
->sumInfoList
[n
];
1710 menuList
= menu
->sumMainMenuList
;
1713 /* select all menu list items belonging to menu record "info" using
1714 hierarchical ID of current menu info (e.g. id = {3} means:
1715 4th element of main menu; {0} = 1st element etc.)*/
1716 for (i
=0; i
<info
->umiIdLen
; i
++) {
1717 currentLE
= menuList
->umlItems
[*id
];
1718 mode
= ¤tLE
->umleManageMode
;
1719 currentLEisSubMenu
= (currentLE
->umleSubMenuList
!= NULL
);
1721 if (info
->umiToBeManaged
) {
1722 /* menu record needs to be managed: */
1723 if (*mode
== UMMM_UNMANAGE
) {
1724 /* "mode" was not touched after reset ("init. state"):
1725 if current list element represents a sub-menu, then
1726 probably the complete sub-menu needs to be managed
1727 too. If current list element indicates single menu
1728 item, then just this item needs to be managed */
1729 if (currentLEisSubMenu
) {
1730 *mode
= UMMM_MANAGE_ALL
;
1732 *mode
= UMMM_MANAGE
;
1734 } else if (*mode
== UMMM_UNMANAGE_ALL
) {
1735 /* "mode" was touched after reset:
1736 current list element represents a sub-menu and min.
1737 one element of the sub-menu needs to be unmanaged ->
1738 the sub-menu needs to be (un)managed element by
1740 *mode
= UMMM_MANAGE
;
1743 /* menu record needs to be unmanaged: */
1744 if (*mode
== UMMM_UNMANAGE
) {
1745 /* "mode" was not touched after reset ("init. state"):
1746 if current list element represents a sub-menu, then
1747 probably the complete sub-menu needs to be unmanaged
1749 if (currentLEisSubMenu
) {
1750 *mode
= UMMM_UNMANAGE_ALL
;
1752 } else if (*mode
== UMMM_MANAGE_ALL
) {
1753 /* "mode" was touched after reset:
1754 current list element represents a sub-menu and min.
1755 one element of the sub-menu needs to be managed ->
1756 the sub-menu needs to be (un)managed element by
1758 *mode
= UMMM_MANAGE
;
1762 menuList
= currentLE
->umleSubMenuList
;
1768 /* if the menu is torn off, unmanage the menu pane
1769 before updating it to prevent the tear-off menu
1770 from shrinking and expanding as the menu entries
1772 if (!XmIsMenuShell(XtParent(menu
->sumMenuPane
)))
1773 XtUnmanageChild(menu
->sumMenuPane
);
1775 /* manage menu widgets according to current / previous manage mode of
1776 user menu window cache */
1777 manageMenuWidgets(menu
->sumMainMenuList
);
1779 /* Note: before new accelerator is assigned it seems to be necessary
1780 to remove old accelerator from user menu widgets. Removing same
1781 accelerator *after* it was assigned to another user menu widget
1783 removeAccelFromMenuWidgets(menu
->sumMainMenuList
);
1785 assignAccelToMenuWidgets(menu
->sumMainMenuList
, window
);
1787 /* if the menu is torn off, then adjust & manage the menu */
1788 if (!XmIsMenuShell(XtParent(menu
->sumMenuPane
)))
1789 manageTearOffMenu(menu
->sumMenuPane
);
1793 ** Create either the variable Shell menu, Macro menu or Background menu
1794 ** items of "window" (driven by value of "menuType")
1796 static void createMenuItems(WindowInfo
*window
, selectedUserMenu
*menu
)
1798 Widget btn
, subPane
, newSubPane
;
1801 menuTreeItem
*menuTree
;
1802 int i
, nTreeEntries
, size
;
1803 char *hierName
, *namePtr
, *subMenuName
, *subSep
, *fullName
;
1804 int menuType
= menu
->sumType
;
1806 userSubMenuCache
*subMenus
= menu
->sumSubMenus
;
1807 userSubMenuInfo
*subMenuInfo
;
1808 UserMenuList
*menuList
;
1809 UserMenuListElement
*currentLE
;
1811 char accKeysBuf
[MAX_ACCEL_LEN
+5];
1814 /* Allocate storage for structures to help find panes of sub-menus */
1815 size
= sizeof(menuTreeItem
) * menu
->sumNbrOfListItems
;
1816 menuTree
= (menuTreeItem
*)XtMalloc(size
);
1819 /* Harmless kludge: undo and redo items are marked specially if found
1820 in the background menu, and used to dim/undim with edit menu */
1821 window
->bgMenuUndoItem
= NULL
;
1822 window
->bgMenuRedoItem
= NULL
;
1825 ** Add items to the menu pane, creating hierarchical sub-menus as
1828 allocUserMenuList(menu
->sumMainMenuList
, subMenus
->usmcNbrOfMainMenuItems
);
1829 for (n
=0; n
<menu
->sumNbrOfListItems
; n
++) {
1830 item
= menu
->sumItemList
[n
];
1831 info
= menu
->sumInfoList
[n
];
1832 menuList
= menu
->sumMainMenuList
;
1835 fullName
= info
->umiName
;
1837 /* create/find sub-menus, stripping off '>' until item name is
1838 reached, then create the menu item */
1840 subPane
= menu
->sumMenuPane
;
1842 subSep
= strchr(namePtr
, '>');
1843 if (subSep
== NULL
) {
1844 btn
= createUserMenuItem(subPane
, namePtr
, item
, n
,
1845 (XtCallbackProc
)(menuType
== SHELL_CMDS
? shellMenuCB
:
1846 (menuType
== MACRO_CMDS
? macroMenuCB
: bgMenuCB
)),
1848 if (menuType
== BG_MENU_CMDS
&& !strcmp(item
->cmd
, "undo()\n"))
1849 window
->bgMenuUndoItem
= btn
;
1850 else if (menuType
== BG_MENU_CMDS
&& !strcmp(item
->cmd
,"redo()\n"))
1851 window
->bgMenuRedoItem
= btn
;
1852 /* generate accelerator keys */
1853 genAccelEventName(accKeysBuf
, item
->modifiers
, item
->keysym
);
1854 accKeys
= item
->keysym
== NoSymbol
? NULL
: XtNewString(accKeysBuf
);
1855 /* create corresponding menu list item */
1856 menuList
->umlItems
[menuList
->umlNbrItems
++] =
1857 allocUserMenuListElement(btn
, accKeys
);
1860 hierName
= copySubstring(fullName
, subSep
- fullName
);
1861 subMenuInfo
= findSubMenuInfo(subMenus
, hierName
);
1862 newSubPane
= findInMenuTree(menuTree
, nTreeEntries
, hierName
);
1863 if (newSubPane
== NULL
) {
1864 subMenuName
= copySubstring(namePtr
, subSep
- namePtr
);
1865 newSubPane
= createUserSubMenu(subPane
, subMenuName
, &btn
);
1866 XtFree(subMenuName
);
1867 menuTree
[nTreeEntries
].name
= hierName
;
1868 menuTree
[nTreeEntries
++].menuPane
= newSubPane
;
1870 currentLE
= allocUserMenuListElement(btn
, NULL
);
1871 menuList
->umlItems
[menuList
->umlNbrItems
++] = currentLE
;
1872 currentLE
->umleSubMenuPane
= newSubPane
;
1873 currentLE
->umleSubMenuList
=
1874 allocUserSubMenuList(subMenuInfo
->usmiId
[subMenuInfo
->usmiIdLen
]);
1876 currentLE
= menuList
->umlItems
[subMenuInfo
->usmiId
[subMenuDepth
]];
1879 subPane
= newSubPane
;
1880 menuList
= currentLE
->umleSubMenuList
;
1882 namePtr
= subSep
+ 1;
1886 *menu
->sumMenuCreated
= True
;
1888 /* Free the structure used to keep track of sub-menus durring creation */
1889 for (i
=0; i
<nTreeEntries
; i
++)
1890 XtFree(menuTree
[i
].name
);
1891 XtFree((char *)menuTree
);
1895 ** Find the widget corresponding to a hierarchical menu name (a>b>c...)
1897 static Widget
findInMenuTree(menuTreeItem
*menuTree
, int nTreeEntries
,
1898 const char *hierName
)
1902 for (i
=0; i
<nTreeEntries
; i
++)
1903 if (!strcmp(hierName
, menuTree
[i
].name
))
1904 return menuTree
[i
].menuPane
;
1908 static char *copySubstring(const char *string
, int length
)
1910 char *retStr
= XtMalloc(length
+ 1);
1912 strncpy(retStr
, string
, length
);
1913 retStr
[length
] = '\0';
1917 static Widget
createUserMenuItem(Widget menuPane
, char *name
, menuItemRec
*f
,
1918 int index
, XtCallbackProc cbRtn
, XtPointer cbArg
)
1921 char accText
[MAX_ACCEL_LEN
];
1924 generateAcceleratorString(accText
, f
->modifiers
, f
->keysym
);
1925 st1
=XmStringCreateSimple(name
);
1926 st2
=XmStringCreateSimple(accText
);
1927 btn
= XtVaCreateWidget("cmd", xmPushButtonWidgetClass
, menuPane
,
1928 XmNlabelString
, st1
,
1929 XmNacceleratorText
, st2
,
1930 XmNmnemonic
, f
->mnemonic
,
1931 XmNuserData
, (XtPointer
)(index
+10), NULL
);
1932 XtAddCallback(btn
, XmNactivateCallback
, cbRtn
, cbArg
);
1939 ** Add a user-defined sub-menu to an established pull-down menu, marking
1940 ** it's userData field with TEMPORARY_MENU_ITEM so it can be found and
1941 ** removed later if the menu is redefined. Returns the menu pane of the
1944 static Widget
createUserSubMenu(Widget parent
, char *label
, Widget
*menuItem
)
1948 static Arg args
[1] = {{XmNuserData
, (XtArgVal
)TEMPORARY_MENU_ITEM
}};
1950 menuPane
= CreatePulldownMenu(parent
, "userPulldown", args
, 1);
1951 *menuItem
= XtVaCreateWidget("userCascade", xmCascadeButtonWidgetClass
, parent
,
1952 XmNlabelString
, st1
=XmStringCreateSimple(label
),
1953 XmNsubMenuId
, menuPane
, XmNuserData
, TEMPORARY_MENU_ITEM
,
1960 ** Cache user menus:
1961 ** Delete all variable menu items of given menu pane
1963 static void deleteMenuItems(Widget menuPane
)
1965 WidgetList itemList
, items
;
1971 /* Fetch the list of children from the menu pane to delete */
1972 XtVaGetValues(menuPane
, XmNchildren
, &itemList
,
1973 XmNnumChildren
, &nItems
, NULL
);
1975 /* make a copy because the widget alters the list as you delete widgets */
1976 items
= (WidgetList
)XtMalloc(sizeof(Widget
) * nItems
);
1977 memcpy(items
, itemList
, sizeof(Widget
) * nItems
);
1979 /* delete all of the widgets not marked as PERMANENT_MENU_ITEM */
1980 for (n
=0; n
<(int)nItems
; n
++) {
1981 XtVaGetValues(items
[n
], XmNuserData
, &userData
, NULL
);
1982 if (userData
!= (XtPointer
)PERMANENT_MENU_ITEM
) {
1983 if (XtClass(items
[n
]) == xmCascadeButtonWidgetClass
) {
1984 XtVaGetValues(items
[n
], XmNsubMenuId
, &subMenuID
, NULL
);
1986 /* prevent dangling submenu tearoffs */
1987 if (!XmIsMenuShell(XtParent(subMenuID
)))
1988 _XmDismissTearOff(XtParent(subMenuID
), NULL
, NULL
);
1990 deleteMenuItems(subMenuID
);
1991 #if XmVersion < 2000
1992 /* Skipping this creates a memory and server resource
1993 leak (though both are reclaimed on window closing). In
1994 Motif 2.0 (and beyond?) there is a potential crash during
1995 phase 2 widget destruction in "SetCascadeField", and in
1996 Motif 1.2 there are free-memory reads. I would really like
1997 to be able to destroy this. */
1998 XtDestroyWidget(subMenuID
);
2001 /* remove accel. before destroy or lose it forever */
2002 XtVaSetValues(items
[n
], XmNaccelerator
, NULL
, NULL
);
2004 XtDestroyWidget(items
[n
]);
2007 XtFree((char *)items
);
2010 static void closeCB(Widget w
, XtPointer clientData
, XtPointer callData
)
2012 userCmdDialog
*ucd
= (userCmdDialog
*)clientData
;
2014 /* Mark that there's no longer a (macro, bg, or shell) dialog up */
2015 if (ucd
->dialogType
== SHELL_CMDS
)
2016 ShellCmdDialog
= NULL
;
2017 else if (ucd
->dialogType
== MACRO_CMDS
)
2018 MacroCmdDialog
= NULL
;
2020 BGMenuCmdDialog
= NULL
;
2022 /* pop down and destroy the dialog (memory for ucd is freed in the
2023 destroy callback) */
2024 XtDestroyWidget(ucd
->dlogShell
);
2027 static void okCB(Widget w
, XtPointer clientData
, XtPointer callData
)
2029 userCmdDialog
*ucd
= (userCmdDialog
*)clientData
;
2031 /* Read the dialog fields, and update the menus */
2032 if (!applyDialogChanges(ucd
))
2035 /* Mark that there's no longer a (macro, bg, or shell) dialog up */
2036 if (ucd
->dialogType
== SHELL_CMDS
)
2037 ShellCmdDialog
= NULL
;
2038 else if (ucd
->dialogType
== MACRO_CMDS
)
2039 MacroCmdDialog
= NULL
;
2041 BGMenuCmdDialog
= NULL
;
2043 /* pop down and destroy the dialog (memory for ucd is freed in the
2044 destroy callback) */
2045 XtDestroyWidget(ucd
->dlogShell
);
2048 static void applyCB(Widget w
, XtPointer clientData
, XtPointer callData
)
2050 applyDialogChanges((userCmdDialog
*)clientData
);
2053 static void checkCB(Widget w
, XtPointer clientData
, XtPointer callData
)
2055 userCmdDialog
*ucd
= (userCmdDialog
*)clientData
;
2057 if (checkMacro(ucd
))
2059 DialogF(DF_INF
, ucd
->dlogShell
, 1, "Macro",
2060 "Macro compiled without error", "OK");
2064 static int checkMacro(userCmdDialog
*ucd
)
2068 f
= readDialogFields(ucd
, False
);
2071 if (!checkMacroText(f
->cmd
, ucd
->dlogShell
, ucd
->cmdTextW
)) {
2078 static int checkMacroText(char *macro
, Widget errorParent
, Widget errFocus
)
2081 char *errMsg
, *stoppedAt
;
2083 prog
= ParseMacro(macro
, &errMsg
, &stoppedAt
);
2085 if (errorParent
!= NULL
) {
2086 ParseError(errorParent
, macro
, stoppedAt
, "macro", errMsg
);
2087 XmTextSetInsertionPosition(errFocus
, stoppedAt
- macro
);
2088 XmProcessTraversal(errFocus
, XmTRAVERSE_CURRENT
);
2093 if (*stoppedAt
!= '\0') {
2094 if (errorParent
!= NULL
) {
2095 ParseError(errorParent
, macro
, stoppedAt
,"macro","syntax error");
2096 XmTextSetInsertionPosition(errFocus
, stoppedAt
- macro
);
2097 XmProcessTraversal(errFocus
, XmTRAVERSE_CURRENT
);
2104 static int applyDialogChanges(userCmdDialog
*ucd
)
2108 /* Get the current contents of the dialog fields */
2109 if (!UpdateManagedList(ucd
->managedList
, True
))
2112 /* Test compile the macro */
2113 if (ucd
->dialogType
== MACRO_CMDS
)
2114 if (!checkMacro(ucd
))
2117 /* Update the menu information */
2118 if (ucd
->dialogType
== SHELL_CMDS
) {
2119 for (i
=0; i
<NShellMenuItems
; i
++)
2120 freeMenuItemRec(ShellMenuItems
[i
]);
2121 freeUserMenuInfoList(ShellMenuInfo
, NShellMenuItems
);
2122 freeSubMenuCache(&ShellSubMenus
);
2123 for (i
=0; i
<ucd
->nMenuItems
; i
++)
2124 ShellMenuItems
[i
] = copyMenuItemRec(ucd
->menuItemsList
[i
]);
2125 NShellMenuItems
= ucd
->nMenuItems
;
2126 parseMenuItemList(ShellMenuItems
, NShellMenuItems
, ShellMenuInfo
, &ShellSubMenus
);
2127 } else if (ucd
->dialogType
== MACRO_CMDS
) {
2128 for (i
=0; i
<NMacroMenuItems
; i
++)
2129 freeMenuItemRec(MacroMenuItems
[i
]);
2130 freeUserMenuInfoList(MacroMenuInfo
, NMacroMenuItems
);
2131 freeSubMenuCache(&MacroSubMenus
);
2132 for (i
=0; i
<ucd
->nMenuItems
; i
++)
2133 MacroMenuItems
[i
] = copyMenuItemRec(ucd
->menuItemsList
[i
]);
2134 NMacroMenuItems
= ucd
->nMenuItems
;
2135 parseMenuItemList(MacroMenuItems
, NMacroMenuItems
, MacroMenuInfo
, &MacroSubMenus
);
2136 } else { /* BG_MENU_CMDS */
2137 for (i
=0; i
<NBGMenuItems
; i
++)
2138 freeMenuItemRec(BGMenuItems
[i
]);
2139 freeUserMenuInfoList(BGMenuInfo
, NBGMenuItems
);
2140 freeSubMenuCache(&BGSubMenus
);
2141 for (i
=0; i
<ucd
->nMenuItems
; i
++)
2142 BGMenuItems
[i
] = copyMenuItemRec(ucd
->menuItemsList
[i
]);
2143 NBGMenuItems
= ucd
->nMenuItems
;
2144 parseMenuItemList(BGMenuItems
, NBGMenuItems
, BGMenuInfo
, &BGSubMenus
);
2147 /* Update the menus themselves in all of the NEdit windows */
2148 rebuildMenuOfAllWindows(ucd
->dialogType
);
2150 /* Note that preferences have been changed */
2155 static void pasteReplayCB(Widget w
, XtPointer clientData
, XtPointer callData
)
2157 userCmdDialog
*ucd
= (userCmdDialog
*)clientData
;
2159 if (GetReplayMacro() == NULL
)
2162 XmTextInsert(ucd
->cmdTextW
, XmTextGetInsertionPosition(ucd
->cmdTextW
),
2166 static void destroyCB(Widget w
, XtPointer clientData
, XtPointer callData
)
2168 userCmdDialog
*ucd
= (userCmdDialog
*)clientData
;
2171 for (i
=0; i
<ucd
->nMenuItems
; i
++)
2172 freeMenuItemRec(ucd
->menuItemsList
[i
]);
2173 XtFree((char *)ucd
->menuItemsList
);
2174 XtFree((char *)ucd
);
2177 static void accFocusCB(Widget w
, XtPointer clientData
, XtPointer callData
)
2179 userCmdDialog
*ucd
= (userCmdDialog
*)clientData
;
2181 RemoveDialogMnemonicHandler(XtParent(ucd
->accTextW
));
2184 static void accLoseFocusCB(Widget w
, XtPointer clientData
, XtPointer callData
)
2186 userCmdDialog
*ucd
= (userCmdDialog
*)clientData
;
2188 AddDialogMnemonicHandler(XtParent(ucd
->accTextW
), FALSE
);
2191 static void accKeyCB(Widget w
, XtPointer clientData
, XKeyEvent
*event
)
2193 userCmdDialog
*ucd
= (userCmdDialog
*)clientData
;
2194 KeySym keysym
= XLookupKeysym(event
, 0);
2195 char outStr
[MAX_ACCEL_LEN
];
2197 /* Accept only real keys, not modifiers alone */
2198 if (IsModifierKey(keysym
))
2201 /* Tab key means go to the next field, don't enter */
2202 if (keysym
== XK_Tab
)
2205 /* Beep and return if the modifiers are buttons or ones we don't support */
2206 if (event
->state
& ~(ShiftMask
| LockMask
| ControlMask
| Mod1Mask
|
2207 Mod2Mask
| Mod3Mask
| Mod4Mask
| Mod5Mask
)) {
2208 XBell(TheDisplay
, 0);
2212 /* Delete or backspace clears field */
2213 if (keysym
== XK_Delete
|| keysym
== XK_BackSpace
) {
2214 XmTextSetString(ucd
->accTextW
, "");
2218 /* generate the string to use in the dialog field */
2219 generateAcceleratorString(outStr
, event
->state
, keysym
);
2221 /* Reject single character accelerators (a very simple way to eliminate
2222 un-modified letters and numbers) The goal is give users a clue that
2223 they're supposed to type the actual keys, not the name. This scheme
2224 is not rigorous and still allows accelerators like Comma. */
2225 if (strlen(outStr
) == 1) {
2226 XBell(TheDisplay
, 0);
2230 /* fill in the accelerator field in the dialog */
2231 XmTextSetString(ucd
->accTextW
, outStr
);
2234 static void sameOutCB(Widget w
, XtPointer clientData
, XtPointer callData
)
2236 XtSetSensitive(((userCmdDialog
*)clientData
)->repInpBtn
,
2237 XmToggleButtonGetState(w
));
2240 static void shellMenuCB(Widget w
, WindowInfo
*window
, XtPointer callData
)
2246 window
= WidgetToWindow(MENU_WIDGET(w
));
2248 /* get the index of the shell command and verify that it's in range */
2249 XtVaGetValues(w
, XmNuserData
, &userData
, NULL
);
2250 index
= (int)userData
- 10;
2251 if (index
<0 || index
>= NShellMenuItems
)
2254 params
[0] = ShellMenuItems
[index
]->name
;
2255 XtCallActionProc(window
->lastFocus
, "shell_menu_command",
2256 ((XmAnyCallbackStruct
*)callData
)->event
, params
, 1);
2259 static void macroMenuCB(Widget w
, WindowInfo
*window
, XtPointer callData
)
2265 window
= WidgetToWindow(MENU_WIDGET(w
));
2267 /* Don't allow users to execute a macro command from the menu (or accel)
2268 if there's already a macro command executing. NEdit can't handle
2269 running multiple, independent uncoordinated, macros in the same
2270 window. Macros may invoke macro menu commands recursively via the
2271 macro_menu_command action proc, which is important for being able to
2272 repeat any operation, and to embed macros within eachother at any
2273 level, however, a call here with a macro running means that THE USER
2274 is explicitly invoking another macro via the menu or an accelerator. */
2275 if (window
->macroCmdData
!= NULL
) {
2276 XBell(TheDisplay
, 0);
2280 /* get the index of the macro command and verify that it's in range */
2281 XtVaGetValues(w
, XmNuserData
, &userData
, NULL
);
2282 index
= (int)userData
- 10;
2283 if (index
<0 || index
>= NMacroMenuItems
)
2286 params
[0] = MacroMenuItems
[index
]->name
;
2287 XtCallActionProc(window
->lastFocus
, "macro_menu_command",
2288 ((XmAnyCallbackStruct
*)callData
)->event
, params
, 1);
2291 static void bgMenuCB(Widget w
, WindowInfo
*window
, XtPointer callData
)
2297 /* Same remark as for macro menu commands (see above). */
2298 if (window
->macroCmdData
!= NULL
) {
2299 XBell(TheDisplay
, 0);
2303 /* get the index of the macro command and verify that it's in range */
2304 XtVaGetValues(w
, XmNuserData
, &userData
, NULL
);
2305 index
= (int)userData
- 10;
2306 if (index
<0 || index
>= NBGMenuItems
)
2309 params
[0] = BGMenuItems
[index
]->name
;
2310 XtCallActionProc(window
->lastFocus
, "bg_menu_command",
2311 ((XmAnyCallbackStruct
*)callData
)->event
, params
, 1);
2315 ** Update the name, accelerator, mnemonic, and command fields in the shell
2316 ** command or macro dialog to agree with the currently selected item in the
2319 static void updateDialogFields(menuItemRec
*f
, userCmdDialog
*ucd
)
2321 char mneString
[2], accString
[MAX_ACCEL_LEN
];
2323 /* fill in the name, accelerator, mnemonic, and command fields of the
2324 dialog for the newly selected item, or blank them if "New" is selected */
2326 XmTextSetString(ucd
->nameTextW
, "");
2327 XmTextSetString(ucd
->cmdTextW
, "");
2328 XmTextSetString(ucd
->accTextW
, "");
2329 XmTextSetString(ucd
->mneTextW
, "");
2330 if (ucd
->dialogType
== SHELL_CMDS
) {
2331 RadioButtonChangeState(ucd
->selInpBtn
, True
, True
);
2332 RadioButtonChangeState(ucd
->sameOutBtn
, True
, True
);
2333 RadioButtonChangeState(ucd
->repInpBtn
, False
, False
);
2334 XtSetSensitive(ucd
->repInpBtn
, True
);
2335 RadioButtonChangeState(ucd
->saveFirstBtn
, False
, False
);
2336 RadioButtonChangeState(ucd
->loadAfterBtn
, False
, False
);
2339 mneString
[0] = f
->mnemonic
;
2340 mneString
[1] = '\0';
2341 generateAcceleratorString(accString
, f
->modifiers
, f
->keysym
);
2342 XmTextSetString(ucd
->nameTextW
, f
->name
);
2343 XmTextSetString(ucd
->cmdTextW
, f
->cmd
);
2344 XmTextSetString(ucd
->accTextW
, accString
);
2345 XmTextSetString(ucd
->mneTextW
, mneString
);
2346 RadioButtonChangeState(ucd
->selInpBtn
, f
->input
==FROM_SELECTION
, False
);
2347 if (ucd
->dialogType
== SHELL_CMDS
) {
2348 RadioButtonChangeState(ucd
->winInpBtn
, f
->input
== FROM_WINDOW
,
2350 RadioButtonChangeState(ucd
->eitherInpBtn
, f
->input
== FROM_EITHER
,
2352 RadioButtonChangeState(ucd
->noInpBtn
, f
->input
== FROM_NONE
,
2354 RadioButtonChangeState(ucd
->sameOutBtn
, f
->output
==TO_SAME_WINDOW
,
2356 RadioButtonChangeState(ucd
->winOutBtn
, f
->output
==TO_NEW_WINDOW
,
2358 RadioButtonChangeState(ucd
->dlogOutBtn
, f
->output
==TO_DIALOG
,
2360 RadioButtonChangeState(ucd
->repInpBtn
, f
->repInput
, False
);
2361 XtSetSensitive(ucd
->repInpBtn
, f
->output
==TO_SAME_WINDOW
);
2362 RadioButtonChangeState(ucd
->saveFirstBtn
, f
->saveFirst
, False
);
2363 RadioButtonChangeState(ucd
->loadAfterBtn
, f
->loadAfter
, False
);
2369 ** Read the name, accelerator, mnemonic, and command fields from the shell or
2370 ** macro commands dialog into a newly allocated menuItemRec. Returns a
2371 ** pointer to the new menuItemRec structure as the function value, or NULL on
2374 static menuItemRec
*readDialogFields(userCmdDialog
*ucd
, int silent
)
2376 char *nameText
, *cmdText
, *mneText
, *accText
;
2379 nameText
= XmTextGetString(ucd
->nameTextW
);
2380 if (*nameText
== '\0')
2384 DialogF(DF_WARN
, ucd
->dlogShell
, 1, "Menu Entry",
2385 "Please specify a name\nfor the menu item", "OK");
2386 XmProcessTraversal(ucd
->nameTextW
, XmTRAVERSE_CURRENT
);
2392 if (strchr(nameText
, ':'))
2396 DialogF(DF_WARN
, ucd
->dlogShell
, 1, "Menu Entry",
2397 "Menu item names may not\ncontain colon (:) characters",
2399 XmProcessTraversal(ucd
->nameTextW
, XmTRAVERSE_CURRENT
);
2405 cmdText
= XmTextGetString(ucd
->cmdTextW
);
2406 if (cmdText
== NULL
|| *cmdText
== '\0')
2410 DialogF(DF_WARN
, ucd
->dlogShell
, 1, "Command to Execute",
2411 "Please specify %s to execute", "OK",
2412 ucd
->dialogType
== SHELL_CMDS
2414 : "macro command(s)");
2415 XmProcessTraversal(ucd
->cmdTextW
, XmTRAVERSE_CURRENT
);
2423 if (ucd
->dialogType
== MACRO_CMDS
|| ucd
->dialogType
== BG_MENU_CMDS
) {
2424 addTerminatingNewline(&cmdText
);
2425 if (!checkMacroText(cmdText
, silent
? NULL
: ucd
->dlogShell
,
2432 f
= (menuItemRec
*)XtMalloc(sizeof(menuItemRec
));
2435 if ((mneText
= XmTextGetString(ucd
->mneTextW
)) != NULL
) {
2436 f
->mnemonic
= mneText
==NULL
? '\0' : mneText
[0];
2438 if (f
->mnemonic
== ':') /* colons mess up string parsing */
2441 if ((accText
= XmTextGetString(ucd
->accTextW
)) != NULL
) {
2442 parseAcceleratorString(accText
, &f
->modifiers
, &f
->keysym
);
2445 if (ucd
->dialogType
== SHELL_CMDS
) {
2446 if (XmToggleButtonGetState(ucd
->selInpBtn
))
2447 f
->input
= FROM_SELECTION
;
2448 else if (XmToggleButtonGetState(ucd
->winInpBtn
))
2449 f
->input
= FROM_WINDOW
;
2450 else if (XmToggleButtonGetState(ucd
->eitherInpBtn
))
2451 f
->input
= FROM_EITHER
;
2453 f
->input
= FROM_NONE
;
2454 if (XmToggleButtonGetState(ucd
->winOutBtn
))
2455 f
->output
= TO_NEW_WINDOW
;
2456 else if (XmToggleButtonGetState(ucd
->dlogOutBtn
))
2457 f
->output
= TO_DIALOG
;
2459 f
->output
= TO_SAME_WINDOW
;
2460 f
->repInput
= XmToggleButtonGetState(ucd
->repInpBtn
);
2461 f
->saveFirst
= XmToggleButtonGetState(ucd
->saveFirstBtn
);
2462 f
->loadAfter
= XmToggleButtonGetState(ucd
->loadAfterBtn
);
2464 f
->input
= XmToggleButtonGetState(ucd
->selInpBtn
) ? FROM_SELECTION
:
2466 f
->output
= TO_SAME_WINDOW
;
2467 f
->repInput
= False
;
2468 f
->saveFirst
= False
;
2469 f
->loadAfter
= False
;
2475 ** Copy a menu item record, and its associated memory
2477 static menuItemRec
*copyMenuItemRec(menuItemRec
*item
)
2479 menuItemRec
*newItem
;
2481 newItem
= (menuItemRec
*)XtMalloc(sizeof(menuItemRec
));
2483 newItem
->name
= XtMalloc(strlen(item
->name
)+1);
2484 strcpy(newItem
->name
, item
->name
);
2485 newItem
->cmd
= XtMalloc(strlen(item
->cmd
)+1);
2486 strcpy(newItem
->cmd
, item
->cmd
);
2491 ** Free a menu item record, and its associated memory
2493 static void freeMenuItemRec(menuItemRec
*item
)
2497 XtFree((char *)item
);
2501 ** Callbacks for managed-list operations
2503 static void *getDialogDataCB(void *oldItem
, int explicitRequest
, int *abort
,
2506 userCmdDialog
*ucd
= (userCmdDialog
*)cbArg
;
2507 menuItemRec
*currentFields
;
2509 /* If the dialog is currently displaying the "new" entry and the
2510 fields are empty, that's just fine */
2511 if (oldItem
== NULL
&& dialogFieldsAreEmpty(ucd
))
2514 /* If there are no problems reading the data, just return it */
2515 currentFields
= readDialogFields(ucd
, True
);
2516 if (currentFields
!= NULL
)
2517 return (void *)currentFields
;
2519 /* If user might not be expecting fields to be read, give more warning */
2520 if (!explicitRequest
)
2522 if (DialogF(DF_WARN
, ucd
->dlogShell
, 2, "Discard Entry",
2523 "Discard incomplete entry\nfor current menu item?", "Keep",
2526 return oldItem
== NULL
2528 : (void *)copyMenuItemRec((menuItemRec
*)oldItem
);
2532 /* Do readDialogFields again without "silent" mode to display warning(s) */
2533 readDialogFields(ucd
, False
);
2539 static void setDialogDataCB(void *item
, void *cbArg
)
2541 updateDialogFields((menuItemRec
*)item
, (userCmdDialog
*)cbArg
);
2544 static int dialogFieldsAreEmpty(userCmdDialog
*ucd
)
2546 return TextWidgetIsBlank(ucd
->nameTextW
) &&
2547 TextWidgetIsBlank(ucd
->cmdTextW
) &&
2548 TextWidgetIsBlank(ucd
->accTextW
) &&
2549 TextWidgetIsBlank(ucd
->mneTextW
) &&
2550 (ucd
->dialogType
!= SHELL_CMDS
|| (
2551 XmToggleButtonGetState(ucd
->selInpBtn
) &&
2552 XmToggleButtonGetState(ucd
->sameOutBtn
) &&
2553 !XmToggleButtonGetState(ucd
->repInpBtn
) &&
2554 !XmToggleButtonGetState(ucd
->saveFirstBtn
) &&
2555 !XmToggleButtonGetState(ucd
->loadAfterBtn
)));
2558 static void freeItemCB(void *item
)
2560 freeMenuItemRec((menuItemRec
*)item
);
2564 ** Gut a text widget of it's ability to process input
2566 static void disableTextW(Widget textW
)
2568 static XtTranslations emptyTable
= NULL
;
2569 static char *emptyTranslations
= "\
2570 <EnterWindow>: enter()\n\
2571 <Btn1Down>: grab-focus()\n\
2572 <Btn1Motion>: extend-adjust()\n\
2573 <Btn1Up>: extend-end()\n\
2574 Shift<Key>Tab: prev-tab-group()\n\
2575 Ctrl<Key>Tab: next-tab-group()\n\
2576 <Key>Tab: next-tab-group()\n\
2577 <LeaveWindow>: leave()\n\
2578 <FocusIn>: focusIn()\n\
2579 <FocusOut>: focusOut()\n\
2580 <Unmap>: unmap()\n";
2582 /* replace the translation table with the slimmed down one above */
2583 if (emptyTable
== NULL
)
2584 emptyTable
= XtParseTranslationTable(emptyTranslations
);
2585 XtVaSetValues(textW
, XmNtranslations
, emptyTable
, NULL
);
2588 static char *writeMenuItemString(menuItemRec
**menuItems
, int nItems
,
2591 char *outStr
, *outPtr
, *c
, accStr
[MAX_ACCEL_LEN
];
2595 /* determine the max. amount of memory needed for the returned string
2596 and allocate a buffer for composing the string */
2598 for (i
=0; i
<nItems
; i
++) {
2600 generateAcceleratorString(accStr
, f
->modifiers
, f
->keysym
);
2601 length
+= strlen(f
->name
) * 2; /* allow for \n & \\ expansions */
2602 length
+= strlen(accStr
);
2603 length
+= strlen(f
->cmd
) * 6; /* allow for \n & \\ expansions */
2604 length
+= 21; /* number of characters added below */
2606 length
++; /* terminating null */
2607 outStr
= XtMalloc(length
);
2609 /* write the string */
2613 for (i
=0; i
<nItems
; i
++) {
2615 generateAcceleratorString(accStr
, f
->modifiers
, f
->keysym
);
2617 for (c
=f
->name
; *c
!='\0'; ++c
) { /* Copy the command name */
2618 if (*c
== '\\') { /* changing backslashes to \\ */
2621 } else if (*c
== '\n') { /* changing newlines to \n */
2629 strcpy(outPtr
, accStr
);
2630 outPtr
+= strlen(accStr
);
2632 if (f
->mnemonic
!= '\0')
2633 *outPtr
++ = f
->mnemonic
;
2635 if (listType
== SHELL_CMDS
) {
2636 if (f
->input
== FROM_SELECTION
)
2638 else if (f
->input
== FROM_WINDOW
)
2640 else if (f
->input
== FROM_EITHER
)
2642 if (f
->output
== TO_DIALOG
)
2644 else if (f
->output
== TO_NEW_WINDOW
)
2654 if (f
->input
== FROM_SELECTION
)
2666 for (c
=f
->cmd
; *c
!='\0'; c
++) { /* Copy the command string, changing */
2667 if (*c
== '\\') { /* backslashes to double backslashes */
2668 *outPtr
++ = '\\'; /* and newlines to backslash-n's, */
2669 *outPtr
++ = '\\'; /* followed by real newlines and tab */
2670 } else if (*c
== '\n') {
2680 if (listType
== MACRO_CMDS
|| listType
== BG_MENU_CMDS
) {
2681 if (*(outPtr
-1) == '\t') outPtr
--;
2694 static int loadMenuItemString(char *inString
, menuItemRec
**menuItems
,
2695 int *nItems
, int listType
)
2699 char *inPtr
= inString
;
2700 char *nameStr
, accStr
[MAX_ACCEL_LEN
], mneChar
;
2702 unsigned int modifiers
;
2703 int i
, input
, output
, saveFirst
, loadAfter
, repInput
;
2704 int nameLen
, accLen
, mneLen
, cmdLen
;
2708 /* remove leading whitespace */
2709 while (*inPtr
== ' ' || *inPtr
== '\t')
2712 /* end of string in proper place */
2713 if (*inPtr
== '\0') {
2717 /* read name field */
2718 nameLen
= strcspn(inPtr
, ":");
2720 return parseError("no name field");
2721 nameStr
= XtMalloc(nameLen
+1);
2722 strncpy(nameStr
, inPtr
, nameLen
);
2723 nameStr
[nameLen
] = '\0';
2726 return parseError("end not expected");
2729 /* read accelerator field */
2730 accLen
= strcspn(inPtr
, ":");
2731 if (accLen
>= MAX_ACCEL_LEN
)
2732 return parseError("accelerator field too long");
2733 strncpy(accStr
, inPtr
, accLen
);
2734 accStr
[accLen
] = '\0';
2737 return parseError("end not expected");
2740 /* read menemonic field */
2741 mneLen
= strcspn(inPtr
, ":");
2743 return parseError("mnemonic field too long");
2750 return parseError("end not expected");
2752 /* read flags field */
2754 output
= TO_SAME_WINDOW
;
2758 for (; *inPtr
!= ':'; inPtr
++) {
2759 if (listType
== SHELL_CMDS
) {
2761 input
= FROM_SELECTION
;
2762 else if (*inPtr
== 'A')
2763 input
= FROM_WINDOW
;
2764 else if (*inPtr
== 'E')
2765 input
= FROM_EITHER
;
2766 else if (*inPtr
== 'W')
2767 output
= TO_NEW_WINDOW
;
2768 else if (*inPtr
== 'D')
2770 else if (*inPtr
== 'X')
2772 else if (*inPtr
== 'S')
2774 else if (*inPtr
== 'L')
2777 return parseError("unreadable flag field");
2780 input
= FROM_SELECTION
;
2782 return parseError("unreadable flag field");
2787 /* read command field */
2788 if (listType
== SHELL_CMDS
) {
2789 if (*inPtr
++ != '\n')
2790 return parseError("command must begin with newline");
2791 while (*inPtr
== ' ' || *inPtr
== '\t') /* leading whitespace */
2793 cmdLen
= strcspn(inPtr
, "\n");
2795 return parseError("shell command field is empty");
2796 cmdStr
= XtMalloc(cmdLen
+1);
2797 strncpy(cmdStr
, inPtr
, cmdLen
);
2798 cmdStr
[cmdLen
] = '\0';
2801 cmdStr
= copyMacroToEnd(&inPtr
);
2805 while (*inPtr
== ' ' || *inPtr
== '\t' || *inPtr
== '\n')
2806 inPtr
++; /* skip trailing whitespace & newline */
2808 /* parse the accelerator field */
2809 if (!parseAcceleratorString(accStr
, &modifiers
, &keysym
))
2810 return parseError("couldn't read accelerator field");
2812 /* create a menu item record */
2813 f
= (menuItemRec
*)XtMalloc(sizeof(menuItemRec
));
2816 f
->mnemonic
= mneChar
;
2817 f
->modifiers
= modifiers
;
2820 f
->repInput
= repInput
;
2821 f
->saveFirst
= saveFirst
;
2822 f
->loadAfter
= loadAfter
;
2825 /* add/replace menu record in the list */
2826 for (i
=0; i
< *nItems
; i
++) {
2827 if (!strcmp(menuItems
[i
]->name
, f
->name
)) {
2828 freeMenuItemRec(menuItems
[i
]);
2834 menuItems
[(*nItems
)++] = f
;
2839 static int parseError(const char *message
)
2841 fprintf(stderr
, "NEdit: Parse error in user defined menu item, %s\n",
2847 ** Create a text string representing an accelerator for the dialog,
2848 ** the shellCommands or macroCommands resource, and for the menu item.
2850 static void generateAcceleratorString(char *text
, unsigned int modifiers
,
2853 char *shiftStr
= "", *ctrlStr
= "", *altStr
= "";
2854 char *mod2Str
= "", *mod3Str
= "", *mod4Str
= "", *mod5Str
= "";
2856 Modifiers numLockMask
= GetNumLockModMask(TheDisplay
);
2858 /* if there's no accelerator, generate an empty string */
2859 if (keysym
== NoSymbol
) {
2865 /* Translate the modifiers into strings.
2866 Lock and NumLock are always ignored (see util/misc.c),
2867 so we don't display them either. */
2868 if (modifiers
& ShiftMask
)
2869 shiftStr
= "Shift+";
2870 if (modifiers
& ControlMask
)
2872 if (modifiers
& Mod1Mask
)
2874 if ((modifiers
& Mod2Mask
) && (Mod2Mask
!= numLockMask
))
2876 if ((modifiers
& Mod3Mask
) && (Mod3Mask
!= numLockMask
))
2878 if ((modifiers
& Mod4Mask
) && (Mod4Mask
!= numLockMask
))
2880 if ((modifiers
& Mod5Mask
) && (Mod5Mask
!= numLockMask
))
2883 /* for a consistent look to the accelerator names in the menus,
2884 capitalize the first letter of the keysym */
2885 strcpy(keyName
, XKeysymToString(keysym
));
2886 *keyName
= toupper(*keyName
);
2888 /* concatenate the strings together */
2889 sprintf(text
, "%s%s%s%s%s%s%s%s", shiftStr
, ctrlStr
, altStr
,
2890 mod2Str
, mod3Str
, mod4Str
, mod5Str
, keyName
);
2894 ** Create a translation table event description string for the menu
2895 ** XmNaccelerator resource.
2897 static void genAccelEventName(char *text
, unsigned int modifiers
,
2900 char *shiftStr
= "", *lockStr
= "", *ctrlStr
= "", *altStr
= "";
2901 char *mod2Str
= "", *mod3Str
= "", *mod4Str
= "", *mod5Str
= "";
2903 /* if there's no accelerator, generate an empty string */
2904 if (keysym
== NoSymbol
) {
2909 /* translate the modifiers into strings */
2910 if (modifiers
& ShiftMask
)
2911 shiftStr
= "Shift ";
2912 if (modifiers
& LockMask
)
2914 if (modifiers
& ControlMask
)
2916 if (modifiers
& Mod1Mask
)
2918 if (modifiers
& Mod2Mask
)
2920 if (modifiers
& Mod3Mask
)
2922 if (modifiers
& Mod4Mask
)
2924 if (modifiers
& Mod5Mask
)
2927 /* put the modifiers together with the key name */
2928 sprintf(text
, "%s%s%s%s%s%s%s%s<Key>%s",
2929 shiftStr
, lockStr
, ctrlStr
, altStr
,
2930 mod2Str
, mod3Str
, mod4Str
, mod5Str
,
2931 XKeysymToString(keysym
));
2935 ** Read an accelerator name and put it into the form of a modifier mask
2936 ** and a KeySym code. Returns false if string can't be read
2937 ** ... does not handle whitespace in string (look at scanf)
2939 static int parseAcceleratorString(const char *string
, unsigned int *modifiers
,
2942 int i
, nFields
, inputLength
= strlen(string
);
2943 char fields
[10][MAX_ACCEL_LEN
];
2945 /* a blank field means no accelerator */
2946 if (inputLength
== 0) {
2952 /* limit the string length so no field strings will overflow */
2953 if (inputLength
> MAX_ACCEL_LEN
)
2956 /* divide the input into '+' separated fields */
2957 nFields
= sscanf(string
, "%[^+]+%[^+]+%[^+]+%[^+]+%[^+]+%[^+]+%[^+]+%[^+]+%[^+]+%[^+]",
2958 fields
[0], fields
[1], fields
[2], fields
[3], fields
[4], fields
[5],
2959 fields
[6], fields
[7], fields
[8], fields
[9]);
2963 /* get the key name from the last field and translate it to a keysym.
2964 If the name is capitalized, try it lowercase as well, since some
2965 of the keysyms are "prettied up" by generateAcceleratorString */
2966 *keysym
= XStringToKeysym(fields
[nFields
-1]);
2967 if (*keysym
== NoSymbol
) {
2968 *fields
[nFields
-1] = tolower(*fields
[nFields
-1]);
2969 *keysym
= XStringToKeysym(fields
[nFields
-1]);
2970 if (*keysym
== NoSymbol
)
2974 /* parse the modifier names from the rest of the fields */
2976 for (i
=0; i
<nFields
-1; i
++) {
2977 if (!strcmp(fields
[i
], "Shift"))
2978 *modifiers
|= ShiftMask
;
2979 else if (!strcmp(fields
[i
], "Lock"))
2980 *modifiers
|= LockMask
;
2981 else if (!strcmp(fields
[i
], "Ctrl"))
2982 *modifiers
|= ControlMask
;
2983 /* comparision with "Alt" for compatibility with old .nedit files*/
2984 else if (!strcmp(fields
[i
], "Alt"))
2985 *modifiers
|= Mod1Mask
;
2986 else if (!strcmp(fields
[i
], "Mod2"))
2987 *modifiers
|= Mod2Mask
;
2988 else if (!strcmp(fields
[i
], "Mod3"))
2989 *modifiers
|= Mod3Mask
;
2990 else if (!strcmp(fields
[i
], "Mod4"))
2991 *modifiers
|= Mod4Mask
;
2992 else if (!strcmp(fields
[i
], "Mod5"))
2993 *modifiers
|= Mod5Mask
;
2998 /* all fields successfully parsed */
3003 ** Scan text from "*inPtr" to the end of macro input (matching brace),
3004 ** advancing inPtr, and return macro text as function return value.
3006 ** This is kind of wastefull in that it throws away the compiled macro,
3007 ** to be re-generated from the text as needed, but compile time is
3008 ** negligible for most macros.
3010 static char *copyMacroToEnd(char **inPtr
)
3012 char *retStr
, *errMsg
, *stoppedAt
, *p
, *retPtr
;
3015 /* Skip over whitespace to find make sure there's a beginning brace
3016 to anchor the parse (if not, it will take the whole file) */
3017 *inPtr
+= strspn(*inPtr
, " \t\n");
3018 if (**inPtr
!= '{') {
3019 ParseError(NULL
, *inPtr
, *inPtr
-1, "macro menu item", "expecting '{'");
3023 /* Parse the input */
3024 prog
= ParseMacro(*inPtr
, &errMsg
, &stoppedAt
);
3026 ParseError(NULL
, *inPtr
, stoppedAt
, "macro menu item", errMsg
);
3031 /* Copy and return the body of the macro, stripping outer braces and
3032 extra leading tabs added by the writer routine */
3034 *inPtr
+= strspn(*inPtr
, " \t");
3035 if (**inPtr
== '\n') (*inPtr
)++;
3036 if (**inPtr
== '\t') (*inPtr
)++;
3037 if (**inPtr
== '\t') (*inPtr
)++;
3038 retPtr
= retStr
= XtMalloc(stoppedAt
- *inPtr
+ 1);
3039 for (p
= *inPtr
; p
< stoppedAt
- 1; p
++) {
3040 if (!strncmp(p
, "\n\t\t", 3)) {
3046 if (*(retPtr
-1) == '\t') retPtr
--;
3053 ** If "*string" is not terminated with a newline character, reallocate the
3054 ** string and add one. (The macro language requires newline terminators for
3055 ** statements, but the text widget doesn't force it like the NEdit text buffer
3056 ** does, so this might avoid some confusion.)
3058 static void addTerminatingNewline(char **string
)
3063 length
= strlen(*string
);
3064 if ((*string
)[length
-1] != '\n') {
3065 newString
= XtMalloc(length
+ 2);
3066 strcpy(newString
, *string
);
3067 newString
[length
] = '\n';
3068 newString
[length
+1] = '\0';
3070 *string
= newString
;
3075 ** Cache user menus:
3076 ** allocate an empty user (shell, macro) menu cache structure
3078 UserMenuCache
*CreateUserMenuCache(void)
3080 /* allocate some memory for the new data structure */
3081 UserMenuCache
*cache
= (UserMenuCache
*)XtMalloc(sizeof(UserMenuCache
));
3083 cache
->umcLanguageMode
= -2;
3084 cache
->umcShellMenuCreated
= False
;
3085 cache
->umcMacroMenuCreated
= False
;
3086 cache
->umcShellMenuList
.umlNbrItems
= 0;
3087 cache
->umcShellMenuList
.umlItems
= NULL
;
3088 cache
->umcMacroMenuList
.umlNbrItems
= 0;
3089 cache
->umcMacroMenuList
.umlItems
= NULL
;
3094 void FreeUserMenuCache(UserMenuCache
*cache
)
3096 freeUserMenuList(&cache
->umcShellMenuList
);
3097 freeUserMenuList(&cache
->umcMacroMenuList
);
3099 XtFree((char *)cache
);
3103 ** Cache user menus:
3104 ** init. a user background menu cache structure
3106 void InitUserBGMenuCache(UserBGMenuCache
*cache
)
3108 cache
->ubmcLanguageMode
= -2;
3109 cache
->ubmcMenuCreated
= False
;
3110 cache
->ubmcMenuList
.umlNbrItems
= 0;
3111 cache
->ubmcMenuList
.umlItems
= NULL
;
3114 void FreeUserBGMenuCache(UserBGMenuCache
*cache
)
3116 freeUserMenuList(&cache
->ubmcMenuList
);
3120 ** Cache user menus:
3121 ** Parse given menu item list and setup a user menu info list for
3122 ** management of user menu.
3124 static void parseMenuItemList(menuItemRec
**itemList
, int nbrOfItems
,
3125 userMenuInfo
**infoList
, userSubMenuCache
*subMenus
)
3130 /* Allocate storage for structures to keep track of sub-menus */
3131 allocSubMenuCache(subMenus
, nbrOfItems
);
3133 /* 1st pass: setup user menu info: extract language modes, menu name &
3134 default indication; build user menu ID */
3135 for (i
=0; i
<nbrOfItems
; i
++) {
3136 infoList
[i
] = parseMenuItemRec(itemList
[i
]);
3137 generateUserMenuId(infoList
[i
], subMenus
);
3140 /* 2nd pass: solve "default" dependencies */
3141 for (i
=0; i
<nbrOfItems
; i
++) {
3144 /* If the user menu item is a default one, then scan the list for
3145 items with the same name and a language mode specified.
3146 If one is found, then set the default index to the index of the
3147 current default item. */
3148 if (info
->umiIsDefault
) {
3149 setDefaultIndex(infoList
, nbrOfItems
, i
);
3155 ** Returns the sub-menu depth (i.e. nesting level) of given
3158 static int getSubMenuDepth(const char *menuName
)
3163 /* determine sub-menu depth by counting '>' of given "menuName" */
3165 while ((subSep
= strchr(subSep
, '>')) != NULL
) {
3174 ** Cache user menus:
3175 ** Parse a singe menu item. Allocate & setup a user menu info element
3176 ** holding extracted info.
3178 static userMenuInfo
*parseMenuItemRec(menuItemRec
*item
)
3180 userMenuInfo
*newInfo
;
3184 /* allocate a new user menu info element */
3185 newInfo
= (userMenuInfo
*)XtMalloc(sizeof(userMenuInfo
));
3187 /* determine sub-menu depth and allocate some memory
3188 for hierarchical ID; init. ID with {0,.., 0} */
3189 newInfo
->umiName
= stripLanguageMode(item
->name
);
3191 subMenuDepth
= getSubMenuDepth(newInfo
->umiName
);
3192 idSize
= sizeof(int)*(subMenuDepth
+1);
3194 newInfo
->umiId
= (int *)XtMalloc(idSize
);
3195 memset(newInfo
->umiId
,0,idSize
);
3197 /* init. remaining parts of user menu info element */
3198 newInfo
->umiIdLen
= 0;
3199 newInfo
->umiIsDefault
= False
;
3200 newInfo
->umiNbrOfLanguageModes
= 0;
3201 newInfo
->umiLanguageMode
= NULL
;
3202 newInfo
->umiDefaultIndex
= -1;
3203 newInfo
->umiToBeManaged
= False
;
3205 /* assign language mode info to new user menu info element */
3206 parseMenuItemName(item
->name
, newInfo
);
3212 ** Cache user menus:
3213 ** Extract language mode related info out of given menu item name string.
3214 ** Store this info in given user menu info structure.
3216 static void parseMenuItemName(char *menuItemName
, userMenuInfo
*info
)
3218 char *atPtr
, *firstAtPtr
, *endPtr
;
3221 int langModes
[MAX_LANGUAGE_MODES
];
3225 atPtr
= firstAtPtr
= strchr(menuItemName
, '@');
3226 if (atPtr
!= NULL
) {
3227 if (!strcmp(atPtr
+1, "*")) {
3228 /* only language is "*": this is for all but language specific
3230 info
->umiIsDefault
= True
;
3234 /* setup a list of all language modes related to given menu item */
3235 while (atPtr
!= NULL
) {
3236 /* extract language mode name after "@" sign */
3237 for(endPtr
=atPtr
+1; isalnum((unsigned char)*endPtr
) || *endPtr
=='_' ||
3238 *endPtr
=='-' || *endPtr
==' ' || *endPtr
=='+' || *endPtr
=='$' ||
3239 *endPtr
=='#'; endPtr
++);
3241 /* lookup corresponding language mode index; if PLAIN is
3242 returned then this means, that language mode name after
3243 "@" is unknown (i.e. not defined) */
3246 languageMode
= FindLanguageMode(atPtr
+1);
3247 if (languageMode
== PLAIN_LANGUAGE_MODE
) {
3248 langModes
[nbrLM
] = UNKNOWN_LANGUAGE_MODE
;
3250 langModes
[nbrLM
] = languageMode
;
3255 /* look for next "@" */
3256 atPtr
= strchr(endPtr
, '@');
3260 info
->umiNbrOfLanguageModes
= nbrLM
;
3261 size
= sizeof(int)*nbrLM
;
3262 info
->umiLanguageMode
= (int *)XtMalloc(size
);
3263 memcpy(info
->umiLanguageMode
, langModes
, size
);
3269 ** Cache user menus:
3270 ** generates an ID (= array of integers) of given user menu info, which
3271 ** allows to find the user menu item within the menu tree later on: 1st
3272 ** integer of ID indicates position within main menu; 2nd integer indicates
3273 ** position within 1st sub-menu etc.
3275 static void generateUserMenuId(userMenuInfo
*info
, userSubMenuCache
*subMenus
)
3278 char *hierName
, *subSep
;
3279 int subMenuDepth
= 0;
3280 int *menuIdx
= &subMenus
->usmcNbrOfMainMenuItems
;
3281 userSubMenuInfo
*curSubMenu
;
3283 /* find sub-menus, stripping off '>' until item name is
3285 subSep
= info
->umiName
;
3286 while ((subSep
= strchr(subSep
, '>')) != NULL
) {
3287 hierName
= copySubstring(info
->umiName
, subSep
- info
->umiName
);
3288 curSubMenu
= findSubMenuInfo(subMenus
, hierName
);
3289 if (curSubMenu
== NULL
) {
3290 /* sub-menu info not stored before: new sub-menu;
3291 remember its hierarchical position */
3292 info
->umiId
[subMenuDepth
] = *menuIdx
;
3295 /* store sub-menu info in list of subMenus; allocate
3296 some memory for hierarchical ID of sub-menu & take over
3297 current hierarchical ID of current user menu info */
3298 curSubMenu
= &subMenus
->usmcInfo
[subMenus
->usmcNbrOfSubMenus
];
3299 subMenus
->usmcNbrOfSubMenus
++;
3300 curSubMenu
->usmiName
= hierName
;
3301 idSize
= sizeof(int)*(subMenuDepth
+2);
3302 curSubMenu
->usmiId
= (int *)XtMalloc(idSize
);
3303 memcpy(curSubMenu
->usmiId
, info
->umiId
, idSize
);
3304 curSubMenu
->usmiIdLen
= subMenuDepth
+1;
3306 /* sub-menu info already stored before: takeover its
3307 hierarchical position */
3309 info
->umiId
[subMenuDepth
] = curSubMenu
->usmiId
[subMenuDepth
];
3313 menuIdx
= &curSubMenu
->usmiId
[subMenuDepth
];
3318 /* remember position of menu item within final (sub) menu */
3319 info
->umiId
[subMenuDepth
] = *menuIdx
;
3320 info
->umiIdLen
= subMenuDepth
+ 1;
3325 ** Cache user menus:
3326 ** Find info corresponding to a hierarchical menu name (a>b>c...)
3328 static userSubMenuInfo
*findSubMenuInfo(userSubMenuCache
*subMenus
,
3329 const char *hierName
)
3333 for (i
=0; i
<subMenus
->usmcNbrOfSubMenus
; i
++)
3334 if (!strcmp(hierName
, subMenus
->usmcInfo
[i
].usmiName
))
3335 return &subMenus
->usmcInfo
[i
];
3340 ** Cache user menus:
3341 ** Returns an allocated copy of menuItemName stripped of language mode
3342 ** parts (i.e. parts starting with "@").
3344 static char *stripLanguageMode(const char *menuItemName
)
3348 firstAtPtr
= strchr(menuItemName
, '@');
3349 if (firstAtPtr
== NULL
)
3350 return XtNewString(menuItemName
);
3352 return copySubstring(menuItemName
, firstAtPtr
-menuItemName
);
3355 static void setDefaultIndex(userMenuInfo
**infoList
, int nbrOfItems
,
3358 char *defaultMenuName
= infoList
[defaultIdx
]->umiName
;
3362 /* Scan the list for items with the same name and a language mode
3363 specified. If one is found, then set the default index to the
3364 index of the current default item. */
3365 for (i
=0; i
<nbrOfItems
; i
++) {
3368 if (!info
->umiIsDefault
&& strcmp(info
->umiName
, defaultMenuName
)==0) {
3369 info
->umiDefaultIndex
= defaultIdx
;
3375 ** Determine the info list menu items, which need to be managed
3376 ** for given language mode. Set / reset "to be managed" indication
3377 ** of info list items accordingly.
3379 static void applyLangModeToUserMenuInfo(userMenuInfo
**infoList
, int nbrOfItems
,
3385 /* 1st pass: mark all items as "to be managed", which are applicable
3386 for all language modes or which are indicated as "default" items */
3387 for (i
=0; i
<nbrOfItems
; i
++) {
3390 info
->umiToBeManaged
=
3391 (info
->umiNbrOfLanguageModes
== 0 || info
->umiIsDefault
);
3394 /* 2nd pass: mark language mode specific items matching given language
3395 mode as "to be managed". Reset "to be managed" indications of
3396 "default" items, if applicable */
3397 for (i
=0; i
<nbrOfItems
; i
++) {
3400 if (info
->umiNbrOfLanguageModes
!= 0) {
3401 if (doesLanguageModeMatch(info
, languageMode
)) {
3402 info
->umiToBeManaged
= True
;
3404 if (info
->umiDefaultIndex
!= -1)
3405 infoList
[info
->umiDefaultIndex
]->umiToBeManaged
= False
;
3412 ** Returns true, if given user menu info is applicable for given language mode
3414 static int doesLanguageModeMatch(userMenuInfo
*info
, int languageMode
)
3418 for (i
=0; i
<info
->umiNbrOfLanguageModes
; i
++) {
3419 if (info
->umiLanguageMode
[i
] == languageMode
)
3426 static void freeUserMenuInfoList(userMenuInfo
**infoList
, int nbrOfItems
)
3430 for (i
=0; i
<nbrOfItems
; i
++) {
3431 freeUserMenuInfo(infoList
[i
]);
3435 static void freeUserMenuInfo(userMenuInfo
*info
)
3437 XtFree(info
->umiName
);
3439 XtFree((char *)info
->umiId
);
3441 if (info
->umiNbrOfLanguageModes
!= 0)
3442 XtFree((char *)info
->umiLanguageMode
);
3444 XtFree((char *)info
);
3448 ** Cache user menus:
3449 ** Allocate & init. storage for structures to manage sub-menus
3451 static void allocSubMenuCache(userSubMenuCache
*subMenus
, int nbrOfItems
)
3453 int size
= sizeof(userSubMenuInfo
) * nbrOfItems
;
3455 subMenus
->usmcNbrOfMainMenuItems
= 0;
3456 subMenus
->usmcNbrOfSubMenus
= 0;
3457 subMenus
->usmcInfo
= (userSubMenuInfo
*)XtMalloc(size
);
3460 static void freeSubMenuCache(userSubMenuCache
*subMenus
)
3464 for (i
=0; i
<subMenus
->usmcNbrOfSubMenus
; i
++) {
3465 XtFree(subMenus
->usmcInfo
[i
].usmiName
);
3466 XtFree((char *)subMenus
->usmcInfo
[i
].usmiId
);
3469 XtFree((char *)subMenus
->usmcInfo
);
3472 static void allocUserMenuList(UserMenuList
*list
, int nbrOfItems
)
3474 int size
= sizeof(UserMenuListElement
*) * nbrOfItems
;
3476 list
->umlNbrItems
= 0;
3477 list
->umlItems
= (UserMenuListElement
**)XtMalloc(size
);
3480 static void freeUserMenuList(UserMenuList
*list
)
3484 for (i
=0; i
<list
->umlNbrItems
; i
++)
3485 freeUserMenuListElement(list
->umlItems
[i
]);
3487 list
->umlNbrItems
= 0;
3489 XtFree((char*) list
->umlItems
);
3490 list
->umlItems
= NULL
;
3493 static UserMenuListElement
*allocUserMenuListElement(Widget menuItem
, char *accKeys
)
3495 UserMenuListElement
*element
;
3497 element
= (UserMenuListElement
*)XtMalloc(sizeof(UserMenuListElement
));
3499 element
->umleManageMode
= UMMM_UNMANAGE
;
3500 element
->umlePrevManageMode
= UMMM_UNMANAGE
;
3501 element
->umleAccKeys
= accKeys
;
3502 element
->umleAccLockPatchApplied
= False
;
3503 element
->umleMenuItem
= menuItem
;
3504 element
->umleSubMenuPane
= NULL
;
3505 element
->umleSubMenuList
= NULL
;
3510 static void freeUserMenuListElement(UserMenuListElement
*element
)
3512 if (element
->umleSubMenuList
!= NULL
)
3513 freeUserSubMenuList(element
->umleSubMenuList
);
3515 XtFree(element
->umleAccKeys
);
3516 XtFree((char *)element
);
3519 static UserMenuList
*allocUserSubMenuList(int nbrOfItems
)
3523 list
= (UserMenuList
*)XtMalloc(sizeof(UserMenuList
));
3525 allocUserMenuList(list
, nbrOfItems
);
3530 static void freeUserSubMenuList(UserMenuList
*list
)
3532 freeUserMenuList(list
);
3534 XtFree((char *)list
);