|
Packit |
b099d7 |
/* $XConsortium: menu.c /main/5 1995/07/15 21:01:38 drk $ */
|
|
Packit |
b099d7 |
/*
|
|
Packit |
b099d7 |
* Motif
|
|
Packit |
b099d7 |
*
|
|
Packit |
b099d7 |
* Copyright (c) 1987-2012, The Open Group. All rights reserved.
|
|
Packit |
b099d7 |
*
|
|
Packit |
b099d7 |
* These libraries and programs are free software; you can
|
|
Packit |
b099d7 |
* redistribute them and/or modify them under the terms of the GNU
|
|
Packit |
b099d7 |
* Lesser General Public License as published by the Free Software
|
|
Packit |
b099d7 |
* Foundation; either version 2 of the License, or (at your option)
|
|
Packit |
b099d7 |
* any later version.
|
|
Packit |
b099d7 |
*
|
|
Packit |
b099d7 |
* These libraries and programs are distributed in the hope that
|
|
Packit |
b099d7 |
* they will be useful, but WITHOUT ANY WARRANTY; without even the
|
|
Packit |
b099d7 |
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
Packit |
b099d7 |
* PURPOSE. See the GNU Lesser General Public License for more
|
|
Packit |
b099d7 |
* details.
|
|
Packit |
b099d7 |
*
|
|
Packit |
b099d7 |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit |
b099d7 |
* License along with these librararies and programs; if not, write
|
|
Packit |
b099d7 |
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
|
|
Packit |
b099d7 |
* Floor, Boston, MA 02110-1301 USA
|
|
Packit |
b099d7 |
*/
|
|
Packit |
b099d7 |
/*
|
|
Packit |
b099d7 |
* HISTORY
|
|
Packit |
b099d7 |
*/
|
|
Packit |
b099d7 |
|
|
Packit |
b099d7 |
|
|
Packit |
b099d7 |
#include <stdio.h>
|
|
Packit |
b099d7 |
#include <string.h>
|
|
Packit |
b099d7 |
#include <Xm/Xm.h>
|
|
Packit |
b099d7 |
#include <Xm/LabelG.h>
|
|
Packit |
b099d7 |
#include <Xm/RowColumn.h>
|
|
Packit |
b099d7 |
#include <Xm/SeparatoG.h>
|
|
Packit |
b099d7 |
#include <Xm/PushBG.h>
|
|
Packit |
b099d7 |
#include <Xm/CascadeB.h>
|
|
Packit |
b099d7 |
#include "toolchest.h"
|
|
Packit |
b099d7 |
|
|
Packit |
b099d7 |
|
|
Packit |
b099d7 |
static struct menu *menus;
|
|
Packit |
b099d7 |
|
|
Packit |
b099d7 |
/* allocate a new menu entry */
|
|
Packit |
b099d7 |
struct menuEntry *
|
|
Packit |
b099d7 |
NewMenuEntry(char *label, enum menuEntryType type)
|
|
Packit |
b099d7 |
{
|
|
Packit |
b099d7 |
register struct menuEntry *ret;
|
|
Packit |
b099d7 |
ret = (struct menuEntry *)tcMalloc(sizeof (struct menuEntry));
|
|
Packit |
b099d7 |
ret->label = label;
|
|
Packit |
b099d7 |
ret->type = type;
|
|
Packit |
b099d7 |
ret->sensitive = TRUE;
|
|
Packit |
b099d7 |
ret->removed = FALSE;
|
|
Packit |
b099d7 |
ret->empty = FALSE;
|
|
Packit |
b099d7 |
#ifdef TCEDIT
|
|
Packit |
b099d7 |
ret->menuName = "";
|
|
Packit |
b099d7 |
ret->execString = "";
|
|
Packit |
b099d7 |
ret->exprString = "";
|
|
Packit |
b099d7 |
#endif
|
|
Packit |
b099d7 |
return (ret);
|
|
Packit |
b099d7 |
}
|
|
Packit |
b099d7 |
|
|
Packit |
b099d7 |
/* look up a menu by name and return it. If it is not found and mallocIt is
|
|
Packit |
b099d7 |
* true, allocate a new one.
|
|
Packit |
b099d7 |
*/
|
|
Packit |
b099d7 |
struct menu *
|
|
Packit |
b099d7 |
FindMenu(char *name, Boolean mallocIt)
|
|
Packit |
b099d7 |
{
|
|
Packit |
b099d7 |
struct menu *menu = menus;
|
|
Packit |
b099d7 |
|
|
Packit |
b099d7 |
/* look for the menu */
|
|
Packit |
b099d7 |
while (menu)
|
|
Packit |
b099d7 |
{
|
|
Packit |
b099d7 |
if (strcmp(menu->name, name) == 0)
|
|
Packit |
b099d7 |
return (menu);
|
|
Packit |
b099d7 |
menu = menu->next;
|
|
Packit |
b099d7 |
};
|
|
Packit |
b099d7 |
/* malloc a new one if appropriate */
|
|
Packit |
b099d7 |
if (mallocIt)
|
|
Packit |
b099d7 |
{
|
|
Packit |
b099d7 |
menu = tcMalloc(sizeof(struct menu));
|
|
Packit |
b099d7 |
menu->next = menus;
|
|
Packit |
b099d7 |
menus = menu;
|
|
Packit |
b099d7 |
menu->name = name;
|
|
Packit |
b099d7 |
menu->firstMenuEntry = NULL;
|
|
Packit |
b099d7 |
menu->lastMenuEntry = NULL;
|
|
Packit |
b099d7 |
menu->referenced = FALSE;
|
|
Packit |
b099d7 |
#ifdef TCMENU
|
|
Packit |
b099d7 |
menu->activeEntry = NULL;
|
|
Packit |
b099d7 |
menu->menuWidget = NULL;
|
|
Packit |
b099d7 |
#endif
|
|
Packit |
b099d7 |
}
|
|
Packit |
b099d7 |
else
|
|
Packit |
b099d7 |
return (NULL);
|
|
Packit |
b099d7 |
}
|
|
Packit |
b099d7 |
|
|
Packit |
b099d7 |
/* remove itemName from menu menu. Return TRUE if it was found */
|
|
Packit |
b099d7 |
static Boolean
|
|
Packit |
b099d7 |
removeItemFromMenu (char *itemName, struct menu *menu)
|
|
Packit |
b099d7 |
{
|
|
Packit |
b099d7 |
struct menuEntry *entry = menu->firstMenuEntry;
|
|
Packit |
b099d7 |
struct menuEntry *prev, *next;
|
|
Packit |
b099d7 |
|
|
Packit |
b099d7 |
while (entry)
|
|
Packit |
b099d7 |
{
|
|
Packit |
b099d7 |
if (strcmp (itemName, entry->label) == 0 && !entry->removed)
|
|
Packit |
b099d7 |
{
|
|
Packit |
b099d7 |
entry->removed = TRUE;
|
|
Packit |
b099d7 |
return (TRUE);
|
|
Packit |
b099d7 |
}
|
|
Packit |
b099d7 |
entry = entry->next;
|
|
Packit |
b099d7 |
}
|
|
Packit |
b099d7 |
return (FALSE);
|
|
Packit |
b099d7 |
}
|
|
Packit |
b099d7 |
|
|
Packit |
b099d7 |
/* remove item name from menu named menuName. If menuName is NULL, remove
|
|
Packit |
b099d7 |
* it from any menu
|
|
Packit |
b099d7 |
*/
|
|
Packit |
b099d7 |
void
|
|
Packit |
b099d7 |
RemoveMenuEntry(char *name, char *menuName)
|
|
Packit |
b099d7 |
{
|
|
Packit |
b099d7 |
register struct menu *menu;
|
|
Packit |
b099d7 |
|
|
Packit |
b099d7 |
if (menuName == NULL)
|
|
Packit |
b099d7 |
{
|
|
Packit |
b099d7 |
Boolean found = FALSE;
|
|
Packit |
b099d7 |
|
|
Packit |
b099d7 |
for (menu = menus; menu; menu = menu->next)
|
|
Packit |
b099d7 |
{
|
|
Packit |
b099d7 |
if (removeItemFromMenu(name, menu))
|
|
Packit |
b099d7 |
{
|
|
Packit |
b099d7 |
if (found)
|
|
Packit |
b099d7 |
FileError ("Item %s removed from more than one menu", name);
|
|
Packit |
b099d7 |
else found = TRUE;
|
|
Packit |
b099d7 |
}
|
|
Packit |
b099d7 |
}
|
|
Packit |
b099d7 |
if (!found)
|
|
Packit |
b099d7 |
FileError ("Can't find %s for removal\n", name);
|
|
Packit |
b099d7 |
}
|
|
Packit |
b099d7 |
else
|
|
Packit |
b099d7 |
{
|
|
Packit |
b099d7 |
menu = FindMenu(menuName, FALSE);
|
|
Packit |
b099d7 |
if (menu == NULL)
|
|
Packit |
b099d7 |
FileError("Cannot find menu %s for removal\n", menuName);
|
|
Packit |
b099d7 |
else if (!removeItemFromMenu(name, menu))
|
|
Packit |
b099d7 |
FileError("Item %s not found in menu %s\n", name, menuName);
|
|
Packit |
b099d7 |
}
|
|
Packit |
b099d7 |
}
|
|
Packit |
b099d7 |
|
|
Packit |
b099d7 |
#ifndef TCEDIT
|
|
Packit |
b099d7 |
/* recursively build a menu, based on info previously read. name is the
|
|
Packit |
b099d7 |
* name of the menu, parent is the parent pane, and isMenuBar is true of
|
|
Packit |
b099d7 |
* the menu is a menu bar.
|
|
Packit |
b099d7 |
*/
|
|
Packit |
b099d7 |
static void
|
|
Packit |
b099d7 |
buildMenu(struct menu *menu, Widget parent, Boolean isMenuBar)
|
|
Packit |
b099d7 |
{
|
|
Packit |
b099d7 |
register struct menuEntry *entry;
|
|
Packit |
b099d7 |
Arg wargs[10];
|
|
Packit |
b099d7 |
int n;
|
|
Packit |
b099d7 |
Widget w;
|
|
Packit |
b099d7 |
XmString xmstr;
|
|
Packit |
b099d7 |
enum menuEntryType lastType = ME_NONE;
|
|
Packit |
b099d7 |
Boolean thisEntryRemoved = FALSE;
|
|
Packit |
b099d7 |
Boolean lastEntryRemoved;
|
|
Packit |
b099d7 |
|
|
Packit |
b099d7 |
if (menu->referenced)
|
|
Packit |
b099d7 |
{
|
|
Packit |
b099d7 |
fprintf (stderr,
|
|
Packit |
b099d7 |
"WARNING: menu %s referenced more than once, extra reference ignored\n",
|
|
Packit |
b099d7 |
menu->name);
|
|
Packit |
b099d7 |
return;
|
|
Packit |
b099d7 |
}
|
|
Packit |
b099d7 |
menu->referenced = TRUE;
|
|
Packit |
b099d7 |
for (entry = menu->firstMenuEntry; entry; entry = entry->next)
|
|
Packit |
b099d7 |
{
|
|
Packit |
b099d7 |
lastEntryRemoved = thisEntryRemoved;
|
|
Packit |
b099d7 |
if (entry->removed)
|
|
Packit |
b099d7 |
{
|
|
Packit |
b099d7 |
thisEntryRemoved = TRUE;
|
|
Packit |
b099d7 |
}
|
|
Packit |
b099d7 |
else
|
|
Packit |
b099d7 |
{
|
|
Packit |
b099d7 |
thisEntryRemoved = FALSE;
|
|
Packit |
b099d7 |
xmstr = XmStringCreateSimple(entry->label);
|
|
Packit |
b099d7 |
switch (entry->type)
|
|
Packit |
b099d7 |
{
|
|
Packit |
b099d7 |
case ME_EXEC:
|
|
Packit |
b099d7 |
case ME_CHECKEXEC:
|
|
Packit |
b099d7 |
case ME_CHECKEXPR:
|
|
Packit |
b099d7 |
if (entry->type == ME_CHECKEXEC)
|
|
Packit |
b099d7 |
entry->sensitive = CheckExec(entry->execString);
|
|
Packit |
b099d7 |
else if (entry->type == ME_CHECKEXPR)
|
|
Packit |
b099d7 |
entry->sensitive = CheckExpr(entry->exprString);
|
|
Packit |
b099d7 |
else
|
|
Packit |
b099d7 |
entry->sensitive = TRUE;
|
|
Packit |
b099d7 |
n = 0;
|
|
Packit |
b099d7 |
XtSetArg (wargs[n], XmNlabelString, xmstr);n++;
|
|
Packit |
b099d7 |
XtSetArg (wargs[n], XmNalignment, XmALIGNMENT_CENTER); n++;
|
|
Packit |
b099d7 |
XtSetArg (wargs[n], XmNsensitive, entry->sensitive); n++;
|
|
Packit |
b099d7 |
/* In the menu bar we must create a cascade button instead of
|
|
Packit |
b099d7 |
* a push button. (Note that since menu pixmaps are only in
|
|
Packit |
b099d7 |
* the widget, we create a widget rather than a gadget
|
|
Packit |
b099d7 |
* for the cascade button
|
|
Packit |
b099d7 |
*/
|
|
Packit |
b099d7 |
w = XtCreateManagedWidget(entry->label,
|
|
Packit |
b099d7 |
isMenuBar?
|
|
Packit |
b099d7 |
xmCascadeButtonWidgetClass:
|
|
Packit |
b099d7 |
xmPushButtonGadgetClass,
|
|
Packit |
b099d7 |
parent, wargs, n);
|
|
Packit |
b099d7 |
XtAddCallback(w, XmNactivateCallback, ExecCallback,
|
|
Packit |
b099d7 |
(caddr_t)entry);
|
|
Packit |
b099d7 |
break;
|
|
Packit |
b099d7 |
|
|
Packit |
b099d7 |
case ME_SEPARATOR:
|
|
Packit |
b099d7 |
/* if we removed the last entry and the last non
|
|
Packit |
b099d7 |
* removed entry was a separator, a title, or the start,
|
|
Packit |
b099d7 |
* remove this entry. However, don't set thisEntryRemoved
|
|
Packit |
b099d7 |
* so that if another separator immediatly follows, it is
|
|
Packit |
b099d7 |
* drawn.
|
|
Packit |
b099d7 |
*/
|
|
Packit |
b099d7 |
if (!(lastEntryRemoved &&
|
|
Packit |
b099d7 |
(lastType == ME_SEPARATOR ||
|
|
Packit |
b099d7 |
lastType == ME_TITLE ||
|
|
Packit |
b099d7 |
lastType == ME_NONE)))
|
|
Packit |
b099d7 |
{
|
|
Packit |
b099d7 |
n = 0;
|
|
Packit |
b099d7 |
w = XmCreateSeparatorGadget (parent, entry->label,
|
|
Packit |
b099d7 |
wargs, n);
|
|
Packit |
b099d7 |
XtManageChild(w);
|
|
Packit |
b099d7 |
}
|
|
Packit |
b099d7 |
break;
|
|
Packit |
b099d7 |
|
|
Packit |
b099d7 |
case ME_TITLE:
|
|
Packit |
b099d7 |
n = 0;
|
|
Packit |
b099d7 |
XtSetArg (wargs[n], XmNlabelString, xmstr);n++;
|
|
Packit |
b099d7 |
XtSetArg (wargs[n], XmNalignment, XmALIGNMENT_CENTER); n++;
|
|
Packit |
b099d7 |
w = XmCreateLabelGadget(parent, entry->label,
|
|
Packit |
b099d7 |
NULL, 0); n++;
|
|
Packit |
b099d7 |
XtManageChild(w);
|
|
Packit |
b099d7 |
n = 0;
|
|
Packit |
b099d7 |
XtSetArg (wargs[n], XmNseparatorType, XmDOUBLE_LINE); n++;
|
|
Packit |
b099d7 |
w = XmCreateSeparatorGadget (parent, "separator",
|
|
Packit |
b099d7 |
wargs, n);
|
|
Packit |
b099d7 |
XtManageChild(w);
|
|
Packit |
b099d7 |
|
|
Packit |
b099d7 |
case ME_LABEL:
|
|
Packit |
b099d7 |
n = 0;
|
|
Packit |
b099d7 |
XtSetArg (wargs[n], XmNlabelString, xmstr);n++;
|
|
Packit |
b099d7 |
XtSetArg (wargs[n], XmNalignment, XmALIGNMENT_CENTER); n++;
|
|
Packit |
b099d7 |
w = XmCreateLabelGadget(parent, entry->label,
|
|
Packit |
b099d7 |
NULL, 0);
|
|
Packit |
b099d7 |
XtManageChild(w);
|
|
Packit |
b099d7 |
break;
|
|
Packit |
b099d7 |
|
|
Packit |
b099d7 |
case ME_MENU:
|
|
Packit |
b099d7 |
{
|
|
Packit |
b099d7 |
struct menu *submenu;
|
|
Packit |
b099d7 |
Widget pane;
|
|
Packit |
b099d7 |
|
|
Packit |
b099d7 |
submenu = FindMenu(entry->menuName, FALSE);
|
|
Packit |
b099d7 |
if (submenu)
|
|
Packit |
b099d7 |
{
|
|
Packit |
b099d7 |
n = 0;
|
|
Packit |
b099d7 |
if (menuVisualStatus != SG_VISUAL_DEFAULT)
|
|
Packit |
b099d7 |
{
|
|
Packit |
b099d7 |
XtSetArg (wargs[n], XmNdepth,
|
|
Packit |
b099d7 |
menuVisualDepth); n++;
|
|
Packit |
b099d7 |
XtSetArg (wargs[n], XmNcolormap,
|
|
Packit |
b099d7 |
menuVisualColormap); n++;
|
|
Packit |
b099d7 |
XtSetArg (wargs[n], XmNvisual, menuVisual); n++;
|
|
Packit |
b099d7 |
}
|
|
Packit |
b099d7 |
pane = XmCreatePulldownMenu(parent, entry->menuName,
|
|
Packit |
b099d7 |
wargs, n);
|
|
Packit |
b099d7 |
wm_windows[0] = XtWindow(pane);
|
|
Packit |
b099d7 |
|
|
Packit |
b099d7 |
n = 0;
|
|
Packit |
b099d7 |
XtSetArg(wargs[n], XmNsubMenuId, pane);n++;
|
|
Packit |
b099d7 |
XtSetArg(wargs[n], XmNlabelString, xmstr);n++;
|
|
Packit |
b099d7 |
if (isMenuBar && showDecal)
|
|
Packit |
b099d7 |
{
|
|
Packit |
b099d7 |
XtSetArg(wargs[n], XmNmenuBarPixmap,
|
|
Packit |
b099d7 |
decalPixmap); n++;
|
|
Packit |
b099d7 |
}
|
|
Packit |
b099d7 |
w = XmCreateCascadeButton(parent, submenu->name,
|
|
Packit |
b099d7 |
wargs, n);
|
|
Packit |
b099d7 |
XtManageChild(w);
|
|
Packit |
b099d7 |
|
|
Packit |
b099d7 |
buildMenu (submenu, pane, FALSE);
|
|
Packit |
b099d7 |
}
|
|
Packit |
b099d7 |
else
|
|
Packit |
b099d7 |
{
|
|
Packit |
b099d7 |
/* menu wasn't found. Mark it so */
|
|
Packit |
b099d7 |
entry->empty = TRUE;
|
|
Packit |
b099d7 |
thisEntryRemoved = TRUE;
|
|
Packit |
b099d7 |
}
|
|
Packit |
b099d7 |
}
|
|
Packit |
b099d7 |
break;
|
|
Packit |
b099d7 |
|
|
Packit |
b099d7 |
default:
|
|
Packit |
b099d7 |
XtError ("Unknown menu item type");
|
|
Packit |
b099d7 |
}
|
|
Packit |
b099d7 |
XmStringFree(xmstr);
|
|
Packit |
b099d7 |
if (!thisEntryRemoved)
|
|
Packit |
b099d7 |
lastType = entry->type;
|
|
Packit |
b099d7 |
}
|
|
Packit |
b099d7 |
}
|
|
Packit |
b099d7 |
}
|
|
Packit |
b099d7 |
|
|
Packit |
b099d7 |
/* build the top level menu. The flag isMenuBar indicates whether it
|
|
Packit |
b099d7 |
* is in a menu bar
|
|
Packit |
b099d7 |
*/
|
|
Packit |
b099d7 |
void
|
|
Packit |
b099d7 |
BuildTopMenu(Widget parent, Boolean isMenuBar)
|
|
Packit |
b099d7 |
{
|
|
Packit |
b099d7 |
struct menu *topMenu;
|
|
Packit |
b099d7 |
|
|
Packit |
b099d7 |
if ((topMenu = FindMenu(TOP_MENU_NAME, FALSE)) == NULL)
|
|
Packit |
b099d7 |
{
|
|
Packit |
b099d7 |
char buf[100];
|
|
Packit |
b099d7 |
sprintf(buf,
|
|
Packit |
b099d7 |
"Menu specification: menu '%s' referenced but not found\n",
|
|
Packit |
b099d7 |
TOP_MENU_NAME);
|
|
Packit |
b099d7 |
XtError(buf);
|
|
Packit |
b099d7 |
}
|
|
Packit |
b099d7 |
buildMenu(topMenu, parent, isMenuBar);
|
|
Packit |
b099d7 |
}
|
|
Packit |
b099d7 |
#endif
|