[comp.sources.x] v03i019: Ardent Window Manager, Patchlevel 9, Part03/12

mikew@wyse.wyse.com (Mike Wexler) (02/18/89)

Submitted-by: kmw@ardent (Ken Wallich)
Posting-number: Volume 3, Issue 19
Archive-name: awm2/part03

#! /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 3 (of 12)."
# Contents:  Resize.c menus/menu.c menus/menu.ext.h
# Wrapped by mikew@wyse on Fri Feb 17 10:50:21 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'Resize.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Resize.c'\"
else
echo shar: Extracting \"'Resize.c'\" \(15574 characters\)
sed "s/^X//" >'Resize.c' <<'END_OF_FILE'
X
X
X
X#ifndef lint
Xstatic char *rcsid_Resize_c = "$Header: /usr/graph2/X11.3/contrib/windowmgrs/awm/RCS/Resize.c,v 1.2 89/02/07 21:23:37 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 * MODIFICATION HISTORY
X *
X * 000 -- M. Gancarz, DEC Ultrix Engineering Group
X * 001 -- Loretta Guarino Reid, DEC Ultrix Engineering Group
X *        Convert to X11
X * 002 -- Jordan Hubbard, U.C. berkeley.
X *	Added alternate placement of resize window, code for title bar
X * 	support.
X */
X
X#include "awm.h"
X#include "X11/Xutil.h"
X
X#define max(a,b) ( (a) > (b) ? (a) : (b) )
X#define min(a,b) ( (a) > (b) ? (b) : (a) )
X#define makemult(a, b) ((b==1) ? (a) : (((int)((a) / (b))) * (b)) )
X
X/*ARGSUSED*/
XBoolean Resize(window, mask, button, x0, y0)
XWindow window;                          /* Event window. */
Xint mask;                               /* Button/key mask. */
Xint button;                             /* Button event detail. */
Xint x0, y0;                             /* Event mouse position. */
X{
X     XWindowAttributes client_info;	/* client window info. */
X     XWindowAttributes frame_info;	/* frame window info */
X     int x1, y1;                        /* fixed box corner   */
X     int x2, y2;                        /* moving box corner   */
X     int x, y;
X     int xinc, yinc;
X     int minwidth, minheight;
X     int maxwidth, maxheight;
X     int ox, oy;			/* which quadrant of window */
X     int pop_x, pop_y;			/* location of pop window */
X     int hsize, vsize;			/* dynamic size */
X     int delta;	
X     int junk_x, junk_y;
X     unsigned int ptrmask;		/* pointer status word */
X     int num_vectors;			/* Number of vectors to XDraw. */
X     Window sub_win;			/* Mouse query sub window. */
X     Window root;			/* Root query window. */
X     XEvent button_event, *b_ev;	/* Button event packet. */
X     XSegment box[MAX_BOX_VECTORS];	/* Box drawing vertex buffer. */
X     XSegment zap[MAX_ZAP_VECTORS];	/* Zap drawing vertex buffer. */
X     Boolean stop;			/* Should the window stop changing? */
X     XSizeHints sizehints;
X     XWindowChanges values;
X     int width_offset, height_offset;	/* to subtract if resize increments */
X     int x_offset, y_offset;		/* add to pointer to get anchor */
X     AwmInfoPtr awi;
X     int (*storegrid_func)();		/* which StoreGrid routine to use */
X     int (*storebox_func)();		/* which StoreBox routing to use */
X     int buttonConfirmEvent;
X     extern void ungrab_pointer();
X     extern void grab_pointer();
X
X     Entry("Resize")
X
X     /*
X      * Do nothing if the event window is the root window.
X      */
X     if (window == RootWindow(dpy, scr))
X	  Leave(FALSE)
X
X     /*
X      * Gather info about the event window.
X      */
X     awi = GetAwmInfo(window);
X     if (!awi)
X	  Leave(FALSE)
X     /*
X      * Do not resize an icon window.
X      */
X     if (window == awi->icon)
X	  Leave(FALSE)
X
X     window = awi->client;
X     b_ev = &button_event;
X     buttonConfirmEvent = ButtonRelease;
X
X     status = XGetWindowAttributes(dpy, window, &client_info);
X     if (status == FAILURE)
X	  Leave(FALSE)
X
X     if (awi->frame) { /* we have to compensate */
X	  status = XGetWindowAttributes(dpy, awi->frame, &frame_info);
X	  client_info.y = frame_info.y;
X	  client_info.x = frame_info.x;
X	  if (status == FAILURE)
X	       Leave(FALSE)
X          if (DECORATED(awi)) {
X	       if (awi->title)
X		    client_info.y += titleHeight + 2;
X	       if (awi->attrs & AT_BORDER) {
X		    client_info.x += BContext + 1;
X		    if (!awi->title)
X			 client_info.y += BContext + 1;
X	       }
X	  }
X     }
X
X     /*
X      * Clear The vector buffers.
X      */
X     bzero(box, sizeof(box));
X     if (Zap)
X	  bzero(zap, sizeof(zap));
X     storegrid_func = StoreGridBox;
X     storebox_func = StoreBox;
X
X     /*
X      * If we are here then we have a resize operation in progress.
X      */
X     
X     /*
X      * Turn on the resize cursor.
X      */
X     grab_pointer();
X     /*
X      * calculate fixed point (x1, y1) and varying point (x2, y2).
X      */
X     hsize = client_info.width;
X     vsize = client_info.height;
X     x1 = client_info.x;
X     y1 = client_info.y;
X     x2 = x1 + hsize;
X     y2 = y1 + vsize;
X
X     /*
X      * Get the event window resize hint.
X      */
X     sizehints.flags = 0;
X     XGetSizeHints(dpy, window, &sizehints, XA_WM_NORMAL_HINTS); 
X     CheckConsistency(&sizehints);
X
X     /* until there are better WM_HINTS, we'll assume that the client's
X      * minimum width and height are the appropriate offsets to subtract
X      * when resizing with an explicit resize increment.
X      */
X     if ((sizehints.flags & PMinSize) && (sizehints.flags & PResizeInc)) {
X	  width_offset = sizehints.min_width;
X	  height_offset = sizehints.min_height;
X     } else
X	  width_offset = height_offset = 0;
X 
X     /*
X      * decide what resize mode we are in. Always rubberband if window
X      * is too small.
X      */
X     if (client_info.width > 2 && client_info.height > 2) {
X	  ox = ((x0 - client_info.x) * 3) / client_info.width;
X	  oy = ((y0 - client_info.y) * 3) / client_info.height;
X	  if ((ox + oy) & 1) {
X	       if (ox & 1) {
X		    /* fix up size hints so that we will never change width */
X		    sizehints.min_width = sizehints.max_width =
X			 client_info.width;
X		    if ((sizehints.flags & PMinSize) == 0) {
X			 sizehints.min_height = 0;
X			 sizehints.flags |= PMinSize;
X		    }
X		    if ((sizehints.flags & PMaxSize) == 0) {
X			 sizehints.max_height = DisplayHeight(dpy, scr);
X			 sizehints.flags |= PMaxSize;
X		    }
X	       }
X	       if (oy & 1) {
X		    /* fix up size hints so that we will never change height */
X		    sizehints.min_height = sizehints.max_height =
X			 client_info.height;
X		    if ((sizehints.flags & PMinSize)==0) {
X			 sizehints.min_width = 0;
X			 sizehints.flags |= PMinSize;
X		    }
X		    if ((sizehints.flags & PMaxSize)==0) {
X			 sizehints.max_width = DisplayWidth(dpy, scr);
X			 sizehints.flags |= PMaxSize;
X		    }
X	       }
X	  }
X     }
X     else ox = oy = 2;
X     /* change fixed point to one that shouldn't move */
X     if (oy == 0) { 
X	  y = y1; y1 = y2; y2 = y;
X     }
X     if (ox == 0) { 
X	  x = x1; x1 = x2; x2 = x;
X     }
X     if (sizehints.flags & PMinSize) {
X	  minwidth = sizehints.min_width;
X	  minheight = sizehints.min_height;
X     } else {
X	  minwidth = 0;
X	  minheight = 0;
X     }
X     if (sizehints.flags & PMaxSize) {
X	  maxwidth = max(sizehints.max_width, minwidth);
X	  maxheight = max(sizehints.max_height, minheight);
X     } else {
X	  maxwidth = DisplayWidth(dpy, scr);
X	  maxheight = DisplayHeight(dpy, scr);
X     }
X     if (sizehints.flags & PResizeInc) {
X	  xinc = sizehints.width_inc;
X	  yinc = sizehints.height_inc;
X     } else {
X	  xinc = 1;
X	  yinc = 1;
X     }
X     switch (ox) {
X     case 0:
X	  pop_x = x1 - PWidth;
X	  break;
X     case 1:
X	  pop_x = x1 + (hsize - PWidth) / 2;
X	  break;
X     case 2:
X	  pop_x = x1;
X	  break;
X     }
X     switch (oy) {
X     case 0:
X	  pop_y = y1 - PHeight;
X	  break;
X     case 1:
X	  pop_y = y1 + (vsize - PHeight) / 2;
X	  break;
X     case 2:
X	  pop_y = y1;
X	  break;
X     }
X     /*
X      * Double expose on the target window is too expensive for some reason
X      * or another. Paint the popup window in the upper left hand
X      * corner of the screen if RootResizeBox is FALSE. This is also
X      * more-or-less consistent with the position of the map request popup.
X      */
X     if (RootResizeBox == TRUE)
X	  values.x = values.y = 0;
X     else {
X	  if (pop_x < 0 || pop_x > (DisplayWidth(dpy, scr) - PWidth))
X	       pop_x = 0;
X	  if (pop_y < 0 || pop_y > (DisplayHeight(dpy, scr) - PHeight))
X	       pop_y = 0;
X	  values.x = pop_x;
X	  values.y = pop_y;
X     }
X     values.stack_mode = Above;
X     XConfigureWindow(dpy, Pop, (unsigned int) CWX|CWY|CWStackMode, &values);
X     XMapWindow(dpy, Pop);
X     if (Grid) {
X	  num_vectors = (*storegrid_func)(box,
X					  MIN(x1, x2), MIN(y1, y2),
X					  MAX(x1, x2), MAX(y1, y2));
X     }
X     else {
X	  num_vectors = (*storebox_func)(box,
X					 MIN(x1, x2), MIN(y1, y2),
X					 MAX(x1, x2), MAX(y1, y2));
X     }
X
X     /*
X      * If we freeze the server, then we will draw solid
X      * lines instead of flickering ones during resizing.
X      */
X     if (Freeze)
X	  XGrabServer(dpy);
X     /* protect us from ourselves */
X     Snatched = True;
X     /*
X      * Process any pending exposure events before drawing the box.
X      */
X     while (QLength(dpy) > 0) {
X	  XPeekEvent(dpy, b_ev);
X	  if (b_ev->xany.window == RootWindow(dpy, scr))
X	       break;
X	  GetButton(b_ev);
X     }
X     if (ResizeRelative) {
X	  x_offset = x2 - x0;
X	  y_offset = y2 - y0;
X     }
X     else
X	  x_offset = y_offset = 0;
X
X     /*
X      * Now draw the box.
X      */
X     DrawBox();
X     Frozen = window;
X 
X     stop = FALSE;
X     x = -1; y = -1;
X     
X     while (!stop) {
X	  if (x != x2 || y != y2) {
X	       x = x2; y = y2;
X
X	       /*
X		* If we've frozen the server, then erase
X		* the old box.
X		*/
X	       if (Freeze)
X		    DrawBox();
X	       
X	       if (Grid) {
X		    num_vectors = (*storegrid_func)(box,
X						    MIN(x1, x), MIN(y1, y),
X						    MAX(x1, x), MAX(y1, y));
X	       }
X	       else {
X		    num_vectors = (*storebox_func)(box,
X						   MIN(x1, x), MIN(y1, y),
X						   MAX(x1, x), MAX(y1, y));
X	       }
X	       
X	       if (Freeze)
X		    DrawBox();
X	       
X	       {
X		    int Hsize = (hsize - width_offset) / xinc;
X		    int Vsize = (vsize - height_offset) / yinc;
X		    int pos = 4;
X		    PText[0] = (Hsize>99) ? (Hsize / 100 + '0')	  : ' ';
X		    PText[1] = (Hsize>9)  ? ((Hsize / 10) % 10 + '0') : ' ';
X		    PText[2] = Hsize % 10 + '0';
X		    if (Vsize>99) PText[pos++] = Vsize / 100 + '0';
X		    if (Vsize>9)  PText[pos++] = (Vsize / 10) % 10 + '0';
X		    PText[pos++] = Vsize % 10 + '0';
X		    while (pos<7) PText[pos++] = ' ';
X	       }
X	       /*
X		* If the font is not fixed width we have to
X		* clear the window to guarantee that the characters
X		* that were there before are erased.
X		*/
X	       if (!(PFontInfo->per_char))
X		    XClearWindow(dpy, Pop);
X	       XDrawImageString(
X				dpy, Pop, PopGC,
X				PPadding, PPadding+PFontInfo->ascent,
X				PText, PTextSize);
X	  }
X	  if (!Freeze) {
X	       DrawBox();
X	       DrawBox();
X	  }
X
X	  if (XPending(dpy) && !ProcessRequests(box, num_vectors) &&
X	      GetButton(b_ev)) {
X	       if ((b_ev->xany.type != ButtonPress) && 
X		   (b_ev->xany.type != ButtonRelease))
X		    continue; /* spurious menu event... */
X
X	       if (Freeze) {
X		    DrawBox();
X		    Frozen = (Window)0;
X		    XUngrabServer(dpy);
X	       }
X
X	       if (b_ev->xany.type == buttonConfirmEvent &&
X		   b_ev->xbutton.button == button)
X		    stop = TRUE;
X	       else {
X		    XUnmapWindow(dpy, Pop);
X		    ResetCursor(button);
X		    Snatched = False;
X		    ungrab_pointer();
X		    Leave(TRUE)
X	       }
X	  }
X	  else {
X	       XQueryPointer(dpy, RootWindow(dpy, scr), &root, 
X			     &sub_win, &x2, &y2, &junk_x, &junk_y, &ptrmask);
X	       x2 += x_offset;	/* get to anchor point */
X	       y2 += y_offset;
X	  }
X	  hsize = max(min(abs (x2 - x1), maxwidth), minwidth);
X	  hsize = makemult(hsize - minwidth, xinc) + minwidth;
X
X	  vsize = max(min(abs(y2 - y1), maxheight), minheight);
X	  vsize = makemult(vsize - minheight, yinc) + minheight; 
X	  if (sizehints.flags & PAspect) {
X	       if ((hsize * sizehints.max_aspect.y > 
X		    vsize * sizehints.max_aspect.x)) {
X		    delta = makemult((hsize * sizehints.max_aspect.y /
X				      sizehints.max_aspect.x) - vsize, 
X				     yinc);
X		    if ((vsize + delta <= maxheight))
X			 vsize += delta;
X		    else {
X			 delta = makemult(hsize - 
X					  (sizehints.max_aspect.x *
X					   vsize/sizehints.max_aspect.y), 
X					  xinc);
X			 if (hsize - delta >= minwidth)
X			      hsize -= delta; 
X		    }
X	       }  
X	       if (hsize * sizehints.min_aspect.y < vsize *
X		   sizehints.min_aspect.x) {
X		    delta = makemult((sizehints.min_aspect.x * 
X				      vsize/sizehints.min_aspect.y) - hsize, 
X				     xinc);
X		    if (hsize + delta <= maxwidth)
X			 hsize += delta;
X		    else {
X			 delta = makemult(vsize - 
X					  (hsize*sizehints.min_aspect.y /
X					   sizehints.min_aspect.x), 
X					  yinc); 
X			 if (vsize - delta >= minheight)
X				vsize -= delta; 
X		    }
X	       }
X	       
X	  }
X	  if (ox == 0)
X	       x2 = x1 - hsize;
X	  else
X	       x2 = x1 + hsize;
X	  
X	  if (oy == 0)
X	       y2 = y1 - vsize;
X	  else
X	       y2 = y1 + vsize;
X	  
X     }
X     if (x2 < x1) {
X	  x = x1; x1 = x2; x2 = x;
X     }
X     if (y2 < y1) {
X	  y = y1; y1 = y2; y2 = y;
X     }
X     XUnmapWindow(dpy, Pop);
X     if ((x1 !=client_info.x) || (y1 != client_info.y) || 
X	 (hsize != client_info.width) ||
X	 (vsize != client_info.height)) {
X	  XWindowChanges xwc;
X	       
X	  xwc.x = x1;
X	  xwc.y = y1;
X	  xwc.width = hsize;
X	  xwc.height = vsize;
X	  ConfigureWindow(window, 
X			  (unsigned int) CWX | CWY | CWHeight | CWWidth, &xwc);
X     }
X     Snatched = False;
X     ungrab_pointer();
X     Leave(TRUE)
X}
X
XCheckConsistency(hints)
XXSizeHints *hints;
X{
X     Entry("CheckConsistency")
X
X     if (hints->min_height < 0)
X	  hints->min_height = 0;
X     if (hints->min_width < 0)
X	  hints->min_width = 0;
X     
X     if (hints->max_height <= 0 || hints->max_width <= 0)
X	  hints->flags &= ~PMaxSize;
X     
X     hints->min_height = min(DisplayHeight(dpy, scr), hints->min_height);
X     hints->min_width =  min(DisplayWidth(dpy, scr),  hints->min_width);
X     
X     hints->max_height = min(DisplayHeight(dpy, scr), hints->max_height);
X     hints->max_width =  min(DisplayWidth(dpy, scr),  hints->max_width);
X     
X     if ((hints->flags & PMinSize) && (hints->flags & PMaxSize) && 
X	 ((hints->min_height > hints->max_height) ||
X	  (hints->min_width > hints->max_width)))
X	  hints->flags &= ~(PMinSize|PMaxSize);
X     
X     if ((hints->flags & PAspect) && 
X	 (hints->min_aspect.x * hints->max_aspect.y > 
X	  hints->max_aspect.x * hints->min_aspect.y))
X	  hints->flags &= ~(PAspect);
X     Leave_void
X}
END_OF_FILE
if test 15574 -ne `wc -c <'Resize.c'`; then
    echo shar: \"'Resize.c'\" unpacked with wrong size!
fi
# end of 'Resize.c'
fi
if test -f 'menus/menu.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'menus/menu.c'\"
else
echo shar: Extracting \"'menus/menu.c'\" \(33843 characters\)
sed "s/^X//" >'menus/menu.c' <<'END_OF_FILE'
X
X#ifndef lint
X     static char sccs_id[] = "@(#)menu.c	2.1 12/16/87  Siemens Corporate Research and Support, Inc.";
X#endif
X
X
X/*
X  RTL Menu Package Version 1.0
X  by Joe Camaratta and Mike Berman, Siemens RTL, Princeton NJ, 1987
X  
X  menu.c: menu utility and support functions.
X  
X  Originally hacked by Adam J. Richter, based on the menu package for xterm.
X  ( misc.c  X10/6.6 )
X
X  */
X
X/*
X *
X * Changed in various and subtle ways by Jordan Hubbard, Ardent Computer.
X * February 1st, 1988: Removed dependence on oldX by nuking AssocTable
X * stuff in favor of contexts. Added "label" panes, useful for titling
X * purposes. Variable height items, variable fonts, pictoral panes
X * (pixmaps) for cute graphic menus.
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  
X  Copyright 1985, 1986, 1987 by the Massachusetts Institute of Technology
X  
X  Permission to use, copy, modify, and distribute this
X  software and its documentation for any purpose and without
X  fee is hereby granted, provided that the above copyright
X  notice appear in all copies and that both that copyright
X  notice and this permission notice appear in supporting
X  documentation, and that the name of M.I.T. not be used in
X  advertising or publicity pertaining to distribution of the
X  software without specific, written prior permission.
X  M.I.T. makes no representations about the suitability of
X  this software for any purpose.  It is provided "as is"
X  without express or implied warranty.
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/* Got that?  Good! Now, there is actually some code in here.. */
X
X
X#include <stdio.h>
X#include "X11/Xlib.h"
X#include "X11/cursorfont.h"
X#include "X11/Xutil.h"
X#include "X11/Intrinsic.h"
X
X#include "menu.h"
X#include "menu.def.h"
X#include "gray1.h"
X#include "arrow_icon.h"
X#include "dbug.h"
X
X#define MakeEven(x) ((x%2 == 0)? x : x-1)
X
X
X#define InvertPlane		1
X
Xstatic char Check_MarkBits[] = {
X     0x00, 0x01, 0x80, 0x01, 0xc0, 0x00, 0x60, 0x00,
X     0x31, 0x00, 0x1b, 0x00, 0x0e, 0x00, 0x04, 0x00
X     };
X
XMenu MenuDefault;
X
X/*
X * the following have already been set my GetDefaults()
X * by the time we get here.
X */
XXFontStruct *MFontInfo;
XXFontStruct *MBoldFontInfo;
Xint MBorderWidth, MPad, MDelta, MItemBorder;
XPixel MForeground, MBackground, MBorder;
X
Xextern Boolean SaveUnder;
Xextern int Reverse;
Xextern Display *dpy;
Xextern int scr;
X
Xstatic XContext Menu_context;
Xstatic XContext Item_context;
Xstatic contexts_created = FALSE;
X
XMenuItem *AddMenuItem(), *Display_Menu(), *MenuGetItem(),
X     *MenuItemByName(), *MenuItemByData(), *GetInitialItem(), *MoveMenu();
XBoolean	 DisposeItem(), SetItemCheck(), SetItemDisable(), Recalc_Menu(),
X     SetupItems(), MapMenu(), SetItemText(), SetupMenuWindow();
Xvoid	 DisposeMenu(), InitMenu(), Undisplay_Menu(), MenuInvert(),
X     PlacePointer(), Draw_Menu(), Draw_Item(),	SetInitialItem(),
X     ClearInitialItem(), Generate_Menu_Entries(), UnmapMenu(),
X     SetInputMask();
XMenu	 *NewMenu(), *MenuGetMenu();
Xint	 ItemGetMiddleY();
X
X/*
X * AddMenuItem() adds a menu item to an existing menu, at the end of the
X * list, which are number sequentially from zero.  The menuitem index is
X * return, or -1 if failed.
X */
X
XMenuItem *AddMenuItem(menu, text, bitmap_file)
XMenu *menu;
Xchar *text;
Xchar *bitmap_file;
X{
X     MenuItem *menuitem, **next;
X     int junk;
X     char *data;
X
X     Entry("AddMenuItem")
X
X     if (!menu || (!text && !bitmap_file) || (menuitem = allocate(MenuItem, 1))
X	== (MenuItem *)0)
X	  Leave(NULLITEM)
X     bzero((char *)menuitem, sizeof(MenuItem));
X     ItemText(menuitem) = allocate(char, (strlen(text) + 1));
X     strcpy(ItemText(menuitem), text);
X     ItemTextLength(menuitem) = strlen(text);
X     if (bitmap_file) {
X	  bitmap_file = (char *)expand_from_path(bitmap_file);
X	  if (XmuReadBitmapDataFromFile(bitmap_file,
X			      &(menuitem->itemTextWidth),
X			      &(menuitem->itemHeight),
X			      &data,
X			      &junk, &junk) != BitmapSuccess) {
X	       fprintf(stderr, "awm: Can't read bitmap file '%s'\n",
X		       bitmap_file);
X	       exit(1);
X	  }
X	  menuitem->itemBackground =
X	       XCreatePixmapFromBitmapData(dpy, RootWindow(dpy, scr),
X					   data,
X					   menuitem->itemTextWidth,
X					   menuitem->itemHeight,
X					   MForeground,
X					   MBackground,
X					   DefaultDepth(dpy, scr));
X	  if (!menuitem->itemBackground) {
X	       fprintf(stderr, "awm: Can't create pixmap for file '%s'\n",
X		       bitmap_file);
X	       exit(1);
X	  }
X	  free(data);
X	  free(bitmap_file);
X     }
X     for(next = &menu->menuItems; *next; next = &(*next)->nextItem);
X
X     *next = menuitem;
X
X     SetMenuFlag(menu, menuChanged);
X     Leave(menuitem)
X}
X
X/*
X * DisposeItem() releases the memory allocated for the given indexed
X * menuitem.  Nonzero is returned if an item was actual disposed of.
X * It also checks to see whether the item we're disposing is the
X * initial item for the menu -- if so, null out the initial item.
X */
XBoolean DisposeItem(menu, item)
XMenu *menu;
XMenuItem *item;
X{
X     MenuItem **next, **last, *menuitem;
X 
X     Entry("DisposeItem")
X
X     if (MenuIsNull(menu) || ItemIsNull(item))
X	  Leave(FALSE)
X     next = &MenuItems(menu);
X     do {
X	  if(!*next)
X	       Leave(FALSE)
X	  last = next;
X	  next = &(*next)->nextItem;
X     } while((*last != item) && !ItemIsNull(*next));
X     menuitem = *last;
X     *last = *next;
X     if (ItemWindow(menuitem)) {
X	  XDeleteContext(dpy, ItemWindow(menuitem), Item_context);
X	  XDestroyWindow(dpy, ItemWindow(menuitem));
X     }
X     if (ItemIsInitialItem(menu, menuitem))
X	  ClearInitialItem(menu);
X
X     if (ItemText(menuitem))
X	  free((char*)ItemText(menuitem));
X     free((char*)menuitem);
X
X     SetMenuFlag(menu, menuChanged);
X     Leave(TRUE)
X}
X
X/*
X * DisposeMenu() releases the memory allocated for the given menu.
X */
Xvoid DisposeMenu(menu)
XMenu *menu;
X{
X     Entry("DisposeMenu")
X
X     if(!menu)
X	  Leave_void
X     if (TestMenuFlag(menu, menuMapped))
X	  UnmapMenu(menu);
X     while(DisposeItem(menu, MenuItems(menu)));
X     if(MenuWindow(menu)) {
X	  XDeleteContext(dpy, MenuWindow(menu), Menu_context);
X	  XDestroyWindow(dpy, MenuWindow(menu));
X     }
X     XFreePixmap (dpy, MenuGreyPixmap(menu));
X     XFreePixmap (dpy, MenuArrowPixmap(menu));
X     XFreePixmap (dpy, MenuCheckmarkPixmap(menu));
X     XFreeGC (dpy, MenuNormalGC(menu));
X     XFreeGC (dpy, MenuInvertGC(menu));
X     XFreeGC (dpy, menu->boldGC);
X     
X     if (MenuHasInitialItem(menu))
X	  ClearInitialItem(menu);
X     free((char*) menu);
X     Leave_void
X}
X
Xstatic char *Name;
X
Xvoid InitMenu(name, options)
Xchar *name;
Xunsigned int options;
X{
X     char *cp;
X     
X     Entry("InitMenu")
X
X     Name = name;
X     MenuDefault.menuFlags = menuChanged;
X     
X     MenuDefault.menuInitialItemText = (char *) NULL;
X     MenuDefault.display = dpy;
X     MenuDefault.screen = scr;
X     MenuDefault.menuOptions = options;
X     Leave_void
X}
X
X/*
X * ItemText changes the text of item of the menu.
X */
XBoolean SetItemText(menu, item, text)
XMenu *menu;
XMenuItem *item;
Xchar *text;
X{
X     Entry("SetItemText")
X
X     if (strcmp (ItemText(item), text) == 0)
X	  Leave (True)
X     
X     if(ItemText(item))
X	  free((char *) ItemText(item));
X     
X     ItemText(item) = allocate(char, (strlen(text) + 1));
X     strcpy(ItemText(item), text);
X     
X     ItemTextLength(item) = strlen (text);
X     SetMenuFlag(menu, menuChanged);
X     
X     (void) Recalc_Menu (menu);
X     Leave(TRUE)
X}
X
X/*
X * NewMenu() returns a pointer to an initialized new Menu structure, or NULL
X * if failed.
X *
X * The Menu structure _menuDefault contains the default menu settings.
X */
XMenu *NewMenu()
X{
X     extern Pixmap MakeGreyStipple ();
X     Menu *menu = 0;
X     
X     XGCValues gcValues;
X     
X     static unsigned long gcMask =
X	  (GCFunction | GCForeground | GCBackground | GCFont | GCStipple |
X	   GCSubwindowMode | GCGraphicsExposures);
X     
X     char *cp;
X
X     Entry("NewMenu")
X
X     /*
X      * Allocate the memory for the menu structure.
X      */
X     if(MenuIsNull((menu = allocate(Menu, 1))))
X	  Leave(NULLMENU)
X     
X     /*
X      * Initialize to default values.
X      */
X     *menu = MenuDefault;
X     gcValues.font = MFontInfo->fid;
X     
X     /*
X      * If the menu cursor hasn't been given, make a default one.
X      */
X
X     MenuCursor(menu) = XCreateFontCursor (dpy, XC_right_ptr);
X     MenuArrowPixmap(menu) = XCreatePixmapFromBitmapData(dpy,
X							 RootWindow(dpy, scr),
X							 arrow_bits,
X							 arrow_width,
X							 arrow_height,
X							 MForeground,
X							 MBackground,
X							 DefaultDepth(dpy, scr));
X
X     MenuGreyPixmap(menu) = XCreateBitmapFromData(dpy,
X						  RootWindow(dpy, scr),
X						  gray1_bits,
X						  gray1_width, gray1_height);
X     
X     MenuCheckmarkPixmap(menu) = XCreatePixmapFromBitmapData(dpy,
X							     RootWindow(dpy, scr),
X							     Check_MarkBits,
X							     checkMarkWidth,
X							     checkMarkHeight,
X							     MForeground,
X							     MBackground,
X							     DefaultDepth(dpy, scr));
X
X     gcValues.foreground = MForeground;
X     gcValues.background = MBackground;
X
X     gcValues.stipple = MenuGreyPixmap(menu);
X     gcValues.function = GXcopy;
X     gcValues.subwindow_mode = IncludeInferiors;
X     gcValues.graphics_exposures = False;
X     MenuNormalGC(menu) =
X	  XCreateGC (dpy, RootWindow(dpy, scr),
X		     gcMask,
X		     &gcValues);
X     /* reverse */
X     gcValues.foreground = MBackground;
X     gcValues.background = MForeground;
X
X     MenuInvertGC(menu) = XCreateGC(dpy, RootWindow (dpy, scr),
X				    gcMask,
X				    &gcValues);
X     gcValues.foreground = MForeground;
X     gcValues.background = MBackground;
X     gcValues.font = MBoldFontInfo->fid;
X     menu->boldGC = XCreateGC(dpy, RootWindow(dpy, scr),
X			      gcMask,
X			      &gcValues);
X     Leave(menu)
X}
X
X
X/*
X * SetItemCheck sets the check state of item of the menu to "state".
X */
XBoolean SetItemCheck(menu, item, state)
XMenu *menu;
XMenuItem *item;
Xint state;
X{
X     Entry("SetItemCheck")
X
X     if (TestItemFlag(item,itemChecked) == state) /* Exit if unchanged */
X	  Leave (True)
X     
X     if (state)
X	  SetItemFlag(item, itemChecked);
X     else
X	  ResetItemFlag(item, itemChecked);
X     
X     SetItemFlag(item, itemChanged);
X     SetMenuFlag(menu, menuItemChanged);
X     
X     Leave(TRUE)
X}
X/*
X * SetItemDeaf sets the "deaf" state of item of the menu to "state".
X * "deaf" means that the item is display only and not sensitive to input.
X */
XBoolean SetItemDeaf(menu, item, state)
XMenu *menu;
XMenuItem *item;
Xint state;
X{
X     Entry("SetItemDeaf")
X
X     if (TestItemFlag(item,itemDeaf) == state) /* Exit if unchanged */
X	  Leave (True)
X     
X     if (state)
X	  SetItemFlag(item, itemDeaf);
X     else
X	  ResetItemFlag(item, itemDeaf);
X     
X     SetItemFlag(item, itemChanged);
X     SetMenuFlag(menu, menuItemChanged);
X     if (ItemIsInitialItem(menu, item))
X	  ClearInitialItem(menu);
X     Leave(TRUE)
X}
X
X/*
X * SetItemDisable sets the disable state of item "n" of the menu to "state".
X */
XBoolean SetItemDisable(menu, item, state)
XMenu *menu;
XMenuItem *item;
Xint state;
X{
X     Entry("SetItemDisable")
X
X     if (TestItemFlag(item,itemDisabled) == state) /* Exit if unchanged */
X	  Leave (True)
X     
X     if(state)
X     {
X	  SetItemFlag(item, itemDisabled);
X	  /* if disabled item is currently initial item, null initial item */
X	  if (ItemIsInitialItem(menu, item))
X	       ClearInitialItem(menu);
X     }
X     else
X	  ResetItemFlag(item, itemDisabled);
X     
X     SetItemFlag(item, itemChanged);
X     SetMenuFlag(menu, menuItemChanged);
X     
X     Leave(TRUE)
X}
X
XMenuItem *Display_Menu(menu, parent, x, y)
XMenu *menu;
XMenu *parent;
Xint x;
Xint y;
X{
X     MenuItem *item;
X     
X     Entry("Display_Menu")
X
X     if (MenuIsNull(menu))
X	  Leave(FALSE)
X     
X     MenuParent(menu) = parent;
X     
X     if (MenuIsNull(parent))
X	  MenuNested(menu) = 0;
X     else
X	  MenuNested(menu) = MenuNested(parent) + 1;
X     if (!MenuWindow(menu) || TestMenuFlag(menu,
X        (menuChanged | menuItemChanged))) {
X	  if (!SetupMenuWindow(menu))
X	       Leave(NULL)
X	  Generate_Menu_Entries(menu);
X     }
X     if (TestOptionFlag(menu,savebits) &&
X	 (MenuSavedPixmap(menu) != (Pixmap) 0))
X	  SetInputMask(menu, MenuIgnoreMask);
X     else
X	  SetInputMask(menu, ExposureMask);
X     if (!(item = MoveMenu(menu, x, y)) || !MapMenu(menu))
X	  Leave(FALSE)
X     Draw_Menu(menu);
X     
X     Leave(item)
X}
X
Xvoid Undisplay_Menu(menu)
XMenu *menu;
X{
X     Entry("Undisplay_Menu")
X
X     if (MenuIsNull(menu))
X	  Leave_void
X     
X     MenuParent(menu) = NULLMENU;
X     MenuNested(menu) = 0;
X     
X     UnmapMenu(menu);
X     Leave_void
X}
X
Xvoid MenuInvert(menu, item)
XMenu *menu;
XMenuItem *item;
X{
X     Entry("MenuInvert")
X
X     XFillRectangle(dpy,
X		    ItemWindow(item),
X		    MenuInvertGC(menu),
X		    0, 0, 
X		    MenuWidth(menu),
X		    item->itemHeight);
X     Leave_void
X}
X
X/*
X * Recalculate all of the various menu and item variables.
X */
XBoolean Recalc_Menu(menu)
XMenu *menu;
X{
X     MenuItem *item;
X     int max, height, fontheight, boldfontheight, nitems;
X     /* Gets set to false first time we see an item with text */
X     unsigned int menuIsPictures = TRUE;
X     
X     Entry("Recalc_Menu")
X
X     /*
X      * We must have already gotten the menu font.
X      */
X     if(!MFontInfo)
X	  Leave(FALSE)
X     /*
X      * Initialize the various max width variables.
X      */
X     fontheight = MFontInfo->ascent + MFontInfo->descent + 2;
X     boldfontheight = MBoldFontInfo->ascent + MBoldFontInfo->descent + 2;
X     height = nitems = 0;
X     MenuMaxTextWidth(menu) = 0;
X     /*
X      * The item height is the maximum of the font height and the
X      * checkbox height, unless we find out that it's a pixmap (in which
X      * case, most of these values are overridden).
X      */
X     max = fontheight;
X     if(checkMarkHeight > max)
X	  max = checkMarkHeight;
X     
X     max += 2*MItemBorder;
X     max = MakeEven(max);
X     	   
X     /*
X      * Go through the menu item list.
X      */
X     for(item = MenuItems(menu) ; item ; item = ItemNext(item)) {
X	  if (item->itemBackground)	/* pixmap is static size */
X	       max = item->itemHeight;
X	  else {
X	       if (ItemIsDeaf(item))	/* It's a label, use bold info */
X		    max = boldfontheight;
X	       else
X		    max = fontheight;
X	  }
X	  if (checkMarkHeight > max)
X	       max = checkMarkHeight;
X	  if (!item->itemBackground) {
X	       max += 2 * MItemBorder;
X	       max = MakeEven(max);
X	       item->itemHeight = max;
X	  }
X	  height += max;
X	  nitems++;
X	  /*
X	   * Check the text width with the max value stored in
X	   * menu.
X	   */
X	  if (!item->itemBackground) {
X	       if ((ItemTextWidth(item) = XTextWidth(ItemIsDeaf(item) ?
X						     MBoldFontInfo
X						     : MFontInfo,
X						     ItemText(item),
X						     strlen (ItemText(item))))
X                  > MenuMaxTextWidth(menu))
X                    MenuMaxTextWidth(menu) = ItemTextWidth(item);
X	       menuIsPictures = FALSE;
X          }
X          /* ItemTextWidth is really pixmap size. Yick. */
X	  else {
X               if (ItemTextWidth(item) > MenuMaxTextWidth(menu))
X                    MenuMaxTextWidth(menu) = ItemTextWidth(item);
X          }
X
X     }
X     /*
X      * Set the menu height and then set the menu width.
X      */
X     MenuHeight(menu) = height;
X     menu->avgHeight = height / nitems;
X
X     if (menuIsPictures == TRUE)
X	  MenuWidth(menu) = MenuMaxTextWidth(menu) + (2 * MItemBorder);
X     else {
X	  MenuWidth(menu) = 4 * MenuItemPad(menu) + MenuMaxTextWidth(menu) +
X	       checkMarkWidth + arrow_width + (2 * MItemBorder);
X     }
X     MenuItemWidth(menu) = MenuWidth(menu) - (2 * MItemBorder);
X     Leave(TRUE)
X}
X
X/*
X * Figure out where to popup the menu, relative to the where the button was
X * pressed.
X * Returns pointer to initial item to warp to.
X */
Xstatic MenuItem *MoveMenu(menu, ev_x, ev_y)
XMenu *menu;
Xint ev_x, ev_y;
X{
X     int x, y;
X     int total_width, total_height;
X     int offset;
X     MenuItem *item;
X     Window junk;
X     int r_x, foo, state;
X     
X     Entry("MoveMenu")
X
X     /*
X      * Get the coordinates of the mouse when the button was pressed.
X      */
X     
X     total_width = MenuWidth(menu) + 2 * MenuBorderWidth(menu);
X     total_height = MenuHeight(menu) + 2 * MenuBorderWidth(menu);
X
X     XQueryPointer(dpy, RootWindow(dpy, scr), &junk, &junk, &r_x, &y,
X		   &foo, &foo, &state); 
X     x = ev_x - MenuItemPad(menu);
X     if (x < 0)
X	  x = 0;
X     else if (TestOptionFlag(menu, rightoffset) &&
X	      !MenuIsNull(MenuParent(menu)))
X     {
X	  /* check whether parent is close to right edge... */
X	  /* "too close" means that child would leave < delta of its parent */
X	  /* visible to its left.                                           */
X	  if (TestOptionFlag(menu, bigoffset))
X	  {
X	       if (MenuX(MenuParent(menu)) + MenuWidth(MenuParent(menu)) > 
X		   DisplayWidth(dpy, scr) - total_width)
X		    x = MenuX(MenuParent(menu))
X			 - total_width + 2*MenuBorderWidth(menu);
X	  }
X	  else
X	  {
X	       if (MenuX(MenuParent(menu)) + MenuDelta(MenuParent(menu)) > 
X		   DisplayWidth(dpy, scr) - total_width)
X	       {
X		    x = (MenuX(MenuParent(menu)) + MenuWidth(MenuParent(menu)) +
X			 2 * MenuBorderWidth(MenuParent(menu))
X			 - total_width - MenuDelta(menu));
X	       }
X	  }
X     }
X     if (x + total_width >
X	 DisplayWidth(dpy, scr))
X	  x = DisplayWidth(dpy, scr)
X	       - total_width;
X     
X     /*
X      * If we have an initial item, try to popup the menu centered
X      * vertically within this item.
X      */
X     if(MenuHasInitialItem(menu)) {
X	  int tmp_y;
X
X	  /*
X	   * Look through the item list. "y" is the vertical position
X	   * of the top of the current item and "n" is the item number.
X	   */
X	  offset = MenuBorderWidth(menu);
X	  for(item = MenuItems(menu) ; ;) {
X	       /*
X		* On finding the initial item, center within this item.
X		*/
X	       if (ItemIsInitialItem(menu, item)) {
X		    y -= offset;
X		    break;
X	       }
X	       else
X		    offset += item->itemHeight;
X	       /*
X		* If we run out of items, turn off the initial item
X		* and treat this as if no initial item.
X		*/
X	       if(!(item = ItemNext(item))) {
X		    ClearInitialItem(menu);
X		    break;
X	       }
X	  }
X     }
X     
X     if (y < 0)
X	  y = 0;
X     else if (y + total_height >
X	      DisplayHeight(dpy, scr))
X     {
X	  y = DisplayHeight(dpy, scr)
X	       - (total_height + 1);
X     }
X     y = MakeEven(y) + 1;
X     XMoveWindow(dpy, MenuWindow(menu), x, y);
X     MenuX(menu) = x;
X     MenuY(menu) = y;
X     
X     if (!ItemIsInitialItem(menu, item))
X	  item = MenuItems(menu);
X     Leave(item)
X}
X
X
Xvoid PlacePointer(menu, item)
XMenu *menu;
XMenuItem *item;
X{
X     int y;
X     
X     Entry("PlacePointer")
X
X     y = ItemGetMiddleY(item);
X     
X     XWarpPointer(dpy, None,
X		  RootWindow(dpy, scr), 
X		  0, 0, 0, 0, 
X		  MenuX(menu) + MPad + (MenuWidth(menu) / 2), y);
X     Leave_void
X}
X
X/*
X * Map the menu window.
X */
Xstatic Boolean MapMenu(menu)
XMenu *menu;
X{
X     Entry("MapMenu")
X
X     if (!TestMenuFlag(menu, menuMapped))
X	  MenuItemHighlighted(menu) = NULLITEM;
X     
X     /*
X      * Actually map the window.
X      */
X     
X     if (TestOptionFlag(menu,savebits))
X     {
X	  if ((MenuSavedPixmap(menu) == (Pixmap) 0) ||
X	      (MenuOldWidth(menu) != MenuWidth(menu)) ||
X	      (MenuOldHeight(menu) != MenuHeight(menu)) ||
X	      (MenuOldBorderWidth(menu) != MenuBorderWidth(menu)))
X	  {
X	       if (MenuSavedPixmap(menu) != (Pixmap) 0)
X		    XFreePixmap(dpy, MenuSavedPixmap(menu));
X	       
X	       MenuSavedPixmap(menu) =
X		    XCreatePixmap(dpy, 
X				  RootWindow(dpy, scr), 
X				  MenuWidth(menu) + 2*MenuBorderWidth(menu),
X				  MenuHeight(menu) + 2*MenuBorderWidth(menu),
X				  DefaultDepth(dpy, scr));
X	       DBUG_5("Pixmaps","Created pixmap: width %d, height %d, depth %d\n",
X		      MenuWidth(menu) + 2*MenuBorderWidth(menu),
X		      MenuHeight(menu) + 2*MenuBorderWidth(menu),
X		      DefaultDepth(dpy, scr)); 
X	       MenuOldWidth(menu) = MenuWidth(menu);
X	       MenuOldHeight(menu) = MenuHeight(menu);
X	       MenuOldBorderWidth(menu) = MenuBorderWidth(menu);
X	  }
X	  else
X	       SetInputMask(menu, ExposureMask);
X	  
X	  if (MenuSavedPixmap(menu) != (Pixmap) 0) { 
X	       /*	XFillRectangle(dpy,
X			MenuSavedPixmap(menu),
X			SaveGC,
X			0,0,
X			MenuWidth(menu) + 2*MenuBorderWidth(menu),
X			MenuHeight(menu) + 2*MenuBorderWidth(menu)); */
X	       SetInputMask(menu, MenuIgnoreMask);
X	       XCopyArea(dpy, 
X			 RootWindow(dpy, scr),
X			 MenuSavedPixmap(menu),
X			 MenuNormalGC(menu),
X			 MenuX(menu), 
X			 MenuY(menu), 
X			 (unsigned int) (MenuWidth(menu) + 2*MenuBorderWidth(menu)), 
X			 (unsigned int) (MenuHeight(menu) + 2*MenuBorderWidth(menu)), 
X			 0, 0);
X	  }
X	  else
X	       SetInputMask(menu, ExposureMask);
X	  
X     }
X     
X     XRaiseWindow(dpy, MenuWindow(menu));
X     XMapWindow(dpy, MenuWindow(menu));
X     SetMenuFlag(menu, menuMapped);
X     Leave(TRUE)
X}
X
Xstatic void Generate_Menu_Entries (menu)
XMenu *menu;
X{
X     MenuItem *item;
X     
X     Entry("Generate_Menu_Entries")
X
X     for (item = MenuItems(menu); item; (item = ItemNext(item))) {
X	  
X	  if (ItemGenerator(item)) {
X	       char *newText;
X	       
X	       (ItemGenerator(item)) (&newText, &ItemCallback(item));
X	       SetItemText (menu, item, newText);
X	  }
X	  
X	  if (ItemCheckproc(item))
X	       SetItemCheck (menu, item, (ItemCheckproc(item))(menu,item));
X     }
X     Leave_void
X}
X
X/*
X * Draw the entire menu in the blank window.
X */
Xvoid Draw_Menu(menu)
XMenu *menu;
X{
X     MenuItem *item;
X     
X     Entry("Draw_Menu")
X
X     ResetMenuFlag(menu, menuChanged);
X     /*
X      * For each item in the list, first draw any check mark and then
X      * draw the rest of it.
X      */
X     for(item = MenuItems(menu) ; item ; item = ItemNext(item)) {
X	  if (TestOptionFlag(menu, savebits))
X	  {
X	       /* go ahead and draw it, don't wait for exposes */
X	       Draw_Item(menu, item);
X	  }
X     }
X     Leave_void
X}
X
X/*
X * Draw the item  at vertical position y.
X */
Xvoid Draw_Item(menu, item)
XMenu *menu;
XMenuItem *item;
X{
X     int y;  /* baseline */
X     int x = MenuItemPad(menu);
X     int x1 = 2 * MenuItemPad(menu) + checkMarkWidth;
X     int pad;
X     int high;
X     XGCValues gcValues;
X     GC theGC;
X
X     Entry("Draw_Item")
X
X     high = (MenuItemHighlighted(menu) == item);
X     theGC = high ? MenuInvertGC(menu) : MenuNormalGC(menu);
X
X     if (TestItemFlag(item, itemDisabled))
X     {
X	  gcValues.fill_style = FillOpaqueStippled;
X	  XChangeGC(dpy, theGC, (GCFillStyle), &gcValues);
X     }
X     
X     if (!item->itemBackground) {
X	  XFillRectangle(dpy, ItemWindow(item),
X			 (high) ? MenuNormalGC(menu) : MenuInvertGC(menu),
X			 0, 0, MenuWidth(menu), item->itemHeight);
X	  
X	  /*
X	   * Draw the check mark, possibly dimmed, wherever is necessary.
X	   */
X     }
X     if(TestItemFlag(item, itemChecked)){
X	  XCopyArea (dpy, MenuCheckmarkPixmap(menu),
X		     ItemWindow(item),
X		     theGC,
X		     0, 0, checkMarkWidth, checkMarkHeight,
X		     (int) x, (item->itemHeight - checkMarkHeight) / 2);
X     }
X     /* Draw submenu indicator arrow */
X     if(ItemSubmenu(item)) {
X	  XCopyArea (dpy, MenuArrowPixmap(menu),
X		     ItemWindow(item),
X		     theGC,
X		     0, 0,
X		     arrow_width, arrow_height,
X		     (int) (x + MenuItemWidth(menu) -
X			    arrow_width - MenuItemPad(menu)),
X		     (item->itemHeight - arrow_height) / 2 - 1);
X     }
X     /*
X      * Draw the text, centered vertically.
X      */
X     if (!item->itemBackground) {
X	  if (!TestItemFlag(item, itemDeaf)) {
X	       pad = (item->itemHeight - 
X		      (MFontInfo->ascent + MFontInfo->descent)) / 2;
X	       y = item->itemHeight - pad - MFontInfo->descent;
X	       
X	       XDrawImageString(dpy, ItemWindow(item),
X				theGC,
X				x1, y, ItemText(item), ItemTextLength(item));
X	       if (TestItemFlag(item, itemDisabled))
X	       { 
X		    gcValues.fill_style = FillSolid;
X		    XChangeGC(dpy, theGC,
X			      (GCFillStyle), &gcValues);
X	       }
X	       
X	  }
X	  else {
X	       pad = (item->itemHeight - (MBoldFontInfo->ascent +
X					  MBoldFontInfo->descent)) / 2;
X	       y = item->itemHeight - pad - MBoldFontInfo->descent;
X	       XDrawImageString(dpy, ItemWindow(item), menu->boldGC, x1, y,
X				ItemText(item), ItemTextLength(item));
X	  }
X     }
X     Leave_void
X}
X
X
X/*
X * UnmapMenu() unmaps a menu, if it is currently mapped.
X */
Xstatic void UnmapMenu(menu)
XMenu *menu;
X{
X     Entry("UnmapMenu")
X
X     if(!menu || !(TestMenuFlag(menu, menuMapped)))
X	  Leave_void
X     XUnmapWindow(dpy, MenuWindow(menu));
X     
X     if (TestOptionFlag(menu, savebits))
X     {
X	  if (MenuSavedPixmap(menu))
X	       XCopyArea (dpy,
X			  MenuSavedPixmap(menu),
X			  RootWindow (dpy, scr),
X			  MenuNormalGC(menu),
X			  0, 0, 
X			  MenuWidth(menu) + 2*MenuBorderWidth(menu),
X			  MenuHeight(menu) + 2*MenuBorderWidth(menu),
X			  MenuX(menu), MenuY(menu));
X	  
X     }
X     ResetMenuFlag(menu, menuMapped);
X     Leave_void
X}
X
X
Xstatic Boolean SetupMenuWindow (menu)
XMenu *menu;
X{
X     int changed = TestMenuFlag(menu, (menuChanged | menuItemChanged));
X 
X     Entry("SetupMenuWindow")
X
X     if (contexts_created == FALSE) {
X	  contexts_created = TRUE;
X	  Menu_context = XUniqueContext(); 
X	  Item_context = XUniqueContext();
X     }
X     
X     /*
X      * If the entire menu has changed, throw away any saved pixmap and
X      * then call RecalcMenu().
X      */
X     
X     if(changed & menuChanged) {
X	  if(!Recalc_Menu(menu))
X	       Leave(FALSE)
X	  changed &= ~menuItemChanged;
X     }
X     
X     if(!MenuWindow(menu)) {
X	  static unsigned long valuemask =
X	       CWOverrideRedirect | CWBorderPixel | CWBackPixel;
X	  XSetWindowAttributes attributes;
X	  
X	  attributes.override_redirect = True;
X	  attributes.border_pixel = MBorder;
X	  attributes.background_pixel = MBackground;
X	  if (SaveUnder) {
X	       attributes.save_under = True;
X	       valuemask |= CWSaveUnder;
X	  }
X
X	  if((MenuWindow(menu) =
X	      XCreateWindow(dpy, 
X			    RootWindow(dpy, scr),
X			    0, 0,
X			    MenuWidth(menu), MenuHeight(menu),
X			    MenuBorderWidth(menu),
X			    DefaultDepth(dpy, scr),
X			    InputOutput, 
X			    DefaultVisual(dpy, scr),
X			    valuemask, &attributes)
X	      ) == (Window)0)
X	       Leave(FALSE)
X	  else if (SetupItems(menu) == FALSE)
X	       Leave(FALSE)
X
X	  XSaveContext(dpy, MenuWindow(menu), Menu_context, (char *) menu);
X	  XMapSubwindows(dpy, MenuWindow(menu));
X	  
X	  XDefineCursor(dpy, MenuWindow(menu), MenuCursor(menu));
X     }
X     else if(changed & menuChanged) {
X	  XResizeWindow(dpy, MenuWindow(menu),
X			MenuWidth(menu), MenuHeight(menu));
X	  if (SetupItems(menu) == FALSE)
X	       Leave(FALSE)
X	  XMapSubwindows(dpy, MenuWindow(menu));
X     }
X     Leave(TRUE)
X}
X
Xstatic Boolean SetupItems(menu)
XMenu *menu;
X{
X     int y;
X     MenuItem *item;
X     int changed = TestMenuFlag(menu, (menuChanged | menuItemChanged));
X
X     Entry("SetupItems")
X     
X     for (item = MenuItems(menu), y = 0; item;
X	  y += item->itemHeight, item = ItemNext(item)) {
X	  if (!ItemWindow(item)) {
X	       static unsigned long valuemask =
X		    (CWOverrideRedirect | CWBorderPixel | CWBackPixel);
X	       XSetWindowAttributes attributes;
X
X	       attributes.override_redirect = True;
X	       attributes.border_pixel = MBorder;
X	       attributes.background_pixel = MBackground;
X
X	       if((ItemWindow(item) =
X		   XCreateWindow(dpy, 
X				 MenuWindow(menu),
X				 0, y, 
X				 MenuItemWidth(menu), 
X				 item->itemHeight - (2 * MItemBorder), 
X				 MItemBorder,
X				 DefaultDepth(dpy, scr),
X				 InputOutput, 
X				 DefaultVisual(dpy, scr),
X				 valuemask, &attributes)
X		   ) == (Window) 0)
X		    Leave(FALSE)
X	       if (item->itemBackground) {
X		    XSetWindowBackgroundPixmap(dpy, ItemWindow(item),
X					       item->itemBackground);
X		    XFreePixmap(dpy, item->itemBackground);
X	       }
X	       ItemMenu(item) = menu;
X	       XSaveContext(dpy, ItemWindow(item), Item_context,
X			    (char *) item);
X	       XDefineCursor(dpy, ItemWindow(item),
X			     MenuCursor(menu));
X	  }
X	  
X	  else if (changed & menuChanged) {
X	       XResizeWindow(dpy, ItemWindow(item),
X			     MenuItemWidth(menu), 
X			     item->itemHeight - (2 * MItemBorder));
X	       XMoveWindow(dpy, ItemWindow(item), 0, y);
X	  }
X     }
X     Leave(TRUE)
X}
X
Xstatic void SetInputMask(menu, mask)
XMenu *menu;
Xunsigned int mask;
X{
X     MenuItem *item;
X 
X     Entry("SetInputMask")
X
X     XSelectInput(dpy, MenuWindow(menu),
X		  (mask | MenuEventMask));
X     for(item = MenuItems(menu) ; item ; item = ItemNext(item))
X     {
X	  if (TestItemFlag(item, itemDisabled) || TestItemFlag(item, itemDeaf))
X	       XSelectInput(dpy, ItemWindow(item),
X			    (mask | MenuIgnoreMask));
X	  else if (ItemIsLeaf(item))
X	       XSelectInput(dpy, ItemWindow(item),
X			    (mask | NormalItemEventMask));
X	  else
X	       XSelectInput(dpy, ItemWindow(item),
X			    (mask | SubmenuItemEventMask));
X     }
X     Leave_void
X}
X
XMenuItem *MenuItemByData(menu, data)
XMenu* menu;
Xpointer data;
X{
X     MenuItem *item;
X     
X     Entry("MenuItemByData")
X
X     for (item = MenuItems(menu);
X	  !ItemIsNull(item) && (ItemData(item) != data);
X	  item = ItemNext(item));
X     
X     Leave(item)
X}   
X
XMenuItem *MenuItemByName (menu, name)
XMenu *menu;
Xchar *name;
X{
X     MenuItem *item;
X
X     Entry("MenuItemByName")
X
X     for (item = MenuItems(menu); item; item = ItemNext(item))
X	  if (strcmp (name, ItemText(item)) == 0)
X	       Leave(item)
X     Leave(NULLITEM)
X}
X
XMenuItem *MenuGetItem(menu, window) 
XMenu *menu;
XWindow window;
X{    
X     MenuItem *foo = 0;
X     Window tmpwindow = window;
X
X     Entry("MenuGetItem")
X
X     if (!menu || !window)
X	  Leave(NULLITEM)
X     if (window == menu->menuWindow)
X	  if (menu->highlightedItem)
X	       tmpwindow = menu->highlightedItem->itemWindow;
X     XFindContext(dpy, tmpwindow, Item_context, &foo);
X     Leave(foo)
X}
X
XMenu *MenuGetMenu(menu, window)
XMenu *menu;
XWindow window;
X{
X     Menu *bar = 0;
X 
X     Entry("MenuGetMenu")
X
X     XFindContext(dpy, window, Menu_context, &bar);
X     Leave(bar)
X}
X
Xint ItemGetMiddleY(item)
XMenuItem *item;
X{
X     Window child;
X     XWindowAttributes attributes;
X     int x, y;
X 
X     Entry("ItemGetMiddleY")
X
X     XGetWindowAttributes(dpy, ItemWindow(item), &attributes);
X     XTranslateCoordinates(dpy,
X			   MenuWindow(ItemMenu(item)), 
X			   RootWindow(dpy, scr),
X			   attributes.x, attributes.y, 
X			   &x, &y, &child);
X     Leave((item->itemHeight / 2) + y)
X}
X
Xvoid SetInitialItem(menu, item)
XMenu *menu;
XMenuItem *item;
X{
X     extern char *realloc();
X     
X     Entry("SetInitialItem")
X
X     if (MenuHasInitialItem(menu)) {
X	  if (strlen(MenuInitialItemText(menu)) < strlen(ItemText(item)))
X	       MenuInitialItemText(menu) =
X		    realloc(MenuInitialItemText(menu), 
X			    strlen(ItemText(item)) + 1);
X     }
X     else
X	  MenuInitialItemText(menu) =
X	       allocate(char,(strlen(ItemText(item)) + 1));
X     strcpy(MenuInitialItemText(menu), ItemText(item));
X     Leave_void
X}
X
Xvoid ClearInitialItem(menu)
XMenu *menu;
X{
X     Entry("ClearInitialItem")
X
X     if (MenuHasInitialItem(menu)) {
X	  free(MenuInitialItemText(menu));
X	  MenuInitialItemText(menu) = (char *) NULL;
X     }
X     Leave_void
X}
X
XMenuItem *GetInitialItem(menu)
XMenu *menu;
X{
X     MenuItem *item;
X     
X     Entry("GetInitialItem")
X
X     if (MenuHasInitialItem(menu)) {
X	  for(item = MenuItems(menu) ; item ; item = ItemNext(item)) {
X	       if (ItemIsInitialItem(menu, item))
X		    Leave(item)
X	  }
X     }
X     Leave((MenuItem *) NULL)
X}
X
X
X/* Some utility functions */
X
Xvoid Retch(s, p1, p2, p3, p4)
Xchar *s;
Xlong p1, p2, p3, p4;
X{
X     char buffer[1024];
X     
X     sprintf(buffer, s, p1, p2, p3, p4);
X     fprintf(stderr, "Error in %s %s\n", curr_rtn(), buffer);
X     return;
X}
END_OF_FILE
if test 33843 -ne `wc -c <'menus/menu.c'`; then
    echo shar: \"'menus/menu.c'\" unpacked with wrong size!
fi
# end of 'menus/menu.c'
fi
if test -f 'menus/menu.ext.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'menus/menu.ext.h'\"
else
echo shar: Extracting \"'menus/menu.ext.h'\" \(1789 characters\)
sed "s/^X//" >'menus/menu.ext.h' <<'END_OF_FILE'
X
X/*
X#ifndef lint
Xstatic char sccs_id[] = "@(#)menu.extern.h	2.1 12/16/87  Siemens Corporate Research and Support, Inc.";
X#endif
X*/
X
X
X/* 
X  RTL Menu Package Version 1.0
X  by Joe Camaratta and Mike Berman, Siemens RTL, Princeton NJ, 1987
X
X  menu.extern.h: external function declarations for menu package
X*/
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
Xextern MenuItem *AddMenuItem();
Xextern Boolean     DisposeItem();
Xextern void     DisposeMenu();
Xextern void     InitMenu();
Xextern Boolean     SetItemText();
Xextern Menu     *NewMenu();
Xextern Boolean     SetItemCheck();
Xextern Boolean     SetItemDisable();
Xextern MenuItem *Display_Menu();
Xextern void     Undisplay_Menu();
Xextern void     MenuInvert();
Xextern void     PlacePointer();
Xextern void     Draw_Menu();
Xextern void     Draw_Item();
X
Xextern MenuItem *MenuGetItem();
Xextern MenuItem *MenuItemByName();
Xextern MenuItem *MenuItemByData();
Xextern Menu     *MenuGetMenu();
Xextern int      ItemGetMiddleY();
Xextern void     SetInitialItem();
Xextern void     ClearInitialItem();
Xextern MenuItem *GetInitialItem();
X
Xextern MenuItem *TrackMenu();
X
X
X
X
X
X
X
X
X
X
END_OF_FILE
if test 1789 -ne `wc -c <'menus/menu.ext.h'`; then
    echo shar: \"'menus/menu.ext.h'\" unpacked with wrong size!
fi
# end of 'menus/menu.ext.h'
fi
echo shar: End of archive 3 \(of 12\).
cp /dev/null ark3isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 12 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
Moderator of comp.sources.x