[comp.windows.x] Second posting of awm, Part16

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

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 16 (of 17)."
# Contents:  awm/awm.c
# Wrapped by jkh@ardent on Thu Jun 16 00:44:27 1988
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'awm/awm.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'awm/awm.c'\"
else
echo shar: Extracting \"'awm/awm.c'\" \(36694 characters\)
sed "s/^X//" >'awm/awm.c' <<'END_OF_FILE'
X#ident   "%W% %G%"
X
X#ifndef lint
static char *rcsid_awm_c = "$Header: awm.c,v 1.1 88/06/15 15:24:56 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 * MODIFICATION HISTORY
X *
X * 000 -- M. Gancarz, DEC Ultrix Engineering Group
X * 001 -- Loretta Guarino Reid, DEC Ultrix Engineering Group,
X *  Western Software Lab. Convert to X11.
X * 002 -- Jordan Hubbard, U.C. Berkeley. Add title bar context stuff.
X * 003 -- Jordan Hubbard, Ardent Computer. Added gadgets, border contexts.
X */
X
X#include <sys/time.h>
X#include <signal.h>
X#include <fcntl.h>
X#include <sys/ioctl.h>
X#include "awm.h"
X#include "X11/Xutil.h"
X#include "X11/cursorfont.h"
X
X#ifdef PROFIL
X#include <signal.h>
X/*
X * Dummy handler for profiling.
X */
ptrap()
X{
X     exit(0);
X}
X#endif
X
Boolean NeedRootInput=FALSE;
MenuOptionsMask options;
char *sfilename;
char execfile[NAME_LEN]; /* Pointer to file to exec with -e */
Boolean Snatched;
extern FILE *yyin;
extern int errorStatus;
extern int ErrorHandler();
extern XContext AwmContext;
X
X/*
X * Main program.
X */
main(argc, argv, environ)
int argc;
char **argv;
char **environ;
X{
X     int hi;			/* Button event high detail. */
X     int lo;			/* Button event low detail. */
X     int x, y;                  /* Mouse X and Y coordinates. */
X     int root_x, root_y;        /* Mouse root X and Y coordinates. */
X     int cur_x, cur_y;		/* Current mouse X and Y coordinates. */
X     int down_x, down_y;	/* mouse X and Y at ButtonPress. */
X     int str_width;             /* Width in pixels of output string. */
X     int pop_width, pop_height; /* Pop up window width and height. */
X     int context;		/* Root, window, or icon context. */
X     int ptrmask;		/* for QueryPointer */
X     Boolean func_stat;		/* If true, function swallowed a ButtonUp. */
X     Boolean delta_done;	/* If true, then delta functions are done. */
X     Boolean local;		/* If true, then do not use system defaults. */
X     Boolean nolocal;		/* If true, ignore user defaults */
X     register Binding *bptr;	/* Pointer to Bindings list. */
X     char *root_name;		/* Root window name. */
X     char *cp;			/* scratch */
X     char *display = NULL;	/* Display name pointer. */
X     char message[128];		/* Error message buffer. */
X     char *rc_file;		/* Pointer to $HOME/.awmrc. */
X     Window event_win;          /* Event window. */
X     Window sub_win;		/* Subwindow for XUpdateMouse calls. */
X     Window root;		/* Root window for QueryPointer. */
X     XWindowAttributes event_info;/* Event window info. */
X     AwmInfoPtr awi;
X     XEvent button_event; 	/* Button input event. */
X     GC gc;			/* graphics context for gray background */
X     XImage grayimage;		/* for gray background */
X     XGCValues xgc;		/* to create font GCs */
X     char *malloc();
X     XSetWindowAttributes swa;
X     unsigned long valuemask;
X     Window bwin;		/* Button window */
X     int num;
X     
X     /* next three variables are for XQueryWindow */
X     Window junk;
X     Window *kiddies;
X     unsigned int nkids;
X     
X     Entry("main")
X	  
X#ifdef PROFIL
X	  signal(SIGTERM, ptrap);
X#endif
X     
X     /* 
X      * Parse the command line arguments.
X      */
X     Argv = argv;
X     Environ = environ;
X     execfile[0] = '\0';
X     local = nolocal = FALSE;
X     argc--, argv++;
X     /*
X      * The destruction of '-e' args below is to prevent the startup
X      * command from being invoked again if we do an f.restart (see
X      * Restart.c and Argv)
X      */
X     while (argc) {
X	  if (**argv == '-') {
X	       if (!strcmp(*argv, "-display") || !strcmp(*argv, "-d")) {
X		    argc--; argv++;
X		    if (argc <= 0)
X			 Usage();
X		    display = *argv;
X	       }
X	       else if (!(strcmp(*argv, "-f"))) {
X		    argc--, argv++;
X		    if ((argc == 0) || (Startup_File[0] != '\0'))
X			 Usage();
X		    strncpy(Startup_File, *argv, NAME_LEN);
X	       }
X	       else if (!(strcmp(*argv, "-e"))) {
X		    strcpy(*argv, "--");	/* destroy the arg */
X		    argc--; argv++;
X		    if ((argc == 0) || (execfile[0] != '\0'))
X			 Usage();
X		    strncpy(execfile, *argv, NAME_LEN);
X	       }
X	       /* Destroyed arg, skip over what used to be filename for -e */
X	       else if (!(strcmp(*argv, "--"))) {
X		    argv++; argc--;
X		    continue;
X	       }
X	       else if (!(strcmp(*argv, "-b")))
X		    local = TRUE;
X	       else if (!(strcmp(*argv, "-i")))
X		    nolocal = TRUE;
X	       
X	       else Usage();
X	  }
X	  else
X	       Usage();
X	  argc--, argv++;
X     }
X     
X     /* Open the damn display */
X     if ((dpy = XOpenDisplay(display)) == NULL) {
X	  fprintf(stderr, "awm: Unable to open display\n");
X	  exit(1);
X     }
X     scr = DefaultScreen(dpy); 
X     
X     /*
X      * Set XErrorFunction to be non-terminating.
X      */
X     XSetErrorHandler(ErrorHandler);
X     
X     /*
X      * Force child processes to disinherit the TCP file descriptor.
X      * This helps shell commands forked and exec'ed from menus
X      * to work properly. God knows if this works under SysV.
X      */
X     if ((status = fcntl(ConnectionNumber(dpy), F_SETFD, 1)) == -1) {
X	  perror("awm: child cannot disinherit TCP fd");
X	  Error("TCP file descriptor problems");
X     }
X     
X     /*
X      * Initialize the menus for later use.
X      */
X     RTLMenu_Option_Set(options, rightoffset);
X     RTLMenu_Initialize(options);
X     
X     /* Init the context manager stuff */
X     AwmContext = XUniqueContext();
X     
X     /*
X      * Get all the defaults we expect from the resource manager.
X      */
X     FocusSetByUser = FALSE;
X     Get_Defaults();
X     /*
X      * Initialize the default bindings.
X      */
X     if (!local)
X	  InitBindings();
X     
X     /*
X      * Read in and parse $HOME/.awmrc, if it exists.
X      */
X     if (!nolocal) {
X	  sfilename = rc_file = malloc(NAME_LEN);
X	  sprintf(rc_file, "%s/.awmrc", getenv("HOME"));
X	  if ((yyin = fopen(rc_file, "r")) != NULL) {
X	       Lineno = 1;
X	       yyparse();
X	       fclose(yyin);
X	       if (Startup_File_Error)
X		    Error("Bad .awmrc file...aborting");
X	  }
X     }
X     /* 
X      * Read in and parse the startup file from the command line, if
X      * specified.
X      */
X     if (Startup_File[0] != '\0') {
X	  sfilename = Startup_File;
X	  if ((yyin = fopen(Startup_File, "r")) == NULL) {
X	       sprintf(message, "Cannot open startup file '%s'", Startup_File);
X	       Error(message);
X	  }
X	  Lineno = 1;
X	  yyparse();
X	  fclose(yyin);
X	  if (Startup_File_Error)
X	       Error("Bad startup file...aborting");
X     }
X     
X     if (Startup_File_Error)
X	  Error("Bad startup file...aborting");
X     /*
X      * Catch some of the basic signals so we don't get rudely killed without
X      * cleaning up first.
X      */
X     signal(SIGHUP, Quit);
X     signal(SIGTERM, Quit);
X     signal(SIGQUIT, Quit);
X     signal(SIGINT, Quit);
X     
X     /*
X      * If the root window has not been named, name it.
X      */
X     status = XFetchName(dpy, RootWindow(dpy, scr), &root_name);
X     if (root_name == NULL) 
X	  XStoreName(dpy, RootWindow(dpy, scr), " X Root Window ");
X     else free(root_name);
X     /* register the root window */
X     RegisterWindow(RootWindow(dpy, scr));
X     
X     ScreenHeight = DisplayHeight(dpy, scr);
X     ScreenWidth = DisplayWidth(dpy, scr);
X     
X     /*
X      * Create the menus. This function also sticks the RTL menu "handle"
X      * into the appropriate binding after it's been created and initialized.
X      */
X     Create_Menus();
X     
X     /*
X      * check the gadgets.
X      */
X     if (CheckGadgets()) {
X	  fprintf(stderr, "Error in gadget declarations. Exiting...\n");
X	  Cleanup();
X	  exit(1);
X     }
X     
X     /*
X      * Store all the cursors.
X      */
X     StoreCursors();
X     
X     /* 
X      * grab the mouse buttons according to the map structure
X      */
X     Grab_Buttons();
X     
X     /*
X      * Initialize titlebar data.
X      */
X     if (Titles)
X	  Init_Titles();
X     /*
X      * Set initial focus to PointerRoot.
X      */
X     XSetInputFocus(dpy, PointerRoot, None, CurrentTime);
X     /* 
X      * watch for initial window mapping and window destruction
X      */
X     
X     errorStatus = False;
X     swa.event_mask = (SubstructureRedirectMask | FocusChangeMask |
X		       (NeedRootInput ? EVENTMASK | OwnerGrabButtonMask : 0));
X     XChangeWindowAttributes(dpy, RootWindow(dpy, scr), CWEventMask, &swa);
X     XSync(dpy, False);
X     if (errorStatus == True) {
X	  fprintf(stderr,
X		  "Hmmm.. Looks like you're running another window manager!\n");
X	  exit(1);
X     }
X     /*
X      * Before we go creating more windows, we buzz through the ones that
X      * are currently mapped and reparent and/or select on them as necessary
X      * (for autoraise and titles).
X      */
X     
X     if (XQueryTree(dpy, DefaultRootWindow(dpy), &junk, &junk, &kiddies,
X		    &nkids) != BadWindow) {
X	  unsigned int i;
X
X	  for (i = 0; i < nkids; i++) {
X	       XWindowAttributes xwa;
X	       Window transient;
X	       AwmInfoPtr awi;
X	       unsigned long event_mask;
X	       
X	       XGetWindowAttributes(dpy, kiddies[i], &xwa);
X	       
X	       /* check to see if it's a popup or something */
X	       XGetTransientForHint(dpy, kiddies[i], &transient);
X	       if (xwa.class == InputOutput && xwa.map_state == IsViewable &&
X		   xwa.override_redirect == False && transient == None) {
X		    awi = RegisterWindow(kiddies[i]);
X		    awi->placed = TRUE;
X		    if (Titles) { /* add title to this window */
X			 AddTitle(kiddies[i]);
X			 if (UseGadgets)
X			      PutGadgets(kiddies[i]);
X		    }
X		    event_mask = PropertyChangeMask;
X		    if (!awi->frame || !FrameFocus)
X			 event_mask |= (EnterWindowMask | LeaveWindowMask);
X		    SetBorderPixmaps(dpy, kiddies[i], GrayPixmap);
X		    XSelectInput(dpy, kiddies[i], event_mask);
X	       }
X	  }
X	  XFree(kiddies);
X     }
X     /*
X      * Calculate size of the resize pop-up window.
X      */
X     valuemask = CWBorderPixel | CWBackPixel;
X     swa.border_pixel = PBorder;
X     swa.background_pixel = PBackground;
X     if (SaveUnder) {
X	  swa.save_under = True;
X	  valuemask |= CWSaveUnder;
X     }
X     str_width = XTextWidth(PFontInfo, PText, strlen(PText));
X     pop_width = str_width + (PPadding << 1);
X     PWidth = pop_width + (PBorderWidth << 1);
X     pop_height = PFontInfo->ascent + PFontInfo->descent + (PPadding << 1);
X     PHeight = pop_height + (PBorderWidth << 1);
X     
X     /*
X      * Create the pop-up window.  Create it at (0, 0) for now.  We will
X      * move it where we want later.
X      */
X     Pop = XCreateWindow(dpy, RootWindow(dpy, scr),
X			 0, 0,
X			 pop_width, pop_height,
X			 PBorderWidth,
X			 0,
X			 CopyFromParent,
X			 CopyFromParent,
X			 valuemask,
X			 &swa);
X     if (Pop == FAILURE)
X	  Error("Can't create pop-up dimension display window.");
X     
X     /*
X      * Create graphics context.
X      */
X     xgc.foreground = ITextForeground;
X     xgc.background = ITextBackground;
X     xgc.font = IFontInfo->fid;
X     xgc.graphics_exposures = FALSE;
X     IconGC = XCreateGC(dpy, 
X			RootWindow(dpy, scr),
X			(GCForeground|GCBackground|GCGraphicsExposures|GCFont),
X			&xgc);
X     
X     xgc.foreground = PForeground;
X     xgc.background = PBackground;
X     xgc.font = PFontInfo->fid;
X     PopGC = XCreateGC(dpy, 
X		       RootWindow(dpy, scr),
X		       (GCForeground|GCBackground|GCFont), &xgc);
X     xgc.line_width = DRAW_WIDTH;
X     xgc.foreground = DRAW_VALUE;
X     xgc.function = DRAW_FUNC;
X     xgc.subwindow_mode = IncludeInferiors;
X     DrawGC = XCreateGC(dpy, RootWindow(dpy, scr), 
X			GCLineWidth|GCForeground|GCFunction|GCSubwindowMode,
X			&xgc);
X     /*
X      * As our last "startup" task, invoke the execfile if was specified.
X      */
X     if (execfile[0] != '\0') {
X	  if (access(execfile, X_OK) == 0) {
X	       if (fork() == 0) {
X		    setpgrp(0, 0);
X		    execl("/bin/sh", "sh", execfile, 0);
X		    _exit(127);
X	       }
X	  }
X     }
X     /*
X      * Tell the user we're alive and well.
X      */
X     XBell(dpy, VOLUME_PERCENTAGE(Volume));
X     
X     /* 
X      * Main command loop.
X      */
X     while (TRUE) {
X	  
X	  delta_done = func_stat = FALSE;
X	  
X	  /*
X	   * Get the next mouse button event.  Spin our wheels until
X	   * a ButtonPressed event is returned.
X	   * Note that mouse events within an icon window are handled
X	   * in the "GetButton" function or by the icon's owner if
X	   * it is not awm.
X	   */
X	  while (TRUE) {
X	       if (!GetButton(&button_event))
X		    continue;
X	       else if (button_event.type == ButtonPress)
X		    break;
X	  }
X	  bwin = button_event.xbutton.window;
X	  /* save mouse coords in case we want them later for a delta action */
X	  down_x = button_event.xbutton.x;
X	  down_y = button_event.xbutton.y;
X	  
X	  /*
X	   * Okay, determine the event window and mouse coordinates.
X	   */
X	  status = XTranslateCoordinates(dpy, 
X					 bwin,
X					 RootWindow(dpy, scr),
X					 button_event.xbutton.x, 
X					 button_event.xbutton.y,
X					 &x, &y,
X					 &event_win);
X	  if (status == BadWindow)
X	       continue;
X	  
X	  awi = GetAwmInfo(bwin);
X          if (awi->frame == bwin)
X               context = BORDER;
X	  else if (awi->title == bwin)
X	       context = TITLE;
X	  else if (IsGadgetWin(bwin, &num))
X	       context = GADGET | (1 << (num + BITS_USED));
X	  else if (awi->icon == bwin)
X	       context = ICON;
X	  else if (awi->client == RootWindow(dpy, scr)) {
X	       event_win = RootWindow(dpy, scr);
X	       context = ROOT;
X	  }
X	  else
X	       context = WINDOW;
X	  /*
X	   * Get the button event detail.
X	   */
X	  lo = button_event.xbutton.button;
X	  hi = button_event.xbutton.state;
X	  
X	  /*
X	   * Determine which function was selected and invoke it.
X	   */
X	  for(bptr = Blist; bptr; bptr = bptr->next) {
X	       if ((bptr->button != lo) ||
X		   (((int)bptr->mask & ModMask) != hi))
X		    continue;
X	       
X	       if ((bptr->context & context) != context)
X		    continue;
X	       
X	       if (!(bptr->mask & ButtonDown))
X		    continue;
X	       
X	       /*
X		* Found a match! Invoke the function.
X		*/
X	       if ((*bptr->func)(event_win, (int)bptr->mask & ModMask,
X				 bptr->button,
X				 x, y,
X				 bptr->menu, bptr->menuname))
X		    func_stat = TRUE;
X	       break;
X	  }
X	  
X	  /*
X	   * If the function ate the ButtonUp event, then restart the loop.
X	   */
X	  
X	  if (func_stat)
X	       continue;
X	  while (TRUE) {
X	       /*
X		* Wait for the next button event.
X		*/
X	       if (XPending(dpy) && GetButton(&button_event)) {
X		    bwin = button_event.xbutton.window;
X		    
X		    /*
X		     * If it's not a release of button that was pressed,
X		     * don't do the function bound to 'ButtonUp'.
X		     */
X		    if (button_event.type != ButtonRelease)
X			 break;
X		    if (lo != button_event.xbutton.button)
X			 break;
X		    if ((hi | ButtonMask(lo)) != button_event.xbutton.state)
X			 break;
X		    /*
X		     * Okay, determine the event window and mouse coordinates.
X		     */
X		    status = XTranslateCoordinates(dpy, 
X						   bwin,
X						   RootWindow(dpy, scr),
X						   button_event.xbutton.x,
X						   button_event.xbutton.y,
X						   &x, &y,
X						   &event_win);
X		    if (status == BadWindow)
X			 break;
X		    
X		    awi = GetAwmInfo(bwin);
X		    if (awi->frame == bwin)
X			 context = BORDER;
X		    else if (awi->title == bwin)
X			 context = TITLE;
X		    else if (IsGadgetWin(bwin, &num))
X			 context = GADGET | (1 << (num + BITS_USED));
X		    else if (bwin == awi->icon)
X			 context = ICON;
X		    else if (!event_win || awi->client == RootWindow(dpy, scr)) {
X			 event_win = RootWindow(dpy, scr);
X			 context = ROOT;
X		    }
X		    else
X			 context = WINDOW;
X		    /*
X		     * Determine which function was selected and invoke it.
X		     */
X		    for(bptr = Blist; bptr; bptr = bptr->next) {
X			 
X			 if ((bptr->button != lo) ||
X			     (((int)bptr->mask & ModMask) != hi))
X			      continue;
X			 
X			 if (!((bptr->context & context) == context))
X			      continue;
X			 
X			 if (!(bptr->mask & ButtonUp))
X			      continue;
X			 
X			 /*
X			  * Found a match! Invoke the function.
X			  */
X			 
X			 (*bptr->func)(event_win,
X				       (int)bptr->mask & ModMask,
X				       bptr->button,
X				       x, y,
X				       bptr->menu, bptr->menuname);
X			 break;
X		    }
X		    break;
X	       }
X	       XQueryPointer(dpy, RootWindow(dpy, scr),
X			     &root, &junk, &root_x, &root_y, &cur_x, &cur_y,
X			     &ptrmask);
X	       if (!delta_done &&
X		   (abs(cur_x - x) > Delta || abs(cur_y - y) > Delta)) {
X		    /*
X		     * Delta functions are done once (and only once.)
X		     */
X		    delta_done = TRUE;
X		    
X		    /*
X		     * Determine the new event window's coordinates from the
X		     * original ButtonPress event.
X		     */
X		    status = XTranslateCoordinates(dpy, bwin,
X						   RootWindow(dpy, scr),
X						   down_x, down_y, &x, &y,
X						   &junk);
X		    if (status == BadWindow)
X			 break;
X		    /*
X		     * Determine the event window and context.
X		     */
X		    if (awi->title == bwin)
X			 context = TITLE;
X		    else if (IsGadgetWin(bwin, &num))
X			 context = GADGET | (1 << (num + BITS_USED));
X		    else if (event_win == RootWindow(dpy, scr))
X			 context = ROOT;
X		    else if (awi->icon == bwin)
X			 context = ICON;
X		    else
X			 context = WINDOW;
X		    /*
X		     * Determine which function was selected and invoke it.
X		     */
X		    for(bptr = Blist; bptr; bptr = bptr->next) {
X			 
X			 if ((bptr->button != lo) ||
X			     (((int)bptr->mask & ModMask) != hi))
X			      continue;
X			 
X			 if (!((bptr->context & context) == context))
X			      continue;
X			 
X			 if (!(bptr->mask & DeltaMotion))
X			      continue;
X			 
X			 /*
X			  * Found a match! Invoke the function.
X			  */
X			 
X			 if ((*bptr->func)(event_win,
X					   (int)bptr->mask & ModMask,
X					   bptr->button,
X					   x, y,
X					   bptr->menu, bptr->menuname)) {
X			      func_stat = TRUE;
X			      break;
X			 }
X		    }
X		    /*
X		     * If the function ate the ButtonUp event,
X		     * then restart the loop.
X		     */
X		    
X		    if (func_stat)
X			 break;
X	       }
X	  }
X     }
X}
X
X/*
X * Get defaults from the resource manager. Most of these things used to be
X * in the rc file, but they really belong here, I think.
X */
Get_Defaults()
X{
X     register char *cp;
X     
X     /*
X      * Get the pixmap search path, if it exists.
X      */
X     awmPath = GetStringRes("path", NULL);
X     
X     Autoselect = GetBoolRes("autoselect", FALSE);
X     Autoraise = GetBoolRes("autoraise", FALSE);
X     ConstrainResize = GetBoolRes("constainResize", FALSE);
X     FrameFocus = GetBoolRes("frameFocus", FALSE);
X     Freeze = GetBoolRes("freeze", FALSE);
X     Grid = GetBoolRes("grid", FALSE);
X     Titles = GetBoolRes("titles", FALSE);
X     TitlePush = GetBoolRes("title.push", TRUE);
X     UseGadgets = GetBoolRes("gadgets", FALSE);
X     Hilite = GetBoolRes("hilite", FALSE);
X     BorderHilite = GetBoolRes("border.hilite", Hilite);
X     RootResizeBox = GetBoolRes("rootResizeBox", FALSE);
X     ResizeRelative = GetBoolRes("resizeRelative", FALSE);
X     NIcon = GetBoolRes("normali", TRUE);
X     ShowName = GetBoolRes("showName", TRUE);
X     NWindow = GetBoolRes("normalw", TRUE);
X     Push = GetBoolRes("pushRelative", FALSE);
X     Reverse = GetBoolRes("reverse", FALSE);
X     SaveUnder = GetBoolRes("saveUnder", FALSE);
X     Wall = GetBoolRes("wall", FALSE);
X     WarpOnRaise = GetBoolRes("warpOnRaise", FALSE);
X     WarpOnIconify = GetBoolRes("warpOnIconify", FALSE);
X     WarpOnDeIconify = GetBoolRes("warpOnDeIconify", FALSE);
X     Zap = GetBoolRes("zap", FALSE);
X     
X     GadgetPad = GetIntRes("gadget.pad", DEF_GADGET_PAD);
X     GadgetBorder = GetIntRes("gadget.border", DEF_GADGET_BORDER);
X     HIconPad = GetIntRes("icon.vPad", DEF_ICON_PAD);
X     VIconPad = GetIntRes("icon.hPad", DEF_ICON_PAD);
X     RaiseDelay = GetIntRes("raiseDelay", DEF_RAISE_DELAY);
X     MaxColors = GetIntRes("maxColors", DEF_MAX_COLORS);
X     PBorderWidth = GetIntRes("popup.borderWidth", DEF_POP_BORDER_WIDTH);
X     IBorderWidth = GetIntRes("icon.borderWidth", DEF_ICON_BORDER_WIDTH);
X     PPadding = GetIntRes("popup.pad", DEF_POP_PAD);
X     MBorderWidth = GetIntRes("menu.borderWidth", DEF_MENU_BORDER_WIDTH);
X     MItemBorder = GetIntRes("menu.itemBorder", 1);
X     MDelta = GetIntRes("menu.delta", DEF_MENU_DELTA);
X     MPad = GetIntRes("menu.pad", DEF_MENU_PAD);
X     Delta = GetIntRes("delta", DEF_DELTA);
X     Volume = GetIntRes("volume", DEF_VOLUME);
X     Pushval = GetIntRes("push", DEF_PUSH);
X     BContext = GetIntRes("borderContext.width", DEF_BCONTEXT_WIDTH);
X     BCursor = GetIntRes("borderContext.cursor", DEF_BCONTEXT_CURSOR);
X     TCursor = GetIntRes("title.cursor", DEF_TITLE_CURSOR);
X     TitleHeight = GetIntRes("title.height", 0);
X     TitlePad = GetIntRes("title.pad", DEF_TITLE_PAD);
X     NameOffset = GetIntRes("windowName.offset", 0);
X     
X     /*
X      * Retrieve the information structure for the specifed fonts and
X      * set the global font information pointers.
X      */
X     /* Default foreground/background colors */
X     ForeColor = GetColorRes("foreground", BlackPixel(dpy, scr));
X     BackColor = GetColorRes("background", WhitePixel(dpy, scr));
X     
X     if (Reverse) { /* Swap the forecolor and backcolor */
X	  Pixel tmp;
X	  
X	  tmp = ForeColor;
X	  ForeColor = BackColor;
X          BackColor = tmp;
X     }
X     
X     /*
X      * Create and store the grey and solid pixmaps
X      */
X     GrayPixmap = XCreatePixmapFromBitmapData(dpy, RootWindow(dpy, scr),
X					      gray_bits,
X					      gray_width, gray_height,
X					      ForeColor,
X					      BackColor,
X					      DefaultDepth(dpy, scr));
X
X     SolidPixmap = XCreatePixmapFromBitmapData(dpy, RootWindow(dpy, scr),
X					       solid_bits,
X					       solid_width, solid_height,
X					       ForeColor,
X					       BackColor,
X					       DefaultDepth(dpy, scr));
X
X     IFontInfo = GetFontRes("icon.font", DEF_ICON_FONT);
X     PFontInfo = GetFontRes("popup.font", DEF_POPUP_FONT);
X     MFontInfo = GetFontRes("menu.font", DEF_MENU_FONT);
X     MBoldFontInfo = GetFontRes("menu.boldFont", DEF_BOLD_FONT);
X
X     WBorder = GetColorRes("border.foreground", ForeColor);
X     BForeground = GetColorRes("borderContext.foreground", ForeColor);
X     BBackground = GetColorRes("borderContext.background", BackColor);
X     IForeground = GetColorRes("icon.foreground", ForeColor);
X     IBackground = GetColorRes("icon.background", BackColor);
X     IBorder = GetColorRes("icon.border", IForeground);
X     ITextForeground = GetColorRes("icon.text.foreground", IForeground);
X     ITextBackground = GetColorRes("icon.text.background", IBackground);
X     PBorder = GetColorRes("popup.border", ForeColor);
X     PForeground = GetColorRes("popup.foreground", PBorder);
X     PBackground = GetColorRes("popup.background", BackColor);
X     MForeground = GetColorRes("menu.foreground", ForeColor);
X     MBackground = GetColorRes("menu.background", BackColor);
X     MBorder = GetColorRes("menu.border", MForeground);
X     
X     IBackPixmap = GetPixmapRes("icon.pixmap", GrayPixmap, IForeground,
X				IBackground);
X     
X#ifdef NEATEN
X     AbsMinWidth = GetIntRes("neaten.absMinWidth", DEFAULT_ABS_MIN);
X     AbsMinHeight = GetIntRes("neaten.absMinHeight", DEFAULT_ABS_MIN);
X     
X     RetainSize = GetBoolRes("neaten.retainSize", TRUE);
X     KeepOpen = GetBoolRes("neaten.keepOpen", TRUE);
X     Fill = GetBoolRes("neaten.fill", TRUE);
X     UsePriorities = GetBoolRes("neaten.usePriorities", TRUE);
X     FixTopOfStack = GetBoolRes("neaten.fixTopOfStack", TRUE);
X     
X     PrimaryIconPlacement = GetStringRes("neaten.primaryIconPlacement",
X					 DEF_PRIMARY_PLACEMENT);
X     SecondaryIconPlacement = GetStringRes("neaten.secondaryIconPlacement",
X					   DEF_SECONDARY_PLACEMENT);
X#endif
X     
X     Leave_void
X}
X
X/*
X * Look up string resource "string". If undefined, return "def_val"
X */
char *GetStringRes(string, def_val)
char *string, *def_val;
X{
X     char *cp;
X     
X     Entry("GetStringRes")
X     
X     if ((cp = XGetDefault(dpy, NAME, string)) ||
X	 (cp = XGetDefault(dpy, CLASS, string))) {
X	  if (!strlen(cp))
X	       Leave(def_val)
X	  else
X	       Leave(cp)
X     }
X     Leave(def_val)
X}
X
X/*
X * Look up boolean resource "string". If undefined, return "def_val"
X */
Boolean GetBoolRes(string, def_val)
char *string;
Boolean def_val;
X{
X     char *cp;
X     
X     Entry("GetBoolRes")
X     
X     if ((cp = XGetDefault(dpy, NAME, string)) ||
X	 (cp = XGetDefault(dpy, CLASS, string))) {
X	  if (!strlen(cp))
X	       Leave(def_val)
X	  
X	  /* look for "yes" (or "yeah" or "yup" ...) */
X	  if (*cp == 'y' || *cp == 'Y')
X	       Leave(TRUE)
X	  else if (!strcmp(cp, "on") || !strcmp(cp, "ON") ||
X		   !strcmp(cp, "On"))
X	       Leave(TRUE)
X	  else if (!strcmp(cp, "True") || !strcmp(cp, "TRUE") ||
X		   !strcmp(cp, "true"))
X	       Leave(TRUE)
X	  else
X	       Leave(FALSE)
X     }
X     Leave(def_val)
X}
X
X/*
X * Look up integer resource "string". If undefined or non-numeric,
X * return def_val.
X */
int GetIntRes(string, def_val)
char *string;
int def_val;
X{
X     char *cp;
X     
X     Entry("GetIntRes")
X     
X     if ((cp = XGetDefault(dpy, NAME, string)) ||
X	 (cp = XGetDefault(dpy, CLASS, string))) {
X	  if (!strlen(cp) || !((*cp >= '0' && *cp <= '9') || *cp == '-'))
X	       Leave(def_val)
X	  Leave(atoi(cp))
X     }
X     Leave(def_val)
X}
X
X/*
X * Try to load pixmap file named by resource "string". Return 0 if
X * unsuccessful. Otherwise, set width, height and return data.
X */
char *GetPixmapDataRes(string, wide, high)
char *string;
int *wide, *high;
X{
X     char *cp, *cp2;
X     
X     Entry("GetPixmapDataRes")
X     
X     if ((cp = XGetDefault(dpy, NAME, string)) ||
X	 (cp = XGetDefault(dpy, CLASS, string))) {
X	  char *data;
X	  int junk;
X	  
X	  cp2 = expand_from_path(cp);
X	  if (!cp2) {
X	       fprintf(stderr, "awm: Can't find pixmap file '%s' for '%s'\n",
X		       cp, string);
X	       Leave(0)
X	  }
X	  if (XReadBitmapFileData(cp2, wide, high, &data, &junk, &junk)
X	      != BitmapSuccess) {
X	       fprintf(stderr, "awm: Can't read pixmap file '%s' for '%s'.\n",
X		       cp, string);
X	  }
X	  else {
X	       Leave(data)
X	  }
X     }
X     Leave(0)
X}
X
X/*
X * Try to allocate pixmap resources named by "string", return "def_pix"
X * if not found.
X */
Pixmap GetPixmapRes(string, def_pix, fg, bg)
char *string;
Pixmap def_pix;
Pixel fg, bg;
X{
X     char *data;
X     Pixmap tmp;
X     int wide, high;
X
X     Entry("GetPixmapRes")
X
X     if (data = GetPixmapDataRes(string, &wide, &high)) {
X	  tmp = XCreatePixmapFromBitmapData(dpy, RootWindow(dpy, scr),
X					    data, wide, high, fg, bg,
X					    DefaultDepth(dpy, scr));
X	  XFree(data);
X	  if (!tmp) {
X	       fprintf(stderr, "awm: Can't create pixmap '%s', using default.\n", string);
X	       tmp = def_pix;
X	  }
X     }
X     else
X	  tmp = def_pix;
X     Leave(tmp)
X     }
X
X/*
X * Try to allocate color resource named by "string", return "color"
X * if not found.
X */
Pixel GetColorRes(string, color)
char *string;
Pixel color;
X{
X     char *cp;
X     Pixel tmp_color;
X     
X     Entry("GetColorRes")
X     
X     if ((cp = XGetDefault(dpy, NAME, string)) ||
X	 (cp = XGetDefault(dpy, CLASS, string))) {
X	  if ((tmp_color = LookupColor(cp)) != NOCOLOR)
X	       Leave(tmp_color)
X	  else
X	       tmp_color = color;
X     }
X     else
X	  tmp_color = color;
X     Leave(tmp_color)
X}
X
X/*
X * Try and get font resource "string", using "default" if not found. If
X * neither are available, use server default.
X */
X
XXFontStruct *GetFontRes(string, dflt)
char *string, *dflt;
X{
X     char *cp;
X     XFontStruct *tmp;
X     static XFontStruct *def_font = 0;
X     
X     Entry("GetFontRes")
X     
X     if (!def_font)
X	  def_font = XLoadQueryFont(dpy, DEF_FONT);
X     
X     if ((cp = XGetDefault(dpy, NAME, string)) ||
X	 (cp = XGetDefault(dpy, CLASS, string))) {
X	  if (tmp = XLoadQueryFont(dpy, cp))
X	       Leave(tmp)
X	  else
X	       fprintf(stderr, "awm: Can't load %s '%s', trying '%s'.\n",
X		       string, cp, dflt);
X     }
X     if (!dflt) /* NULL means we're not supposed to try again */
X	  Leave(NULL)
X     if (tmp = XLoadQueryFont(dpy, dflt))
X	  Leave(tmp)
X     else
X	  fprintf(stderr, "awm: Can't open default font '%s', using server default.\n", dflt);
X     Leave(def_font)
X}
X
AwmInfoPtr GetAwmInfo(w)
Window w;
X{
X     static AwmInfoPtr tmp;
X     
X     Entry("GetAwmInfo")
X     
X     if (!XFindContext(dpy, w, AwmContext, &tmp))
X	  Leave(tmp)
X     else
X	  Leave((AwmInfoPtr)NULL)
X}
X
AwmInfoPtr RegisterWindow(w)
Window w;
X{
X     AwmInfoPtr tmp;
X     
X     Entry("RegisterWindow")
X     
X     tmp = (AwmInfoPtr)malloc(sizeof(AwmInfo));
X     tmp->client = w;
X     tmp->title = tmp->frame = tmp->icon = (Window)0;
X     tmp->gadgets = (Window *)0;
X     tmp->name = (char *)0;
X     tmp->own = (Boolean)FALSE;
X     tmp->back = tmp->bold = tmp->BC_back = tmp->BC_bold =
X	  tmp->iconPixmap = (Pixmap)0;
X     tmp->state = WINDOW;
X     tmp->winGC = XCreateGC(dpy, w, (unsigned long)0, 0);
X     tmp->placed = FALSE;
X     XSaveContext(dpy, w, AwmContext, tmp);
X     Leave(tmp)
X}
X
X/*
X * Initialize the default bindings.  First, write the character array
X * out to a temp file, then point the parser to it and read it in.
X * Afterwards, we unlink the temp file.
X */
InitBindings()
X{
X     char *mktemp();
X     char *tempfile;
X     register FILE *fp;		/* Temporary file pointer. */
X     register char **ptr;	/* Default bindings string array pointer. */
X     
X     Entry("InitBindings")
X     
X     /*
X      * Create and write the temp file.
X      */
X     /*
X      * This used to just call mktemp() on TEMPFILE, which was very
X      * evil as it involved writing on a string constant. This extra
X      * mastication is necessary to prevent that.
X      */
X     tempfile = (char *)malloc(strlen(TEMPFILE) + 1);
X     strcpy(tempfile, TEMPFILE);
X     sfilename = mktemp(tempfile);
X     if ((fp = fopen(tempfile, "w")) == NULL) {
X	  perror("awm: cannot create temp file");
X	  exit(1);
X     }
X     for (ptr = DefaultBindings; *ptr; ptr++) {
X	  fputs(*ptr, fp);
X	  fputc('\n', fp);
X     }
X     fclose(fp);
X     
X     /*
X      * Read in the bindings from the temp file and parse them.
X      */
X     if ((yyin = fopen(tempfile, "r")) == NULL) {
X	  perror("awm: cannot open temp file");
X	  exit(1);
X     }
X     Lineno = 1;
X     yyparse();
X     fclose(yyin);
X     unlink(tempfile);
X     free(tempfile);
X     if (Startup_File_Error)
X	  Error("Bad default bindings...aborting");
X     
X     /*
X      * Parse the system startup file, if one exists.
X      */
X     if ((yyin = fopen(SYSFILE, "r")) != NULL) {
X	  sfilename = SYSFILE;
X	  Lineno = 1;
X	  yyparse();
X	  fclose(yyin);
X	  if (Startup_File_Error)
X	       Error("Bad system startup file...aborting");
X     }
X     Leave_void
X}
X
X/*
X * Create the menus and alter any appropriate bindings so that the RTL menu
X * handle is passed along in subsequent actions.
X */
Create_Menus()
X{
X     Binding *bptr;
X     MenuInfo *minfo;
X     MenuLink *lnk;
X     
X     Entry("Create_Menus")
X     
X     /*
X      * We start with the bindings list because we don't want to bother
X      * creating a menu that's been declared but not referenced.
X      */
X     for(bptr = Blist; bptr; bptr = bptr->next) {
X	  if (bptr->func == DoMenu) {
X	       if (minfo = (MenuInfo *)FindMenu(bptr->menuname))
X		    bptr->menu = (RTLMenu)create_menu(minfo);
X	       else {
X		    fprintf(stderr, "awm: non-existent menu reference: \"%s\"\n",
X			    bptr->menuname);
X		    Startup_File_Error = TRUE;
X	       }
X	  }
X     }
X     for (lnk = Menus; lnk; lnk = lnk->next) {
X	  free(lnk->menu);
X	  free(lnk);
X     }
X     Leave_void
X}
X
X/*
X * Grab the mouse buttons according to the bindings list.
X */
X
Grab_Buttons()
X{
X     Binding *bptr;
X     
X     Entry("Grab_Buttons")
X     
X     /*
X      * don't grab buttons if you don't have to - allow application
X      * access to buttons unless context includes window.
X      */
X     for (bptr = Blist; bptr; bptr = bptr->next) {
X	  if (bptr->context == ROOT)
X	       NeedRootInput = TRUE;
X	  else if (bptr->context & WINDOW) /* We gotta grab on windows */
X	       GrabAll(bptr->mask);
X     }
X     Leave_void
X}
X
X/*
X * Register a grab on all windows in the hierarchy. This is better than
X * registering a grab on the RootWindow since it leaves button/key chords
X * available for other contexts.
X */
GrabAll(mask)
unsigned int mask;
X{
X     int junk, nkids;
X     Window *kiddies;
X     
X     Entry("GrabAll")
X     
X     if (XQueryTree(dpy, DefaultRootWindow(dpy), &junk, &junk, &kiddies, &nkids)
X	 != BadWindow) {
X	  unsigned int i;
X	  
X	  for (i = 0; i < nkids; i++) {
X	       Window transient;
X	       XWindowAttributes xwa;
X	       
X	       /* check to see if it's a popup or something */
X	       XGetWindowAttributes(dpy, kiddies[i], &xwa);
X	       XGetTransientForHint(dpy, kiddies[i], &transient);
X	       if (xwa.class == InputOutput && xwa.map_state == IsViewable &&
X		   xwa.override_redirect == False && transient == None)
X		    Grab(mask, kiddies[i]);
X	  }
X     }
X     else {
X	  fprintf(stderr, "awm: Can't XQueryTree in GrabAll!\n");
X	  exit(1);
X     }
X     Leave_void
X}
X
X/*
X * Grab a mouse button according to the given mask.
X */
Grab(mask, w)
unsigned int mask;
Window w;
X{
X     unsigned int m = LeftMask | MiddleMask | RightMask;
X     
X     Entry("Grab")
X     
X     switch (mask & m) {
X     case LeftMask:
X	  XGrabButton(dpy, LeftButton, mask & ModMask, w, TRUE, EVENTMASK,
X		      GrabModeAsync, GrabModeAsync, None, LeftButtonCursor);
X	  break;
X	  
X     case MiddleMask:
X	  XGrabButton(dpy, MiddleButton, mask & ModMask, w, TRUE, EVENTMASK,
X		      GrabModeAsync, GrabModeAsync, None, MiddleButtonCursor);
X	  break;
X	  
X     case RightMask:
X	  XGrabButton(dpy, RightButton, mask & ModMask, w, TRUE, EVENTMASK,
X		      GrabModeAsync, GrabModeAsync, None, RightButtonCursor);
X	  break;
X     }
X     Leave_void
X}
X
X/*
X * Restore cursor to normal state.
X */
ResetCursor(button)
int button;
X{
X     Entry("ResetCursor")
X     
X     switch (button) {
X     case LeftButton:
X	  XChangeActivePointerGrab(dpy, EVENTMASK, LeftButtonCursor,
X				   CurrentTime);
X	  break;
X	  
X     case MiddleButton:
X	  XChangeActivePointerGrab(dpy, EVENTMASK, MiddleButtonCursor,
X				   CurrentTime);
X	  break;
X	  
X     case RightButton:
X	  XChangeActivePointerGrab(dpy, EVENTMASK, RightButtonCursor,
X				   CurrentTime);
X	  break;
X     }
X     Leave_void
X}
X
X/*
X * error routine for .awmrc parser
X */
yyerror(s)
char*s;
X{
X     Entry("yyerror")
X     
X     fprintf(stderr, "awm: %s: Line %d: %s\n", sfilename, Lineno, s);
X     Startup_File_Error = TRUE;
X     Leave_void
X}
X
X/*
X * warning routine for .awmrc parser
X */
yywarn(s)
char*s;
X{
X     Entry("yywarn")
X     
X     fprintf(stderr, "awm: Warning: %s: Line %d: %s\n", sfilename, Lineno, s);
X     Leave_void
X}
X
X/*
X * Print usage message and quit.
X */
Usage()
X{
X     Entry("Usage")
X     
X     fputs("Usage: awm [-b] [-i] [-f <file>] [-e <file>] [<host>:<display>]\n\n",
X	   stderr);
X     fputs("The -b option bypasses system and default bindings\n", stderr);
X     fputs("The -i option ignores the $HOME/.awmrc file\n", stderr);
X     fputs("The -f option specifies an alternate startup file\n", stderr);
X     fputs("The -e option specifies a program/script to exec after startup\n",
X	   stderr);
X     exit(1);
X}
X
X/*
X * error handler for X I/O errors
X */
XXIOError(dsp)
Display *dsp;
X{
X     perror("awm");
X     exit(3);
X}
END_OF_FILE
if test 36694 -ne `wc -c <'awm/awm.c'`; then
    echo shar: \"'awm/awm.c'\" unpacked with wrong size!
fi
# end of 'awm/awm.c'
fi
echo shar: End of archive 16 \(of 17\).
cp /dev/null ark16isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 17 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

dshr@SUN.COM (David Rosenthal) (06/16/88)

Is there any way you can be persuaded to use the "xstuff" technology
instead of dumping these immense quantities of code into my
overflowing mailbox?  We set up a server using the same technology for
NeWS,  it has been very popoular and has materially reduced the overhead
for people reading NeWS-makers.

	David.