[comp.sources.x] v00i009: Ardent Window Manager, Part09/13

mikew@wyse.wyse.com (Mike Wexler) (08/11/88)

Submitted-by: unido!pcsbsd!jkh (Jordan Hubbard)
Posting-number: Volume 0, Issue 9
Archive-name: awm/part09

[NOTE: Jordan Hubbard has moved.  The first postings listed his 
address as jkh@ardent.  His current address is unido!pcsbst!jkh]

#! /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 9 (of 13)."
# Contents:  awm/GetButton.c awm/menus/track_menu.c
# Wrapped by mikew@wyse on Mon Aug  8 12:01:47 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f awm/GetButton.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"awm/GetButton.c\"
else
echo shar: Extracting \"awm/GetButton.c\" \(21347 characters\)
sed "s/^X//" >awm/GetButton.c <<'END_OF_awm/GetButton.c'
X#ident   "%W% %G%"
X
X
X
X#ifndef lint
Xstatic char *rcsid_GetButton_c = "$Header: GetButton.c,v 1.4 88/07/23 18:20:45 jkh Exp $";
X#endif	lint
X
X#include "X11/copyright.h"
X/*
X *
X * Copyright 1987, 1988 by Ardent Computer Corporation, Sunnyvale, Ca.
X *
X * Copyright 1987 by Jordan Hubbard.
X *
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 Ardent Computer
X * Corporation or Jordan Hubbard not be used in advertising or publicity
X * pertaining to distribution of the software without specific, written
X * prior permission.
X *
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/*
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 from R2 uwm.
X */
X
X#ifndef lint
Xstatic 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
Xextern XContext AwmContext;
Xextern Window FocusWindow;
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
Xstatic Icon_modified = FALSE;
X
XBoolean 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
X     if (b_ev->xany.window == 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			 FocusWindow = RootWindow(dpy, scr);
X		    }
X	       }
X	       Leave(FALSE)
X	       
X	  case FocusOut:
X	       if (b_ev->xfocus.detail == NotifyPointerRoot) {
X		    if (FocusSetByUser == FALSE && !FocusSetByWM) {
X			 XSetInputFocus(dpy, PointerRoot, None,
X					CurrentTime);
X			 FocusWindow = RootWindow(dpy, scr);
X		    }
X	       }
X	       Leave(FALSE)
X	       
X	  case ButtonPress:
X	  case ButtonRelease:
X	       Leave(TRUE)
X
X	  default: 
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     switch (b_ev->type) {
X	  XEvent e_fake;
X
X     case MotionNotify: 
X     case ButtonPress: 
X     case ButtonRelease: 
X	  Leave(TRUE)
X	  break;
X
X     case FocusIn:
X	  if (!FocusSetByWM) {
X	       e_fake.xcrossing.type = FocusIn;
X	       e_fake.xcrossing.focus = TRUE;
X	       e_fake.xcrossing.window = b_ev->xcrossing.window;
X	       HandleFocusIn(&e_fake);
X	  }
X	  Leave(FALSE)
X	  break;
X
X     case FocusOut:
X	  if (!FocusSetByWM) {
X	       e_fake.xcrossing.type = FocusOut;
X	       e_fake.xcrossing.focus = TRUE;
X	       e_fake.xcrossing.window = b_ev->xcrossing.window;
X	       HandleFocusOut(&e_fake);
X	  }
X	  Leave(FALSE)
X	  break;
X	  
X     case EnterNotify:
X	  HandleFocusIn(b_ev);
X	  Leave(FALSE)
X
X     case LeaveNotify: 
X	  HandleFocusOut(b_ev);
X	  Leave(FALSE)
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	  win = b_ev->xmap.window;
X          if (!(awi = GetAwmInfo(win)))
X              Leave(FALSE)
X	  if (IsIcon(win, FALSE))
X	      Leave(FALSE)
X          XMapWindow(dpy, awi->frame);
X	  XMapWindow(dpy, awi->client);
X          Leave(FALSE)
X	  break;
X	  
X     case UnmapNotify:
X	  win = b_ev->xunmap.window;
X          if (!(awi = GetAwmInfo(win)))
X              Leave(FALSE)
X
X	  if (IsIcon(win, FALSE))
X	       Leave(FALSE)
X	   XUnmapWindow(dpy, awi->frame);
X	  Leave(FALSE)
X	  break;
X
X     case DestroyNotify:
X	  win = b_ev->xdestroywindow.window;
X          if (!(awi = GetAwmInfo(win)))
X              Leave(FALSE)
X	  if (win != awi->title) {
X	       /* remove any icon associated with this window */
X	       RemoveIcon(win);
X	       /* remove the frame/titlebar (if present) */
X	       NoDecorate(win, TRUE);
X	       /* punt the rest of the per-window info */
X	       XDeleteContext(dpy, awi->client, AwmContext);
X	       free(awi);
X	  }
X          Leave(FALSE)
X
X     case PropertyNotify:
X	  win = b_ev->xproperty.window;
X          if (!(awi = GetAwmInfo(win)))
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 && awi->own && awi->iconPixmap == IBackPixmap) {
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)) +
X			(HIconPad << 1)) {
X			 XResizeWindow(dpy, win, 
X				       XTextWidth(IFontInfo, ICONSTR,
X						  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, (FocusWindow == awi->client));
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	  win = b_ev->xexpose.window;
X          if (!(awi = GetAwmInfo(win))) /* probably a menu */
X               Leave(FALSE)
X	  if (awi->title == win) {
X	       if (b_ev->xexpose.count == 0) {
X		    XEvent evt;
X
X		    /* Eat up any previous exposes */
X		    while (XCheckTypedWindowEvent(dpy, awi->title, Expose,
X						  &evt));
X		    PaintTitle(win, (FocusWindow == awi->client));
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     win = b_ev->xany.window;
X     if (!(awi = GetAwmInfo(win)))
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     /*
X      * If we don't own it, or it's got a background pixmap, we don't have
X      * to repaint it.
X      */
X     if (!awi->own || (awi->iconPixmap != IBackPixmap))
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 != XTextWidth(IFontInfo, ICONSTR,
X					   strlen(ICONSTR))+(HIconPad << 1)) {
X	       XResizeWindow(dpy, icon, 
X			     XTextWidth(IFontInfo, ICONSTR,
X					strlen(ICONSTR)) + (HIconPad << 1),
X			     IFontInfo->ascent + IFontInfo->descent + 
X			     (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#ifndef NO_ICON_TYPIN     
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#endif
X     Leave(FALSE)
X}
X
XCheckMap(window)
XWindow 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     unsigned long event_mask;
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	       awi = RegisterWindow(window);
X	       Decorate(awi->client);
X	       event_mask = PropertyChangeMask | FocusChangeMask;
X	       if (!FrameFocus)
X		    event_mask |= (EnterWindowMask | LeaveWindowMask);
X	       XSelectInput(dpy, window, event_mask);
X	       SetBorderPixmaps(dpy, GrayPixmap);
X	  }
X	  if ((wmhints = XGetWMHints(dpy, window))) {
X	       if ((wmhints->flags & StateHint) && (awi->state & ST_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 if ((awi = GetAwmInfo(window)) == NULL)
X	  awi = RegisterWindow(window);
X     if (awi->state & ST_WINDOW) {
X	  if (!transient_for)
X	       PlaceWindow(window);
X	  XMapRaised(dpy, awi->frame);
X	  XMapWindow(dpy, awi->client);
X	  XSync(dpy, 0);
X     }
X     Leave_void
X}
X
XConfigure(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
XCirculate(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
XPlaceWindow(window)
XWindow 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 (awi->frame)
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->state |= ST_PLACED;
X}
X
XBoolean ConfigureWindow(w, mask, xwc)
XWindow w;
Xunsigned long mask;
XXWindowChanges *xwc;
X{
X     XWindowAttributes xwa;
X     AwmInfoPtr awi;
X     int height, width, x, y;
X     int bch = 0, bcv = 0;
X     Entry("ConfigureWindow")
X
X     awi = GetAwmInfo(w);
X     if (!awi)
X          Leave(FALSE)
X
X     if (awi->attrs & AT_BORDER) {
X	  bcv = BContext + 1;
X	  bch = bcv * 2;
X     }
X
X     height = xwc->height;
X     width = xwc->width;
X     x = y = 0;
X     /* width */
X     xwc->width += bch;
X     if (awi->title)
X	  XResizeWindow(dpy, awi->title, xwc->width, titleHeight);
X     /* height */
X     if (awi->attrs & AT_TITLE) {
X	  y = titleHeight + 2;
X	  xwc->height += y;
X     }
X     if (awi->attrs & AT_BORDER) {
X	  if (!(awi->attrs & AT_TITLE)) {
X	       xwc->height += (bcv * 2);
X	       y = bcv;
X	  }
X	  else
X	       xwc->height += bcv;
X	  xwc->x -= (BContext + (awi->border_width ? awi->border_width : 1));
X	  x = BContext;
X     }
X     if (PushDown == FALSE) {
X	  if (awi->attrs & AT_TITLE)
X	       xwc->y -= (titleHeight + 2);
X	  else if (awi->attrs & AT_BORDER)
X	       xwc->y -= (BContext + (awi->border_width ?
X				      awi->border_width : 1));
X     }
X     XConfigureWindow(dpy, awi->frame, mask, xwc);
X     if (awi->gadgets)
X	  PutGadgets(w);
X     xwc->width = width;
X     xwc->height = height;
X     xwc->x = x;
X     xwc->y = y;
X     XConfigureWindow(dpy, awi->client, mask, xwc);
X     Leave(TRUE)
X}
X
Xint
XProcessRequests(box, num_vectors)
XXSegment *box;
Xint 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_awm/GetButton.c
if test 21347 -ne `wc -c <awm/GetButton.c`; then
    echo shar: \"awm/GetButton.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f awm/menus/track_menu.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"awm/menus/track_menu.c\"
else
echo shar: Extracting \"awm/menus/track_menu.c\" \(26723 characters\)
sed "s/^X//" >awm/menus/track_menu.c <<'END_OF_awm/menus/track_menu.c'
X#ident   "%W% %G%"
X
X#ifndef lint
X     static char sccs_id[] = "@(#)track_menu.c	2.1 12/16/87  Siemens Corporate Research and Support, Inc.";
X#endif
X
X
X#include "X11/copyright.h"
X
X/* 
X  RTL Menu Package Version 1.0
X  by Joe Camaratta and Mike Berman, Siemens RTL, Princeton NJ, 1987
X  
X  track_menu.c: bring up menus and track the mouse
X  */
X
X/*
X *
X * Copyright 1987, 1988 by Ardent Computer Corporation, Sunnyvale, Ca.
X *
X * Copyright 1987 by Jordan Hubbard.
X *
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 Ardent Computer
X * Corporation or Jordan Hubbard not be used in advertising or publicity
X * pertaining to distribution of the software without specific, written
X * prior permission.
X *
X */
X
X
X/*
X  
X  Copyright 1987 by
X  Siemens Corporate Research and Support, Inc., Princeton, New Jersey
X  
X  Permission to use, copy, modify, and distribute this software
X  and its documentation for any purpose and without fee is
X  hereby granted, provided that the above copyright notice
X  appear in all copies and that both that copyright notice and
X  this permission notice appear in supporting documentation, and
X  that the name of Siemens not be used in advertising or
X  publicity pertaining to distribution of the software without
X  specific, written prior permission.  Siemens makes no
X  representations about the suitability of this software for any
X  purpose.  It is provided "as is" without express or implied
X  warranty.
X  
X  */
X
X/*
X * The menu package will break if you don't define this, but
X * it's there in case you want to see just how and where the
X * "eventstack" stuff is used and, if necessary, replace it.
X */
X#define SAVE_EVENTS
X
X
X#include <stdio.h>
X#include "X11/Xlib.h"
X#include "X11/cursorfont.h"
X#include "arrow_icon.h"
X#include "null_icon.h"
X#include "menu.h"
X#include "menu.def.h"
X#include "menu.ext.h"
X#include "dbug.h"
X#ifdef SAVE_EVENTS
X#include "eventstack.h"
X#endif
X
X#define MIN(x,y) (((x) <= (y))? x:y)
X#define MAX(x,y) (((x) >= (y))? x:y)
X
X#define CLICK_TIME 290 /* in milliseconds */
X
X#define CursorLockMask (ButtonReleaseMask | ExposureMask)
X
X/* Event macros */
X
X#define EventGetXCoord(rep) ((rep).xmotion.x)
X#define EventGetYCoord(rep) ((rep).xmotion.y)
X#define EventType(rep) ((rep).type)
X#define EventXWindow(rep) ((rep).xcrossing.window)
X#define EventXTime(rep) ((rep).xcrossing.time)
X#define EventXMode(rep) ((rep).xcrossing.mode)
X#define EventXRootX(rep) ((rep).xcrossing.x_root)
X#define EventXRootY(rep) ((rep).xcrossing.y_root)
X#define EventXDetail(rep) ((rep).xcrossing.detail)
X#define EventMWindow(rep) ((rep).xmotion.window)
X#define EventMTime(rep) ((rep).xmotion.time)
X#define EventButton(rep) ((rep).xbutton.button)
X#define EventBWindow(rep) ((rep).xbutton.window)
X#define EventBTime(rep) ((rep).xbutton.time)
X#define EventEX(rep) ((rep).xexpose.x)
X#define EventEY(rep) ((rep).xexpose.y)
X#define EventEWidth(rep) ((rep).xexpose.width)
X#define EventEHeight(rep) ((rep).xexpose.height)
X#define PointerEvent(rep) \
X     ((EventType(rep) == ButtonPress) || \
X      (EventType(rep) == ButtonRelease) || \
X      (EventType(rep) == MotionNotify) || \
X      (EventType(rep) == EnterNotify) || \
X      (EventType(rep) == LeaveNotify) || \
X      (EventType(rep) == FocusIn) || \
X      (EventType(rep) == FocusOut))
X#define KeyEvent(rep) \
X     ((EventType(rep) == KeyPress) || (EventType(rep) == KeyRelease))
X/* Possible states for the state machine */
Xtypedef enum
X{
X     Initial,      /* Inside a submenu, but not any item */
X     CheckTrigger, /* Inside an item that has submenu, checking for pullright */
X     Leaf,         /* Inside an item with no submenu */
X     Exit,         /* Preparing to exit */
X     LevelControl  /* Not in any submenu, waiting to enter something */
X     } State;
X
XState InitialState(), CheckTriggerState(), LeafState(), LevelControlState(),
X     GetItemState();
Xbool EventNotSignificant(), PushSubmenu();
X
Xvoid OutputEvent(), GetNextSignificantEvent(), PopSubmenu(), 
X     Highlight(), Unhighlight(), DisplayInitialMenus(), LockCursor(),
X     TossExtraMoves(), UnlockCursor();
X
Xvoid ProcessExposeEvents();
X
Xvoid SaveTest();
X
XMenuItem *MenuGetItem();
XMenu *MenuGetMenu();
X
X/* global state variables */
X
Xstatic MenuItem *current_item;
Xstatic Menu *current_menu;
Xstatic Window root_window;
Xextern Display *dpy;
Xextern int scr;
Xstatic int level;            /* submenu level */
Xstatic Time button_time;     /* time button press invoked */
Xstatic Cursor wait_cursor = None;  /* empty cursor for lock state */
Xstatic bool click_allowed;
Xstatic bool lock_event_mask, unlock_event_mask;
X
Xextern int Autoselect;
Xextern int MDelta;
X
X#ifdef SAVE_EVENTS
Xstatic struct Ev_q *ev_save = 0;
X#endif
X
X
XMenuItem *TrackMenu(root_menu, root_x, root_y, 
X		    init_button, root, buttime)
XMenu *root_menu;    /* Pointer to root menu requested to pop up   */
Xint root_x, root_y; /* Position to start menu                     */
Xint init_button;    /* The # of button used to pop up menu        */
XWindow root;        /* Window label for parent of menu            */
XTime buttime;       /* timestamp for button (or 0, if CLICK == 0) */
X{
X     State CurrentState = LevelControl;
X     XEvent Event_Reply;
X     int open_x;
X     bool selected = FALSE;
X     MenuItem *selected_item;
X     
X     Entry("TrackMenu")
X     
X     /* Initialize globals */
X     
X     button_time = buttime;
X     root_window = root;
X     level = 0;
X     current_menu = root_menu;
X     click_allowed = (TestOptionFlag(current_menu, clickokay))? TRUE : FALSE;
X     unlock_event_mask = (TestOptionFlag(current_menu, savebits))?
X	  MenuEventMask : (MenuEventMask | ExposureMask);
X     lock_event_mask = (TestOptionFlag(current_menu, savebits))?
X	  CursorLockMask : (CursorLockMask | ExposureMask);
X     
X     /* If not already done, set up the null cursor for lock state */
X     if (wait_cursor == None)
X     {
X	  Pixmap wc_pixmap;
X	  XColor fg, bg;
X	  
X	  wc_pixmap = XCreateBitmapFromData (dpy, root_window,
X					     null_icon_bits,
X					     null_icon_width, null_icon_height);
X	  wait_cursor = XCreatePixmapCursor (dpy, wc_pixmap, wc_pixmap,
X					     &fg, &bg, 1, 1);
X     }
X     
X     
X     /* Block all other action by grabbing the server */
X     /*    XGrabServer (dpy); */
X     /* Don't think we need to grab the server... so for now, we won't */
X     
X#ifdef SAVE_EVENTS     
X     /* Get the present state, so it can be restored later */
X     /* Any events on the queue when we start get saved now, restored later */
X     SaveEvents (dpy, &ev_save, ~(unsigned long) ButtonReleaseMask);
X#endif
X     
X     LockCursor(root_window);
X     if (!(current_item =
X	   Display_Menu(current_menu, NULLMENU, root_x, root_y)))
X     {
X	  CurrentState = Exit;
X     }
X     /*
X      * First item is a label and autoselect is on, so we want
X      * to push on to the first "real" item.
X      */
X     if (ItemIsDeaf(current_item) && Autoselect)
X	  current_item = current_item->nextItem;
X     LockCursor(ItemWindow(current_item));
X     open_x = root_x;
X     
X     /* Push to appropriate previous item, if any */
X     while (MenuHasInitialItem(current_menu) && (CurrentState != Exit))
X     {
X	  current_item = GetInitialItem(current_menu);
X	  ClearInitialItem(current_menu);
X	  
X	  /* if the initial item can't be selected, take first in list */
X	  if (ItemIsNull(current_item) || ItemIsDisabled(current_item))
X	  {
X	       current_item = MenuItems(current_menu);
X	       break;
X	  }
X	  else if (ItemIsLeaf(current_item)) /* then we're done */
X	       break;
X	  else
X	  {
X	       open_x += ItemGetArrowPosition(current_item);
X	       if (!ItemIsDeaf(current_item))
X		    Highlight(current_item);
X	       TossExtraMoves(ItemWindow(current_item));
X	       (void)PushSubmenu(open_x);
X	  }
X     }
X     ProcessExposeEvents();
X     if (CurrentState != Exit)
X	  CurrentState = (ItemIsLeaf(current_item)) ? Leaf : CheckTrigger;
X     if (!ItemIsDeaf(current_item))
X	  Highlight(current_item);
X     XSync (dpy, 0);  /* get release click, if it's in queue */
X#ifdef SAVE_EVENTS
X     DisposeEvents(dpy, (PointerMotionMask | EnterWindowMask |
X			 LeaveWindowMask | ExposureMask));
X#endif
X     LockCursor(ItemWindow(current_item));
X     PlacePointer(current_menu,current_item); 
X     UnlockCursor();
X     	
X     /* State Machine */
X     
X     while (CurrentState != Exit)
X     {
X	  GetNextSignificantEvent(&Event_Reply, init_button);
X	  switch (CurrentState)
X	  {
X	  case LevelControl:
X	       CurrentState = LevelControlState(Event_Reply);
X	       break;
X	  case Initial:
X	       CurrentState = InitialState(Event_Reply);
X	       break;
X	  case CheckTrigger:
X	       CurrentState = CheckTriggerState(Event_Reply);
X	       break;
X	  case Leaf:
X	       CurrentState = LeafState(Event_Reply, &selected);
X	       break;
X	  default:
X	       Retch("(RTLmenu) YOW! Unknown State! (%d)\n",
X		     CurrentState);
X	       CurrentState = Exit;
X	       break;
X	  }
X     }
X     /* Clean up and exit */
X     
X     selected_item = (selected)? current_item : NULLITEM;
X     while (level)
X     {
X	  if (selected)
X	       SetInitialItem(current_menu, current_item);
X	  PopSubmenu();
X     }
X     if (selected)
X     {
X	  SetInitialItem(current_menu, current_item);
X     }
X     
X     Undisplay_Menu(current_menu);
X     UnlockCursor();
X     XUngrabPointer(dpy, CurrentTime);
X     
X     /* Throw out any left over events from menu world */
X     /*    if (TestOptionFlag(current_menu, savebits)) {
X	   XSync(dpy,1); 
X	   XUngrabServer(dpy, CurrentTime);  add this if grab added! 
X	   }
X	   else
X	   XSync(dpy,0);*/
X     
X     /* Push back any events that were lying around when menus started */
X     
X     XFlush(dpy);
X#ifdef SAVE_EVENTS
X     DisposeEvents(dpy, (PointerMotionMask | EnterWindowMask |
X			 LeaveWindowMask | ExposureMask));
X     RestoreEvents(dpy, &ev_save);
X#endif
X     Leave(selected_item)
X}
X
X/* Used for debugging */
X
Xvoid OutputEvent(Event_Reply)
XXEvent Event_Reply;
X{
X     Entry("OutputEvent")
X
X     switch (EventType(Event_Reply))
X     {
X     case ButtonPress:
X     case ButtonRelease:
X	  DBUG_5("RTLmenu","Button Press/Release, button %d on window %d at time %d\n",
X		 EventButton(Event_Reply), EventBWindow(Event_Reply), 
X		 EventBTime(Event_Reply));
X	  break;
X     case MotionNotify:
X	  DBUG_5("RTLmenu","Motion Notify on window %d at time %d, x=%d\n", 
X		 EventMWindow(Event_Reply), EventMTime(Event_Reply),
X		 EventGetXCoord(Event_Reply));
X	  break;
X     case EnterNotify:
X	  DBUG_4("RTLmenu","Enter Notify on window %d at time %d\n",
X		 EventXWindow(Event_Reply), EventXTime(Event_Reply));
X	  break;
X     case LeaveNotify:
X	  DBUG_4("RTLmenu","Leave Notify on window %d at time %d\n",
X		 EventXWindow(Event_Reply), EventXTime(Event_Reply));
X	  break;
X     default:
X	  DBUG_3("RTLmenu","Unexpected event type %d\n", EventType(Event_Reply));
X	  break;
X     }
X     Leave_void
X}
X
Xstatic bool locked = FALSE;
X
X/* Lock the cursor: make it disappear, and ignore events it generates.  */
X/* Optionally, confine it to a single window.                           */
X/* (Using "None" for confine_window doesn't confine it.    )            */
Xvoid LockCursor(confine_window)
XWindow confine_window;
X{
X     int result;
X     
X     Entry("LockCursor")
X     
X     locked = TRUE;
X     result = XGrabPointer(dpy,
X			   RootWindow(dpy, MenuScreen(current_menu)),
X			   True, lock_event_mask, GrabModeSync, 
X			   GrabModeAsync, confine_window,
X			   wait_cursor, CurrentTime);
X     DBUG_3("RTLmenu","Lock Cursor grab = %d\n",result);
X     Leave_void
X}
X
X/* Unlock (and unconfine) the cursor.  If cursor lock is not set,    */
X/* this does nothing.                                                */
X
Xvoid UnlockCursor()
X{
X     int result;
X     
X     Entry("UnlockCursor")
X     
X     if (locked)
X     {
X	  locked = FALSE;
X	  result = XGrabPointer(dpy, 
X				RootWindow(dpy, MenuScreen(current_menu)),
X				True,  unlock_event_mask,
X				GrabModeAsync, GrabModeAsync, None,
X				MenuCursor(current_menu), CurrentTime);
X	  DBUG_3("RTLmenu","Unlock Cursor grab = %d\n",result);	    
X     }
X     Leave_void
X}
X
X/* Keep getting the X events, until finding one that may be interesting */
X/* to the operation of the state machine. */
X
Xvoid GetNextSignificantEvent(Event_Reply,init_button)
XXEvent *Event_Reply;
Xint init_button;		/* the button that initiated the menu */
X{
X     XEvent Next_Event_Reply;
X     bool InsignificantEvent = True;
X     
X     Entry("GetNextSignificantEvent")
X     
X     /* Loop as long as any of a number of "insignificant" events */
X     /* are found; when the event no longer matches one of the tests, */
X     /* it is assumed to be "significant" and returned.*/
X     do
X     {
X	  XNextEvent(dpy, Event_Reply);
X	  DBUG_EXECUTE("RTLmenu", OutputEvent(*Event_Reply));
X	  
X	  /* If this event is an "enter", check whether there is a   */
X	  /* "leave" for the same window already in the queue,       */
X	  /* immediately following it; if so, throw them both out    */
X	  /* and get the next event                                  */
X	  /* NOTE: might try to look further ahead, but this is      */
X	  /* tricky because other events might intervene.            */
X	  
X	  if ((EventType(*Event_Reply) == EnterNotify) &&
X	      (EventXMode(*Event_Reply) == NotifyNormal) &&
X	      (QLength(dpy) > 0) &&
X	      (MenuGetMenu(current_menu, EventXWindow(*Event_Reply))
X	       != current_menu))
X	  {
X	       XPeekEvent(dpy, &Next_Event_Reply);
X	       if ((EventType(Next_Event_Reply) == LeaveNotify) &&
X		   (EventXMode(Next_Event_Reply) == NotifyNormal) &&
X		   (EventXWindow(Next_Event_Reply) == EventXWindow(*Event_Reply)))
X	       {
X		    DBUG_2("RTLmenu","TOSS: Enter/leave pair.\n");
X		    XNextEvent(dpy, Event_Reply);
X		    XNextEvent(dpy, Event_Reply);
X	       }
X	  }
X#ifdef SAVE_EVENTS
X	  if (EventNotSignificant(*Event_Reply, init_button))
X	  {
X	       if (!(PointerEvent(*Event_Reply) || KeyEvent(*Event_Reply)
X		     || EventType(*Event_Reply) == Expose))
X	       {
X		    /* might be significant elsewhere -- save it for later */
X		    AddEventToStore(&ev_save, *Event_Reply);
X	       }
X	  }
X	  else
X#else
X	       if (!EventNotSignificant(*Event_Reply, init_button))
X#endif
X		    InsignificantEvent = FALSE;
X     }
X     while (InsignificantEvent);
X     
X     DBUG_2("RTLmenu","--->");
X     Leave_void
X}
X
X/* Check whether the event matches one of the events considered */
X/* "not significant".*/
Xbool EventNotSignificant(Event_Reply, init_button)
XXEvent Event_Reply;
Xint init_button;
X{
X     Entry("EventNotSignificant")
X
X     /* Insignificant if not in following list */
X     Leave(!((EventType(Event_Reply) == ButtonRelease) ||
X	       (EventType(Event_Reply) == ButtonPress) ||
X	       (EventType(Event_Reply) == MotionNotify) ||
X	       (EventType(Event_Reply) == EnterNotify) ||
X	       (EventType(Event_Reply) == Expose) ||
X	       (EventType(Event_Reply) == LeaveNotify))
X	     ||
X	     /* Insignificant if leave or enter is not "Normal"  */
X	     (((EventType(Event_Reply) == LeaveNotify) ||
X	       (EventType(Event_Reply) == EnterNotify)) &&
X	      (EventXMode(Event_Reply) != NotifyNormal))
X	     ||
X	     /* Insignificant if hit button other than initial one */
X	     ((EventType(Event_Reply) == ButtonRelease) &&
X	      (EventButton(Event_Reply) != init_button))
X	     ||
X	     /* Insignificant if tail end of a click -- and clicks allowed */
X	     (click_allowed &&
X	      (EventType(Event_Reply) == ButtonRelease) &&
X	      (EventBTime(Event_Reply) - button_time < CLICK_TIME))
X	     )
X}
X
XState LevelControlState(rep)
XXEvent rep;
X{
X     State next_state;
X     Menu *entered_menu;
X     MenuItem *entered_item;
X     
X     Entry("LevelControlState")
X     switch (EventType(rep))
X     {
X     case MotionNotify:
X     case LeaveNotify: 
X	  next_state = LevelControl; /* loop back to this state */
X	  break;
X     case EnterNotify:
X	  /* Decide whether we've entered a menu window or item window */
X	  entered_menu = MenuGetMenu(current_menu, EventXWindow(rep));
X	  entered_item = MenuGetItem(current_menu,EventXWindow(rep));
X	  
X	  if ((MenuIsNull(entered_menu)) && (ItemIsNull(entered_item)))
X	       /* Must be some other window; carry on */
X	       next_state = LevelControl;
X	  else if (!ItemIsNull(entered_item) &&
X		   MenuIsDisplayed(ItemMenu(entered_item)))
X	  {
X	       /* we entered an item, but not a window. This should only happen */
X	       /* when we stayed in the parent of the current submenu.  So,     */
X	       /* Pop that submenu and get to the item.                         */
X	       if (level)
X	       {
X		    LockCursor(ItemWindow(entered_item));
X		    PopSubmenu();
X		    ProcessExposeEvents();
X		    UnlockCursor();
X		    current_item = entered_item;
X		    Highlight(current_item);
X		    next_state = GetItemState(rep);
X	       }
X	       else /* I must be very confused... */
X	       {
X		    Retch("(RTLmenu) Tried to pop the root menu...\n");
X		    next_state = Exit;
X	       }
X	  }
X	  
X	  else if (!MenuIsNull(entered_menu)&&
X		   MenuIsDisplayed(entered_menu))
X	  {
X	       /* entered a menu that is displayed */
X	       while ((current_menu != entered_menu) && level)
X		    /* drop down the menu that was entered */
X		    PopSubmenu();
X	       ProcessExposeEvents();
X	       UnlockCursor();
X	       if (current_menu == entered_menu)
X		    next_state = Initial;
X	       else
X	       {
X		    next_state = Exit;
X		    Retch("(RTLmenu) Couldn't find the menu I entered!!\n");
X	       }
X	  }
X	  else 
X	       next_state = LevelControl;
X	  break;
X     case ButtonRelease:
X	  next_state = Exit;
X	  break;
X     default:
X	  Retch("RTLmenu","YOW! Unexpected event! (%d)\n", rep.type);
X	  next_state = Exit;
X	  break;
X     }
X     Leave(next_state)
X}
X
X/* Figure out the status of the item we've just entered */
XState GetItemState(rep)
XXEvent rep;
X{
X     int open_x;
X     State next_state;
X     
X     Entry("GetItemState")
X     if (ItemIsNull(current_item))
X     {
X	  Retch("(RTLmenu) null current item!");
X	  next_state = Exit;
X     }
X     else if (MenuIsNull(current_menu))
X     {
X	  Retch("(RTLmenu) null current menu!");
X	  next_state = Exit;
X     }
X     else if (ItemIsLeaf(current_item))
X     {
X	  if (MenuHasInitialItem(current_menu))
X	       ClearInitialItem(current_menu);
X	  next_state = Leaf;
X     }
X     else if (EventGetXCoord(rep) >= (int)(ItemGetArrowPosition(current_item) - 4))
X     {
X	  /* entered item in "auto pop-up zone", i.e., over pull-right arrow. */
X	  LockCursor(ItemWindow(current_item));
X	  TossExtraMoves(ItemWindow(current_item));
X	  if (PushSubmenu(EventXRootX(rep)))
X	  {
X	       LockCursor(ItemWindow(current_item));
X	       PlacePointer(current_menu, current_item); 
X	       next_state = Initial;
X	       ProcessExposeEvents();
X	  }
X	  else
X	       next_state = CheckTrigger;
X	  UnlockCursor();
X     }
X     else if (MenuHasInitialItem(current_menu))
X     {
X	  /* Entered menu has initial item -- move to it */
X	  DBUG_2("RTLmenu","Pushing for initial item.");
X	  current_item = GetInitialItem(current_menu);
X	  open_x = ItemGetArrowPosition(current_item) +
X	       EventXRootX(rep);	    
X	  ClearInitialItem(current_menu);
X	  LockCursor(ItemWindow(current_item));
X	  if (PushSubmenu(open_x))
X	  {
X	       ProcessExposeEvents();
X	       LockCursor(ItemWindow(current_item));
X	       PlacePointer(current_menu, current_item); 
X	       next_state = Initial;
X	  }
X	  UnlockCursor();
X     }
X     else /* parent pull */
X	  next_state = CheckTrigger;
X     Leave(next_state)
X}
X
XState InitialState( rep)
XXEvent rep;
X{
X     State next_state;
X     
X     Entry("Initial")
X     switch (EventType(rep))
X     {
X     case EnterNotify:
X	  if (MenuIsNull(current_menu))
X	  {
X	       Retch("(RTLmenu) null current menu!?!?");
X	       next_state = Exit;
X	  }
X	  else if (EventXDetail(rep) == NotifyInferior)
X	       next_state = Initial;
X	  else
X	  {
X	       current_item = MenuGetItem(current_menu, EventXWindow(rep));
X	       if (ItemIsNull(current_item))
X	       {
X		    /* Retch("(RTLmenu) Window entered not an item!\n"); */
X		    next_state = Exit;
X	       }
X	       else
X	       {
X		    Highlight(current_item);
X		    next_state = GetItemState(rep);
X	       }
X	  }
X	  break;
X     case LeaveNotify:
X	  /* Decide whether we're actually leaving      */
X	  /* this menu for another submenu or the root, */
X	  /* or going into an item.                     */
X	  next_state = (EventXDetail(rep) == NotifyInferior)?
X	       Initial : LevelControl;
X	  break;
X     case ButtonRelease:
X	  next_state = Exit;
X	  break;
X     case MotionNotify:
X	  next_state = Initial;
X	  break;
X     default:
X	  Retch("(RTLmenu) YOW! Unexpected event! (%d)\n", rep.type);
X	  next_state = Exit;
X	  break;
X     }
X     Leave(next_state)
X}
X
X#define NotSet -1
X/* Look to see if pull-right is requested */
XState CheckTriggerState(rep)
XXEvent rep;
X{
X     State next_state = CheckTrigger;
X     static int Trigger = NotSet;
X     static int OldX, NewX, childX, button;
X     
X     Entry("CheckTrigger")
X     if (MenuIsNull(current_menu) || ItemIsNull(current_item))
X     {
X	  Retch("(RTLmenu) Null menu or item...");
X	  next_state = Exit;
X	  goto exit;
X     }
X     if (Trigger == NotSet) /* set it */
X     {
X	  Trigger = MIN(EventGetXCoord(rep) + MenuDelta(current_menu),
X			ItemGetArrowPosition(current_item));
X	  NewX = NotSet;
X     }
X     switch (EventType(rep))
X     {
X     case LeaveNotify:
X	  next_state = Initial;
X	  Unhighlight(MenuGetItem(current_menu, EventXWindow(rep)));
X	  Trigger = NotSet;
X	  break;
X     case ButtonRelease:
X	  next_state = Exit;
X	  Trigger = NotSet;
X	  break;
X	  
X     case ButtonPress:
X	  button = rep.xbutton.button;
X	  while (TRUE) {
X	       XNextEvent(dpy, &rep);
X	       if (rep.type == ButtonRelease &&
X		   rep.xbutton.button == button)
X		    break;
X	  }
X	  next_state = CheckTrigger;
X	  childX = TestOptionFlag(current_menu, fixedchild) ?
X	       (MenuX(current_menu) + ItemGetArrowPosition(current_item)) :
X		    EventXRootX(rep);
X	  Trigger = NotSet;
X	  if (PushSubmenu(childX))
X	  {
X	       next_state = LevelControl;
X	       ProcessExposeEvents();
X	       LockCursor(ItemWindow(current_item));
X	       PlacePointer(current_menu, current_item);
X	  }
X	  UnlockCursor();
X	  break;
X
X     case MotionNotify:
X	  next_state = CheckTrigger;
X	  OldX = NewX;
X	  NewX = EventGetXCoord(rep);
X	  if (NewX >= Trigger)
X	  {
X	       LockCursor(ItemWindow(current_item));
X	       childX = TestOptionFlag(current_menu, fixedchild)?
X		    (MenuX(current_menu) + ItemGetArrowPosition(current_item)):
X			 EventXRootX(rep);
X	       Trigger = NotSet;
X	       if (PushSubmenu(childX))
X	       {
X		    next_state = LevelControl;
X		    ProcessExposeEvents();
X		    LockCursor(ItemWindow(current_item));
X		    PlacePointer(current_menu, current_item); 
X	       }
X	       UnlockCursor();
X	  }
X	  else if (NewX < OldX) /* reverse motion */
X	       Trigger = MIN(Trigger, NewX + MenuDelta(current_menu));
X	  break;
X
X     default:
X	  Retch("(RTLmenu) YOW! Unexpected event!\n");
X	  next_state = Exit;
X	  break;
X     }
X exit:
X     Leave(next_state)
X}
X
XState LeafState(rep,selected)
XXEvent rep;
Xbool *selected;
X{
X     State next_state;
X     
X     Entry("LeafState")
X     switch(EventType(rep))
X     {
X     case LeaveNotify:
X	  Unhighlight(MenuGetItem(current_menu, EventXWindow(rep)));
X	  next_state = Initial;
X	  break;
X	  
X     case ButtonRelease:
X	  *selected = TRUE;
X	  next_state = Exit;
X	  break;
X     
X     case ButtonPress:
X     case EnterNotify:
X     case MotionNotify: /* if events set right, this never happens */
X	  next_state = Leaf;
X	  break;
X	  
X     default:
X	  Retch("(RTLMenu) YOW! Unexpected event! (%d)\n",
X		rep.type);
X	  next_state = Exit;
X	  break;
X     }
X     Leave(next_state)
X}
X
Xbool PushSubmenu(x)
Xint x;
X{
X     int y;
X     bool pushed;
X     MenuItem *new_current_item;
X     
X     Entry("PushSubmenu")
X
X     if (ItemIsNull(current_item))
X     {
X	  Retch("(RTLMenu) Can't push from null item.\n");
X	  pushed = FALSE;
X     }
X     else if (MenuIsNull(ItemSubmenu(current_item)))
X     {
X	  Retch("(RTLmenu) Null submenu.\n");
X	  pushed = FALSE;
X     }	
X     else if (ItemIsNull(MenuItems(ItemSubmenu(current_item))))
X	  /* submenu has no items -- don't push, but not an error */
X	  pushed = FALSE;
X     else
X     {
X	  y =  ItemGetMiddleY(current_item);
X	  ++level;
X	  
X	  if (new_current_item =
X	      Display_Menu(ItemSubmenu(current_item), current_menu, x, y))
X	  {
X	       XFlush(dpy);
X	       current_menu = ItemSubmenu(current_item);
X	       current_item = new_current_item;
X	       if (ItemIsDeaf(current_item) && Autoselect)
X		    current_item = current_item->nextItem;
X	       pushed = TRUE;
X	  }
X	  else
X	  {
X	       Retch("(RTLmenu) Display_Menu failed!\n");
X	       pushed = FALSE;
X	  }
X     }
X     Leave(pushed)
X}
X
Xvoid PopSubmenu()
X{
X     Menu *parent;
X     MenuItem *item;
X     
X     Entry("PopSubmenu")
X     --level;
X     parent = current_menu->parentMenu;
X     Undisplay_Menu(current_menu);
X     current_menu = parent;
X     if (!MenuIsNull(current_menu))
X     {
X	  item = MenuItemHighlighted(current_menu);
X	  if (!ItemIsNull(item))
X	  {
X	       current_item = item;
X	  }
X     }
X     
X     Leave_void
X}
X
Xvoid Highlight(item)
XMenuItem *item;
X{
X     MenuItem *old_highlight;
X     
X     Entry("Highlight")
X     
X     old_highlight = MenuItemHighlighted(current_menu);
X     if ((item != old_highlight) && /* else, already highlighted */
X	 (!ItemIsNull(item)))
X     {
X	  if (!ItemIsNull(old_highlight) && !ItemIsDeaf(item))
X	       Unhighlight(old_highlight); 
X	  MenuInvert(ItemMenu(item), item);
X	  SetHighlightItem(ItemMenu(item), item);
X     }
X     Leave_void
X}
X
Xvoid Unhighlight(item)
XMenuItem *item;
X{
X     Entry("Unhighlight")
X     if (!ItemIsNull(item))
X     {
X	  if (MenuItemHighlighted(current_menu) == item)
X	  {
X	       MenuInvert(ItemMenu(item), item);
X	       ResetHighlightItem(ItemMenu(item));
X	  }
X     }
X     Leave_void
X}
X
Xvoid TossExtraMoves(window)
XWindow window;
X{
X     XEvent ev;
X     
X     Entry("TossExtraMoves")
X     /*    XSync(dpy,0);     /* make sure they're all on the queue      */
X     while (XCheckTypedWindowEvent(dpy, window, MotionNotify, &ev))
X	  DBUG_2("RTLmenu","Tossing extra motion.\n");
X     Leave_void
X}
X
X
Xvoid ProcessExposeEvents()
X{
X     MenuItem *item;
X     XEvent ev;
X     
X     Entry("ProcessExposeEvents")
X
X     XSync(dpy,0);
X     while (XCheckTypedEvent(dpy, Expose, &ev))
X     {
X	  item = MenuGetItem(current_menu, EventXWindow(ev));
X	  if (!ItemIsNull(item))
X	       Draw_Item(ItemMenu(item), item, EventEX(ev), EventEY(ev),
X			 EventEWidth(ev), EventEHeight(ev));
X     }
X     Leave_void
X}
END_OF_awm/menus/track_menu.c
if test 26723 -ne `wc -c <awm/menus/track_menu.c`; then
    echo shar: \"awm/menus/track_menu.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of archive 9 \(of 13\).
cp /dev/null ark9isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 13 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
Mike Wexler(wyse!mikew)    Phone: (408)433-1000 x1330