1 static const char CVSID
[] = "$Id: userCmds.c,v 1.46 2004/06/09 17:52:58 edg 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 *
13 * This software is distributed in the hope that it will be useful, but WITHOUT *
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or *
15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License *
18 * You should have received a copy of the GNU General Public License along with *
19 * software; if not, write to the Free Software Foundation, Inc., 59 Temple *
20 * Place, Suite 330, Boston, MA 02111-1307 USA *
22 * Nirvana Text Editor *
25 * Written by Mark Edel *
27 *******************************************************************************/
30 #include "../config.h"
37 #include "preferences.h"
43 #include "interpret.h"
45 #include "../util/DialogF.h"
46 #include "../util/misc.h"
47 #include "../util/managedList.h"
54 #include "../util/VMSparam.h"
57 #include <sys/param.h>
62 #include <X11/keysym.h>
63 #include <X11/IntrinsicP.h>
67 #include <Xm/LabelG.h>
69 #include <Xm/ToggleB.h>
70 #include <Xm/SelectioB.h>
71 #include <Xm/RowColumn.h>
72 #include <Xm/CascadeB.h>
73 #include <Xm/MenuShell.h>
80 #define MENU_WIDGET(w) (XmGetPostedFromWidget(XtParent(w)))
82 #define MENU_WIDGET(w) (w)
85 extern void _XmDismissTearOff(Widget w
, XtPointer call
, XtPointer x
);
87 /* max. number of user programmable menu commands allowed per each of the
88 macro, shell, and background menus */
89 #define MAX_ITEMS_PER_MENU 400
91 /* indicates, that an unknown (i.e. not existing) language mode
92 is bound to an user menu item */
93 #define UNKNOWN_LANGUAGE_MODE -2
95 /* major divisions (in position units) in User Commands dialogs */
96 #define LEFT_MARGIN_POS 1
97 #define RIGHT_MARGIN_POS 99
99 #define SHELL_CMD_TOP 70
100 #define MACRO_CMD_TOP 40
102 /* types of current dialog and/or menu */
103 enum dialogTypes
{SHELL_CMDS
, MACRO_CMDS
, BG_MENU_CMDS
};
105 /* Structure representing a menu item for shell, macro and BG menus*/
108 unsigned int modifiers
;
119 /* Structure for widgets and flags associated with shell command,
120 macro command and BG command editing dialogs */
124 Widget nameTextW
, accTextW
, mneTextW
, cmdTextW
, saveFirstBtn
;
125 Widget loadAfterBtn
, selInpBtn
, winInpBtn
, eitherInpBtn
, noInpBtn
;
126 Widget repInpBtn
, sameOutBtn
, dlogOutBtn
, winOutBtn
, dlogShell
;
128 menuItemRec
**menuItemsList
;
132 /* Structure for keeping track of hierarchical sub-menus during user-menu
139 /* Structure holding hierarchical info about one sub-menu.
141 Suppose following user menu items:
143 b.) "subMenuA>menuItemA1"
144 c.) "subMenuA>menuItemA2"
145 d.) "subMenuA>subMenuB>menuItemB1"
146 e.) "subMenuA>subMenuB>menuItemB2"
148 Structure of this user menu is:
150 Main Menu Name Sub-Menu A Name Sub-Menu B Name
151 element nbr. element nbr. element nbr.
153 1 subMenuA --+-> 0 menuItemA1
155 +-> 2 subMenuB --+-> 0 menuItemB1
158 Above example holds 2 sub-menus:
159 1.) "subMenuA" (hierarchical ID = {1} means: element nbr. "1" of main menu)
160 2.) "subMenuA>subMenuB" (hierarchical ID = {1, 2} means: el. nbr. "2" of
161 "subMenuA", which itself is el. nbr. "0" of main menu) */
163 char *usmiName
; /* hierarchical name of sub-menu */
164 int *usmiId
; /* hierarchical ID of sub-menu */
165 int usmiIdLen
; /* length of hierarchical ID */
168 /* Holds info about sub-menu structure of an user menu */
170 int usmcNbrOfMainMenuItems
; /* number of main menu items */
171 int usmcNbrOfSubMenus
; /* number of sub-menus */
172 userSubMenuInfo
*usmcInfo
; /* list of sub-menu info */
175 /* Structure holding info about a single menu item.
176 According to above example there exist 5 user menu items:
177 a.) "menuItem1" (hierarchical ID = {0} means: element nbr. "0" of main menu)
178 b.) "menuItemA1" (hierarchical ID = {1, 0} means: el. nbr. "0" of
179 "subMenuA", which itself is el. nbr. "1" of main menu)
180 c.) "menuItemA2" (hierarchical ID = {1, 1})
181 d.) "menuItemB1" (hierarchical ID = {1, 2, 0})
182 e.) "menuItemB2" (hierarchical ID = {1, 2, 1})
185 char *umiName
; /* hierarchical name of menu item
186 (w.o. language mode info) */
187 int *umiId
; /* hierarchical ID of menu item */
188 int umiIdLen
; /* length of hierarchical ID */
189 Boolean umiIsDefault
; /* menu item is default one ("@*") */
190 int umiNbrOfLanguageModes
; /* number of language modes
191 applicable for this menu item */
192 int *umiLanguageMode
; /* list of applicable lang. modes */
193 int umiDefaultIndex
; /* array index of menu item to be
194 used as default, if no lang. mode
196 Boolean umiToBeManaged
; /* indicates, that menu item needs
200 /* Structure holding info about a selected user menu (shell, macro or
203 int sumType
; /* type of menu (shell, macro or
205 Widget sumMenuPane
; /* pane of main menu */
206 int sumNbrOfListItems
; /* number of menu items */
207 menuItemRec
**sumItemList
; /* list of menu items */
208 userMenuInfo
**sumInfoList
; /* list of infos about menu items */
209 userSubMenuCache
*sumSubMenus
; /* info about sub-menu structure */
210 UserMenuList
*sumMainMenuList
; /* cached info about main menu */
211 Boolean
*sumMenuCreated
; /* pointer to "menu created"
215 /* Descriptions of the current user programmed menu items for re-generating
216 menus and processing shell, macro, and background menu selections */
217 static menuItemRec
*ShellMenuItems
[MAX_ITEMS_PER_MENU
];
218 static userMenuInfo
*ShellMenuInfo
[MAX_ITEMS_PER_MENU
];
219 static userSubMenuCache ShellSubMenus
;
220 static int NShellMenuItems
= 0;
221 static menuItemRec
*MacroMenuItems
[MAX_ITEMS_PER_MENU
];
222 static userMenuInfo
*MacroMenuInfo
[MAX_ITEMS_PER_MENU
];
223 static userSubMenuCache MacroSubMenus
;
224 static int NMacroMenuItems
= 0;
225 static menuItemRec
*BGMenuItems
[MAX_ITEMS_PER_MENU
];
226 static userMenuInfo
*BGMenuInfo
[MAX_ITEMS_PER_MENU
];
227 static userSubMenuCache BGSubMenus
;
228 static int NBGMenuItems
= 0;
230 /* Top level shells of the user-defined menu editing dialogs */
231 static Widget ShellCmdDialog
= NULL
;
232 static Widget MacroCmdDialog
= NULL
;
233 static Widget BGMenuCmdDialog
= NULL
;
235 /* Paste learn/replay sequence buttons in user defined menu editing dialogs
236 (for dimming and undimming externally when replay macro is available) */
237 static Widget MacroPasteReplayBtn
= NULL
;
238 static Widget BGMenuPasteReplayBtn
= NULL
;
240 static void editMacroOrBGMenu(WindowInfo
*window
, int dialogType
);
241 static void dimSelDepItemsInMenu(Widget menuPane
, menuItemRec
**menuList
,
242 int nMenuItems
, int sensitive
);
243 static void rebuildMenuOfAllWindows(int menuType
);
244 static void rebuildMenu(WindowInfo
*window
, int menuType
);
245 static Widget
findInMenuTree(menuTreeItem
*menuTree
, int nTreeEntries
,
246 const char *hierName
);
247 static char *copySubstring(const char *string
, int length
);
248 static Widget
createUserMenuItem(Widget menuPane
, char *name
, menuItemRec
*f
,
249 int index
, XtCallbackProc cbRtn
, XtPointer cbArg
);
250 static Widget
createUserSubMenu(Widget parent
, char *label
, Widget
*menuItem
);
251 static void deleteMenuItems(Widget menuPane
);
252 static void selectUserMenu(WindowInfo
*window
, int menuType
, selectedUserMenu
*menu
);
253 static void updateMenu(WindowInfo
*window
, int menuType
);
254 static void manageTearOffMenu(Widget menuPane
);
255 static void resetManageMode(UserMenuList
*list
);
256 static void manageAllSubMenuWidgets(UserMenuListElement
*subMenu
);
257 static void unmanageAllSubMenuWidgets(UserMenuListElement
*subMenu
);
258 static void manageMenuWidgets(UserMenuList
*list
);
259 static void removeAccelFromMenuWidgets(UserMenuList
*menuList
);
260 static void assignAccelToMenuWidgets(UserMenuList
*menuList
, WindowInfo
*window
);
261 static void manageUserMenu(selectedUserMenu
*menu
, WindowInfo
*window
);
262 static void createMenuItems(WindowInfo
*window
, selectedUserMenu
*menu
);
263 static void okCB(Widget w
, XtPointer clientData
, XtPointer callData
);
264 static void applyCB(Widget w
, XtPointer clientData
, XtPointer callData
);
265 static void checkCB(Widget w
, XtPointer clientData
, XtPointer callData
);
266 static int checkMacro(userCmdDialog
*ucd
);
267 static int checkMacroText(char *macro
, Widget errorParent
, Widget errFocus
);
268 static int applyDialogChanges(userCmdDialog
*ucd
);
269 static void dismissCB(Widget w
, XtPointer clientData
, XtPointer callData
);
270 static void pasteReplayCB(Widget w
, XtPointer clientData
, XtPointer callData
);
271 static void destroyCB(Widget w
, XtPointer clientData
, XtPointer callData
);
272 static void accKeyCB(Widget w
, XtPointer clientData
, XKeyEvent
*event
);
273 static void sameOutCB(Widget w
, XtPointer clientData
, XtPointer callData
);
274 static void shellMenuCB(Widget w
, WindowInfo
*window
, XtPointer callData
);
275 static void macroMenuCB(Widget w
, WindowInfo
*window
, XtPointer callData
);
276 static void bgMenuCB(Widget w
, WindowInfo
*window
, XtPointer callData
) ;
277 static void accFocusCB(Widget w
, XtPointer clientData
, XtPointer callData
);
278 static void accLoseFocusCB(Widget w
, XtPointer clientData
,
280 static void updateDialogFields(menuItemRec
*f
, userCmdDialog
*ucd
);
281 static menuItemRec
*readDialogFields(userCmdDialog
*ucd
, int silent
);
282 static menuItemRec
*copyMenuItemRec(menuItemRec
*item
);
283 static void freeMenuItemRec(menuItemRec
*item
);
284 static void *getDialogDataCB(void *oldItem
, int explicitRequest
, int *abort
,
286 static void setDialogDataCB(void *item
, void *cbArg
);
287 static void freeItemCB(void *item
);
288 static int dialogFieldsAreEmpty(userCmdDialog
*ucd
);
289 static void disableTextW(Widget textW
);
290 static char *writeMenuItemString(menuItemRec
**menuItems
, int nItems
,
292 static int loadMenuItemString(char *inString
, menuItemRec
**menuItems
,
293 int *nItems
, int listType
);
294 static void generateAcceleratorString(char *text
, unsigned int modifiers
,
296 static void genAccelEventName(char *text
, unsigned int modifiers
,
298 static int parseAcceleratorString(const char *string
, unsigned int *modifiers
,
300 static int parseError(const char *message
);
301 static char *copyMacroToEnd(char **inPtr
);
302 static void addTerminatingNewline(char **string
);
303 static void parseMenuItemList(menuItemRec
**itemList
, int nbrOfItems
,
304 userMenuInfo
**infoList
, userSubMenuCache
*subMenus
);
305 static int getSubMenuDepth(const char *menuName
);
306 static userMenuInfo
*parseMenuItemRec(menuItemRec
*item
);
307 static void parseMenuItemName(char *menuItemName
, userMenuInfo
*info
);
308 static void generateUserMenuId(userMenuInfo
*info
, userSubMenuCache
*subMenus
);
309 static userSubMenuInfo
*findSubMenuInfo(userSubMenuCache
*subMenus
,
310 const char *hierName
);
311 static char *stripLanguageMode(const char *menuItemName
);
312 static void setDefaultIndex(userMenuInfo
**infoList
, int nbrOfItems
,
314 static void applyLangModeToUserMenuInfo(userMenuInfo
**infoList
, int nbrOfItems
,
316 static int doesLanguageModeMatch(userMenuInfo
*info
, int languageMode
);
317 static void freeUserMenuInfoList(userMenuInfo
**infoList
, int nbrOfItems
);
318 static void freeUserMenuInfo(userMenuInfo
*info
);
319 static void allocSubMenuCache(userSubMenuCache
*subMenus
, int nbrOfItems
);
320 static void freeSubMenuCache(userSubMenuCache
*subMenus
);
321 static void allocUserMenuList(UserMenuList
*list
, int nbrOfItems
);
322 static void freeUserMenuList(UserMenuList
*list
);
323 static UserMenuListElement
*allocUserMenuListElement(Widget menuItem
, char *accKeys
);
324 static void freeUserMenuListElement(UserMenuListElement
*element
);
325 static UserMenuList
*allocUserSubMenuList(int nbrOfItems
);
326 static void freeUserSubMenuList(UserMenuList
*list
);
329 ** Present a dialog for editing the user specified commands in the shell menu
331 void EditShellMenu(WindowInfo
*window
)
333 Widget form
, accLabel
, inpLabel
, inpBox
, outBox
, outLabel
;
334 Widget nameLabel
, cmdLabel
, okBtn
, applyBtn
, dismissBtn
;
340 /* if the dialog is already displayed, just pop it to the top and return */
341 if (ShellCmdDialog
!= NULL
) {
342 RaiseShellWindow(ShellCmdDialog
);
346 /* Create a structure for keeping track of dialog state */
347 ucd
= (userCmdDialog
*)XtMalloc(sizeof(userCmdDialog
));
348 ucd
->window
= window
;
350 /* Set the dialog to operate on the Shell menu */
351 ucd
->menuItemsList
= (menuItemRec
**)XtMalloc(sizeof(menuItemRec
*) *
353 for (i
=0; i
<NShellMenuItems
; i
++)
354 ucd
->menuItemsList
[i
] = copyMenuItemRec(ShellMenuItems
[i
]);
355 ucd
->nMenuItems
= NShellMenuItems
;
356 ucd
->dialogType
= SHELL_CMDS
;
359 XtSetArg(args
[ac
], XmNdeleteResponse
, XmDO_NOTHING
); ac
++;
360 XtSetArg(args
[ac
], XmNiconName
, "NEdit Shell Menu"); ac
++;
361 XtSetArg(args
[ac
], XmNtitle
, "Shell Menu"); ac
++;
362 ucd
->dlogShell
= CreateWidget(TheAppShell
, "shellCommands",
363 topLevelShellWidgetClass
, args
, ac
);
364 AddSmallIcon(ucd
->dlogShell
);
365 form
= XtVaCreateManagedWidget("editShellCommands", xmFormWidgetClass
,
366 ucd
->dlogShell
, XmNautoUnmanage
, False
,
367 XmNresizePolicy
, XmRESIZE_NONE
, NULL
);
368 ShellCmdDialog
= ucd
->dlogShell
;
369 XtAddCallback(form
, XmNdestroyCallback
, destroyCB
, ucd
);
370 AddMotifCloseCallback(ucd
->dlogShell
, dismissCB
, ucd
);
373 XtSetArg(args
[ac
], XmNtopAttachment
, XmATTACH_POSITION
); ac
++;
374 XtSetArg(args
[ac
], XmNtopPosition
, 2); ac
++;
375 XtSetArg(args
[ac
], XmNleftAttachment
, XmATTACH_POSITION
); ac
++;
376 XtSetArg(args
[ac
], XmNleftPosition
, LEFT_MARGIN_POS
); ac
++;
377 XtSetArg(args
[ac
], XmNrightAttachment
, XmATTACH_POSITION
); ac
++;
378 XtSetArg(args
[ac
], XmNrightPosition
, LIST_RIGHT
-1); ac
++;
379 XtSetArg(args
[ac
], XmNbottomAttachment
, XmATTACH_POSITION
); ac
++;
380 XtSetArg(args
[ac
], XmNbottomPosition
, SHELL_CMD_TOP
); ac
++;
381 ucd
->managedList
= CreateManagedList(form
, "list", args
, ac
,
382 (void **)ucd
->menuItemsList
, &ucd
->nMenuItems
, MAX_ITEMS_PER_MENU
,
383 20, getDialogDataCB
, ucd
, setDialogDataCB
, ucd
, freeItemCB
);
385 ucd
->loadAfterBtn
= XtVaCreateManagedWidget("loadAfterBtn",
386 xmToggleButtonWidgetClass
, form
,
387 XmNlabelString
, s1
=MKSTRING("Re-load file after executing command"),
389 XmNalignment
, XmALIGNMENT_BEGINNING
,
391 XmNleftAttachment
, XmATTACH_POSITION
,
392 XmNleftPosition
, LIST_RIGHT
,
393 XmNrightAttachment
, XmATTACH_POSITION
,
394 XmNrightPosition
, RIGHT_MARGIN_POS
,
395 XmNbottomAttachment
, XmATTACH_POSITION
,
396 XmNbottomPosition
, SHELL_CMD_TOP
, NULL
);
398 ucd
->saveFirstBtn
= XtVaCreateManagedWidget("saveFirstBtn",
399 xmToggleButtonWidgetClass
, form
,
400 XmNlabelString
, s1
=MKSTRING("Save file before executing command"),
402 XmNalignment
, XmALIGNMENT_BEGINNING
,
404 XmNleftAttachment
, XmATTACH_POSITION
,
405 XmNleftPosition
, LIST_RIGHT
,
406 XmNrightAttachment
, XmATTACH_POSITION
,
407 XmNrightPosition
, RIGHT_MARGIN_POS
,
408 XmNbottomAttachment
, XmATTACH_WIDGET
,
409 XmNbottomWidget
, ucd
->loadAfterBtn
, NULL
);
411 ucd
->repInpBtn
= XtVaCreateManagedWidget("repInpBtn",
412 xmToggleButtonWidgetClass
, form
,
413 XmNlabelString
, s1
=MKSTRING("Output replaces input"),
415 XmNalignment
, XmALIGNMENT_BEGINNING
,
417 XmNleftAttachment
, XmATTACH_POSITION
,
418 XmNleftPosition
, LIST_RIGHT
,
419 XmNrightAttachment
, XmATTACH_POSITION
,
420 XmNrightPosition
, RIGHT_MARGIN_POS
,
421 XmNbottomAttachment
, XmATTACH_WIDGET
,
422 XmNbottomWidget
, ucd
->saveFirstBtn
, NULL
);
424 outBox
= XtVaCreateManagedWidget("outBox", xmRowColumnWidgetClass
, form
,
425 XmNpacking
, XmPACK_TIGHT
,
426 XmNorientation
, XmHORIZONTAL
,
427 XmNradioBehavior
, True
,
428 XmNradioAlwaysOne
, True
,
429 XmNleftAttachment
, XmATTACH_POSITION
,
430 XmNleftPosition
, LIST_RIGHT
+ 2,
431 XmNrightAttachment
, XmATTACH_POSITION
,
432 XmNrightPosition
, RIGHT_MARGIN_POS
,
433 XmNbottomAttachment
, XmATTACH_WIDGET
,
434 XmNbottomWidget
, ucd
->repInpBtn
,
435 XmNbottomOffset
, 4, NULL
);
436 ucd
->sameOutBtn
= XtVaCreateManagedWidget("sameOutBtn",
437 xmToggleButtonWidgetClass
, outBox
,
438 XmNlabelString
, s1
=MKSTRING("same window"),
440 XmNalignment
, XmALIGNMENT_BEGINNING
,
444 XtAddCallback(ucd
->sameOutBtn
, XmNvalueChangedCallback
, sameOutCB
, ucd
);
445 ucd
->dlogOutBtn
= XtVaCreateManagedWidget("dlogOutBtn",
446 xmToggleButtonWidgetClass
, outBox
,
447 XmNlabelString
, s1
=MKSTRING("dialog"),
449 XmNalignment
, XmALIGNMENT_BEGINNING
,
451 XmNset
, False
, NULL
);
453 ucd
->winOutBtn
= XtVaCreateManagedWidget("winOutBtn", xmToggleButtonWidgetClass
,
455 XmNlabelString
, s1
=MKSTRING("new window"),
457 XmNalignment
, XmALIGNMENT_BEGINNING
,
459 XmNset
, False
, NULL
);
461 outLabel
= XtVaCreateManagedWidget("outLabel", xmLabelGadgetClass
, form
,
462 XmNlabelString
, s1
=MKSTRING("Command Output:"),
463 XmNalignment
, XmALIGNMENT_BEGINNING
,
465 XmNleftAttachment
, XmATTACH_POSITION
,
466 XmNleftPosition
, LIST_RIGHT
,
467 XmNrightAttachment
, XmATTACH_POSITION
,
468 XmNrightPosition
, RIGHT_MARGIN_POS
,
469 XmNbottomAttachment
, XmATTACH_WIDGET
,
470 XmNbottomWidget
, outBox
, NULL
);
473 inpBox
= XtVaCreateManagedWidget("inpBox", xmRowColumnWidgetClass
, form
,
474 XmNpacking
, XmPACK_TIGHT
,
475 XmNorientation
, XmHORIZONTAL
,
476 XmNradioBehavior
, True
,
477 XmNradioAlwaysOne
, True
,
478 XmNleftAttachment
, XmATTACH_POSITION
,
479 XmNleftPosition
, LIST_RIGHT
+ 2,
480 XmNrightAttachment
, XmATTACH_POSITION
,
481 XmNrightPosition
, RIGHT_MARGIN_POS
,
482 XmNbottomAttachment
, XmATTACH_WIDGET
,
483 XmNbottomWidget
, outLabel
, NULL
);
484 ucd
->selInpBtn
= XtVaCreateManagedWidget("selInpBtn", xmToggleButtonWidgetClass
,
486 XmNlabelString
, s1
=MKSTRING("selection"),
488 XmNalignment
, XmALIGNMENT_BEGINNING
,
492 ucd
->winInpBtn
= XtVaCreateManagedWidget("winInpBtn",
493 xmToggleButtonWidgetClass
, inpBox
,
494 XmNlabelString
, s1
=MKSTRING("window"),
496 XmNalignment
, XmALIGNMENT_BEGINNING
,
498 XmNset
, False
, NULL
);
500 ucd
->eitherInpBtn
= XtVaCreateManagedWidget("eitherInpBtn",
501 xmToggleButtonWidgetClass
, inpBox
,
502 XmNlabelString
, s1
=MKSTRING("either"),
504 XmNalignment
, XmALIGNMENT_BEGINNING
,
506 XmNset
, False
, NULL
);
508 ucd
->noInpBtn
= XtVaCreateManagedWidget("noInpBtn",
509 xmToggleButtonWidgetClass
, inpBox
,
510 XmNlabelString
, s1
=MKSTRING("none"),
512 XmNalignment
, XmALIGNMENT_BEGINNING
,
514 XmNset
, False
, NULL
);
516 inpLabel
= XtVaCreateManagedWidget("inpLabel", xmLabelGadgetClass
, form
,
517 XmNlabelString
, s1
=MKSTRING("Command Input:"),
518 XmNalignment
, XmALIGNMENT_BEGINNING
,
520 XmNleftAttachment
, XmATTACH_POSITION
,
521 XmNleftPosition
, LIST_RIGHT
,
522 XmNrightAttachment
, XmATTACH_POSITION
,
523 XmNrightPosition
, RIGHT_MARGIN_POS
,
524 XmNbottomAttachment
, XmATTACH_WIDGET
,
525 XmNbottomWidget
, inpBox
, NULL
);
528 ucd
->mneTextW
= XtVaCreateManagedWidget("mne", xmTextWidgetClass
, form
,
531 XmNleftAttachment
, XmATTACH_POSITION
,
532 XmNleftPosition
, RIGHT_MARGIN_POS
-10,
533 XmNrightAttachment
, XmATTACH_POSITION
,
534 XmNrightPosition
, RIGHT_MARGIN_POS
,
535 XmNbottomAttachment
, XmATTACH_WIDGET
,
536 XmNbottomWidget
, inpLabel
, NULL
);
537 RemapDeleteKey(ucd
->mneTextW
);
539 ucd
->accTextW
= XtVaCreateManagedWidget("acc", xmTextWidgetClass
, form
,
541 XmNmaxLength
, MAX_ACCEL_LEN
-1,
542 XmNcursorPositionVisible
, False
,
543 XmNleftAttachment
, XmATTACH_POSITION
,
544 XmNleftPosition
, LIST_RIGHT
,
545 XmNrightAttachment
, XmATTACH_POSITION
,
546 XmNrightPosition
, RIGHT_MARGIN_POS
-15,
547 XmNbottomAttachment
, XmATTACH_WIDGET
,
548 XmNbottomWidget
, inpLabel
, NULL
);
549 XtAddEventHandler(ucd
->accTextW
, KeyPressMask
, False
,
550 (XtEventHandler
)accKeyCB
, ucd
);
551 XtAddCallback(ucd
->accTextW
, XmNfocusCallback
, accFocusCB
, ucd
);
552 XtAddCallback(ucd
->accTextW
, XmNlosingFocusCallback
, accLoseFocusCB
, ucd
);
553 accLabel
= XtVaCreateManagedWidget("accLabel", xmLabelGadgetClass
, form
,
554 XmNlabelString
, s1
=MKSTRING("Accelerator"),
556 XmNuserData
, ucd
->accTextW
,
557 XmNalignment
, XmALIGNMENT_BEGINNING
,
559 XmNleftAttachment
, XmATTACH_POSITION
,
560 XmNleftPosition
, LIST_RIGHT
,
561 XmNrightAttachment
, XmATTACH_POSITION
,
562 XmNrightPosition
, LIST_RIGHT
+ 24,
563 XmNbottomAttachment
, XmATTACH_WIDGET
,
564 XmNbottomWidget
, ucd
->mneTextW
, NULL
);
567 XtVaCreateManagedWidget("mneLabel", xmLabelGadgetClass
, form
,
568 XmNlabelString
, s1
=MKSTRING("Mnemonic"),
570 XmNuserData
, ucd
->mneTextW
,
571 XmNalignment
, XmALIGNMENT_END
,
573 XmNleftAttachment
, XmATTACH_POSITION
,
574 XmNleftPosition
, LIST_RIGHT
+ 24,
575 XmNrightAttachment
, XmATTACH_POSITION
,
576 XmNrightPosition
, RIGHT_MARGIN_POS
,
577 XmNbottomAttachment
, XmATTACH_WIDGET
,
578 XmNbottomWidget
, ucd
->mneTextW
, NULL
);
581 ucd
->nameTextW
= XtVaCreateManagedWidget("name", xmTextWidgetClass
, form
,
582 XmNleftAttachment
, XmATTACH_POSITION
,
583 XmNleftPosition
, LIST_RIGHT
,
584 XmNrightAttachment
, XmATTACH_POSITION
,
585 XmNrightPosition
, RIGHT_MARGIN_POS
,
586 XmNbottomAttachment
, XmATTACH_WIDGET
,
587 XmNbottomWidget
, accLabel
, NULL
);
588 RemapDeleteKey(ucd
->nameTextW
);
590 nameLabel
= XtVaCreateManagedWidget("nameLabel", xmLabelGadgetClass
, form
,
591 XmNlabelString
, s1
=MKSTRING("Menu Entry"),
593 XmNuserData
, ucd
->nameTextW
,
594 XmNalignment
, XmALIGNMENT_BEGINNING
,
596 XmNleftAttachment
, XmATTACH_POSITION
,
597 XmNleftPosition
, LIST_RIGHT
,
598 XmNbottomAttachment
, XmATTACH_WIDGET
,
599 XmNbottomWidget
, ucd
->nameTextW
, NULL
);
602 XtVaCreateManagedWidget("nameNotes", xmLabelGadgetClass
, form
,
603 XmNlabelString
, s1
=MKSTRING("(> for sub-menu, @ language mode)"),
604 XmNalignment
, XmALIGNMENT_END
,
606 XmNleftAttachment
, XmATTACH_WIDGET
,
607 XmNleftWidget
, nameLabel
,
608 XmNrightAttachment
, XmATTACH_POSITION
,
609 XmNrightPosition
, RIGHT_MARGIN_POS
,
610 XmNbottomAttachment
, XmATTACH_WIDGET
,
611 XmNbottomWidget
, ucd
->nameTextW
, NULL
);
614 XtVaCreateManagedWidget("topLabel", xmLabelGadgetClass
, form
,
615 XmNlabelString
, s1
=MKSTRING(
616 "Select a shell menu item from the list at left.\n\
617 Select \"New\" to add a new command to the menu."),
618 XmNtopAttachment
, XmATTACH_POSITION
,
620 XmNleftAttachment
, XmATTACH_POSITION
,
621 XmNleftPosition
, LIST_RIGHT
,
622 XmNrightAttachment
, XmATTACH_POSITION
,
623 XmNrightPosition
, RIGHT_MARGIN_POS
,
624 XmNbottomAttachment
, XmATTACH_WIDGET
,
625 XmNbottomWidget
, nameLabel
, NULL
);
628 cmdLabel
= XtVaCreateManagedWidget("cmdLabel", xmLabelGadgetClass
, form
,
629 XmNlabelString
, s1
=MKSTRING("Shell Command to Execute"),
631 XmNalignment
, XmALIGNMENT_BEGINNING
,
633 XmNtopAttachment
, XmATTACH_POSITION
,
634 XmNtopPosition
, SHELL_CMD_TOP
,
635 XmNleftAttachment
, XmATTACH_POSITION
,
636 XmNleftPosition
, LEFT_MARGIN_POS
, NULL
);
638 XtVaCreateManagedWidget("cmdLabel", xmLabelGadgetClass
, form
,
639 XmNlabelString
, s1
=MKSTRING("(% expands to current filename, # to line number)"),
640 XmNalignment
, XmALIGNMENT_END
,
642 XmNtopAttachment
, XmATTACH_POSITION
,
643 XmNtopPosition
, SHELL_CMD_TOP
,
644 XmNleftAttachment
, XmATTACH_WIDGET
,
645 XmNleftWidget
, cmdLabel
,
646 XmNrightAttachment
, XmATTACH_POSITION
,
647 XmNrightPosition
, RIGHT_MARGIN_POS
, NULL
);
650 okBtn
= XtVaCreateManagedWidget("ok",xmPushButtonWidgetClass
,form
,
651 XmNlabelString
, s1
=MKSTRING("OK"),
652 XmNleftAttachment
, XmATTACH_POSITION
,
654 XmNrightAttachment
, XmATTACH_POSITION
,
655 XmNrightPosition
, 29,
656 XmNbottomAttachment
, XmATTACH_POSITION
,
657 XmNbottomPosition
, 99, NULL
);
658 XtAddCallback(okBtn
, XmNactivateCallback
, okCB
, ucd
);
661 applyBtn
= XtVaCreateManagedWidget("apply",xmPushButtonWidgetClass
,form
,
662 XmNlabelString
, s1
=MKSTRING("Apply"),
664 XmNleftAttachment
, XmATTACH_POSITION
,
666 XmNrightAttachment
, XmATTACH_POSITION
,
667 XmNrightPosition
, 58,
668 XmNbottomAttachment
, XmATTACH_POSITION
,
669 XmNbottomPosition
, 99, NULL
);
670 XtAddCallback(applyBtn
, XmNactivateCallback
, applyCB
, ucd
);
673 dismissBtn
= XtVaCreateManagedWidget("dismiss",xmPushButtonWidgetClass
,form
,
674 XmNlabelString
, s1
=MKSTRING("Dismiss"),
675 XmNleftAttachment
, XmATTACH_POSITION
,
677 XmNrightAttachment
, XmATTACH_POSITION
,
678 XmNrightPosition
, 87,
679 XmNbottomAttachment
, XmATTACH_POSITION
,
680 XmNbottomPosition
, 99, NULL
);
681 XtAddCallback(dismissBtn
, XmNactivateCallback
, dismissCB
, ucd
);
685 XtSetArg(args
[ac
], XmNeditMode
, XmMULTI_LINE_EDIT
); ac
++;
686 XtSetArg(args
[ac
], XmNscrollHorizontal
, False
); ac
++;
687 XtSetArg(args
[ac
], XmNwordWrap
, True
); ac
++;
688 XtSetArg(args
[ac
], XmNtopAttachment
, XmATTACH_WIDGET
); ac
++;
689 XtSetArg(args
[ac
], XmNtopWidget
, cmdLabel
); ac
++;
690 XtSetArg(args
[ac
], XmNleftAttachment
, XmATTACH_POSITION
); ac
++;
691 XtSetArg(args
[ac
], XmNleftPosition
, LEFT_MARGIN_POS
); ac
++;
692 XtSetArg(args
[ac
], XmNrightAttachment
, XmATTACH_POSITION
); ac
++;
693 XtSetArg(args
[ac
], XmNrightPosition
, RIGHT_MARGIN_POS
); ac
++;
694 XtSetArg(args
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
695 XtSetArg(args
[ac
], XmNbottomWidget
, okBtn
); ac
++;
696 XtSetArg(args
[ac
], XmNbottomOffset
, 5); ac
++;
697 ucd
->cmdTextW
= XmCreateScrolledText(form
, "name", args
, ac
);
698 AddMouseWheelSupport(ucd
->cmdTextW
);
699 XtManageChild(ucd
->cmdTextW
);
700 MakeSingleLineTextW(ucd
->cmdTextW
);
701 RemapDeleteKey(ucd
->cmdTextW
);
702 XtVaSetValues(cmdLabel
, XmNuserData
, ucd
->cmdTextW
, NULL
); /* for mnemonic */
704 /* Disable text input for the accelerator key widget, let the
705 event handler manage it instead */
706 disableTextW(ucd
->accTextW
);
708 /* initializs the dialog fields to match "New" list item */
709 updateDialogFields(NULL
, ucd
);
711 /* Set initial default button */
712 XtVaSetValues(form
, XmNdefaultButton
, okBtn
, NULL
);
713 XtVaSetValues(form
, XmNcancelButton
, dismissBtn
, NULL
);
715 /* Handle mnemonic selection of buttons and focus to dialog */
716 AddDialogMnemonicHandler(form
, FALSE
);
718 /* realize all of the widgets in the new window */
719 RealizeWithoutForcingPosition(ucd
->dlogShell
);
723 ** Present a dialogs for editing the user specified commands in the Macro
724 ** and background menus
726 void EditMacroMenu(WindowInfo
*window
)
728 editMacroOrBGMenu(window
, MACRO_CMDS
);
730 void EditBGMenu(WindowInfo
*window
)
732 editMacroOrBGMenu(window
, BG_MENU_CMDS
);
735 static void editMacroOrBGMenu(WindowInfo
*window
, int dialogType
)
737 Widget form
, accLabel
, pasteReplayBtn
;
738 Widget nameLabel
, cmdLabel
, okBtn
, applyBtn
, dismissBtn
;
745 /* if the dialog is already displayed, just pop it to the top and return */
746 if (dialogType
== MACRO_CMDS
&& MacroCmdDialog
!= NULL
) {
747 RaiseShellWindow(MacroCmdDialog
);
750 if (dialogType
== BG_MENU_CMDS
&& BGMenuCmdDialog
!= NULL
) {
751 RaiseShellWindow(BGMenuCmdDialog
);
755 /* Create a structure for keeping track of dialog state */
756 ucd
= (userCmdDialog
*)XtMalloc(sizeof(userCmdDialog
));
757 ucd
->window
= window
;
759 /* Set the dialog to operate on the Macro menu */
760 ucd
->menuItemsList
= (menuItemRec
**)XtMalloc(sizeof(menuItemRec
**) *
762 if (dialogType
== MACRO_CMDS
) {
763 for (i
=0; i
<NMacroMenuItems
; i
++)
764 ucd
->menuItemsList
[i
] = copyMenuItemRec(MacroMenuItems
[i
]);
765 ucd
->nMenuItems
= NMacroMenuItems
;
766 } else { /* BG_MENU_CMDS */
767 for (i
=0; i
<NBGMenuItems
; i
++)
768 ucd
->menuItemsList
[i
] = copyMenuItemRec(BGMenuItems
[i
]);
769 ucd
->nMenuItems
= NBGMenuItems
;
771 ucd
->dialogType
= dialogType
;
773 title
= dialogType
== MACRO_CMDS
? "Macro Commands" :
774 "Window Background Menu";
776 XtSetArg(args
[ac
], XmNdeleteResponse
, XmDO_NOTHING
); ac
++;
777 XtSetArg(args
[ac
], XmNiconName
, title
); ac
++;
778 XtSetArg(args
[ac
], XmNtitle
, title
); ac
++;
779 ucd
->dlogShell
= CreateWidget(TheAppShell
, "macros",
780 topLevelShellWidgetClass
, args
, ac
);
781 AddSmallIcon(ucd
->dlogShell
);
782 form
= XtVaCreateManagedWidget("editMacroCommands", xmFormWidgetClass
,
783 ucd
->dlogShell
, XmNautoUnmanage
, False
,
784 XmNresizePolicy
, XmRESIZE_NONE
, NULL
);
785 XtAddCallback(form
, XmNdestroyCallback
, destroyCB
, ucd
);
786 AddMotifCloseCallback(ucd
->dlogShell
, dismissCB
, ucd
);
789 XtSetArg(args
[ac
], XmNtopAttachment
, XmATTACH_POSITION
); ac
++;
790 XtSetArg(args
[ac
], XmNtopPosition
, 2); ac
++;
791 XtSetArg(args
[ac
], XmNleftAttachment
, XmATTACH_POSITION
); ac
++;
792 XtSetArg(args
[ac
], XmNleftPosition
, LEFT_MARGIN_POS
); ac
++;
793 XtSetArg(args
[ac
], XmNrightAttachment
, XmATTACH_POSITION
); ac
++;
794 XtSetArg(args
[ac
], XmNrightPosition
, LIST_RIGHT
-1); ac
++;
795 XtSetArg(args
[ac
], XmNbottomAttachment
, XmATTACH_POSITION
); ac
++;
796 XtSetArg(args
[ac
], XmNbottomPosition
, MACRO_CMD_TOP
); ac
++;
797 ucd
->managedList
= CreateManagedList(form
, "list", args
, ac
,
798 (void **)ucd
->menuItemsList
, &ucd
->nMenuItems
, MAX_ITEMS_PER_MENU
, 20,
799 getDialogDataCB
, ucd
, setDialogDataCB
, ucd
, freeItemCB
);
801 ucd
->selInpBtn
= XtVaCreateManagedWidget("selInpBtn",
802 xmToggleButtonWidgetClass
, form
,
803 XmNlabelString
, s1
=MKSTRING("Requires Selection"),
805 XmNalignment
, XmALIGNMENT_BEGINNING
,
808 XmNleftAttachment
, XmATTACH_POSITION
,
809 XmNleftPosition
, LIST_RIGHT
,
810 XmNbottomAttachment
, XmATTACH_POSITION
,
811 XmNbottomPosition
, MACRO_CMD_TOP
, NULL
);
814 ucd
->mneTextW
= XtVaCreateManagedWidget("mne", xmTextWidgetClass
, form
,
817 XmNleftAttachment
, XmATTACH_POSITION
,
818 XmNleftPosition
, RIGHT_MARGIN_POS
-21-5,
819 XmNrightAttachment
, XmATTACH_POSITION
,
820 XmNrightPosition
, RIGHT_MARGIN_POS
-21,
821 XmNbottomAttachment
, XmATTACH_WIDGET
,
822 XmNbottomWidget
, ucd
->selInpBtn
,
823 XmNbottomOffset
, 5, NULL
);
824 RemapDeleteKey(ucd
->mneTextW
);
826 ucd
->accTextW
= XtVaCreateManagedWidget("acc", xmTextWidgetClass
, form
,
828 XmNmaxLength
, MAX_ACCEL_LEN
-1,
829 XmNcursorPositionVisible
, False
,
830 XmNleftAttachment
, XmATTACH_POSITION
,
831 XmNleftPosition
, LIST_RIGHT
,
832 XmNrightAttachment
, XmATTACH_POSITION
,
833 XmNrightPosition
, RIGHT_MARGIN_POS
-20-10,
834 XmNbottomAttachment
, XmATTACH_WIDGET
,
835 XmNbottomWidget
, ucd
->selInpBtn
,
836 XmNbottomOffset
, 5, NULL
);
837 XtAddEventHandler(ucd
->accTextW
, KeyPressMask
, False
,
838 (XtEventHandler
)accKeyCB
, ucd
);
839 XtAddCallback(ucd
->accTextW
, XmNfocusCallback
, accFocusCB
, ucd
);
840 XtAddCallback(ucd
->accTextW
, XmNlosingFocusCallback
, accLoseFocusCB
, ucd
);
842 accLabel
= XtVaCreateManagedWidget("accLabel", xmLabelGadgetClass
, form
,
843 XmNlabelString
, s1
=MKSTRING("Accelerator"),
845 XmNuserData
, ucd
->accTextW
,
846 XmNalignment
, XmALIGNMENT_BEGINNING
,
848 XmNleftAttachment
, XmATTACH_POSITION
,
849 XmNleftPosition
, LIST_RIGHT
,
850 XmNrightAttachment
, XmATTACH_POSITION
,
851 XmNrightPosition
, LIST_RIGHT
+ 22,
852 XmNbottomAttachment
, XmATTACH_WIDGET
,
853 XmNbottomWidget
, ucd
->mneTextW
, NULL
);
856 XtVaCreateManagedWidget("mneLabel", xmLabelGadgetClass
, form
,
857 XmNlabelString
, s1
=MKSTRING("Mnemonic"),
859 XmNuserData
, ucd
->mneTextW
,
860 XmNalignment
, XmALIGNMENT_END
,
862 XmNleftAttachment
, XmATTACH_POSITION
,
863 XmNleftPosition
, LIST_RIGHT
+ 22,
864 XmNrightAttachment
, XmATTACH_POSITION
,
865 XmNrightPosition
, RIGHT_MARGIN_POS
-21,
866 XmNbottomAttachment
, XmATTACH_WIDGET
,
867 XmNbottomWidget
, ucd
->mneTextW
, NULL
);
870 pasteReplayBtn
= XtVaCreateManagedWidget("pasteReplay",
871 xmPushButtonWidgetClass
, form
,
872 XmNlabelString
, s1
=MKSTRING("Paste Learn/\nReplay Macro"),
874 XmNsensitive
, GetReplayMacro() != NULL
,
875 XmNleftAttachment
, XmATTACH_POSITION
,
876 XmNleftPosition
, RIGHT_MARGIN_POS
-20,
877 XmNrightAttachment
, XmATTACH_POSITION
,
878 XmNrightPosition
, RIGHT_MARGIN_POS
,
879 XmNbottomAttachment
, XmATTACH_POSITION
,
880 XmNbottomPosition
, MACRO_CMD_TOP
, NULL
);
881 XtAddCallback(pasteReplayBtn
, XmNactivateCallback
,
885 ucd
->nameTextW
= XtVaCreateManagedWidget("name", xmTextWidgetClass
, form
,
886 XmNleftAttachment
, XmATTACH_POSITION
,
887 XmNleftPosition
, LIST_RIGHT
,
888 XmNrightAttachment
, XmATTACH_POSITION
,
889 XmNrightPosition
, RIGHT_MARGIN_POS
,
890 XmNbottomAttachment
, XmATTACH_WIDGET
,
891 XmNbottomWidget
, accLabel
, NULL
);
892 RemapDeleteKey(ucd
->nameTextW
);
894 nameLabel
= XtVaCreateManagedWidget("nameLabel", xmLabelGadgetClass
, form
,
895 XmNlabelString
, s1
=MKSTRING("Menu Entry"),
897 XmNuserData
, ucd
->nameTextW
,
898 XmNalignment
, XmALIGNMENT_BEGINNING
,
900 XmNleftAttachment
, XmATTACH_POSITION
,
901 XmNleftPosition
, LIST_RIGHT
,
902 XmNbottomAttachment
, XmATTACH_WIDGET
,
903 XmNbottomWidget
, ucd
->nameTextW
, NULL
);
906 XtVaCreateManagedWidget("nameNotes", xmLabelGadgetClass
, form
,
907 XmNlabelString
, s1
=MKSTRING("(> for sub-menu, @ language mode)"),
908 XmNalignment
, XmALIGNMENT_END
,
910 XmNleftAttachment
, XmATTACH_WIDGET
,
911 XmNleftWidget
, nameLabel
,
912 XmNrightAttachment
, XmATTACH_POSITION
,
913 XmNrightPosition
, RIGHT_MARGIN_POS
,
914 XmNbottomAttachment
, XmATTACH_WIDGET
,
915 XmNbottomWidget
, ucd
->nameTextW
, NULL
);
918 XtVaCreateManagedWidget("topLabel", xmLabelGadgetClass
, form
,
919 XmNlabelString
, s1
=MKSTRING(
920 "Select a macro menu item from the list at left.\n\
921 Select \"New\" to add a new command to the menu."),
922 XmNtopAttachment
, XmATTACH_POSITION
,
924 XmNleftAttachment
, XmATTACH_POSITION
,
925 XmNleftPosition
, LIST_RIGHT
,
926 XmNrightAttachment
, XmATTACH_POSITION
,
927 XmNrightPosition
, RIGHT_MARGIN_POS
,
928 XmNbottomAttachment
, XmATTACH_WIDGET
,
929 XmNbottomWidget
, nameLabel
, NULL
);
932 cmdLabel
= XtVaCreateManagedWidget("cmdLabel", xmLabelGadgetClass
, form
,
933 XmNlabelString
, s1
=MKSTRING("Macro Command to Execute"),
935 XmNalignment
, XmALIGNMENT_BEGINNING
,
937 XmNtopAttachment
, XmATTACH_POSITION
,
938 XmNtopPosition
, MACRO_CMD_TOP
,
939 XmNleftAttachment
, XmATTACH_POSITION
,
940 XmNleftPosition
, LEFT_MARGIN_POS
, NULL
);
943 okBtn
= XtVaCreateManagedWidget("ok",xmPushButtonWidgetClass
,form
,
944 XmNlabelString
, s1
=MKSTRING("OK"),
945 XmNleftAttachment
, XmATTACH_POSITION
,
947 XmNrightAttachment
, XmATTACH_POSITION
,
948 XmNrightPosition
, 23,
949 XmNbottomAttachment
, XmATTACH_POSITION
,
950 XmNbottomPosition
, 99, NULL
);
951 XtAddCallback(okBtn
, XmNactivateCallback
, okCB
, ucd
);
954 applyBtn
= XtVaCreateManagedWidget("apply",xmPushButtonWidgetClass
,form
,
955 XmNlabelString
, s1
=MKSTRING("Apply"),
957 XmNleftAttachment
, XmATTACH_POSITION
,
959 XmNrightAttachment
, XmATTACH_POSITION
,
960 XmNrightPosition
, 46,
961 XmNbottomAttachment
, XmATTACH_POSITION
,
962 XmNbottomPosition
, 99, NULL
);
963 XtAddCallback(applyBtn
, XmNactivateCallback
, applyCB
, ucd
);
966 applyBtn
= XtVaCreateManagedWidget("check",xmPushButtonWidgetClass
,form
,
967 XmNlabelString
, s1
=MKSTRING("Check"),
969 XmNleftAttachment
, XmATTACH_POSITION
,
971 XmNrightAttachment
, XmATTACH_POSITION
,
972 XmNrightPosition
, 69,
973 XmNbottomAttachment
, XmATTACH_POSITION
,
974 XmNbottomPosition
, 99, NULL
);
975 XtAddCallback(applyBtn
, XmNactivateCallback
, checkCB
, ucd
);
978 dismissBtn
= XtVaCreateManagedWidget("dismiss",xmPushButtonWidgetClass
,form
,
979 XmNlabelString
, s1
=MKSTRING("Dismiss"),
980 XmNleftAttachment
, XmATTACH_POSITION
,
982 XmNrightAttachment
, XmATTACH_POSITION
,
983 XmNrightPosition
, 92,
984 XmNbottomAttachment
, XmATTACH_POSITION
,
985 XmNbottomPosition
, 99, NULL
);
986 XtAddCallback(dismissBtn
, XmNactivateCallback
, dismissCB
, ucd
);
990 XtSetArg(args
[ac
], XmNeditMode
, XmMULTI_LINE_EDIT
); ac
++;
991 XtSetArg(args
[ac
], XmNtopAttachment
, XmATTACH_WIDGET
); ac
++;
992 XtSetArg(args
[ac
], XmNtopWidget
, cmdLabel
); ac
++;
993 XtSetArg(args
[ac
], XmNleftAttachment
, XmATTACH_POSITION
); ac
++;
994 XtSetArg(args
[ac
], XmNleftPosition
, LEFT_MARGIN_POS
); ac
++;
995 XtSetArg(args
[ac
], XmNrightAttachment
, XmATTACH_POSITION
); ac
++;
996 XtSetArg(args
[ac
], XmNrightPosition
, RIGHT_MARGIN_POS
); ac
++;
997 XtSetArg(args
[ac
], XmNbottomAttachment
, XmATTACH_WIDGET
); ac
++;
998 XtSetArg(args
[ac
], XmNbottomWidget
, okBtn
); ac
++;
999 XtSetArg(args
[ac
], XmNbottomOffset
, 5); ac
++;
1000 ucd
->cmdTextW
= XmCreateScrolledText(form
, "name", args
, ac
);
1001 AddMouseWheelSupport(ucd
->cmdTextW
);
1002 XtManageChild(ucd
->cmdTextW
);
1003 RemapDeleteKey(ucd
->cmdTextW
);
1004 XtVaSetValues(cmdLabel
, XmNuserData
, ucd
->cmdTextW
, NULL
); /* for mnemonic */
1006 /* Disable text input for the accelerator key widget, let the
1007 event handler manage it instead */
1008 disableTextW(ucd
->accTextW
);
1010 /* initializs the dialog fields to match "New" list item */
1011 updateDialogFields(NULL
, ucd
);
1013 /* Set initial default button */
1014 XtVaSetValues(form
, XmNdefaultButton
, okBtn
, NULL
);
1015 XtVaSetValues(form
, XmNcancelButton
, dismissBtn
, NULL
);
1017 /* Handle mnemonic selection of buttons and focus to dialog */
1018 AddDialogMnemonicHandler(form
, FALSE
);
1020 /* Make widgets for top level shell and paste-replay buttons available
1021 to other functions */
1022 if (dialogType
== MACRO_CMDS
) {
1023 MacroCmdDialog
= ucd
->dlogShell
;
1024 MacroPasteReplayBtn
= pasteReplayBtn
;
1026 BGMenuCmdDialog
= ucd
->dlogShell
;
1027 BGMenuPasteReplayBtn
= pasteReplayBtn
;
1030 /* Realize all of the widgets in the new dialog */
1031 RealizeWithoutForcingPosition(ucd
->dlogShell
);
1035 ** Update the Shell, Macro, and Window Background menus of window
1036 ** "window" from the currently loaded command descriptions.
1038 void UpdateUserMenus(WindowInfo
*window
)
1040 if (!IsTopDocument(window
))
1043 /* update user menus, which are shared over all documents, only
1044 if language mode was changed */
1045 if (window
->userMenuCache
->umcLanguageMode
!= window
->languageMode
) {
1047 updateMenu(window
, SHELL_CMDS
);
1049 updateMenu(window
, MACRO_CMDS
);
1051 /* remember language mode assigned to shared user menus */
1052 window
->userMenuCache
->umcLanguageMode
= window
->languageMode
;
1055 /* update background menu, which is owned by a single document, only
1056 if language mode was changed */
1057 if (window
->userBGMenuCache
.ubmcLanguageMode
!= window
->languageMode
) {
1058 updateMenu(window
, BG_MENU_CMDS
);
1060 /* remember language mode assigned to background menu */
1061 window
->userBGMenuCache
.ubmcLanguageMode
= window
->languageMode
;
1066 ** Dim/undim buttons for pasting replay macros into macro and bg menu dialogs
1068 void DimPasteReplayBtns(int sensitive
)
1070 if (MacroCmdDialog
!= NULL
)
1071 XtSetSensitive(MacroPasteReplayBtn
, sensitive
);
1072 if (BGMenuCmdDialog
!= NULL
)
1073 XtSetSensitive(BGMenuPasteReplayBtn
, sensitive
);
1077 ** Dim/undim user programmable menu items which depend on there being
1078 ** a selection in their associated window.
1080 void DimSelectionDepUserMenuItems(WindowInfo
*window
, int sensitive
)
1082 if (!IsTopDocument(window
))
1086 dimSelDepItemsInMenu(window
->shellMenuPane
, ShellMenuItems
,
1087 NShellMenuItems
, sensitive
);
1089 dimSelDepItemsInMenu(window
->macroMenuPane
, MacroMenuItems
,
1090 NMacroMenuItems
, sensitive
);
1091 dimSelDepItemsInMenu(window
->bgMenuPane
, BGMenuItems
,
1092 NBGMenuItems
, sensitive
);
1095 static void dimSelDepItemsInMenu(Widget menuPane
, menuItemRec
**menuList
,
1096 int nMenuItems
, int sensitive
)
1104 XtVaGetValues(menuPane
, XmNchildren
, &items
, XmNnumChildren
, &nItems
, NULL
);
1105 for (n
=0; n
<(int)nItems
; n
++) {
1106 XtVaGetValues(items
[n
], XmNuserData
, &userData
, NULL
);
1107 if (userData
!= (XtPointer
)PERMANENT_MENU_ITEM
) {
1108 if (XtClass(items
[n
]) == xmCascadeButtonWidgetClass
) {
1109 XtVaGetValues(items
[n
], XmNsubMenuId
, &subMenu
, NULL
);
1110 dimSelDepItemsInMenu(subMenu
, menuList
, nMenuItems
, sensitive
);
1112 index
= (int)userData
- 10;
1113 if (index
<0 || index
>= nMenuItems
)
1115 if (menuList
[index
]->input
== FROM_SELECTION
)
1116 XtSetSensitive(items
[n
], sensitive
);
1123 ** Harmless kludge for making undo/redo menu items in background menu properly
1124 ** sensitive (even though they're programmable) along with real undo item
1127 void SetBGMenuUndoSensitivity(WindowInfo
*window
, int sensitive
)
1129 if (window
->bgMenuUndoItem
!= NULL
)
1130 SetSensitive(window
, window
->bgMenuUndoItem
, sensitive
);
1132 void SetBGMenuRedoSensitivity(WindowInfo
*window
, int sensitive
)
1134 if (window
->bgMenuRedoItem
!= NULL
)
1135 SetSensitive(window
, window
->bgMenuRedoItem
, sensitive
);
1139 ** Generate a text string for the preferences file describing the contents
1140 ** of the shell cmd list. This string is not exactly of the form that it
1141 ** can be read by LoadShellCmdsString, rather, it is what needs to be written
1142 ** to a resource file such that it will read back in that form.
1144 char *WriteShellCmdsString(void)
1146 return writeMenuItemString(ShellMenuItems
, NShellMenuItems
,
1151 ** Generate a text string for the preferences file describing the contents of
1152 ** the macro menu and background menu commands lists. These strings are not
1153 ** exactly of the form that it can be read by LoadMacroCmdsString, rather, it
1154 ** is what needs to be written to a resource file such that it will read back
1157 char *WriteMacroCmdsString(void)
1159 return writeMenuItemString(MacroMenuItems
, NMacroMenuItems
, MACRO_CMDS
);
1162 char *WriteBGMenuCmdsString(void)
1164 return writeMenuItemString(BGMenuItems
, NBGMenuItems
, BG_MENU_CMDS
);
1168 ** Read a string representing shell command menu items and add them to the
1169 ** internal list used for constructing shell menus
1171 int LoadShellCmdsString(char *inString
)
1173 return loadMenuItemString(inString
, ShellMenuItems
, &NShellMenuItems
,
1178 ** Read strings representing macro menu or background menu command menu items
1179 ** and add them to the internal lists used for constructing menus
1181 int LoadMacroCmdsString(char *inString
)
1183 return loadMenuItemString(inString
, MacroMenuItems
, &NMacroMenuItems
,
1187 int LoadBGMenuCmdsString(char *inString
)
1189 return loadMenuItemString(inString
, BGMenuItems
, &NBGMenuItems
,
1194 ** Cache user menus:
1195 ** Setup user menu info after read of macro, shell and background menu
1196 ** string (reason: language mode info from preference string is read *after*
1197 ** user menu preference string was read).
1199 void SetupUserMenuInfo()
1201 parseMenuItemList(ShellMenuItems
, NShellMenuItems
, ShellMenuInfo
, &ShellSubMenus
);
1202 parseMenuItemList(MacroMenuItems
, NMacroMenuItems
, MacroMenuInfo
, &MacroSubMenus
);
1203 parseMenuItemList(BGMenuItems
, NBGMenuItems
, BGMenuInfo
, &BGSubMenus
);
1207 ** Search through the shell menu and execute the first command with menu item
1208 ** name "itemName". Returns True on successs and False on failure.
1211 int DoNamedShellMenuCmd(WindowInfo
*window
, const char *itemName
, int fromMacro
)
1215 for (i
=0; i
<NShellMenuItems
; i
++) {
1216 if (!strcmp(ShellMenuItems
[i
]->name
, itemName
)) {
1217 if (ShellMenuItems
[i
]->output
== TO_SAME_WINDOW
&&
1218 CheckReadOnly(window
))
1220 DoShellMenuCmd(window
, ShellMenuItems
[i
]->cmd
,
1221 ShellMenuItems
[i
]->input
, ShellMenuItems
[i
]->output
,
1222 ShellMenuItems
[i
]->repInput
, ShellMenuItems
[i
]->saveFirst
,
1223 ShellMenuItems
[i
]->loadAfter
, fromMacro
);
1232 ** Search through the Macro or background menu and execute the first command
1233 ** with menu item name "itemName". Returns True on successs and False on
1236 int DoNamedMacroMenuCmd(WindowInfo
*window
, const char *itemName
)
1240 for (i
=0; i
<NMacroMenuItems
; i
++) {
1241 if (!strcmp(MacroMenuItems
[i
]->name
, itemName
)) {
1242 DoMacro(window
, MacroMenuItems
[i
]->cmd
, "macro menu command");
1249 int DoNamedBGMenuCmd(WindowInfo
*window
, const char *itemName
)
1253 for (i
=0; i
<NBGMenuItems
; i
++) {
1254 if (!strcmp(BGMenuItems
[i
]->name
, itemName
)) {
1255 DoMacro(window
, BGMenuItems
[i
]->cmd
, "background menu macro");
1263 ** Cache user menus:
1264 ** Rebuild all of the Shell, Macro, Background menus of given editor window.
1266 void RebuildAllMenus(WindowInfo
*window
)
1268 rebuildMenu(window
, SHELL_CMDS
);
1269 rebuildMenu(window
, MACRO_CMDS
);
1270 rebuildMenu(window
, BG_MENU_CMDS
);
1274 ** Cache user menus:
1275 ** Rebuild either Shell, Macro or Background menus of all editor windows.
1277 static void rebuildMenuOfAllWindows(int menuType
)
1281 for (w
=WindowList
; w
!=NULL
; w
=w
->next
)
1282 rebuildMenu(w
, menuType
);
1286 ** Rebuild either the Shell, Macro or Background menu of "window", depending
1287 ** on value of "menuType". Rebuild is realized by following main steps:
1288 ** - dismiss user (sub) menu tearoff.
1289 ** - delete all user defined menu widgets.
1290 ** - update user menu including (re)creation of menu widgets.
1292 static void rebuildMenu(WindowInfo
*window
, int menuType
)
1294 selectedUserMenu menu
;
1296 /* Background menu is always rebuild (exists once per document).
1297 Shell, macro (user) menu cache is rebuild only, if given window is
1298 currently displayed on top. */
1299 if (menuType
!= BG_MENU_CMDS
&& !IsTopDocument(window
))
1302 /* Fetch the appropriate menu data */
1303 selectUserMenu(window
, menuType
, &menu
);
1305 /* dismiss user menu tearoff, to workaround the quick
1306 but noticeable shrink-expand bug, most probably
1307 triggered by the rebuild of the user menus. In any
1308 case, the submenu tearoffs will later be dismissed
1309 too in order to prevent dangling tearoffs, so doing
1310 this also for the main user menu tearoffs shouldn't
1312 if (!XmIsMenuShell(XtParent(menu
.sumMenuPane
)))
1313 _XmDismissTearOff(XtParent(menu
.sumMenuPane
), NULL
, NULL
);
1315 /* destroy all widgets related to menu pane */
1316 deleteMenuItems(menu
.sumMenuPane
);
1318 /* remove cached user menu info */
1319 freeUserMenuList(menu
.sumMainMenuList
);
1320 *menu
.sumMenuCreated
= False
;
1322 /* re-create & cache user menu items */
1323 updateMenu(window
, menuType
);
1327 ** Fetch the appropriate menu info for given menu type
1329 static void selectUserMenu(WindowInfo
*window
, int menuType
, selectedUserMenu
*menu
)
1331 if (menuType
== SHELL_CMDS
) {
1332 menu
->sumMenuPane
= window
->shellMenuPane
;
1333 menu
->sumNbrOfListItems
= NShellMenuItems
;
1334 menu
->sumItemList
= ShellMenuItems
;
1335 menu
->sumInfoList
= ShellMenuInfo
;
1336 menu
->sumSubMenus
= &ShellSubMenus
;
1337 menu
->sumMainMenuList
= &window
->userMenuCache
->umcShellMenuList
;
1338 menu
->sumMenuCreated
= &window
->userMenuCache
->umcShellMenuCreated
;
1339 } else if (menuType
== MACRO_CMDS
) {
1340 menu
->sumMenuPane
= window
->macroMenuPane
;
1341 menu
->sumNbrOfListItems
= NMacroMenuItems
;
1342 menu
->sumItemList
= MacroMenuItems
;
1343 menu
->sumInfoList
= MacroMenuInfo
;
1344 menu
->sumSubMenus
= &MacroSubMenus
;
1345 menu
->sumMainMenuList
= &window
->userMenuCache
->umcMacroMenuList
;
1346 menu
->sumMenuCreated
= &window
->userMenuCache
->umcMacroMenuCreated
;
1347 } else { /* BG_MENU_CMDS */
1348 menu
->sumMenuPane
= window
->bgMenuPane
;
1349 menu
->sumNbrOfListItems
= NBGMenuItems
;
1350 menu
->sumItemList
= BGMenuItems
;
1351 menu
->sumInfoList
= BGMenuInfo
;
1352 menu
->sumSubMenus
= &BGSubMenus
;
1353 menu
->sumMainMenuList
= &window
->userBGMenuCache
.ubmcMenuList
;
1354 menu
->sumMenuCreated
= &window
->userBGMenuCache
.ubmcMenuCreated
;
1356 menu
->sumType
= menuType
;
1360 ** Updates either the Shell, Macro or Background menu of "window", depending
1361 ** on value of "menuType". Update is realized by following main steps:
1362 ** - set / reset "to be managed" flag of user menu info list items
1363 ** according to current selected language mode.
1364 ** - create *all* user menu items (widgets etc). related to given
1365 ** window & menu type, if not done before.
1366 ** - manage / unmanage user menu widgets according to "to be managed"
1367 ** indication of user menu info list items.
1369 static void updateMenu(WindowInfo
*window
, int menuType
)
1371 selectedUserMenu menu
;
1373 /* Fetch the appropriate menu data */
1374 selectUserMenu(window
, menuType
, &menu
);
1376 /* Set / reset "to be managed" flag of all info list items */
1377 applyLangModeToUserMenuInfo(menu
.sumInfoList
, menu
.sumNbrOfListItems
,
1378 window
->languageMode
);
1380 /* create user menu items, if not done before */
1381 if (!*menu
.sumMenuCreated
)
1382 createMenuItems(window
, &menu
);
1384 /* manage user menu items depending on current language mode */
1385 manageUserMenu(&menu
, window
);
1387 if (menuType
== BG_MENU_CMDS
) {
1388 /* Set the proper sensitivity of items which may be dimmed */
1389 SetBGMenuUndoSensitivity(window
, XtIsSensitive(window
->undoItem
));
1390 SetBGMenuRedoSensitivity(window
, XtIsSensitive(window
->redoItem
));
1393 DimSelectionDepUserMenuItems(window
, window
->buffer
->primary
.selected
);
1397 ** Manually adjust the dimension of the menuShell _before_
1398 ** re-managing the menu pane, to either expose hidden menu
1399 ** entries or remove empty space.
1401 static void manageTearOffMenu(Widget menuPane
)
1403 Dimension width
, height
, border
;
1405 /* somehow OM went into a long CPU cycling when we
1406 attempt to change the shell window dimension by
1407 setting the XmNwidth & XmNheight directly. Using
1408 XtResizeWidget() seem to fix it */
1409 XtVaGetValues(XtParent(menuPane
), XmNborderWidth
, &border
, NULL
);
1410 XtVaGetValues(menuPane
, XmNwidth
, &width
, XmNheight
, &height
, NULL
);
1411 XtResizeWidget(XtParent(menuPane
), width
, height
, border
);
1413 XtManageChild(menuPane
);
1417 ** Cache user menus:
1418 ** Reset manage mode of user menu items in window cache.
1420 static void resetManageMode(UserMenuList
*list
)
1423 UserMenuListElement
*element
;
1425 for (i
=0; i
<list
->umlNbrItems
; i
++) {
1426 element
= list
->umlItems
[i
];
1428 /* remember current manage mode before reset it to
1430 element
->umlePrevManageMode
= element
->umleManageMode
;
1431 element
->umleManageMode
= UMMM_UNMANAGE
;
1433 /* recursively reset manage mode of sub-menus */
1434 if (element
->umleSubMenuList
!= NULL
)
1435 resetManageMode(element
->umleSubMenuList
);
1440 ** Cache user menus:
1441 ** Manage all menu widgets of given user sub-menu list.
1443 static void manageAllSubMenuWidgets(UserMenuListElement
*subMenu
)
1446 UserMenuList
*subMenuList
;
1447 UserMenuListElement
*element
;
1448 WidgetList widgetList
;
1449 Cardinal nWidgetListItems
;
1451 /* if the sub-menu is torn off, unmanage the menu pane
1452 before updating it to prevent the tear-off menu
1453 from shrinking and expanding as the menu entries
1455 if (!XmIsMenuShell(XtParent(subMenu
->umleSubMenuPane
))) {
1456 XtUnmanageChild(subMenu
->umleSubMenuPane
);
1459 /* manage all children of sub-menu pane */
1460 XtVaGetValues(subMenu
->umleSubMenuPane
,
1461 XmNchildren
, &widgetList
,
1462 XmNnumChildren
, &nWidgetListItems
,
1464 XtManageChildren(widgetList
, nWidgetListItems
);
1466 /* scan, if an menu item of given sub-menu holds a nested
1468 subMenuList
= subMenu
->umleSubMenuList
;
1470 for (i
=0; i
<subMenuList
->umlNbrItems
; i
++) {
1471 element
= subMenuList
->umlItems
[i
];
1473 if (element
->umleSubMenuList
!= NULL
) {
1474 /* if element is a sub-menu, then continue managing
1475 all items of that sub-menu recursively */
1476 manageAllSubMenuWidgets(element
);
1480 /* manage sub-menu pane widget itself */
1481 XtManageChild(subMenu
->umleMenuItem
);
1483 /* if the sub-menu is torn off, then adjust & manage the menu */
1484 if (!XmIsMenuShell(XtParent(subMenu
->umleSubMenuPane
))) {
1485 manageTearOffMenu(subMenu
->umleSubMenuPane
);
1488 /* redisplay sub-menu tearoff window, if the sub-menu
1489 was torn off before */
1490 ShowHiddenTearOff(subMenu
->umleSubMenuPane
);
1494 ** Cache user menus:
1495 ** Unmanage all menu widgets of given user sub-menu list.
1497 static void unmanageAllSubMenuWidgets(UserMenuListElement
*subMenu
)
1501 UserMenuList
*subMenuList
;
1502 UserMenuListElement
*element
;
1503 WidgetList widgetList
;
1504 Cardinal nWidgetListItems
;
1506 /* if sub-menu is torn-off, then unmap its shell
1507 (so tearoff window isn't displayed anymore) */
1508 shell
= XtParent(subMenu
->umleSubMenuPane
);
1509 if (!XmIsMenuShell(shell
)) {
1510 XtUnmapWidget(shell
);
1513 /* unmanage all children of sub-menu pane */
1514 XtVaGetValues(subMenu
->umleSubMenuPane
,
1515 XmNchildren
, &widgetList
,
1516 XmNnumChildren
, &nWidgetListItems
,
1518 XtUnmanageChildren(widgetList
, nWidgetListItems
);
1520 /* scan, if an menu item of given sub-menu holds a nested
1522 subMenuList
= subMenu
->umleSubMenuList
;
1524 for (i
=0; i
<subMenuList
->umlNbrItems
; i
++) {
1525 element
= subMenuList
->umlItems
[i
];
1527 if (element
->umleSubMenuList
!= NULL
) {
1528 /* if element is a sub-menu, then continue unmanaging
1529 all items of that sub-menu recursively */
1530 unmanageAllSubMenuWidgets(element
);
1534 /* unmanage sub-menu pane widget itself */
1535 XtUnmanageChild(subMenu
->umleMenuItem
);
1539 ** Cache user menus:
1540 ** Manage / unmanage menu widgets according to given user menu list.
1542 static void manageMenuWidgets(UserMenuList
*list
)
1545 UserMenuListElement
*element
;
1547 /* (un)manage all elements of given user menu list */
1548 for (i
=0; i
<list
->umlNbrItems
; i
++) {
1549 element
= list
->umlItems
[i
];
1551 if (element
->umlePrevManageMode
!= element
->umleManageMode
||
1552 element
->umleManageMode
== UMMM_MANAGE
) {
1553 /* previous and current manage mode differ OR
1554 current manage mode indicates: element needs to be
1555 (un)managed individually */
1556 if (element
->umleManageMode
== UMMM_MANAGE_ALL
) {
1557 /* menu item represented by "element" is a sub-menu and
1558 needs to be completely managed */
1559 manageAllSubMenuWidgets(element
);
1560 } else if (element
->umleManageMode
== UMMM_MANAGE
) {
1561 if (element
->umlePrevManageMode
== UMMM_UNMANAGE
||
1562 element
->umlePrevManageMode
== UMMM_UNMANAGE_ALL
) {
1563 /* menu item represented by "element" was unmanaged
1564 before and needs to be managed now */
1565 XtManageChild(element
->umleMenuItem
);
1568 /* if element is a sub-menu, then continue (un)managing
1569 single elements of that sub-menu one by one */
1570 if (element
->umleSubMenuList
!= NULL
) {
1571 /* if the sub-menu is torn off, unmanage the menu pane
1572 before updating it to prevent the tear-off menu
1573 from shrinking and expanding as the menu entries
1575 if (!XmIsMenuShell(XtParent(element
->umleSubMenuPane
))) {
1576 XtUnmanageChild(element
->umleSubMenuPane
);
1579 /* (un)manage menu entries of sub-menu */
1580 manageMenuWidgets(element
->umleSubMenuList
);
1582 /* if the sub-menu is torn off, then adjust & manage the menu */
1583 if (!XmIsMenuShell(XtParent(element
->umleSubMenuPane
))) {
1584 manageTearOffMenu(element
->umleSubMenuPane
);
1587 /* if the sub-menu was torn off then redisplay it */
1588 ShowHiddenTearOff(element
->umleSubMenuPane
);
1590 } else if (element
->umleManageMode
== UMMM_UNMANAGE_ALL
){
1591 /* menu item represented by "element" is a sub-menu and
1592 needs to be completely unmanaged */
1593 unmanageAllSubMenuWidgets(element
);
1595 /* current mode is UMMM_UNMANAGE -> menu item represented
1596 by "element" is a single menu item and needs to be
1598 XtUnmanageChild(element
->umleMenuItem
);
1605 ** Cache user menus:
1606 ** Remove accelerators from all items of given user (sub-)menu list.
1608 static void removeAccelFromMenuWidgets(UserMenuList
*menuList
)
1611 UserMenuListElement
*element
;
1613 /* scan all elements of this (sub-)menu */
1614 for (i
=0; i
<menuList
->umlNbrItems
; i
++) {
1615 element
= menuList
->umlItems
[i
];
1617 if (element
->umleSubMenuList
!= NULL
) {
1618 /* if element is a sub-menu, then continue removing accelerators
1619 from all items of that sub-menu recursively */
1620 removeAccelFromMenuWidgets(element
->umleSubMenuList
);
1621 } else if (element
->umleAccKeys
!= NULL
&&
1622 element
->umleManageMode
== UMMM_UNMANAGE
&&
1623 element
->umlePrevManageMode
== UMMM_MANAGE
) {
1624 /* remove accelerator if one was bound */
1625 XtVaSetValues(element
->umleMenuItem
, XmNaccelerator
, NULL
, NULL
);
1631 ** Cache user menus:
1632 ** Assign accelerators to all managed items of given user (sub-)menu list.
1634 static void assignAccelToMenuWidgets(UserMenuList
*menuList
, WindowInfo
*window
)
1637 UserMenuListElement
*element
;
1639 /* scan all elements of this (sub-)menu */
1640 for (i
=0; i
<menuList
->umlNbrItems
; i
++) {
1641 element
= menuList
->umlItems
[i
];
1643 if (element
->umleSubMenuList
!= NULL
) {
1644 /* if element is a sub-menu, then continue assigning accelerators
1645 to all managed items of that sub-menu recursively */
1646 assignAccelToMenuWidgets(element
->umleSubMenuList
, window
);
1647 } else if (element
->umleAccKeys
!= NULL
&&
1648 element
->umleManageMode
== UMMM_MANAGE
&&
1649 element
->umlePrevManageMode
== UMMM_UNMANAGE
) {
1650 /* assign accelerator if applicable */
1651 XtVaSetValues(element
->umleMenuItem
, XmNaccelerator
,
1652 element
->umleAccKeys
, NULL
);
1653 if (!element
->umleAccLockPatchApplied
) {
1654 UpdateAccelLockPatch(window
->splitPane
, element
->umleMenuItem
);
1655 element
->umleAccLockPatchApplied
= True
;
1662 ** Cache user menus:
1663 ** (Un)Manage all items of selected user menu.
1665 static void manageUserMenu(selectedUserMenu
*menu
, WindowInfo
*window
)
1669 Boolean currentLEisSubMenu
;
1671 UserMenuList
*menuList
;
1672 UserMenuListElement
*currentLE
;
1673 UserMenuManageMode
*mode
;
1675 /* reset manage mode of all items of selected user menu in window cache */
1676 resetManageMode(menu
->sumMainMenuList
);
1678 /* set manage mode of all items of selected user menu in window cache
1679 according to the "to be managed" indication of the info list */
1680 for (n
=0; n
<menu
->sumNbrOfListItems
; n
++) {
1681 info
= menu
->sumInfoList
[n
];
1683 menuList
= menu
->sumMainMenuList
;
1686 /* select all menu list items belonging to menu record "info" using
1687 hierarchical ID of current menu info (e.g. id = {3} means:
1688 4th element of main menu; {0} = 1st element etc.)*/
1689 for (i
=0; i
<info
->umiIdLen
; i
++) {
1690 currentLE
= menuList
->umlItems
[*id
];
1691 mode
= ¤tLE
->umleManageMode
;
1692 currentLEisSubMenu
= (currentLE
->umleSubMenuList
!= NULL
);
1694 if (info
->umiToBeManaged
) {
1695 /* menu record needs to be managed: */
1696 if (*mode
== UMMM_UNMANAGE
) {
1697 /* "mode" was not touched after reset ("init. state"):
1698 if current list element represents a sub-menu, then
1699 probably the complete sub-menu needs to be managed
1700 too. If current list element indicates single menu
1701 item, then just this item needs to be managed */
1702 if (currentLEisSubMenu
) {
1703 *mode
= UMMM_MANAGE_ALL
;
1705 *mode
= UMMM_MANAGE
;
1707 } else if (*mode
== UMMM_UNMANAGE_ALL
) {
1708 /* "mode" was touched after reset:
1709 current list element represents a sub-menu and min.
1710 one element of the sub-menu needs to be unmanaged ->
1711 the sub-menu needs to be (un)managed element by
1713 *mode
= UMMM_MANAGE
;
1716 /* menu record needs to be unmanaged: */
1717 if (*mode
== UMMM_UNMANAGE
) {
1718 /* "mode" was not touched after reset ("init. state"):
1719 if current list element represents a sub-menu, then
1720 probably the complete sub-menu needs to be unmanaged
1722 if (currentLEisSubMenu
) {
1723 *mode
= UMMM_UNMANAGE_ALL
;
1725 } else if (*mode
== UMMM_MANAGE_ALL
) {
1726 /* "mode" was touched after reset:
1727 current list element represents a sub-menu and min.
1728 one element of the sub-menu needs to be managed ->
1729 the sub-menu needs to be (un)managed element by
1731 *mode
= UMMM_MANAGE
;
1735 menuList
= currentLE
->umleSubMenuList
;
1741 /* if the menu is torn off, unmanage the menu pane
1742 before updating it to prevent the tear-off menu
1743 from shrinking and expanding as the menu entries
1745 if (!XmIsMenuShell(XtParent(menu
->sumMenuPane
)))
1746 XtUnmanageChild(menu
->sumMenuPane
);
1748 /* manage menu widgets according to current / previous manage mode of
1749 user menu window cache */
1750 manageMenuWidgets(menu
->sumMainMenuList
);
1752 /* Note: before new accelerator is assigned it seems to be necessary
1753 to remove old accelerator from user menu widgets. Removing same
1754 accelerator *after* it was assigned to another user menu widget
1756 removeAccelFromMenuWidgets(menu
->sumMainMenuList
);
1758 assignAccelToMenuWidgets(menu
->sumMainMenuList
, window
);
1760 /* if the menu is torn off, then adjust & manage the menu */
1761 if (!XmIsMenuShell(XtParent(menu
->sumMenuPane
)))
1762 manageTearOffMenu(menu
->sumMenuPane
);
1766 ** Create either the variable Shell menu, Macro menu or Background menu
1767 ** items of "window" (driven by value of "menuType")
1769 static void createMenuItems(WindowInfo
*window
, selectedUserMenu
*menu
)
1771 Widget btn
, subPane
, newSubPane
;
1774 menuTreeItem
*menuTree
;
1775 int i
, nTreeEntries
, size
;
1776 char *hierName
, *namePtr
, *subMenuName
, *subSep
, *fullName
;
1777 int menuType
= menu
->sumType
;
1779 userSubMenuCache
*subMenus
= menu
->sumSubMenus
;
1780 userSubMenuInfo
*subMenuInfo
;
1781 UserMenuList
*menuList
;
1782 UserMenuListElement
*currentLE
;
1784 char accKeysBuf
[MAX_ACCEL_LEN
+5];
1787 /* Allocate storage for structures to help find panes of sub-menus */
1788 size
= sizeof(menuTreeItem
) * menu
->sumNbrOfListItems
;
1789 menuTree
= (menuTreeItem
*)XtMalloc(size
);
1792 /* Harmless kludge: undo and redo items are marked specially if found
1793 in the background menu, and used to dim/undim with edit menu */
1794 window
->bgMenuUndoItem
= NULL
;
1795 window
->bgMenuRedoItem
= NULL
;
1798 ** Add items to the menu pane, creating hierarchical sub-menus as
1801 allocUserMenuList(menu
->sumMainMenuList
, subMenus
->usmcNbrOfMainMenuItems
);
1802 for (n
=0; n
<menu
->sumNbrOfListItems
; n
++) {
1803 item
= menu
->sumItemList
[n
];
1804 info
= menu
->sumInfoList
[n
];
1805 menuList
= menu
->sumMainMenuList
;
1808 fullName
= info
->umiName
;
1810 /* create/find sub-menus, stripping off '>' until item name is
1811 reached, then create the menu item */
1813 subPane
= menu
->sumMenuPane
;
1815 subSep
= strchr(namePtr
, '>');
1816 if (subSep
== NULL
) {
1817 btn
= createUserMenuItem(subPane
, namePtr
, item
, n
,
1818 (XtCallbackProc
)(menuType
== SHELL_CMDS
? shellMenuCB
:
1819 (menuType
== MACRO_CMDS
? macroMenuCB
: bgMenuCB
)),
1821 if (menuType
== BG_MENU_CMDS
&& !strcmp(item
->cmd
, "undo()\n"))
1822 window
->bgMenuUndoItem
= btn
;
1823 else if (menuType
== BG_MENU_CMDS
&& !strcmp(item
->cmd
,"redo()\n"))
1824 window
->bgMenuRedoItem
= btn
;
1825 /* generate accelerator keys */
1826 genAccelEventName(accKeysBuf
, item
->modifiers
, item
->keysym
);
1827 accKeys
= item
->keysym
== NoSymbol
? NULL
: XtNewString(accKeysBuf
);
1828 /* create corresponding menu list item */
1829 menuList
->umlItems
[menuList
->umlNbrItems
++] =
1830 allocUserMenuListElement(btn
, accKeys
);
1833 hierName
= copySubstring(fullName
, subSep
- fullName
);
1834 subMenuInfo
= findSubMenuInfo(subMenus
, hierName
);
1835 newSubPane
= findInMenuTree(menuTree
, nTreeEntries
, hierName
);
1836 if (newSubPane
== NULL
) {
1837 subMenuName
= copySubstring(namePtr
, subSep
- namePtr
);
1838 newSubPane
= createUserSubMenu(subPane
, subMenuName
, &btn
);
1839 XtFree(subMenuName
);
1840 menuTree
[nTreeEntries
].name
= hierName
;
1841 menuTree
[nTreeEntries
++].menuPane
= newSubPane
;
1843 currentLE
= allocUserMenuListElement(btn
, NULL
);
1844 menuList
->umlItems
[menuList
->umlNbrItems
++] = currentLE
;
1845 currentLE
->umleSubMenuPane
= newSubPane
;
1846 currentLE
->umleSubMenuList
=
1847 allocUserSubMenuList(subMenuInfo
->usmiId
[subMenuInfo
->usmiIdLen
]);
1849 currentLE
= menuList
->umlItems
[subMenuInfo
->usmiId
[subMenuDepth
]];
1852 subPane
= newSubPane
;
1853 menuList
= currentLE
->umleSubMenuList
;
1855 namePtr
= subSep
+ 1;
1859 *menu
->sumMenuCreated
= True
;
1861 /* Free the structure used to keep track of sub-menus durring creation */
1862 for (i
=0; i
<nTreeEntries
; i
++)
1863 XtFree(menuTree
[i
].name
);
1864 XtFree((char *)menuTree
);
1868 ** Find the widget corresponding to a hierarchical menu name (a>b>c...)
1870 static Widget
findInMenuTree(menuTreeItem
*menuTree
, int nTreeEntries
,
1871 const char *hierName
)
1875 for (i
=0; i
<nTreeEntries
; i
++)
1876 if (!strcmp(hierName
, menuTree
[i
].name
))
1877 return menuTree
[i
].menuPane
;
1881 static char *copySubstring(const char *string
, int length
)
1883 char *retStr
= XtMalloc(length
+ 1);
1885 strncpy(retStr
, string
, length
);
1886 retStr
[length
] = '\0';
1890 static Widget
createUserMenuItem(Widget menuPane
, char *name
, menuItemRec
*f
,
1891 int index
, XtCallbackProc cbRtn
, XtPointer cbArg
)
1894 char accText
[MAX_ACCEL_LEN
];
1897 generateAcceleratorString(accText
, f
->modifiers
, f
->keysym
);
1898 st1
=XmStringCreateSimple(name
);
1899 st2
=XmStringCreateSimple(accText
);
1900 btn
= XtVaCreateWidget("cmd", xmPushButtonWidgetClass
, menuPane
,
1901 XmNlabelString
, st1
,
1902 XmNacceleratorText
, st2
,
1903 XmNmnemonic
, f
->mnemonic
,
1904 XmNuserData
, index
+10, NULL
);
1905 XtAddCallback(btn
, XmNactivateCallback
, cbRtn
, cbArg
);
1912 ** Add a user-defined sub-menu to an established pull-down menu, marking
1913 ** it's userData field with TEMPORARY_MENU_ITEM so it can be found and
1914 ** removed later if the menu is redefined. Returns the menu pane of the
1917 static Widget
createUserSubMenu(Widget parent
, char *label
, Widget
*menuItem
)
1921 static Arg args
[1] = {{XmNuserData
, (XtArgVal
)TEMPORARY_MENU_ITEM
}};
1923 menuPane
= CreatePulldownMenu(parent
, "userPulldown", args
, 1);
1924 *menuItem
= XtVaCreateWidget("userCascade", xmCascadeButtonWidgetClass
, parent
,
1925 XmNlabelString
, st1
=XmStringCreateSimple(label
),
1926 XmNsubMenuId
, menuPane
, XmNuserData
, TEMPORARY_MENU_ITEM
,
1933 ** Cache user menus:
1934 ** Delete all variable menu items of given menu pane
1936 static void deleteMenuItems(Widget menuPane
)
1938 WidgetList itemList
, items
;
1944 /* Fetch the list of children from the menu pane to delete */
1945 XtVaGetValues(menuPane
, XmNchildren
, &itemList
,
1946 XmNnumChildren
, &nItems
, NULL
);
1948 /* make a copy because the widget alters the list as you delete widgets */
1949 items
= (WidgetList
)XtMalloc(sizeof(Widget
) * nItems
);
1950 memcpy(items
, itemList
, sizeof(Widget
) * nItems
);
1952 /* delete all of the widgets not marked as PERMANENT_MENU_ITEM */
1953 for (n
=0; n
<(int)nItems
; n
++) {
1954 XtVaGetValues(items
[n
], XmNuserData
, &userData
, NULL
);
1955 if (userData
!= (XtPointer
)PERMANENT_MENU_ITEM
) {
1956 if (XtClass(items
[n
]) == xmCascadeButtonWidgetClass
) {
1957 XtVaGetValues(items
[n
], XmNsubMenuId
, &subMenuID
, NULL
);
1959 /* prevent dangling submenu tearoffs */
1960 if (!XmIsMenuShell(XtParent(subMenuID
)))
1961 _XmDismissTearOff(XtParent(subMenuID
), NULL
, NULL
);
1963 deleteMenuItems(subMenuID
);
1964 #if XmVersion < 2000
1965 /* Skipping this creates a memory and server resource
1966 leak (though both are reclaimed on window closing). In
1967 Motif 2.0 (and beyond?) there is a potential crash during
1968 phase 2 widget destruction in "SetCascadeField", and in
1969 Motif 1.2 there are free-memory reads. I would really like
1970 to be able to destroy this. */
1971 XtDestroyWidget(subMenuID
);
1974 /* remove accel. before destroy or lose it forever */
1975 XtVaSetValues(items
[n
], XmNaccelerator
, NULL
, NULL
);
1977 XtDestroyWidget(items
[n
]);
1980 XtFree((char *)items
);
1983 static void dismissCB(Widget w
, XtPointer clientData
, XtPointer callData
)
1985 userCmdDialog
*ucd
= (userCmdDialog
*)clientData
;
1987 /* Mark that there's no longer a (macro, bg, or shell) dialog up */
1988 if (ucd
->dialogType
== SHELL_CMDS
)
1989 ShellCmdDialog
= NULL
;
1990 else if (ucd
->dialogType
== MACRO_CMDS
)
1991 MacroCmdDialog
= NULL
;
1993 BGMenuCmdDialog
= NULL
;
1995 /* pop down and destroy the dialog (memory for ucd is freed in the
1996 destroy callback) */
1997 XtDestroyWidget(ucd
->dlogShell
);
2000 static void okCB(Widget w
, XtPointer clientData
, XtPointer callData
)
2002 userCmdDialog
*ucd
= (userCmdDialog
*)clientData
;
2004 /* Read the dialog fields, and update the menus */
2005 if (!applyDialogChanges(ucd
))
2008 /* Mark that there's no longer a (macro, bg, or shell) dialog up */
2009 if (ucd
->dialogType
== SHELL_CMDS
)
2010 ShellCmdDialog
= NULL
;
2011 else if (ucd
->dialogType
== MACRO_CMDS
)
2012 MacroCmdDialog
= NULL
;
2014 BGMenuCmdDialog
= NULL
;
2016 /* pop down and destroy the dialog (memory for ucd is freed in the
2017 destroy callback) */
2018 XtDestroyWidget(ucd
->dlogShell
);
2021 static void applyCB(Widget w
, XtPointer clientData
, XtPointer callData
)
2023 applyDialogChanges((userCmdDialog
*)clientData
);
2026 static void checkCB(Widget w
, XtPointer clientData
, XtPointer callData
)
2028 userCmdDialog
*ucd
= (userCmdDialog
*)clientData
;
2030 if (checkMacro(ucd
))
2032 DialogF(DF_INF
, ucd
->dlogShell
, 1, "Macro",
2033 "Macro compiled without error", "Dismiss");
2037 static int checkMacro(userCmdDialog
*ucd
)
2041 f
= readDialogFields(ucd
, False
);
2044 if (!checkMacroText(f
->cmd
, ucd
->dlogShell
, ucd
->cmdTextW
)) {
2051 static int checkMacroText(char *macro
, Widget errorParent
, Widget errFocus
)
2054 char *errMsg
, *stoppedAt
;
2056 prog
= ParseMacro(macro
, &errMsg
, &stoppedAt
);
2058 if (errorParent
!= NULL
) {
2059 ParseError(errorParent
, macro
, stoppedAt
, "macro", errMsg
);
2060 XmTextSetInsertionPosition(errFocus
, stoppedAt
- macro
);
2061 XmProcessTraversal(errFocus
, XmTRAVERSE_CURRENT
);
2066 if (*stoppedAt
!= '\0') {
2067 if (errorParent
!= NULL
) {
2068 ParseError(errorParent
, macro
, stoppedAt
,"macro","syntax error");
2069 XmTextSetInsertionPosition(errFocus
, stoppedAt
- macro
);
2070 XmProcessTraversal(errFocus
, XmTRAVERSE_CURRENT
);
2077 static int applyDialogChanges(userCmdDialog
*ucd
)
2081 /* Get the current contents of the dialog fields */
2082 if (!UpdateManagedList(ucd
->managedList
, True
))
2085 /* Test compile the macro */
2086 if (ucd
->dialogType
== MACRO_CMDS
)
2087 if (!checkMacro(ucd
))
2090 /* Update the menu information */
2091 if (ucd
->dialogType
== SHELL_CMDS
) {
2092 for (i
=0; i
<NShellMenuItems
; i
++)
2093 freeMenuItemRec(ShellMenuItems
[i
]);
2094 freeUserMenuInfoList(ShellMenuInfo
, NShellMenuItems
);
2095 freeSubMenuCache(&ShellSubMenus
);
2096 for (i
=0; i
<ucd
->nMenuItems
; i
++)
2097 ShellMenuItems
[i
] = copyMenuItemRec(ucd
->menuItemsList
[i
]);
2098 NShellMenuItems
= ucd
->nMenuItems
;
2099 parseMenuItemList(ShellMenuItems
, NShellMenuItems
, ShellMenuInfo
, &ShellSubMenus
);
2100 } else if (ucd
->dialogType
== MACRO_CMDS
) {
2101 for (i
=0; i
<NMacroMenuItems
; i
++)
2102 freeMenuItemRec(MacroMenuItems
[i
]);
2103 freeUserMenuInfoList(MacroMenuInfo
, NMacroMenuItems
);
2104 freeSubMenuCache(&MacroSubMenus
);
2105 for (i
=0; i
<ucd
->nMenuItems
; i
++)
2106 MacroMenuItems
[i
] = copyMenuItemRec(ucd
->menuItemsList
[i
]);
2107 NMacroMenuItems
= ucd
->nMenuItems
;
2108 parseMenuItemList(MacroMenuItems
, NMacroMenuItems
, MacroMenuInfo
, &MacroSubMenus
);
2109 } else { /* BG_MENU_CMDS */
2110 for (i
=0; i
<NBGMenuItems
; i
++)
2111 freeMenuItemRec(BGMenuItems
[i
]);
2112 freeUserMenuInfoList(BGMenuInfo
, NBGMenuItems
);
2113 freeSubMenuCache(&BGSubMenus
);
2114 for (i
=0; i
<ucd
->nMenuItems
; i
++)
2115 BGMenuItems
[i
] = copyMenuItemRec(ucd
->menuItemsList
[i
]);
2116 NBGMenuItems
= ucd
->nMenuItems
;
2117 parseMenuItemList(BGMenuItems
, NBGMenuItems
, BGMenuInfo
, &BGSubMenus
);
2120 /* Update the menus themselves in all of the NEdit windows */
2121 rebuildMenuOfAllWindows(ucd
->dialogType
);
2123 /* Note that preferences have been changed */
2128 static void pasteReplayCB(Widget w
, XtPointer clientData
, XtPointer callData
)
2130 userCmdDialog
*ucd
= (userCmdDialog
*)clientData
;
2132 if (GetReplayMacro() == NULL
)
2135 XmTextInsert(ucd
->cmdTextW
, XmTextGetInsertionPosition(ucd
->cmdTextW
),
2139 static void destroyCB(Widget w
, XtPointer clientData
, XtPointer callData
)
2141 userCmdDialog
*ucd
= (userCmdDialog
*)clientData
;
2144 for (i
=0; i
<ucd
->nMenuItems
; i
++)
2145 freeMenuItemRec(ucd
->menuItemsList
[i
]);
2146 XtFree((char *)ucd
->menuItemsList
);
2147 XtFree((char *)ucd
);
2150 static void accFocusCB(Widget w
, XtPointer clientData
, XtPointer callData
)
2152 userCmdDialog
*ucd
= (userCmdDialog
*)clientData
;
2154 RemoveDialogMnemonicHandler(XtParent(ucd
->accTextW
));
2157 static void accLoseFocusCB(Widget w
, XtPointer clientData
, XtPointer callData
)
2159 userCmdDialog
*ucd
= (userCmdDialog
*)clientData
;
2161 AddDialogMnemonicHandler(XtParent(ucd
->accTextW
), FALSE
);
2164 static void accKeyCB(Widget w
, XtPointer clientData
, XKeyEvent
*event
)
2166 userCmdDialog
*ucd
= (userCmdDialog
*)clientData
;
2167 KeySym keysym
= XLookupKeysym(event
, 0);
2168 char outStr
[MAX_ACCEL_LEN
];
2170 /* Accept only real keys, not modifiers alone */
2171 if (IsModifierKey(keysym
))
2174 /* Tab key means go to the next field, don't enter */
2175 if (keysym
== XK_Tab
)
2178 /* Beep and return if the modifiers are buttons or ones we don't support */
2179 if (event
->state
& ~(ShiftMask
| LockMask
| ControlMask
| Mod1Mask
|
2180 Mod2Mask
| Mod3Mask
| Mod4Mask
| Mod5Mask
)) {
2181 XBell(TheDisplay
, 0);
2185 /* Delete or backspace clears field */
2186 if (keysym
== XK_Delete
|| keysym
== XK_BackSpace
) {
2187 XmTextSetString(ucd
->accTextW
, "");
2191 /* generate the string to use in the dialog field */
2192 generateAcceleratorString(outStr
, event
->state
, keysym
);
2194 /* Reject single character accelerators (a very simple way to eliminate
2195 un-modified letters and numbers) The goal is give users a clue that
2196 they're supposed to type the actual keys, not the name. This scheme
2197 is not rigorous and still allows accelerators like Comma. */
2198 if (strlen(outStr
) == 1) {
2199 XBell(TheDisplay
, 0);
2203 /* fill in the accelerator field in the dialog */
2204 XmTextSetString(ucd
->accTextW
, outStr
);
2207 static void sameOutCB(Widget w
, XtPointer clientData
, XtPointer callData
)
2209 XtSetSensitive(((userCmdDialog
*)clientData
)->repInpBtn
,
2210 XmToggleButtonGetState(w
));
2213 static void shellMenuCB(Widget w
, WindowInfo
*window
, XtPointer callData
)
2219 window
= WidgetToWindow(MENU_WIDGET(w
));
2221 /* get the index of the shell command and verify that it's in range */
2222 XtVaGetValues(w
, XmNuserData
, &userData
, NULL
);
2223 index
= (int)userData
- 10;
2224 if (index
<0 || index
>= NShellMenuItems
)
2227 params
[0] = ShellMenuItems
[index
]->name
;
2228 XtCallActionProc(window
->lastFocus
, "shell_menu_command",
2229 ((XmAnyCallbackStruct
*)callData
)->event
, params
, 1);
2232 static void macroMenuCB(Widget w
, WindowInfo
*window
, XtPointer callData
)
2238 window
= WidgetToWindow(MENU_WIDGET(w
));
2240 /* Don't allow users to execute a macro command from the menu (or accel)
2241 if there's already a macro command executing. NEdit can't handle
2242 running multiple, independent uncoordinated, macros in the same
2243 window. Macros may invoke macro menu commands recursively via the
2244 macro_menu_command action proc, which is important for being able to
2245 repeat any operation, and to embed macros within eachother at any
2246 level, however, a call here with a macro running means that THE USER
2247 is explicitly invoking another macro via the menu or an accelerator. */
2248 if (window
->macroCmdData
!= NULL
) {
2249 XBell(TheDisplay
, 0);
2253 /* get the index of the macro command and verify that it's in range */
2254 XtVaGetValues(w
, XmNuserData
, &userData
, NULL
);
2255 index
= (int)userData
- 10;
2256 if (index
<0 || index
>= NMacroMenuItems
)
2259 params
[0] = MacroMenuItems
[index
]->name
;
2260 XtCallActionProc(window
->lastFocus
, "macro_menu_command",
2261 ((XmAnyCallbackStruct
*)callData
)->event
, params
, 1);
2264 static void bgMenuCB(Widget w
, WindowInfo
*window
, XtPointer callData
)
2270 /* Same remark as for macro menu commands (see above). */
2271 if (window
->macroCmdData
!= NULL
) {
2272 XBell(TheDisplay
, 0);
2276 /* get the index of the macro command and verify that it's in range */
2277 XtVaGetValues(w
, XmNuserData
, &userData
, NULL
);
2278 index
= (int)userData
- 10;
2279 if (index
<0 || index
>= NBGMenuItems
)
2282 params
[0] = BGMenuItems
[index
]->name
;
2283 XtCallActionProc(window
->lastFocus
, "bg_menu_command",
2284 ((XmAnyCallbackStruct
*)callData
)->event
, params
, 1);
2288 ** Update the name, accelerator, mnemonic, and command fields in the shell
2289 ** command or macro dialog to agree with the currently selected item in the
2292 static void updateDialogFields(menuItemRec
*f
, userCmdDialog
*ucd
)
2294 char mneString
[2], accString
[MAX_ACCEL_LEN
];
2296 /* fill in the name, accelerator, mnemonic, and command fields of the
2297 dialog for the newly selected item, or blank them if "New" is selected */
2299 XmTextSetString(ucd
->nameTextW
, "");
2300 XmTextSetString(ucd
->cmdTextW
, "");
2301 XmTextSetString(ucd
->accTextW
, "");
2302 XmTextSetString(ucd
->mneTextW
, "");
2303 if (ucd
->dialogType
== SHELL_CMDS
) {
2304 RadioButtonChangeState(ucd
->selInpBtn
, True
, True
);
2305 RadioButtonChangeState(ucd
->sameOutBtn
, True
, True
);
2306 RadioButtonChangeState(ucd
->repInpBtn
, False
, False
);
2307 XtSetSensitive(ucd
->repInpBtn
, True
);
2308 RadioButtonChangeState(ucd
->saveFirstBtn
, False
, False
);
2309 RadioButtonChangeState(ucd
->loadAfterBtn
, False
, False
);
2312 mneString
[0] = f
->mnemonic
;
2313 mneString
[1] = '\0';
2314 generateAcceleratorString(accString
, f
->modifiers
, f
->keysym
);
2315 XmTextSetString(ucd
->nameTextW
, f
->name
);
2316 XmTextSetString(ucd
->cmdTextW
, f
->cmd
);
2317 XmTextSetString(ucd
->accTextW
, accString
);
2318 XmTextSetString(ucd
->mneTextW
, mneString
);
2319 RadioButtonChangeState(ucd
->selInpBtn
, f
->input
==FROM_SELECTION
, False
);
2320 if (ucd
->dialogType
== SHELL_CMDS
) {
2321 RadioButtonChangeState(ucd
->winInpBtn
, f
->input
== FROM_WINDOW
,
2323 RadioButtonChangeState(ucd
->eitherInpBtn
, f
->input
== FROM_EITHER
,
2325 RadioButtonChangeState(ucd
->noInpBtn
, f
->input
== FROM_NONE
,
2327 RadioButtonChangeState(ucd
->sameOutBtn
, f
->output
==TO_SAME_WINDOW
,
2329 RadioButtonChangeState(ucd
->winOutBtn
, f
->output
==TO_NEW_WINDOW
,
2331 RadioButtonChangeState(ucd
->dlogOutBtn
, f
->output
==TO_DIALOG
,
2333 RadioButtonChangeState(ucd
->repInpBtn
, f
->repInput
, False
);
2334 XtSetSensitive(ucd
->repInpBtn
, f
->output
==TO_SAME_WINDOW
);
2335 RadioButtonChangeState(ucd
->saveFirstBtn
, f
->saveFirst
, False
);
2336 RadioButtonChangeState(ucd
->loadAfterBtn
, f
->loadAfter
, False
);
2342 ** Read the name, accelerator, mnemonic, and command fields from the shell or
2343 ** macro commands dialog into a newly allocated menuItemRec. Returns a
2344 ** pointer to the new menuItemRec structure as the function value, or NULL on
2347 static menuItemRec
*readDialogFields(userCmdDialog
*ucd
, int silent
)
2349 char *nameText
, *cmdText
, *mneText
, *accText
;
2352 nameText
= XmTextGetString(ucd
->nameTextW
);
2353 if (*nameText
== '\0')
2357 DialogF(DF_WARN
, ucd
->dlogShell
, 1, "Menu Entry",
2358 "Please specify a name\nfor the menu item", "Dismiss");
2359 XmProcessTraversal(ucd
->nameTextW
, XmTRAVERSE_CURRENT
);
2365 if (strchr(nameText
, ':'))
2369 DialogF(DF_WARN
, ucd
->dlogShell
, 1, "Menu Entry",
2370 "Menu item names may not\ncontain colon (:) characters",
2372 XmProcessTraversal(ucd
->nameTextW
, XmTRAVERSE_CURRENT
);
2378 cmdText
= XmTextGetString(ucd
->cmdTextW
);
2379 if (cmdText
== NULL
|| *cmdText
== '\0')
2383 DialogF(DF_WARN
, ucd
->dlogShell
, 1, "Command to Execute",
2384 "Please specify %s to execute", "Dismiss",
2385 ucd
->dialogType
== SHELL_CMDS
2387 : "macro command(s)");
2388 XmProcessTraversal(ucd
->cmdTextW
, XmTRAVERSE_CURRENT
);
2399 if (ucd
->dialogType
== MACRO_CMDS
|| ucd
->dialogType
== BG_MENU_CMDS
) {
2400 addTerminatingNewline(&cmdText
);
2401 if (!checkMacroText(cmdText
, silent
? NULL
: ucd
->dlogShell
,
2408 f
= (menuItemRec
*)XtMalloc(sizeof(menuItemRec
));
2411 if ((mneText
= XmTextGetString(ucd
->mneTextW
)) != NULL
) {
2412 f
->mnemonic
= mneText
==NULL
? '\0' : mneText
[0];
2414 if (f
->mnemonic
== ':') /* colons mess up string parsing */
2417 if ((accText
= XmTextGetString(ucd
->accTextW
)) != NULL
) {
2418 parseAcceleratorString(accText
, &f
->modifiers
, &f
->keysym
);
2421 if (ucd
->dialogType
== SHELL_CMDS
) {
2422 if (XmToggleButtonGetState(ucd
->selInpBtn
))
2423 f
->input
= FROM_SELECTION
;
2424 else if (XmToggleButtonGetState(ucd
->winInpBtn
))
2425 f
->input
= FROM_WINDOW
;
2426 else if (XmToggleButtonGetState(ucd
->eitherInpBtn
))
2427 f
->input
= FROM_EITHER
;
2429 f
->input
= FROM_NONE
;
2430 if (XmToggleButtonGetState(ucd
->winOutBtn
))
2431 f
->output
= TO_NEW_WINDOW
;
2432 else if (XmToggleButtonGetState(ucd
->dlogOutBtn
))
2433 f
->output
= TO_DIALOG
;
2435 f
->output
= TO_SAME_WINDOW
;
2436 f
->repInput
= XmToggleButtonGetState(ucd
->repInpBtn
);
2437 f
->saveFirst
= XmToggleButtonGetState(ucd
->saveFirstBtn
);
2438 f
->loadAfter
= XmToggleButtonGetState(ucd
->loadAfterBtn
);
2440 f
->input
= XmToggleButtonGetState(ucd
->selInpBtn
) ? FROM_SELECTION
:
2442 f
->output
= TO_SAME_WINDOW
;
2443 f
->repInput
= False
;
2444 f
->saveFirst
= False
;
2445 f
->loadAfter
= False
;
2451 ** Copy a menu item record, and its associated memory
2453 static menuItemRec
*copyMenuItemRec(menuItemRec
*item
)
2455 menuItemRec
*newItem
;
2457 newItem
= (menuItemRec
*)XtMalloc(sizeof(menuItemRec
));
2459 newItem
->name
= XtMalloc(strlen(item
->name
)+1);
2460 strcpy(newItem
->name
, item
->name
);
2461 newItem
->cmd
= XtMalloc(strlen(item
->cmd
)+1);
2462 strcpy(newItem
->cmd
, item
->cmd
);
2467 ** Free a menu item record, and its associated memory
2469 static void freeMenuItemRec(menuItemRec
*item
)
2473 XtFree((char *)item
);
2477 ** Callbacks for managed-list operations
2479 static void *getDialogDataCB(void *oldItem
, int explicitRequest
, int *abort
,
2482 userCmdDialog
*ucd
= (userCmdDialog
*)cbArg
;
2483 menuItemRec
*currentFields
;
2485 /* If the dialog is currently displaying the "new" entry and the
2486 fields are empty, that's just fine */
2487 if (oldItem
== NULL
&& dialogFieldsAreEmpty(ucd
))
2490 /* If there are no problems reading the data, just return it */
2491 currentFields
= readDialogFields(ucd
, True
);
2492 if (currentFields
!= NULL
)
2493 return (void *)currentFields
;
2495 /* If user might not be expecting fields to be read, give more warning */
2496 if (!explicitRequest
)
2498 if (DialogF(DF_WARN
, ucd
->dlogShell
, 2, "Discard Entry",
2499 "Discard incomplete entry\nfor current menu item?", "Keep",
2502 return oldItem
== NULL
2504 : (void *)copyMenuItemRec((menuItemRec
*)oldItem
);
2508 /* Do readDialogFields again without "silent" mode to display warning(s) */
2509 readDialogFields(ucd
, False
);
2515 static void setDialogDataCB(void *item
, void *cbArg
)
2517 updateDialogFields((menuItemRec
*)item
, (userCmdDialog
*)cbArg
);
2520 static int dialogFieldsAreEmpty(userCmdDialog
*ucd
)
2522 return TextWidgetIsBlank(ucd
->nameTextW
) &&
2523 TextWidgetIsBlank(ucd
->cmdTextW
) &&
2524 TextWidgetIsBlank(ucd
->accTextW
) &&
2525 TextWidgetIsBlank(ucd
->mneTextW
) &&
2526 (ucd
->dialogType
!= SHELL_CMDS
|| (
2527 XmToggleButtonGetState(ucd
->selInpBtn
) &&
2528 XmToggleButtonGetState(ucd
->sameOutBtn
) &&
2529 !XmToggleButtonGetState(ucd
->repInpBtn
) &&
2530 !XmToggleButtonGetState(ucd
->saveFirstBtn
) &&
2531 !XmToggleButtonGetState(ucd
->loadAfterBtn
)));
2534 static void freeItemCB(void *item
)
2536 freeMenuItemRec((menuItemRec
*)item
);
2540 ** Gut a text widget of it's ability to process input
2542 static void disableTextW(Widget textW
)
2544 static XtTranslations emptyTable
= NULL
;
2545 static char *emptyTranslations
= "\
2546 <EnterWindow>: enter()\n\
2547 <Btn1Down>: grab-focus()\n\
2548 <Btn1Motion>: extend-adjust()\n\
2549 <Btn1Up>: extend-end()\n\
2550 Shift<Key>Tab: prev-tab-group()\n\
2551 Ctrl<Key>Tab: next-tab-group()\n\
2552 <Key>Tab: next-tab-group()\n\
2553 <LeaveWindow>: leave()\n\
2554 <FocusIn>: focusIn()\n\
2555 <FocusOut>: focusOut()\n\
2556 <Unmap>: unmap()\n";
2558 /* replace the translation table with the slimmed down one above */
2559 if (emptyTable
== NULL
)
2560 emptyTable
= XtParseTranslationTable(emptyTranslations
);
2561 XtVaSetValues(textW
, XmNtranslations
, emptyTable
, NULL
);
2564 static char *writeMenuItemString(menuItemRec
**menuItems
, int nItems
,
2567 char *outStr
, *outPtr
, *c
, accStr
[MAX_ACCEL_LEN
];
2571 /* determine the max. amount of memory needed for the returned string
2572 and allocate a buffer for composing the string */
2574 for (i
=0; i
<nItems
; i
++) {
2576 generateAcceleratorString(accStr
, f
->modifiers
, f
->keysym
);
2577 length
+= strlen(f
->name
) * 2; /* allow for \n & \\ expansions */
2578 length
+= strlen(accStr
);
2579 length
+= strlen(f
->cmd
) * 6; /* allow for \n & \\ expansions */
2580 length
+= 21; /* number of characters added below */
2582 length
++; /* terminating null */
2583 outStr
= XtMalloc(length
);
2585 /* write the string */
2589 for (i
=0; i
<nItems
; i
++) {
2591 generateAcceleratorString(accStr
, f
->modifiers
, f
->keysym
);
2593 for (c
=f
->name
; *c
!='\0'; ++c
) { /* Copy the command name */
2594 if (*c
== '\\') { /* changing backslashes to \\ */
2597 } else if (*c
== '\n') { /* changing newlines to \n */
2605 strcpy(outPtr
, accStr
);
2606 outPtr
+= strlen(accStr
);
2608 if (f
->mnemonic
!= '\0')
2609 *outPtr
++ = f
->mnemonic
;
2611 if (listType
== SHELL_CMDS
) {
2612 if (f
->input
== FROM_SELECTION
)
2614 else if (f
->input
== FROM_WINDOW
)
2616 else if (f
->input
== FROM_EITHER
)
2618 if (f
->output
== TO_DIALOG
)
2620 else if (f
->output
== TO_NEW_WINDOW
)
2630 if (f
->input
== FROM_SELECTION
)
2642 for (c
=f
->cmd
; *c
!='\0'; c
++) { /* Copy the command string, changing */
2643 if (*c
== '\\') { /* backslashes to double backslashes */
2644 *outPtr
++ = '\\'; /* and newlines to backslash-n's, */
2645 *outPtr
++ = '\\'; /* followed by real newlines and tab */
2646 } else if (*c
== '\n') {
2656 if (listType
== MACRO_CMDS
|| listType
== BG_MENU_CMDS
) {
2657 if (*(outPtr
-1) == '\t') outPtr
--;
2670 static int loadMenuItemString(char *inString
, menuItemRec
**menuItems
,
2671 int *nItems
, int listType
)
2675 char *inPtr
= inString
;
2676 char *nameStr
, accStr
[MAX_ACCEL_LEN
], mneChar
;
2678 unsigned int modifiers
;
2679 int i
, input
, output
, saveFirst
, loadAfter
, repInput
;
2680 int nameLen
, accLen
, mneLen
, cmdLen
;
2684 /* remove leading whitespace */
2685 while (*inPtr
== ' ' || *inPtr
== '\t')
2688 /* read name field */
2689 nameLen
= strcspn(inPtr
, ":");
2691 return parseError("no name field");
2692 nameStr
= XtMalloc(nameLen
+1);
2693 strncpy(nameStr
, inPtr
, nameLen
);
2694 nameStr
[nameLen
] = '\0';
2697 return parseError("end not expected");
2700 /* read accelerator field */
2701 accLen
= strcspn(inPtr
, ":");
2702 if (accLen
>= MAX_ACCEL_LEN
)
2703 return parseError("accelerator field too long");
2704 strncpy(accStr
, inPtr
, accLen
);
2705 accStr
[accLen
] = '\0';
2708 return parseError("end not expected");
2711 /* read menemonic field */
2712 mneLen
= strcspn(inPtr
, ":");
2714 return parseError("mnemonic field too long");
2721 return parseError("end not expected");
2723 /* read flags field */
2725 output
= TO_SAME_WINDOW
;
2729 for (; *inPtr
!= ':'; inPtr
++) {
2730 if (listType
== SHELL_CMDS
) {
2732 input
= FROM_SELECTION
;
2733 else if (*inPtr
== 'A')
2734 input
= FROM_WINDOW
;
2735 else if (*inPtr
== 'E')
2736 input
= FROM_EITHER
;
2737 else if (*inPtr
== 'W')
2738 output
= TO_NEW_WINDOW
;
2739 else if (*inPtr
== 'D')
2741 else if (*inPtr
== 'X')
2743 else if (*inPtr
== 'S')
2745 else if (*inPtr
== 'L')
2748 return parseError("unreadable flag field");
2751 input
= FROM_SELECTION
;
2753 return parseError("unreadable flag field");
2758 /* read command field */
2759 if (listType
== SHELL_CMDS
) {
2760 if (*inPtr
++ != '\n')
2761 return parseError("command must begin with newline");
2762 while (*inPtr
== ' ' || *inPtr
== '\t') /* leading whitespace */
2764 cmdLen
= strcspn(inPtr
, "\n");
2766 return parseError("shell command field is empty");
2767 cmdStr
= XtMalloc(cmdLen
+1);
2768 strncpy(cmdStr
, inPtr
, cmdLen
);
2769 cmdStr
[cmdLen
] = '\0';
2772 cmdStr
= copyMacroToEnd(&inPtr
);
2776 while (*inPtr
== ' ' || *inPtr
== '\t' || *inPtr
== '\n')
2777 inPtr
++; /* skip trailing whitespace & newline */
2779 /* parse the accelerator field */
2780 if (!parseAcceleratorString(accStr
, &modifiers
, &keysym
))
2781 return parseError("couldn't read accelerator field");
2783 /* create a menu item record */
2784 f
= (menuItemRec
*)XtMalloc(sizeof(menuItemRec
));
2787 f
->mnemonic
= mneChar
;
2788 f
->modifiers
= modifiers
;
2791 f
->repInput
= repInput
;
2792 f
->saveFirst
= saveFirst
;
2793 f
->loadAfter
= loadAfter
;
2796 /* add/replace menu record in the list */
2797 for (i
=0; i
< *nItems
; i
++) {
2798 if (!strcmp(menuItems
[i
]->name
, f
->name
)) {
2799 freeMenuItemRec(menuItems
[i
]);
2805 menuItems
[(*nItems
)++] = f
;
2807 /* end of string in proper place */
2813 static int parseError(const char *message
)
2815 fprintf(stderr
, "NEdit: Parse error in user defined menu item, %s\n",
2821 ** Create a text string representing an accelerator for the dialog,
2822 ** the shellCommands or macroCommands resource, and for the menu item.
2824 static void generateAcceleratorString(char *text
, unsigned int modifiers
,
2827 char *shiftStr
= "", *ctrlStr
= "", *altStr
= "";
2828 char *mod2Str
= "", *mod3Str
= "", *mod4Str
= "", *mod5Str
= "";
2830 Modifiers numLockMask
= GetNumLockModMask(TheDisplay
);
2832 /* if there's no accelerator, generate an empty string */
2833 if (keysym
== NoSymbol
) {
2839 /* Translate the modifiers into strings.
2840 Lock and NumLock are always ignored (see util/misc.c),
2841 so we don't display them either. */
2842 if (modifiers
& ShiftMask
)
2843 shiftStr
= "Shift+";
2844 if (modifiers
& ControlMask
)
2846 if (modifiers
& Mod1Mask
)
2848 if ((modifiers
& Mod2Mask
) && (Mod2Mask
!= numLockMask
))
2850 if ((modifiers
& Mod3Mask
) && (Mod3Mask
!= numLockMask
))
2852 if ((modifiers
& Mod4Mask
) && (Mod4Mask
!= numLockMask
))
2854 if ((modifiers
& Mod5Mask
) && (Mod5Mask
!= numLockMask
))
2857 /* for a consistent look to the accelerator names in the menus,
2858 capitalize the first letter of the keysym */
2859 strcpy(keyName
, XKeysymToString(keysym
));
2860 *keyName
= toupper(*keyName
);
2862 /* concatenate the strings together */
2863 sprintf(text
, "%s%s%s%s%s%s%s%s", shiftStr
, ctrlStr
, altStr
,
2864 mod2Str
, mod3Str
, mod4Str
, mod5Str
, keyName
);
2868 ** Create a translation table event description string for the menu
2869 ** XmNaccelerator resource.
2871 static void genAccelEventName(char *text
, unsigned int modifiers
,
2874 char *shiftStr
= "", *lockStr
= "", *ctrlStr
= "", *altStr
= "";
2875 char *mod2Str
= "", *mod3Str
= "", *mod4Str
= "", *mod5Str
= "";
2877 /* if there's no accelerator, generate an empty string */
2878 if (keysym
== NoSymbol
) {
2883 /* translate the modifiers into strings */
2884 if (modifiers
& ShiftMask
)
2885 shiftStr
= "Shift ";
2886 if (modifiers
& LockMask
)
2888 if (modifiers
& ControlMask
)
2890 if (modifiers
& Mod1Mask
)
2892 if (modifiers
& Mod2Mask
)
2894 if (modifiers
& Mod3Mask
)
2896 if (modifiers
& Mod4Mask
)
2898 if (modifiers
& Mod5Mask
)
2901 /* put the modifiers together with the key name */
2902 sprintf(text
, "%s%s%s%s%s%s%s%s<Key>%s",
2903 shiftStr
, lockStr
, ctrlStr
, altStr
,
2904 mod2Str
, mod3Str
, mod4Str
, mod5Str
,
2905 XKeysymToString(keysym
));
2909 ** Read an accelerator name and put it into the form of a modifier mask
2910 ** and a KeySym code. Returns false if string can't be read
2911 ** ... does not handle whitespace in string (look at scanf)
2913 static int parseAcceleratorString(const char *string
, unsigned int *modifiers
,
2916 int i
, nFields
, inputLength
= strlen(string
);
2917 char fields
[10][MAX_ACCEL_LEN
];
2919 /* a blank field means no accelerator */
2920 if (inputLength
== 0) {
2926 /* limit the string length so no field strings will overflow */
2927 if (inputLength
> MAX_ACCEL_LEN
)
2930 /* divide the input into '+' separated fields */
2931 nFields
= sscanf(string
, "%[^+]+%[^+]+%[^+]+%[^+]+%[^+]+%[^+]+%[^+]+%[^+]+%[^+]+%[^+]",
2932 fields
[0], fields
[1], fields
[2], fields
[3], fields
[4], fields
[5],
2933 fields
[6], fields
[7], fields
[8], fields
[9]);
2937 /* get the key name from the last field and translate it to a keysym.
2938 If the name is capitalized, try it lowercase as well, since some
2939 of the keysyms are "prettied up" by generateAcceleratorString */
2940 *keysym
= XStringToKeysym(fields
[nFields
-1]);
2941 if (*keysym
== NoSymbol
) {
2942 *fields
[nFields
-1] = tolower(*fields
[nFields
-1]);
2943 *keysym
= XStringToKeysym(fields
[nFields
-1]);
2944 if (*keysym
== NoSymbol
)
2948 /* parse the modifier names from the rest of the fields */
2950 for (i
=0; i
<nFields
-1; i
++) {
2951 if (!strcmp(fields
[i
], "Shift"))
2952 *modifiers
|= ShiftMask
;
2953 else if (!strcmp(fields
[i
], "Lock"))
2954 *modifiers
|= LockMask
;
2955 else if (!strcmp(fields
[i
], "Ctrl"))
2956 *modifiers
|= ControlMask
;
2957 /* comparision with "Alt" for compatibility with old .nedit files*/
2958 else if (!strcmp(fields
[i
], "Alt"))
2959 *modifiers
|= Mod1Mask
;
2960 else if (!strcmp(fields
[i
], "Mod2"))
2961 *modifiers
|= Mod2Mask
;
2962 else if (!strcmp(fields
[i
], "Mod3"))
2963 *modifiers
|= Mod3Mask
;
2964 else if (!strcmp(fields
[i
], "Mod4"))
2965 *modifiers
|= Mod4Mask
;
2966 else if (!strcmp(fields
[i
], "Mod5"))
2967 *modifiers
|= Mod5Mask
;
2972 /* all fields successfully parsed */
2977 ** Scan text from "*inPtr" to the end of macro input (matching brace),
2978 ** advancing inPtr, and return macro text as function return value.
2980 ** This is kind of wastefull in that it throws away the compiled macro,
2981 ** to be re-generated from the text as needed, but compile time is
2982 ** negligible for most macros.
2984 static char *copyMacroToEnd(char **inPtr
)
2986 char *retStr
, *errMsg
, *stoppedAt
, *p
, *retPtr
;
2989 /* Skip over whitespace to find make sure there's a beginning brace
2990 to anchor the parse (if not, it will take the whole file) */
2991 *inPtr
+= strspn(*inPtr
, " \t\n");
2992 if (**inPtr
!= '{') {
2993 ParseError(NULL
, *inPtr
, *inPtr
-1, "macro menu item", "expecting '{'");
2997 /* Parse the input */
2998 prog
= ParseMacro(*inPtr
, &errMsg
, &stoppedAt
);
3000 ParseError(NULL
, *inPtr
, stoppedAt
, "macro menu item", errMsg
);
3005 /* Copy and return the body of the macro, stripping outer braces and
3006 extra leading tabs added by the writer routine */
3008 *inPtr
+= strspn(*inPtr
, " \t");
3009 if (**inPtr
== '\n') (*inPtr
)++;
3010 if (**inPtr
== '\t') (*inPtr
)++;
3011 if (**inPtr
== '\t') (*inPtr
)++;
3012 retPtr
= retStr
= XtMalloc(stoppedAt
- *inPtr
+ 1);
3013 for (p
= *inPtr
; p
< stoppedAt
- 1; p
++) {
3014 if (!strncmp(p
, "\n\t\t", 3)) {
3020 if (*(retPtr
-1) == '\t') retPtr
--;
3027 ** If "*string" is not terminated with a newline character, reallocate the
3028 ** string and add one. (The macro language requires newline terminators for
3029 ** statements, but the text widget doesn't force it like the NEdit text buffer
3030 ** does, so this might avoid some confusion.)
3032 static void addTerminatingNewline(char **string
)
3037 length
= strlen(*string
);
3038 if ((*string
)[length
-1] != '\n') {
3039 newString
= XtMalloc(length
+ 2);
3040 strcpy(newString
, *string
);
3041 newString
[length
] = '\n';
3042 newString
[length
+1] = '\0';
3044 *string
= newString
;
3049 ** Cache user menus:
3050 ** allocate an empty user (shell, macro) menu cache structure
3052 UserMenuCache
*CreateUserMenuCache()
3054 /* allocate some memory for the new data structure */
3055 UserMenuCache
*cache
= (UserMenuCache
*)XtMalloc(sizeof(UserMenuCache
));
3057 cache
->umcLanguageMode
= -2;
3058 cache
->umcShellMenuCreated
= False
;
3059 cache
->umcMacroMenuCreated
= False
;
3060 cache
->umcShellMenuList
.umlNbrItems
= 0;
3061 cache
->umcShellMenuList
.umlItems
= NULL
;
3062 cache
->umcMacroMenuList
.umlNbrItems
= 0;
3063 cache
->umcMacroMenuList
.umlItems
= NULL
;
3068 void FreeUserMenuCache(UserMenuCache
*cache
)
3070 freeUserMenuList(&cache
->umcShellMenuList
);
3071 freeUserMenuList(&cache
->umcMacroMenuList
);
3073 XtFree((char *)cache
);
3077 ** Cache user menus:
3078 ** init. a user background menu cache structure
3080 void InitUserBGMenuCache(UserBGMenuCache
*cache
)
3082 cache
->ubmcLanguageMode
= -2;
3083 cache
->ubmcMenuCreated
= False
;
3084 cache
->ubmcMenuList
.umlNbrItems
= 0;
3085 cache
->ubmcMenuList
.umlItems
= NULL
;
3088 void FreeUserBGMenuCache(UserBGMenuCache
*cache
)
3090 freeUserMenuList(&cache
->ubmcMenuList
);
3094 ** Cache user menus:
3095 ** Parse given menu item list and setup a user menu info list for
3096 ** management of user menu.
3098 static void parseMenuItemList(menuItemRec
**itemList
, int nbrOfItems
,
3099 userMenuInfo
**infoList
, userSubMenuCache
*subMenus
)
3104 /* Allocate storage for structures to keep track of sub-menus */
3105 allocSubMenuCache(subMenus
, nbrOfItems
);
3107 /* 1st pass: setup user menu info: extract language modes, menu name &
3108 default indication; build user menu ID */
3109 for (i
=0; i
<nbrOfItems
; i
++) {
3110 infoList
[i
] = parseMenuItemRec(itemList
[i
]);
3111 generateUserMenuId(infoList
[i
], subMenus
);
3114 /* 2nd pass: solve "default" dependencies */
3115 for (i
=0; i
<nbrOfItems
; i
++) {
3118 /* If the user menu item is a default one, then scan the list for
3119 items with the same name and a language mode specified.
3120 If one is found, then set the default index to the index of the
3121 current default item. */
3122 if (info
->umiIsDefault
) {
3123 setDefaultIndex(infoList
, nbrOfItems
, i
);
3129 ** Returns the sub-menu depth (i.e. nesting level) of given
3132 static int getSubMenuDepth(const char *menuName
)
3137 /* determine sub-menu depth by counting '>' of given "menuName" */
3139 while ((subSep
= strchr(subSep
, '>')) != NULL
) {
3148 ** Cache user menus:
3149 ** Parse a singe menu item. Allocate & setup a user menu info element
3150 ** holding extracted info.
3152 static userMenuInfo
*parseMenuItemRec(menuItemRec
*item
)
3154 userMenuInfo
*newInfo
;
3158 /* allocate a new user menu info element */
3159 newInfo
= (userMenuInfo
*)XtMalloc(sizeof(userMenuInfo
));
3161 /* determine sub-menu depth and allocate some memory
3162 for hierarchical ID; init. ID with {0,.., 0} */
3163 newInfo
->umiName
= stripLanguageMode(item
->name
);
3165 subMenuDepth
= getSubMenuDepth(newInfo
->umiName
);
3166 idSize
= sizeof(int)*(subMenuDepth
+1);
3168 newInfo
->umiId
= (int *)XtMalloc(idSize
);
3169 memset(newInfo
->umiId
,0,idSize
);
3171 /* init. remaining parts of user menu info element */
3172 newInfo
->umiIdLen
= 0;
3173 newInfo
->umiIsDefault
= False
;
3174 newInfo
->umiNbrOfLanguageModes
= 0;
3175 newInfo
->umiLanguageMode
= NULL
;
3176 newInfo
->umiDefaultIndex
= -1;
3177 newInfo
->umiToBeManaged
= False
;
3179 /* assign language mode info to new user menu info element */
3180 parseMenuItemName(item
->name
, newInfo
);
3186 ** Cache user menus:
3187 ** Extract language mode related info out of given menu item name string.
3188 ** Store this info in given user menu info structure.
3190 static void parseMenuItemName(char *menuItemName
, userMenuInfo
*info
)
3192 char *atPtr
, *firstAtPtr
, *endPtr
;
3195 int langModes
[MAX_LANGUAGE_MODES
];
3199 atPtr
= firstAtPtr
= strchr(menuItemName
, '@');
3200 if (atPtr
!= NULL
) {
3201 if (!strcmp(atPtr
+1, "*")) {
3202 /* only language is "*": this is for all but language specific
3204 info
->umiIsDefault
= True
;
3208 /* setup a list of all language modes related to given menu item */
3209 while (atPtr
!= NULL
) {
3210 /* extract language mode name after "@" sign */
3211 for(endPtr
=atPtr
+1; isalnum((unsigned char)*endPtr
) || *endPtr
=='_' ||
3212 *endPtr
=='-' || *endPtr
==' ' || *endPtr
=='+' || *endPtr
=='$' ||
3213 *endPtr
=='#'; endPtr
++);
3215 /* lookup corresponding language mode index; if PLAIN is
3216 returned then this means, that language mode name after
3217 "@" is unknown (i.e. not defined) */
3220 languageMode
= FindLanguageMode(atPtr
+1);
3221 if (languageMode
== PLAIN_LANGUAGE_MODE
) {
3222 langModes
[nbrLM
] = UNKNOWN_LANGUAGE_MODE
;
3224 langModes
[nbrLM
] = languageMode
;
3229 /* look for next "@" */
3230 atPtr
= strchr(endPtr
, '@');
3234 info
->umiNbrOfLanguageModes
= nbrLM
;
3235 size
= sizeof(int)*nbrLM
;
3236 info
->umiLanguageMode
= (int *)XtMalloc(size
);
3237 memcpy(info
->umiLanguageMode
, langModes
, size
);
3243 ** Cache user menus:
3244 ** generates an ID (= array of integers) of given user menu info, which
3245 ** allows to find the user menu item within the menu tree later on: 1st
3246 ** integer of ID indicates position within main menu; 2nd integer indicates
3247 ** position within 1st sub-menu etc.
3249 static void generateUserMenuId(userMenuInfo
*info
, userSubMenuCache
*subMenus
)
3252 char *hierName
, *subSep
;
3253 int subMenuDepth
= 0;
3254 int *menuIdx
= &subMenus
->usmcNbrOfMainMenuItems
;
3255 userSubMenuInfo
*curSubMenu
;
3257 /* find sub-menus, stripping off '>' until item name is
3259 subSep
= info
->umiName
;
3260 while ((subSep
= strchr(subSep
, '>')) != NULL
) {
3261 hierName
= copySubstring(info
->umiName
, subSep
- info
->umiName
);
3262 curSubMenu
= findSubMenuInfo(subMenus
, hierName
);
3263 if (curSubMenu
== NULL
) {
3264 /* sub-menu info not stored before: new sub-menu;
3265 remember its hierarchical position */
3266 info
->umiId
[subMenuDepth
] = *menuIdx
;
3269 /* store sub-menu info in list of subMenus; allocate
3270 some memory for hierarchical ID of sub-menu & take over
3271 current hierarchical ID of current user menu info */
3272 curSubMenu
= &subMenus
->usmcInfo
[subMenus
->usmcNbrOfSubMenus
];
3273 subMenus
->usmcNbrOfSubMenus
++;
3274 curSubMenu
->usmiName
= hierName
;
3275 idSize
= sizeof(int)*(subMenuDepth
+2);
3276 curSubMenu
->usmiId
= (int *)XtMalloc(idSize
);
3277 memcpy(curSubMenu
->usmiId
, info
->umiId
, idSize
);
3278 curSubMenu
->usmiIdLen
= subMenuDepth
+1;
3280 /* sub-menu info already stored before: takeover its
3281 hierarchical position */
3283 info
->umiId
[subMenuDepth
] = curSubMenu
->usmiId
[subMenuDepth
];
3287 menuIdx
= &curSubMenu
->usmiId
[subMenuDepth
];
3292 /* remember position of menu item within final (sub) menu */
3293 info
->umiId
[subMenuDepth
] = *menuIdx
;
3294 info
->umiIdLen
= subMenuDepth
+ 1;
3299 ** Cache user menus:
3300 ** Find info corresponding to a hierarchical menu name (a>b>c...)
3302 static userSubMenuInfo
*findSubMenuInfo(userSubMenuCache
*subMenus
,
3303 const char *hierName
)
3307 for (i
=0; i
<subMenus
->usmcNbrOfSubMenus
; i
++)
3308 if (!strcmp(hierName
, subMenus
->usmcInfo
[i
].usmiName
))
3309 return &subMenus
->usmcInfo
[i
];
3314 ** Cache user menus:
3315 ** Returns an allocated copy of menuItemName stripped of language mode
3316 ** parts (i.e. parts starting with "@").
3318 static char *stripLanguageMode(const char *menuItemName
)
3322 firstAtPtr
= strchr(menuItemName
, '@');
3323 if (firstAtPtr
== NULL
)
3324 return XtNewString(menuItemName
);
3326 return copySubstring(menuItemName
, firstAtPtr
-menuItemName
);
3329 static void setDefaultIndex(userMenuInfo
**infoList
, int nbrOfItems
,
3332 char *defaultMenuName
= infoList
[defaultIdx
]->umiName
;
3336 /* Scan the list for items with the same name and a language mode
3337 specified. If one is found, then set the default index to the
3338 index of the current default item. */
3339 for (i
=0; i
<nbrOfItems
; i
++) {
3342 if (!info
->umiIsDefault
&& strcmp(info
->umiName
, defaultMenuName
)==0) {
3343 info
->umiDefaultIndex
= defaultIdx
;
3349 ** Determine the info list menu items, which need to be managed
3350 ** for given language mode. Set / reset "to be managed" indication
3351 ** of info list items accordingly.
3353 static void applyLangModeToUserMenuInfo(userMenuInfo
**infoList
, int nbrOfItems
,
3359 /* 1st pass: mark all items as "to be managed", which are applicable
3360 for all language modes or which are indicated as "default" items */
3361 for (i
=0; i
<nbrOfItems
; i
++) {
3364 info
->umiToBeManaged
=
3365 (info
->umiNbrOfLanguageModes
== 0 || info
->umiIsDefault
);
3368 /* 2nd pass: mark language mode specific items matching given language
3369 mode as "to be managed". Reset "to be managed" indications of
3370 "default" items, if applicable */
3371 for (i
=0; i
<nbrOfItems
; i
++) {
3374 if (info
->umiNbrOfLanguageModes
!= 0) {
3375 if (doesLanguageModeMatch(info
, languageMode
)) {
3376 info
->umiToBeManaged
= True
;
3378 if (info
->umiDefaultIndex
!= -1)
3379 infoList
[info
->umiDefaultIndex
]->umiToBeManaged
= False
;
3386 ** Returns true, if given user menu info is applicable for given language mode
3388 static int doesLanguageModeMatch(userMenuInfo
*info
, int languageMode
)
3392 for (i
=0; i
<info
->umiNbrOfLanguageModes
; i
++) {
3393 if (info
->umiLanguageMode
[i
] == languageMode
)
3400 static void freeUserMenuInfoList(userMenuInfo
**infoList
, int nbrOfItems
)
3404 for (i
=0; i
<nbrOfItems
; i
++) {
3405 freeUserMenuInfo(infoList
[i
]);
3409 static void freeUserMenuInfo(userMenuInfo
*info
)
3411 XtFree(info
->umiName
);
3413 XtFree((char *)info
->umiId
);
3415 if (info
->umiNbrOfLanguageModes
!= 0)
3416 XtFree((char *)info
->umiLanguageMode
);
3418 XtFree((char *)info
);
3422 ** Cache user menus:
3423 ** Allocate & init. storage for structures to manage sub-menus
3425 static void allocSubMenuCache(userSubMenuCache
*subMenus
, int nbrOfItems
)
3427 int size
= sizeof(userSubMenuInfo
) * nbrOfItems
;
3429 subMenus
->usmcNbrOfMainMenuItems
= 0;
3430 subMenus
->usmcNbrOfSubMenus
= 0;
3431 subMenus
->usmcInfo
= (userSubMenuInfo
*)XtMalloc(size
);
3434 static void freeSubMenuCache(userSubMenuCache
*subMenus
)
3438 for (i
=0; i
<subMenus
->usmcNbrOfSubMenus
; i
++) {
3439 XtFree(subMenus
->usmcInfo
[i
].usmiName
);
3440 XtFree((char *)subMenus
->usmcInfo
[i
].usmiId
);
3443 XtFree((char *)subMenus
->usmcInfo
);
3446 static void allocUserMenuList(UserMenuList
*list
, int nbrOfItems
)
3448 int size
= sizeof(UserMenuListElement
*) * nbrOfItems
;
3450 list
->umlNbrItems
= 0;
3451 list
->umlItems
= (UserMenuListElement
**)XtMalloc(size
);
3454 static void freeUserMenuList(UserMenuList
*list
)
3458 for (i
=0; i
<list
->umlNbrItems
; i
++)
3459 freeUserMenuListElement(list
->umlItems
[i
]);
3461 list
->umlNbrItems
= 0;
3463 if (list
->umlItems
!= NULL
) {
3464 XtFree((char *)list
->umlItems
);
3465 list
->umlItems
= NULL
;
3469 static UserMenuListElement
*allocUserMenuListElement(Widget menuItem
, char *accKeys
)
3471 UserMenuListElement
*element
;
3473 element
= (UserMenuListElement
*)XtMalloc(sizeof(UserMenuListElement
));
3475 element
->umleManageMode
= UMMM_UNMANAGE
;
3476 element
->umlePrevManageMode
= UMMM_UNMANAGE
;
3477 element
->umleAccKeys
= accKeys
;
3478 element
->umleAccLockPatchApplied
= False
;
3479 element
->umleMenuItem
= menuItem
;
3480 element
->umleSubMenuPane
= NULL
;
3481 element
->umleSubMenuList
= NULL
;
3486 static void freeUserMenuListElement(UserMenuListElement
*element
)
3488 if (element
->umleSubMenuList
!= NULL
)
3489 freeUserSubMenuList(element
->umleSubMenuList
);
3491 if (element
->umleAccKeys
!= NULL
)
3492 XtFree(element
->umleAccKeys
);
3494 XtFree((char *)element
);
3497 static UserMenuList
*allocUserSubMenuList(int nbrOfItems
)
3501 list
= (UserMenuList
*)XtMalloc(sizeof(UserMenuList
));
3503 allocUserMenuList(list
, nbrOfItems
);
3508 static void freeUserSubMenuList(UserMenuList
*list
)
3510 freeUserMenuList(list
);
3512 XtFree((char *)list
);