[comp.windows.x] awm kit, Part06

jkh@ardent.UUCP (Jordan K. Hubbard) (06/06/88)

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 6 (of 8)."
# Contents:  GetButton.c gram.y
# Wrapped by jkh@ardent on Sun Jun  5 18:56:35 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'GetButton.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'GetButton.c'\"
else
echo shar: Extracting \"'GetButton.c'\" \(19196 characters\)
sed "s/^X//" >'GetButton.c' <<'END_OF_FILE'
X#ifndef lint
X     static char *rcsid_GetButton_c = "$Header: GetButton.c,v 1.24 87/09/09 19:20:45 swick Exp $";
X#endif	lint
X
X#include "X11/copyright.h"
X
X/*
X * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
X *
X *                         All Rights Reserved
X *
X * Permission to use, copy, modify, and distribute this software and its
X * documentation for any purpose and without fee is hereby granted,
X * provided that the above copyright notice appear in all copies and that
X * both that copyright notice and this permission notice appear in
X * supporting documentation, and that the name of Digital Equipment
X * Corporation not be used in advertising or publicity pertaining to
X * distribution of the software without specific, written prior permission.
X *
X *
X * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
X * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
X * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
X * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
X * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
X * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
X * SOFTWARE.
X */
X
X
X
X/*
X * MODIFICATION HISTORY
X *
X * 000 -- M. Gancarz, DEC Ultrix Engineering Group
X * 001 -- L. Guarino Reid, DEC Ultrix Engineering Group, Western Software Lab
X *	  February 16, 1987
X *	  Add EnterWindow, LeaveWindow, and MouseMotion as recognized
X *	  awm buttons for awm menus. Add bug fixes to prevent mem faults
X *	  if icon_str is NULL.
X * 002 -- L. Guarino Reid, DEC Ultrix Engineering Group
X *	  April 16, 1987
X *	  Convert to X11
X * 003 -- J. Hubbard, U.C. Berkeley. Title/gadget box event handling.
X *    December 3, 1987.
X * 004 -- J.Hubbard, Ardent Computer. More conformance with ICCCM. Merge of
X * changes to R2 uwm.
X */
X
X#ifndef lint
static char *sccsid = "@(#)GetButton.c	3.8	1/24/86";
X#endif
X/*
X *	GetButton - This subroutine is used by the Ardent Window Manager (awm)
X *	to acquire button events.  It waits for a button event to occur
X *	and handles all event traffic in the interim.
X *
X *	File:		GetButton.c
X */
X
X#include "awm.h"
X#include "X11/Xutil.h"
X
extern XContext AwmContext;
extern int Fheight;	/* the height of a title bar */
X
X#define ICONSTR	(icon_str ? icon_str : "")
X/* Amount of padding between text in a title bar and the edge of the bar */
X#define PAD	1
X
static Icon_modified = FALSE;
X
Boolean GetButton(b_ev)
XXEvent *b_ev;	/* Button event packet. */
X{
X#define STRLEN 50
X     XKeyPressedEvent *kp_event;	/* Key pressed event. */
X     char *icon_str;		/* Icon's name string. */
X     register int icon_str_len;	/* Icon name string lenght.  */
X     register int key_char;	/* Key press character code. */
X     register int icon_x;	/* Icon window X coordinate. */
X     register int icon_y;	/* Icon window Y coordinate. */
X     register int icon_w;	/* Icon window width. */
X     register int icon_h;	/* Icon window height. */    
X     int status;			/* Routine call return status. */
X     Window icon;		/* Icon window. */
X     Window appl;		/* Application window. */
X     XWindowAttributes win_info;	/* Icon window info structure. */
X     char kbd_str[STRLEN];      /* Keyboard string. */
X     int nbytes;                /* Keyboard string length. */
X     int i;                     /* Iteration counter. */
X     Window win;		/* scratch */
X     AwmInfoPtr awi;
X     
X     Entry("GetButton")
X  
X     /*
X      * Get next event from input queue and store it in the event packet
X      * passed to GetButton.
X      */
X  
X     XNextEvent(dpy, b_ev);
X     /* print_event_info("mainloop", b_ev); /* debugging for event handling */
X
X     /*
X      * The event occured on the root window, check for substructure
X      * changes. Otherwise, it must be a mouse button event. 
X      */
X     win = b_ev->xany.window;
X
X     if (win == RootWindow(dpy, scr)) {
X	  switch (b_ev->xany.type) {
X	  case CreateNotify:
X	  case UnmapNotify:
X	  case ReparentNotify:
X	  case ConfigureNotify:
X	  case GravityNotify:
X	  case MapNotify:
X	  case CirculateNotify:
X	       Leave(FALSE)
X		    
X	  case MappingNotify:
X	       XRefreshKeyboardMapping(b_ev);
X	       Leave(FALSE)
X
X	  case MapRequest: 
X	       CheckMap(b_ev->xmap.window);
X	       Leave(FALSE)
X
X	  case ConfigureRequest: 
X	       Configure((XConfigureEvent *)b_ev);
X	       Leave(FALSE)
X	       
X	  case CirculateRequest: 
X	       Circulate((XCirculateEvent *)b_ev);
X	       Leave(FALSE)
X	       
X	  case DestroyNotify:
X	       RemoveIcon(b_ev->xdestroywindow.window);
X	       Leave(FALSE)
X	       
X	  case FocusIn:
X	       if (b_ev->xfocus.detail == NotifyPointerRoot) {
X		    if (FocusSetByUser) {
X			 XSetInputFocus(dpy, PointerRoot, None,
X					CurrentTime);
X			 FocusSetByUser = FALSE;
X		    }
X	       }
X	       Leave(FALSE)
X	       
X	  case FocusOut:
X	       if (b_ev->xfocus.detail == NotifyPointerRoot) {
X		    if (FocusSetByUser == FALSE)
X			 XSetInputFocus(dpy, PointerRoot, None,
X					CurrentTime);
X	       }
X	       Leave(FALSE)
X	       
X	  case ButtonPress:
X	  case ButtonRelease:
X	       Leave(TRUE)
X	       
X	  default: 
X               fprintf(stderr, "awm: Got weird event #%d on root window\n",
X                 b_ev->xany.type);
X	       Leave(FALSE) 
X	  }
X     }
X     
X     /*
X      * If the event type is EnterWindow, LeaveWindow, or MouseMoved,
X      * we are processing a menu. 
X      * If the event type is ButtonPress or ButtonRelease,
X      * we have a button event.
X      * If it's an expose, then we may have exposed a title bar.
X      * If it's a Notify, we've probably frobbed a titled window.
X      */
X     
X     awi = GetAwmInfo(win);
X     switch (b_ev->type) {
X
X     case MotionNotify: 
X     case ButtonPress: 
X     case ButtonRelease: 
X	  Leave(TRUE) 
X
X     case EnterNotify:
X	  Leave(HandleFocusIn(b_ev))
X
X     case LeaveNotify: 
X	  Leave(HandleFocusOut(b_ev))
X
X     case ConfigureRequest:
X	  Configure((XConfigureEvent *)b_ev);
X	  Leave(FALSE)
X
X     case MapRequest:
X	  CheckMap(b_ev->xmap.window);
X	  Leave(FALSE);
X
X     case MapNotify:
X          if (!awi)
X              Leave(FALSE)
X	  if (IsIcon(win, FALSE))
X	      Leave(FALSE)
X          if (awi->frame)
X              XMapWindow(dpy, awi->frame);
X          else
X              XMapWindow(dpy, awi->client);
X          Leave(FALSE)
X	  break;
X	  
X     case UnmapNotify:
X          if (!awi)
X               Leave(FALSE)
X	  if (IsIcon(win, FALSE))
X	       Leave(FALSE)
X          if (awi->frame)
X	       XUnmapWindow(dpy, awi->frame);
X          else
X	       XUnmapWindow(dpy, awi->client);
X	  Leave(FALSE)
X	  break;
X
X     case DestroyNotify:
X          if (!awi)
X              Leave(FALSE)
X	  /* remove any icon associated with this window */
X	  RemoveIcon(win);
X	  /* remove the frame/titlebar (if present) */
X	  DestroyTitle(win);
X	  /* punt the rest of the per-window info */
X	  XDeleteContext(dpy, awi->client, AwmContext);
X	  free(awi);
X          Leave(FALSE)
X
X     case PropertyNotify:
X          if (!awi)
X               Leave(FALSE)
X	  switch(b_ev->xproperty.atom) {
X
X	  case XA_WM_COMMAND:
X	  case XA_WM_HINTS:
X	  case XA_WM_CLIENT_MACHINE:
X	       break;
X
X	  case XA_WM_ICON_NAME:
X	       /*
X		* Icon was modified by type-in (I still think that's a
X		* gross feature, but some people like it... sigh),
X		* ignore this event.
X		*/
X	       if (Icon_modified == TRUE) {
X		    Icon_modified = FALSE;	/* reset */
X		    Leave(FALSE)
X	       }
X	       if (awi->icon) {
X		    win = awi->icon;
X		    status = XGetWindowAttributes(dpy, win, &win_info);
X		    icon_str = GetIconName(awi->client);
X		    icon_str_len = icon_str ? strlen(icon_str) : 0;
X		    if (win_info.width != XTextWidth(IFontInfo, ICONSTR,
X						     strlen(ICONSTR))+(HIconPad << 1)) {
X			 XResizeWindow(dpy, win, 
X				       XTextWidth(IFontInfo, ICONSTR, strlen(ICONSTR)) +
X				       (HIconPad << 1), IFontInfo->ascent +
X				       IFontInfo->descent + (VIconPad << 1));
X		    }
X		    XClearWindow(dpy, win);
X		    if (icon_str_len != 0) {
X			 XDrawImageString(dpy, win, IconGC, HIconPad,
X					  VIconPad+IFontInfo->ascent, icon_str,
X					  icon_str_len);
X			 free(icon_str);
X		    }
X	       }
X	       break;
X
X	  case XA_WM_ICON_SIZE:
X	       break;
X
X	  case XA_WM_NAME:
X	       if (awi->title) {
X		    if (awi->name)
X			 free(awi->name);
X		    awi->name = (char *)GetTitleName(win);
X		    PaintTitle(win);
X	       }
X	       break;
X
X	  case XA_WM_NORMAL_HINTS:
X	  case XA_WM_SIZE_HINTS:
X	  case XA_WM_ZOOM_HINTS:
X	       break;
X
X	  default:
X	       fprintf(stderr, "awm: Got unknown property %d\n",
X		       b_ev->xproperty.atom);
X	  }
X	  Leave(FALSE)
X	  break;
X	  
X	  
X     case Expose:
X          if (!awi) /* probably a menu */
X               Leave(FALSE)
X	  if (awi->title == win) {
X	       if (b_ev->xexpose.count == 0) {
X		    XEvent evt;
X
X		    while (XCheckTypedWindowEvent(dpy, awi->title, Expose, &evt));
X		    PaintTitle(win);
X		    if (awi->gadgets)
X			 PaintGadgets(win);
X	       }
X	       Leave(FALSE)
X	  }
X	  break;
X	  
X     default:
X	  break;
X     }
X     
X     /*
X      * If we got this far, the event must be for an icon.
X      */
X     
X     if (!awi)
X          Leave(FALSE)
X     status = XGetWindowAttributes(dpy, win, &win_info);
X     if (status == FAILURE)
X	  Leave(FALSE)
X     
X     if (b_ev->type == MapNotify || 
X	 b_ev->type == UnmapNotify ||
X	 b_ev->type == CreateNotify ||
X	 b_ev->type == ReparentNotify ||
X	 b_ev->type == GravityNotify ||
X	 b_ev->type == CirculateNotify ||
X	 b_ev->type == ConfigureNotify)
X	  Leave(FALSE)
X     
X     /*
X      * Initialize the icon position variables.
X      */
X     icon_x = win_info.x;
X     icon_y = win_info.y;
X     
X     /*
X      * Get the name of the window associated with the icon and
X      * determine its length.
X      */
X     if (!awi->icon)
X	  Leave(FALSE)
X     icon = awi->icon;
X     icon_str = GetIconName(awi->client);
X     icon_str_len = icon_str ? strlen(icon_str) : 0;
X     
X     /*
X      * If the event is a window exposure event and the icon's name string
X      * is not of zero length, simply repaint the text in the icon window
X      * and return FALSE.
X      */
X     if (b_ev->type == Expose && (!Freeze || Frozen == 0)) {
X	  if (win_info.width != 
X	      XTextWidth(IFontInfo, ICONSTR, strlen(ICONSTR))+(HIconPad << 1)) {
X	       XResizeWindow(dpy, icon, 
X			     XTextWidth(IFontInfo, ICONSTR, strlen(ICONSTR))+(HIconPad << 1),
X			     IFontInfo->ascent + IFontInfo->descent + (VIconPad << 1));
X	  }
X	  XClearWindow(dpy, icon);
X	  if (icon_str_len != 0) {
X	       XDrawImageString(dpy, icon,
X				IconGC, HIconPad, VIconPad+IFontInfo->ascent,
X				icon_str, icon_str_len);
X	       /*
X		* Remember to free the icon name string.
X		*/
X	       free(icon_str);
X	  }
X	  Leave(FALSE)
X     }
X     
X     /*
X      * If we have gotten this far event can only be a key pressed event.
X      */
X     kp_event = (XKeyPressedEvent *) b_ev;
X     
X     /* 
X      * We convert the key pressed event to ascii.
X      */
X     nbytes = XLookupString(kp_event, kbd_str, STRLEN, NULL);
X     
X     /*
X      * If kbd_str is a "non-string", then don't do anything.
X      */
X     if (nbytes == 0) {
X	  if (icon_str)
X	       free(icon_str);
X	  Leave(FALSE)
X     }
X     for (i = 0; i < nbytes; i++) {
X	  key_char = kbd_str[i];
X	  /*
X	   * If the key was <DELETE>, then delete a character from the end of
X	   * the name, return FALSE.
X	   *
X	   * If the key was <CTRL-U>, then wipe out the entire window name
X	   * and return FALSE.
X	   *
X	   * All other ctrl keys are squashed and we return FALSE.
X	   *
X	   * All printable characters are appended to the window's name, which
X	   * may have to be grown to allow for the extra length.
X	   */
X	  if (key_char == '\177') {
X	       /*
X		* <DELETE>
X		*/
X	       if (icon_str_len > 0) {
X		    icon_str_len--;
X		    icon_str[icon_str_len] = '\0';
X	       }
X	  }
X	  else if (key_char == '\025') {
X	       /*
X		* <CTRL-U>
X		*/
X	       if (icon_str_len > 0) {
X		    icon_str_len = 0;
X		    icon_str[0] = '\0';
X	       }
X	  }
X	  else if (key_char < IFontInfo->min_char_or_byte2 ||
X		   key_char > IFontInfo->max_char_or_byte2) {
X	       /*
X		* Any other random (non-printable) key; ignore it.
X		*/
X	       /* do nothing */ ;
X			   }
X	  else {
X	       /*
X		* ASCII Alphanumerics.
X		*/
X	       if (icon_str == NULL)
X		    icon_str = (char *) malloc (icon_str_len + 2);
X	       else
X		    icon_str = (char *)realloc(icon_str, (icon_str_len + 2));
X	       if (icon_str == NULL) {
X		    errno = ENOMEM;
X		    Error("GetButton -> Realloc of window name string memory failed.");
X	       }
X	       icon_str[icon_str_len] = key_char;
X	       icon_str[icon_str_len + 1] = '\0';
X	       icon_str_len += 1;
X	  }
X     }
X     
X     /*
X      * Now that we have changed the size of the icon we have to reconfigure
X      * it so that everything looks good.  Oh yes, don't forget to move the
X      * mouse so that it stays in the window!
X      */
X     
X     /*
X      * Set the window name to the new string. Icon_modified is a kludge
X      * that tells us to avoid the next PropertyNotify, as it's a result of
X      * this call.
X      */
X     XSetIconName(dpy, awi->client, ICONSTR);
X     Icon_modified = TRUE;
X     /*
X      * Determine the new icon window configuration.
X      */
X     icon_h = IFontInfo->ascent + IFontInfo->descent + (VIconPad << 1);
X     icon_w = XTextWidth(IFontInfo, ICONSTR, strlen(ICONSTR));
X     if (icon_w == 0) {
X	  icon_w = icon_h;
X     }
X     else {
X	  icon_w += (HIconPad << 1);
X     }
X     
X     if (icon_x < 0) icon_x = 0;
X     if (icon_y < 0) icon_y = 0;
X     if (icon_x - 1 + icon_w + (IBorderWidth << 1) > ScreenWidth) {
X	  icon_x = ScreenWidth - icon_w - (IBorderWidth << 1) + 1;
X     }
X     if (icon_y - 1 + icon_h + (IBorderWidth << 1) > ScreenHeight) {
X	  icon_y = ScreenHeight - icon_h - (IBorderWidth << 1) + 1;
X     }
X     
X     XMoveResizeWindow(dpy, icon, icon_x, icon_y, icon_w, icon_h);
X     XWarpPointer(dpy, None, icon, 
X		  0, 0, 0, 0, (icon_w >> 1), (icon_h >> 1));
X     
X     /* 
X      * Free the local storage and return FALSE.
X      */
X     if (icon_str)
X	  free(icon_str);
X     Leave(FALSE)
X}
X
CheckMap(window)
Window window;
X{
X     XWMHints *XGetWMHints();
X     XWMHints *wmhints;
X     int x, y, w, h;
X     Window transient_for;
X     Window jW;
X     int border_width, j;
X     Binding *bptr;
X     AwmInfoPtr awi;
X
X     Entry("CheckMap")
X
X     /* if it's a transient window, we won't rubber-band
X      * note that this call always sets transient_for.
X      */
X     if (!XGetTransientForHint( dpy, window, &transient_for )) {
X	  /*
X	   * Handle any registered grabs for this window. We do this here
X	   * because we may be about to make an icon out of this window
X	   * and we want to register any potential grabs on it before this
X	   * happens.
X	   */
X	  awi = GetAwmInfo(window);
X	  if (!awi) {
X	       for (bptr = Blist; bptr; bptr = bptr->next)
X		    if (bptr->context & WINDOW)
X			 Grab(bptr->mask, window);
X	       XSelectInput(dpy, window, (EnterWindowMask | LeaveWindowMask |
X					  PropertyChangeMask));
X	       awi = RegisterWindow(window);
X	       if (Titles) {
X		    AddTitle(window);
X		    if (UseGadgets)
X			 PutGadgets(window);
X	       }
X	  }
X	  if ((wmhints = XGetWMHints(dpy, window))) {
X	       if ((wmhints->flags & StateHint) && (awi->state == WINDOW) &&
X		   (wmhints->initial_state == IconicState)) {
X		    /* window wants to be created as an icon. Leave size
X		       /* and position alone, create as icon. */
X                         XFree(wmhints);
X                         Iconify(window, 0, 0, 0, 0);
X                         Leave_void
X	       }
X	       XFree(wmhints);
X	  }
X     }
X     else
X	  if ((awi = GetAwmInfo(window)) == NULL)
X	       awi = RegisterWindow(window);
X     if (awi->state == WINDOW) {
X	  PlaceWindow(window);
X	  if (awi->frame) {
X	       XMapRaised(dpy, awi->frame);
X	       XMapWindow(dpy, awi->client);
X	  }
X	  else
X	       XMapRaised(dpy, awi->client);
X     }
X     Leave_void
X}
X
Configure(event)
XXConfigureRequestEvent *event;
X{
X     XWindowChanges values;
X     AwmInfoPtr awi;
X     
X     Entry("Configure")
X
X     values.x = event->x;
X     values.y = event->y;
X     values.width = event->width;
X     values.height = event->height;
X     values.border_width = event->border_width;
X     values.stack_mode = event->detail;
X     values.sibling = event->above;
X
X     ConfigureWindow(event->window, event->value_mask, &values);
X     Leave_void
X}
X
Circulate(event)
XXCirculateEvent *event;
X{
X     Entry("Circulate")
X
X     if (event->place == PlaceOnTop)
X	  XRaiseWindow(event->display, event->window);
X     else
X	  XLowerWindow(event->display, event->window);
X     Leave_void
X}
X
PlaceWindow(window)
Window window;
X{
X     XSizeHints wsh;
X     int x, y, w, h;
X     Boolean configureit = False;
X     XWindowChanges xwc;
X     AwmInfoPtr awi;
X     long flags;
X
X     wsh.flags = 0;
X     flags = CWX | CWY | CWWidth | CWHeight;
X     awi = GetAwmInfo(window);
X     XGetSizeHints(dpy, window, &wsh, XA_WM_NORMAL_HINTS);
X     CheckConsistency(&wsh);
X     AskUser(dpy, scr, window, &x, &y, &w, &h, &wsh);
X
X     wsh.flags |= (USPosition | USSize);
X     wsh.x = x;
X     wsh.y = y;
X     wsh.width = w;
X     wsh.height = h;
X     if (x < 0 || y < 0) {
X	  Window jW;
X	  int j, border_width;
X
X	  XGetGeometry(dpy, window, &jW, &j, &j, &j, &j, &border_width, &j);
X
X	  if (x < 0)
X	       x += DisplayWidth(dpy, scr) - w - (border_width<<1);
X	  if (y < 0)
X	       y += DisplayHeight(dpy, scr) - h - (border_width<<1);
X     }
X     if (IsTitled(window))
X	  XSetSizeHints(dpy, awi->frame, &wsh, XA_WM_NORMAL_HINTS);
X     XSetSizeHints(dpy, awi->client, &wsh, XA_WM_NORMAL_HINTS);
X#ifdef titan /* 5x4 alignment */
X     x += (x % 5);
X     y += (y % 4);
X#endif
X     xwc.x = x;
X     xwc.y = y;
X     xwc.height = h;
X     xwc.width = w;
X     ConfigureWindow(window, flags, &xwc);
X     awi->placed = TRUE;
X}
X
Boolean ConfigureWindow(w, mask, xwc)
Window w;
unsigned long mask;
XXWindowChanges *xwc;
X{
X     XWindowAttributes xwa;
X     AwmInfoPtr awi;
X     Boolean compensate = TRUE;
X
X     Entry("ConfigureWindow")
X
X     awi = GetAwmInfo(w);
X     if (!awi)
X          Leave(FALSE)
X     if (w == awi->frame)
X	  compensate = FALSE;
X	  
X     if (awi->frame) {
X	  if (compensate)
X	       xwc->width += (BContext ? (BContext * 2) + 2 : 0);
X	  XResizeWindow(dpy, awi->title, xwc->width, Fheight);
X	  if (compensate)
X	       xwc->height += (Fheight + 2 + (BContext ? BContext + 1 : 0));
X	  if (TitlePush == FALSE && compensate) {
X	       xwc->y -= (Fheight + 2);
X	       if (xwc->y < 0)
X		    xwc->y = 0;
X	  }
X	  XConfigureWindow(dpy, awi->frame, mask, xwc);
X	  xwc->height -= (Fheight + 2 + (BContext ? BContext + 1 : 0));
X	  xwc->width -= (BContext ? ((BContext * 2) + 2) : 0);
X          xwc->y = Fheight + 2;
X          if (BContext)
X               xwc->x = BContext;
X	  else
X	       xwc->x = 0;
X	  if (awi->gadgets)
X	       PutGadgets(w);
X     }
X     XConfigureWindow(dpy, awi->client, mask, xwc);
X     Leave(TRUE)
X}
X
int
ProcessRequests(box, num_vectors)
XXSegment *box;
int num_vectors;
X{
X	XEvent event;
X
X	XPeekEvent(dpy, &event);
X	switch (event.type) {
X
X	case MapRequest:
X	case ConfigureRequest:
X	case CirculateRequest:
X
X	    DrawBox();
X	    GetButton(&event);
X	    DrawBox();
X	    return TRUE;
X	}
X	return FALSE;
X}
END_OF_FILE
if test 19196 -ne `wc -c <'GetButton.c'`; then
    echo shar: \"'GetButton.c'\" unpacked with wrong size!
fi
# end of 'GetButton.c'
fi
if test -f 'gram.y' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'gram.y'\"
else
echo shar: Extracting \"'gram.y'\" \(25572 characters\)
sed "s/^X//" >'gram.y' <<'END_OF_FILE'
X/* $Header: gram.y,v 1.6 87/05/24 22:11:00 jg Exp $ */
X
X
X/*
X * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
X *
X *                         All Rights Reserved
X *
X * Permission to use, copy, modify, and distribute this software and its
X * documentation for any purpose and without fee is hereby granted,
X * provided that the above copyright notice appear in all copies and that
X * both that copyright notice and this permission notice appear in
X * supporting documentation, and that the name of Digital Equipment
X * Corporation not be used in advertising or publicity pertaining to
X * distribution of the software without specific, written prior permission.
X *
X *
X * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
X * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
X * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
X * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
X * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
X * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
X * SOFTWARE.
X */
X
X
X/*
X * MODIFICATION HISTORY
X *
X * 000 -- M. Gancarz, DEC Ultrix Engineering Group
X * 001 -- Loretta Guarino Reid, DEC Ultrix Engineering Group
X *  Western Software Lab. Convert to X11.
X * 002 -- Jordan Hubbard, U.C. Berkeley. New keywords. Menu
X * changes, gadget boxes, title bars, the kitchen sink.
X */
X
X%{
X#ifndef lint
X     static char *sccsid = "@(#)gram.y	3.8	1/24/86";
X#endif
X     
X#include <X11/copyright.h>
X#include <X11/Xlib.h>
X#include <X11/Xutil.h>
X#include "awm.h"
X#include <signal.h>
X
X/*
X * Values returned by complex expression parser.
X */
X#define C_STRING	1	/* IsString. */
X#define C_MENU		2	/* IsMenu. */
X#define C_MAP		3	/* IsMap. */
X#define C_MENUMAP	4	/* IsMenuMap */
X#define C_PIXMAP	5	/* IsPixmap */
X#define C_ACTION	6	/* IsAction */
X     
X     static int ki;			/* Keyword index. */
X     static int gadgnum;		/* the number of the gadget we're initing */
X     static int g_offset;		/* The gadget offset (if any) specified */
X     static int g_gravity;		/* The gadget gravity (if any) specified */
X     static long g_forecolor;		/* gadget foreground color */
X     static long g_backcolor;		/* gadget background color */
X     static XFontStruct *g_font;	/* gadget font */
X     static int bkmask;			/* Button/key mask. */
X     static int cmask;			/* Context mask. */
X     static char msg[BUFSIZ];		/* Error message buffer. */
X     static char *menu_name;		/* Menu name. */
X     static char *menu_pixmap;		/* Name of pixmap for menu label (optional) */
X     static MenuInfo *menu_info;	/* Menu info. */
X     static ActionLine *ml_ptr;		/* Temporary menu line pointer. */
X     static ActionLine *action;		/* Temporary action pointer */
X     MenuLink *menu_link;		/* Temporary menu link pointer. */
X     GadgetDecl **Gadgets;		/* Pointer to gadget info structs */
X     char *calloc();
X     
X     %}
X
X%union {
X     char *sval;
X     int ival;
X     short shval;
X     struct _actionline *alval;
X     struct _menuinfo *mival;
X     char **cval;
X}
X
X%token NL
X     %token <sval> STRING
X     %token <ival> COMMENT
X     %type <sval> pixmap_file
X     %type <ival> gadget_subscript
X     %type <ival> keyword
X     %type <ival> compexpr
X     %type <ival> keyexpr
X     %type <ival> kmask
X     %type <ival> contexpr
X     %type <ival> contmask
X     %type <ival> buttmodexpr
X     %type <ival> buttmodifier
X     %type <ival> buttexpr
X     %type <sval> menuname
X     %type <sval> strings
X     %type <alval> textaction
X     %type <alval> menuexpr
X     %type <alval> menulist
X     %type <alval> menuline
X     %type <alval> menuaction
X
X     %%	/* beginning of rules section */
X     
X input:	|	input command
X     |	input error command { yyerrok; }
X;
X
X command:	boolvar term
X     |	expr term
X     |	COMMENT	{ Lineno++; }
X     |	term
X     ;
X
X term:		NL	{ Lineno++; }
X|	';'
X     ;
X
X expr:		keyword '=' compexpr
X{
X     switch (KeywordTable[$1].type) {
X     case IsQuitFunction:
X     case IsFunction:
X	  if ($3 == C_MAP) {
X	       bindtofunc($1, bkmask, cmask, NULL);
X	  } else yyerror("illegal construct");
X	  break;
X
X     case IsDownFunction:
X	  if (bkmask & ButtonUp) {
X	       sprintf(msg,
X		       "cannot bind %s to button up",
X		       KeywordTable[$1].name);
X	       yyerror(msg);
X	  }
X	  if ($3 == C_MAP) {
X	       bindtofunc($1, bkmask, cmask, NULL);
X	  } else yyerror("illegal construct");
X	  break;
X
X     case IsMenuMap:
X	  if (bkmask & ButtonUp) {
X	       sprintf(msg,
X		       "cannot bind %s to button up",
X		       KeywordTable[$1].name);
X	       yyerror(msg);
X	  }
X	  if ($3 == C_MENUMAP) {
X	       bindtofunc
X		    ($1, bkmask, cmask, menu_name);
X	  } else yyerror("illegal construct");
X	  break;
X
X     case IsAction:
X	  if ($3 == C_ACTION) {
X	       /*
X		* We pass a structure pointer here where a char pointer
X		* is supposed to go. It was a hack, what can I say.
X		*/
X	       bindtofunc
X		    ($1, bkmask, cmask, (char *)action);
X	  } else yyerror("illegal construct");
X	  break;
X
X     case IsMenu:
X	  if ($3 == C_MENU) {
X	       /*
X		* create a menu definition entry.
X		*/
X	       menu_info = stashmenuinfo(menu_name, ml_ptr, menu_pixmap);
X	       menu_link = stashmenulink(menu_info);
X	       Menus = appendmenulink(Menus, menu_link);
X	  } else yyerror("illegal menu construct");
X	  break;
X
X     case IsGadget:
X	  if (gadgnum < 0) {
X	       sprintf(msg, "Gadget number must be >= 0\n");
X	       yyerror(msg);
X	  }
X	  /* Bump NumGadgets if necessary */
X	  else if (gadgnum >= NumGadgets)
X	       NumGadgets = gadgnum + 1;
X	  if (NumGadgets > MAX_GADGETS) {
X	       sprintf(msg, "\"numgadgets\" (%d) is > MAX_GADGETS (%d)\n",
X		       NumGadgets, MAX_GADGETS);
X	       yyerror(msg);
X	  }
X	  else {
X	       if ($3 != C_STRING && $3 != C_PIXMAP)
X		    yyerror("Illegal gadget assignment");
X	       else
X		    stashGadget(gadgnum, yylval.sval, $3);
X	  }
X	  break;
X
X     default:
X	  yyerror("internal binding error");
X	  break;
X     }
X}
X;
X pixmap_file:	'(' STRING ')' {
X      $$ = $2;
X }
X;
X compexpr:	keyexpr ':' contexpr ':' buttexpr
X{
X     $$ = C_MAP;
X     bkmask = $1 | $5;
X     cmask = $3;
X}
X|	keyexpr ':' contexpr ':' buttexpr ':' menuname
X{
X     $$ = C_MENUMAP;
X     bkmask = $1 | $5;
X     cmask = $3;
X     menu_name = $7;
X}
X|	keyexpr ':' contexpr ':' buttexpr ':' textaction
X{
X     $$ = C_ACTION;
X     bkmask = $1 | $5;
X     cmask = $3;
X     action = $7;
X}
X|	STRING menuexpr
X{
X     $$ = C_MENU;
X     menu_name = $1;
X     menu_pixmap = 0;
X     ml_ptr = $2;
X}
X|	pixmap_file STRING menuexpr
X{
X     $$ = C_MENU;
X     menu_name = $2;
X     menu_pixmap = $1;
X     ml_ptr = $3;
X}
X|	STRING '^' gadgetspec
X{ yylval.sval = $1; $$ = C_STRING; }
X|	pixmap_file '^' gadgetspec
X{ yylval.sval = $1; $$ = C_PIXMAP; }
X|	STRING
X{
X     $$ = C_STRING;
X     /* just in case it's a gadget, set defaults */
X     g_forecolor = ForeColor;
X     g_backcolor = BackColor;
X     g_gravity = NoGadgetGravity;
X     g_offset = 0;
X     g_font = 0;
X}
X|	pixmap_file
X{
X     $$ = C_PIXMAP;
X     /* just in case it's a gadget, set defaults */
X     g_forecolor = ForeColor;
X     g_backcolor = BackColor;
X     g_gravity = NoGadgetGravity;
X     g_offset = 0;
X     g_font = 0;
X}     
X;
X gadgetspec:	 offset
X|  offset '|' gravity
X|  offset '|' gravity '|' forecolor
X|  offset '|' gravity '|' forecolor '|' backcolor
X|  offset '|' gravity '|' forecolor '|' backcolor '|' fontspec
X;
X offset: /* empty */
X{ g_offset = 0; }
X| STRING
X{ g_offset = y_atoi($1); }
X;
X gravity: /* empty */
X{ g_gravity = NoGadgetGravity; }
X| STRING
X{ g_gravity = gravitylookup($1); }
X;
X forecolor: /* empty */
X{ g_forecolor = ForeColor; }
X| STRING
X{ g_forecolor = LookupColor($1); }
X;
X backcolor: /* empty */
X{ g_backcolor = BackColor; }
X| STRING
X{ g_backcolor = LookupColor($1); }
X;
X fontspec: /* empty */
X{ g_font = 0; }
X| STRING
X{
X     g_font = XLoadQueryFont(dpy, $1);
X     if (!g_font) {
X	  sprintf(msg, "Can't open gadget font '%s'\n", $1);
X	  yywarn(msg);
X     }
X}
X;
X
X boolvar:	STRING
X{
X     ki = keywordlookup(yylval.sval);
X     switch (KeywordTable[ki].type) {
X     case IsParser:
X	  (*KeywordTable[ki].fptr)();
X	  break;
X     default:
X	  yyerror("keyword error");
X     }
X}
X;
X
X keyword:	STRING	{
X      $$ = keywordlookup(yylval.sval);
X }
X|	STRING gadget_subscript {
X     $$ = keywordlookup("gadget");
X     gadgnum = $2;
X}
X;
X
X gadget_subscript:	'[' STRING ']' {
X      $$ = y_atoi(yylval.sval);
X }
X;
X
X keyexpr:	/* empty */
X{ $$ = 0; }
X|	kmask
X{ $$ = $1; }
X|	kmask '|' keyexpr
X{ $$ = $1 | $3; }
X;
X
X contexpr:	/* empty */
X{ $$ = 0xffffffff; }
X|	contmask
X{ $$ = $1; }
X|	contmask '|' contexpr
X{ $$ = $1 | $3; }
X;
X
X buttexpr:	buttmodexpr
X{ $$ = CheckButtonState($1); }
X;
X
X kmask:		STRING { $$ = keyexprlookup(yylval.sval); }
X
X contmask:	STRING
X{ $$ = contexprlookup(yylval.sval); }
X|	STRING gadget_subscript
X{ 
X     if ($2 < 0 || $2 >= NumGadgets) {
X	  sprintf(msg, "Bad subscript, gadget #%d must be >= 0 and < %d\n",
X		  $2, NumGadgets);
X	  yyerror(msg);
X     }
X     else {
X	  $$ = contexprlookup("gadget") | (1 << (BITS_USED + $2));
X     }
X}
X;
X buttmodexpr: 	buttmodifier
X{ $$ = $1; }
X|	buttmodexpr buttmodifier
X{ $$ = $1 | $2; }
X;
X
X buttmodifier:	STRING
X{ $$ = buttexprlookup(yylval.sval); }
X;
X
X menuname:	STRING
X{ $$ = $1; }
X;
X
X menuexpr:	'{' menulist '}'
X{ $$ = $2; }
X;
X
X menulist:	menuline
X{ $$ = $1; }
X|	menulist menuline
X{ $$ = appendmenuline($1, $2); }
X|	menulist COMMENT
X{
X     Lineno++;
X     $$ = $1;
X}
X|	COMMENT
X{
X     Lineno++;
X     $$ = NULL;
X}
X|	term
X{ $$ = NULL; }
X|	menulist term
X{ $$ = $1; }
X|	error term
X{
X     $$ = NULL;
X     yyerrok;
X}
X;
X
X menuline:	strings ':' menuaction term
X{
X     $3->name = $1;
X     $3->pixmapname = (char *)0;
X     $$ = $3;
X}
X|	'(' strings ')' ':' menuaction term
X{
X     $5->pixmapname = $2;
X     $5->name = $2;
X     $$ = $5;
X}
X;
X
X menuaction:	STRING
X{
X     ki = keywordlookup(yylval.sval);
X     if ((ki != -1) &&
X	 (KeywordTable[ki].type != IsFunction) &&
X	 (KeywordTable[ki].type != IsImmFunction) &&
X	 (KeywordTable[ki].type != IsQuitFunction) &&
X	 (KeywordTable[ki].type != IsBoolean) &&
X	 (KeywordTable[ki].type != IsDownFunction)) {
X	  sprintf(msg,
X		  "menu action \"%s\" not a function or variable",
X		  KeywordTable[ki].name);
X	  yyerror(msg);
X     }
X     ml_ptr = AllocActionLine();
X     if (KeywordTable[ki].type == IsQuitFunction ||
X	KeywordTable[ki].type == IsImmFunction)
X	  ml_ptr->type = IsImmFunction;
X     else if (KeywordTable[ki].type == IsBoolean) {
X	  ml_ptr->type = IsVar;
X	  ml_ptr->text = (char *)KeywordTable[ki].bptr;
X     }
X     else
X	  ml_ptr->type = IsUwmFunction;
X     ml_ptr->func = KeywordTable[ki].fptr;
X     $$ = ml_ptr;
X}
X|	STRING ':' menuname
X{
X     ki = keywordlookup($1);
X     if (ki != -1 &&
X	 KeywordTable[ki].type != IsMenuMap) {
X	  sprintf(msg,
X		  "menu action \"%s\" not a menu function",
X		  KeywordTable[ki].name);
X	  yyerror(msg);
X     }
X     ml_ptr = AllocActionLine();
X     ml_ptr->type = IsMenuFunction;
X     ml_ptr->text = $3;
X     $$ = ml_ptr;
X}
X|	textaction
X{ $$ = $1; }
X;
X
X textaction: '!' strings
X{
X     $$ = StashActionLine(IsShellCommand, $2);
X}
X|	'^' strings
X{
X     $$ = StashActionLine(IsTextNL, $2);
X}
X|	'|' strings
X{
X     $$ = StashActionLine(IsText, $2);
X}
X;
X
X strings:	STRING	{ $$ = yylval.sval; }
X|	strings STRING
X{ $$ = strconcat($1, $2); }
X;
X
X%%
X
X/*
X * Look up color named by "string" and return pixel value.
X */
long LookupColor(string)
char *string;
X{
X     XColor vis_ret, act_ret;
X     static int ncolors = 0;
X
X     Entry("LookupColor");
X
X     if (MaxColors && ncolors >= MaxColors) {
X	  sprintf(msg, "Can't allocate color '%s', MaxColors (%d) exceeded\n",
X		  string, MaxColors);
X	  yywarn(msg);
X	  Leave(NOCOLOR)
X     }
X     if (!XAllocNamedColor(dpy, DefaultColormap(dpy, scr), string,
X			  &vis_ret, &act_ret)) {
X	 sprintf(msg, "Can't allocate color '%s', using default\n", string);
X	 yywarn(msg);
X	 Leave(NOCOLOR)
X     }
X     ncolors++;
X     Leave(vis_ret.pixel)
X}
X
X/*
X * Look up a string in the keyword table and return its index, else
X * return -1.
X */
int keywordlookup(string)
char *string;
X{
X     int i;
X     
X     Entry("keywordlookup")
X
X     for (i = 0; KeywordTable[i].name; i++) {
X	  if (!strcmp(KeywordTable[i].name, string)) {
X	       free(string);
X	       Leave(i)
X	  }
X     }
X     sprintf(msg,"keyword error: \"%s\"", string);
X     yyerror(msg);
X     free(string);
X     Leave(-1)
X}
X
X/*
X * Look up a string in the key expression table and return its mask, else
X * return -1.
X */
int keyexprlookup(string)
char *string;
X{
X     int i;
X     
X     Entry("keyexprlookup")
X
X     for (i = 0; KeyExprTbl[i].name; i++) {
X	  if (!strcmp(KeyExprTbl[i].name, string)) {
X	       free(string);
X	       Leave(KeyExprTbl[i].mask)
X	  }
X     }
X     sprintf(msg,"key expression error: \"%s\"", string);
X     yyerror(msg);
X     free(string);
X     Leave(-1)
X}
X
int gravitylookup(string)
char *string;
X{
X     int i;
X
X     Entry("gravitylookup")
X
X     for (i = 0; GravityExprTbl[i].name; i++) {
X	  if (!strcmp(GravityExprTbl[i].name, string)) {
X	       free(string);
X	       Leave(GravityExprTbl[i].mask)
X	  }
X     }
X     sprintf(msg, "gravity expression error: \"%s\"", string);
X     yyerror(msg);
X     free(string);
X     Leave(-1);
X}
X    
X/*
X * Look up a string in the context expression table and return its mask, else
X * return -1.
X */
contexprlookup(string)
char *string;
X{
X     int i;
X     
X     Entry("contexprlookup")
X
X     for (i = 0; ContExprTbl[i].name; i++) {
X	  if (!strcmp(ContExprTbl[i].name, string)) {
X	       free(string);
X	       Leave(ContExprTbl[i].mask)
X	  }
X     }
X     sprintf(msg,"context expression error: \"%s\"", string);
X     yyerror(msg);
X     free(string);
X     Leave(-1)
X}
X
X/*
X * Look up a string in the button expression table and return its mask, else
X * return -1.
X */
buttexprlookup(string)
char *string;
X{
X     int i;
X     
X     Entry("buttexprlookup")
X
X     for (i = 0; ButtModTbl[i].name; i++) {
X	  if (!strcmp(ButtModTbl[i].name, string)) {
X	       free(string);
X	       Leave(ButtModTbl[i].mask)
X	  }
X     }
X     sprintf(msg,"button modifier error: \"%s\"", string);
X     yyerror(msg);
X     free(string);
X     Leave(-1)
X}
X
X/*
X * Scan a string and return an integer.  Report an error if any
X * non-numeric characters are found.
X */
y_atoi(s)
char *s;
X{
X     int n = 0;
X     
X     Entry("y_atoi")
X
X     while (*s) {
X	  if (*s >= '0' && *s <= '9')
X	       n = 10 * n + *s - '0';
X	  else {
X	       yyerror("non-numeric argument");
X	       Leave(-1)
X	  }
X	  s++;
X     }
X     Leave(n)
X}
X
X/*
X * Append s2 to s1, extending s1 as necessary.
X */
char *
X     strconcat(s1, s2)
char *s1, *s2;
X{
X     char *malloc();
X     char *p;
X     
X     Entry("strconcat")
X
X     p = malloc(strlen(s1) + strlen(s2) + 2);
X     sprintf(p, "%s %s", s1, s2);
X     free(s1);
X     free(s2);
X     s1 = p;
X     Leave(s1)
X}
X
X/*
X * Check a button expression for errors.
X */
int CheckButtonState(expr)
int expr;
X{
X     Entry("CheckButtonState")
X
X     /*
X      * Check for one (and only one) button.
X      */
X     switch (expr & (LeftMask | MiddleMask | RightMask)) {
X     case 0:
X	  yyerror("no button specified");
X	  break;
X     case LeftMask:
X	  break;
X     case MiddleMask:
X	  break;
X     case RightMask:
X	  break;
X     default:
X	  yyerror("more than one button specified");
X     }
X     
X     /*
X      * Check for one (and only one) up/down/motion modifier.
X      */
X     switch (expr & (ButtonUp | ButtonDown | DeltaMotion)) {
X     case 0:
X	  yyerror("no button action specified");
X	  break;
X     case ButtonUp:
X	  break;
X     case ButtonDown:
X	  break;
X     case DeltaMotion:
X	  break;
X     default:
X	  yyerror("only one of up/down/motion may be specified");
X     }
X     Leave(expr)
X}
X
X/*
X * Bind button/key/context to a function.
X */
bindtofunc(index, mask, context, name)
int index;		/* Index into keyword table. */
int mask;		/* Button/key/modifier mask. */
int context;		/* ROOT, WINDOW, TITLE, ICON, GADGET or BORDER */
char *name;		/* Menu, if needed. */
X{
X     Entry("bindtofunc")
X
X     setbinding(context, index, mask, name);
X     Leave_void
X}
X
X/*
X * Allocate a Binding type and return a pointer.
X */
Binding *
X     AllocBinding()
X{
X     Binding *ptr;
X     
X     Entry("AllocBinding")
X
X     if (!(ptr = (Binding *)calloc(1, sizeof(Binding)))) {
X	  sprintf(msg, "Can't allocate binding--out of space\n");
X	  yyerror(msg);
X	  exit(1);
X     }
X     Leave(ptr)
X}
X
X/*
X * Stash the data in a Binding.
X */
setbinding(cont, i, m, mname)
int cont;		/* Context: ROOT, WINDOW, or ICON. */
int i;			/* Keyword table index. */
int m;		/* Key/button/modifier mask. */
char *mname;		/* Pointer to menu name, if needed. */
X{
X     Binding *ptr;
X     MenuInfo *mi;
X
X     Entry("setbinding")
X
X     ptr = AllocBinding();
X     ptr->context = cont;
X     ptr->mask = m;
X     ptr->func = KeywordTable[i].fptr;
X     ptr->menuname = mname;
X     switch (m & (LeftMask | MiddleMask | RightMask)) {
X     case LeftMask:
X	  ptr->button = LeftButton;
X	  break;
X     case MiddleMask:
X	  ptr->button = MiddleButton;
X	  break;
X     case RightMask:
X	  ptr->button = RightButton;
X	  break;
X     }
X     appendbinding(ptr);
X     Leave_void
X}
X
X/*
X * Append a Binding to the Bindings list.
X */
appendbinding(binding)
Binding *binding;
X{
X     Binding *ptr;
X     
X     Entry("appendbinding")
X
X     if (Blist == NULL)
X	  Blist = binding;
X     else {
X	  for(ptr = Blist; ptr->next; ptr = ptr->next) /* NULL */;
X	  ptr->next = binding;
X	  ptr = ptr->next;
X	  ptr->next = NULL;
X     }
X     Leave_void
X}
X
X/*
X * Allocate an action line and return a pointer.
X */
ActionLine *AllocActionLine()
X{
X     ActionLine *ptr;
X     
X     Entry("AllocActionLine")
X
X     if (!(ptr = (ActionLine *)calloc(1, sizeof(ActionLine)))) {
X	  sprintf(msg, "Can't allocate action line--out of space\n");
X	  yyerror(msg);
X     }
X     Leave(ptr)
X}
X
X/*
X * Allocate a MenuInfo structure and return a pointer.
X */
MenuInfo *AllocMenuInfo()
X{
X     MenuInfo *ptr;
X     
X     Entry("AllocMenuInfo")
X
X     if (!(ptr = (MenuInfo *)calloc(1, sizeof(MenuInfo)))) {
X	  sprintf(msg, "Can't allocate menu storage--out of space\n");
X	  yyerror(msg);
X     }
X     Leave(ptr)
X}
X
X/*
X * Allocate a MenuLink structure and return a pointer.
X */
MenuLink *AllocMenuLink()
X{
X     MenuLink *ptr;
X 
X     Entry("AllocMenuLink")
X
X     if (!(ptr = (MenuLink *)calloc(1, sizeof(MenuLink)))) {
X	  sprintf(msg, "Can't allocate menu linked list storage--out of space\n");
X	  yyerror(msg);
X     }
X     Leave(ptr)
X}
X
X/*
X * Return storage for Gadgets[] array.
X */
GadgetDecl **allocate_gadgets()
X{
X     GadgetDecl **tmp;
X     int i;
X
X     Entry("allocate_gadgets")
X
X     tmp = (GadgetDecl **)malloc(MAX_GADGETS * sizeof(GadgetDecl *));
X     if (!tmp) {
X	  sprintf(msg, "Can't allocate storage for Gadgets -- out of space\n");
X	  yyerror(msg);
X	  Leave(NULL)
X     }
X     for (i = 0; i < MAX_GADGETS; i++)
X	  tmp[i] = (GadgetDecl *)0;
X     Leave(tmp)
X}
X
X/*
X * Stash a gadget record
X */
GadgetDecl *stashGadget(n, s, type)
int n;
char *s;
int type;
X{
X     GadgetDecl *tmp;
X
X     Entry("stashGadget")
X
X     if (!Gadgets)
X	  Gadgets = (GadgetDecl **)allocate_gadgets();
X     if (n < 0 || n >= NumGadgets) {
X	  sprintf(msg, "stashGadget on gadget #%d when maxgadget = %d\n",
X		  n, NumGadgets);
X	  yyerror(msg);
X	  Leave(NULL)
X     }
X     if (Gadgets[n]) {
X	  sprintf(msg, "gadget #%d redefined\n", n);
X	  yywarn(msg);
X	  FreeGadget(n);
X          tmp = Gadgets[n];
X     }
X     else
X	  Gadgets[n] = tmp = (GadgetDecl *)malloc(sizeof(GadgetDecl));
X     if (!Gadgets[n]) {
X	  sprintf(msg, "Can't allocate new gadget, out of space!\n");
X	  yyerror(msg);
X	  Leave(NULL)
X     }
X     tmp->data = 0;
X     tmp->name = (unsigned char *)0;
X     tmp->high = tmp->wide = tmp->offset = 0;
X     tmp->gravity = g_gravity;
X     tmp->offset = g_offset;
X     tmp->forecolor = g_forecolor ? g_forecolor : BlackPixel(dpy, scr);
X     tmp->backcolor = g_backcolor ? g_backcolor : WhitePixel(dpy, scr);
X     tmp->fontInfo = g_font;
X     g_font = (XFontStruct *)NULL;
X     if (type != C_STRING && type != C_PIXMAP) {
X	  sprintf(msg, "Invalid gadget specification for gadget #%d\n", n);
X	  yyerror(msg);
X	  NumGadgets = 0;
X          Leave(NULL)
X     }
X     if (Reverse) {
X	  unsigned long foo;
X
X	  foo = tmp->forecolor;
X	  tmp->forecolor = tmp->backcolor;
X	  tmp->backcolor = foo;
X     }
X     if (type == C_PIXMAP) {
X	  int junk;
X	  char *nm = s;
X
X	  s = expand_from_path(s);
X	  if (!s) {
X	       sprintf(msg, "Can't find pixmap file '%s' for gadget #%d\n",
X		       nm, n);
X	       yywarn(msg);
X	       s = nm; /* make it into fake text gadget */
X	       type = C_STRING;
X	  }
X	  else if (XReadBitmapFileData(s, &(tmp->wide),
X				  &(tmp->high), &(tmp->data), &junk, &junk)
X	      != BitmapSuccess) {
X	       sprintf(msg, "Can't open pixmap file '%s' for gadget #%d.\n", s, n);
X	       yyerror(msg);
X	       s = nm; /* fake text gadget is better than dying */
X	       type = C_STRING;
X	  }
X	  free(s);
X     }
X     if (type == C_STRING) { /* it's a label */
X	  tmp->name = expand_metachars(s);
X	  if (!tmp->fontInfo) {
X	       if (!GFontInfo) {
X		    GFontInfo = GetFontRes("gadget.font", DEF_GADGET_FONT);
X		    if (!GFontInfo) {
X			 sprintf(msg, "Can't get a default gadget font.\n");
X			 yyerror(msg);
X			 Leave(NULL)
X		    }
X	       }
X	       tmp->fontInfo = GFontInfo;
X	  }
X	  tmp->high = tmp->fontInfo->max_bounds.ascent +
X	       tmp->fontInfo->max_bounds.descent + 2;
X	  if (strlen(tmp->name) > 1)
X	       tmp->wide = XTextWidth(tmp->fontInfo, tmp->name, strlen(tmp->name));
X	  else {
X	       XCharStruct chinfo;
X	       int asc, desc, dir;
X
X	       XTextExtents(tmp->fontInfo, tmp->name, 1, &dir, &asc,
X			    &desc, &chinfo);
X	       tmp->wide = chinfo.width;
X	  }
X
X     }
X     Leave(tmp)
X}
X
X/*
X * This routine expands '\' notation in a string, ala C. Mostly useful for imbedding
X * weird characters in strings that turn into interesting symbols from some font.
X * Unlike C, however, numeric constants (\nnn) are in decimal, not octal. This
X * was done because the most popular glyphs (in cursorfont.h) are identified
X * in decimal.
X */
unsigned char *expand_metachars(s)
register unsigned char *s;
X{
X     register int i, len, val, n;
X     unsigned char *cp, num[5];
X
X     Entry("expand_metachars")
X
X     if (!s)
X	  Leave(s)
X     len = strlen(s);
X     for (i = 0; i < len; i++)
X	  if (s[i] == '\\')
X	       break;
X     if (i == len)
X	  Leave(s)
X     /* we know the string is going to get shorter, len is correct */
X     cp = (unsigned char *)malloc(len);
X     i = n = 0;
X     while (*s) {
X	  if (*s == '\\') {
X	       s++;
X	       while (*s && *s >= '0' && *s <= '9') {
X		    num[n++] = *s;
X		    s++;
X	       }
X	       if (n) {
X		    if (n > 4)
X			 n = 4;
X		    num[n] = '\0';
X		    cp[i++] = (char)atoi(num);
X		    n = 0;
X	       }
X	       else if (*s) {
X		    switch(*s) {
X
X		    case 'b':
X			 val = 8;
X			 break;
X
X		    case 'f':
X			 val = 12;
X
X		    case 'n':
X			 val = 10;
X			 break;
X
X		    case 'r':
X			 val = 13;
X			 break;
X
X		    case 't':
X			 val = 9;
X			 break;
X
X		    default:
X			 val = *s;
X			 break;
X		    }
X		    cp[i++] = val;
X		    s++;
X	       }
X	  }
X	  else {
X	       cp[i++] = *s;
X	       s++;
X	  }
X     }
X     cp[i] = '\0';
X     Leave(cp)
X}
X	  
X/*
X * Stash the data in an action line.
X */
ActionLine *StashActionLine(type, string)
int type;
char *string;
X{
X     ActionLine *ptr;
X     
X     Entry("StashActionLine")
X
X     ptr = AllocActionLine();
X     ptr->type = type;
X     ptr->text = string;
X     Leave(ptr)
X}
X
X/*
X * Stash menu data in a MenuInfo structure;
X */
MenuInfo *stashmenuinfo(name, line, pixmap)
char *name;
ActionLine *line;
char *pixmap;
X{
X     MenuInfo *ptr;
X     
X     Entry("stashmenuinfo")
X
X     ptr = AllocMenuInfo();
X     ptr->name = name;
X     ptr->line = line;
X     ptr->pixmapname = pixmap;
X     ptr->menu = 0;
X     Leave(ptr)
X}
X
X/*
X * Stash menu info data in a MenuLink structure;
X */
MenuLink *stashmenulink(menuinfo)
MenuInfo *menuinfo;
X{
X     MenuLink *ptr;
X     
X     Entry("stashmenulink")
X
X     ptr = AllocMenuLink();
X     ptr->next = NULL;
X     ptr->menu = menuinfo;
X     Leave(ptr)
X}
X
X/*
X * Append an action line to a linked list of menu lines.
X */
ActionLine *appendmenuline(list, line)
ActionLine *list;
ActionLine *line;
X{
X     ActionLine *ptr;
X     
X     Entry("appendmenuline")
X
X     if (list == NULL)
X	  list = line;
X     else {
X	  for(ptr = list; ptr->next; ptr = ptr->next) /* NULL */;
X	  ptr->next = line;
X	  ptr = ptr->next;
X	  ptr->next = NULL;
X     }
X     Leave(list)
X}
X
X/*
X * Append a menu to a linked list of menus.
X */
MenuLink *
X     appendmenulink(list, link)
MenuLink *list;
MenuLink *link;
X{
X     MenuLink *ptr;
X     
X     Entry("appendmenulink")
X
X     if (list == NULL)
X	  list = link;
X     else {
X	  for(ptr = list; ptr->next; ptr = ptr->next) /* NULL */;
X	  ptr->next = link;
X	  ptr = ptr->next;
X	  ptr->next = NULL;
X     }
X     Leave(list)
X}
X     
X/*
X * Reset all previous bindings and free the space allocated to them.
X */
Boolean ResetBindings()
X{
X     Binding *ptr, *nextptr;
X     
X     Entry("ResetBindings")
X
X     for(ptr = Blist; ptr; ptr = nextptr) {
X	  nextptr = ptr->next;
X	  free(ptr);
X     }
X     Blist = NULL;
X     Leave_void
X}
X
X/*
X * De-allocate all menus.
X */
Boolean ResetMenus()
X{
X     MenuLink *mptr, *next_mptr;
X     register ActionLine *lptr, *next_lptr;
X 
X     Entry("ResetMenus")
X     if (!Menus)
X	Leave_void
X     for(mptr = Menus; mptr; mptr = next_mptr) {
X	  free(mptr->menu->name);
X	  RTLMenu_Destroy(mptr->menu->menu);
X	  for(lptr = mptr->menu->line; lptr; lptr = next_lptr) {
X	       free(lptr->name);
X	       if (lptr->text) free(lptr->text);
X	       next_lptr = lptr->next;
X	       free(lptr);
X	  }
X	  next_mptr = mptr->next;
X	  free(mptr);
X     }
X     Menus = NULL;
X     Leave_void
X}
END_OF_FILE
if test 25572 -ne `wc -c <'gram.y'`; then
    echo shar: \"'gram.y'\" unpacked with wrong size!
fi
# end of 'gram.y'
fi
echo shar: End of archive 6 \(of 8\).
cp /dev/null ark6isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 8 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0