[comp.sources.x] v03i017: Ardent Window Manager, Patchlevel 9, Part01/12

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

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

[Due to the size of the diffs and the fact that there are at least
2 widely distributed version out there, I am including the complete
sources and not just a patch. -mcw]

#! /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 1 (of 12)."
# Contents:  README awm.c bitmaps bitmaps/twm.gray.bm menus
# Wrapped by mikew@wyse on Fri Feb 17 10:50:19 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(7615 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
XThis file last changed February 8th, 1989.
X
XIn the grand tradition of adding to the README file, rather than
Xjust starting it from scratch...
X
XThis represents the 2nd netwide release of awm. A number of bugs in
Xthe menu package have been fixed (though by no means all) and awm
Xshould work much better on color systems. The code has been more
Xextensively linted and generally cleaned up. Several new bits of
Xknowledge have made it possible to speed up things quite a bit in
Xcertain situations. Subjective analysis is encouraged.
XMany many niggling little problems have been fixed, though nothing
Xsubstantial has been changed or added. It was felt that increasing
Xthe reliability of awm was far more important than adding new features,
Xthough many are planned. Awm should now be a good deal more portable,
Xif you get any warnings (under BSD or SYSV) during compilation, let us
Xknow.
X
XAs usual, people are encouraged to send mail to: awm-bugs@ardent.ardent.com
Xor to the author:
X
X				Jordan Hubbard
X                                PCS Computer Systeme GmbH
X                                Pfaelzer-Wald-Str. 36
X                                D-8000 Muenchen 90.
X                                West Germany
X				uunet!pyramid!pcsbst!jkh
X
X-------
XOld README follows:
X
XThis represents the first real release of the Ardent Window Manager (awm).
XIt's being released on the same terms as its predecessor (uwm) with
Xone additional request: Since this window manager is the "official"
Xwindow manager of Ardent Computer, a lot more effort and time will
Xbe expended to ensure that it works reliably. Please try and coordinate
Xfixes and enhancements through Ardent so that all may benefit. There
Xare sure to be some bugs, we'll be here trying to fix them. Send
Xbug reports to the author, or to:
X
X	{decwrl, uunet, hplabs, ucbcad, dlb}!ardent!awm-bugs
X
X
XINSTALLATION:
X
XInstallation should be fairly straightforward. If you're using imake,
Xfirst modify $(TOPDIR)/util/imake.includes/Imake.tmpl to define a macro
Xcalled AWMDIR (look at UWMDIR for an example) which should point to
Xsomeplace where you want to stash the system.awmrc file. If you like,
Xyou can just make UWMDIR and AWMDIR point to the same place since uwm
Xand awm's file names are different and won't conflict with eachother. If
Xyou're using make (and don't want to use imake), modify the definition
Xof AWMDIR in the Makefile instead (sort of the wrong way to do it though).
X
XCertain compilers don't like the #ident lines we use for sccs. If yours
Xdoesn't, do a
X
X	make noident
X
XIn the awm directory to remove all #ident lines from the source code.
X
XThe usual differences between system V and BSD include file structures
Xmay also cause you trouble. In particular, <sys/time.h> may be different.
XIf FocusChng.c doesn't compile correctly on your system, see if the
Xcorrect include file is in /usr/include or /usr/include/sys (the correct
Xone should define a timeval struct). I've also heard that SunOS 4.0
Xfails to compile code that compiles fine on SunOS 3.x. I don't know
Xwhat the symptoms are (since I don't have a 4.0 system around), but
XI've heard that the fix is to include <sys/file.h> in exp_path.c and
Xawm.c.
X
XIf you want awm's output to go to the console device (assumed to be
X/dev/console), define CONSOLE in the I/Makefile (there are appropriate
Xcomments that will show you what to do).
X
XIf all this seems confusing, send me mail and I'll try to explain
Xit differently.
X
XSupport for the RTL Neaten package has been added. If you'd like to compile
Xit in, you need to do two things:
X
X  1. Obtain the RTL neaten package somehow. It's too big to bundle with awm,
X     so it's expected that you'll have obtained it by some other means.
X     If you are on a system V system with 14 character file names,
X     you're in for a bit for work. Many of the files in the neaten
X     package have very long names. After you've renamed all of the > 14 char
X     files, you'll want to modify Makefile.rtl (in the awm directory)
X     identically so that the file names match the new ones you've chosen.
X
X  2. The makefile that comes with the neaten package assumes that you want to
X     compile their neatening window manager (nuwm), so you don't want to use
X     that. Awm will automatically use the "Makefile.rtl" makefile to compile
X     the neaten package (see below), as long as it knows where you've put it.
X     Modify awm's Imakefile (or Makefile) to point to the directory
X     where neaten resides (the macro NEATEN_LIB) and uncomment/comment the
X     appropriate macro definition lines.
X
X  3. Do an imake/make. The make will compile all of awm's files and then
X     proceed to make a neaten.a (in the neaten directory) to link against.
X
X
X   If you don't compile awm with Neaten, the function f.neaten can
X   still be bound but it will just print a warning message if invoked.
X
X   Please note that the Neaten package has not been extensively tested with
X   awm and should be considered an experimental "frill" more than anything else.
X   It seems to shuffle icons around ok, though I don't understand some of its
X   window placement logic. If it's useful, use it, if not, don't compile it in.
X
X
XThe rtl menu package in menus (non-optional) has its own Makefile which
Xyou may wish to customize (compiler flags, compiler type, etc), though
Xthe default configuration should produce a working awm binary on your
Xsystem. This whole setup needs to be gone through and redone, but that will
Xhave to wait for another day (or a kind volunteer).
X
X
XFirst time users of awm will probably want to read the manual page carefully
Xand then set about tailoring their .Xdefaults file accordingly. The actual
Xformat of the .awmrc file does not differ substantially from uwm's .uwmrc file,
Xbut since much of the variable declaration stuff has been moved into .Xdefaults,
Xa .uwmrc file will fail miserably if blithly copied into a .awmrc file. It's
Xprobably easier to go from scratch, starting with .Xdefaults.
X
XAfter defaults have been entered (by far the largest task), a careful
Xexamination of your current uwm interface should be done to see what possible
Xbenefits might be derived from title bar, gadget and border contexts.
XYou will most likely be able to eliminate almost all "chorded" buttons and
Xgo to naked buttons on title bars/gadgets/borders. You can now also bind
Xnaked buttons to icons without having the button stolen from applications,
Xso it's usually a win to bind an f.iconify to the icon context if you like the
Xway X10's xterm used to work.
X
XHighlighting is a new feature which does quite a bit more than just tweak
Xborder colors. It will change the title bar text font (and redisplay the text)
Xas well as alternating between two different title bar background pixmaps and
Xor border context pixmaps.
X
XI use a blank pixmap for the regular background (which is the default, I.E.
XI don't declare one) and a pixmap containing 7 horizontal lines for the
XBoldPixmap.  The effect is not unlike a macintosh window. With some careful
Xartistry (and placement) of gadget boxes, one could probably emulate this
Xeven more closely, though I'm not sure why one would want to.
X
XWhen creating gadget box pixmaps, it's suggested that you look at the cursor
Xfont first as there are a lot of suitable glyphs already there.
X
X
XAny and all suggestions are, of course, appreciated. In addition to the
Xawm-bugs address given previously, you may communicate with the author
Xat any of the following addresses:
X
X
X			Author:		Jordan Hubbard
X			Internet:	jkh@violet.berkeley.edu
X			UUCP:		{decwrl, hplabs, uunet}!ardent!jkh
X			U.S. Mail:	Ardent Computer
X					880 Maude
X					Sunnyvale, Ca. 94086
END_OF_FILE
if test 7615 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'awm.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'awm.c'\"
else
echo shar: Extracting \"'awm.c'\" \(43072 characters\)
sed "s/^X//" >'awm.c' <<'END_OF_FILE'
X
X
X
X#ifndef lint
Xstatic char *rcsid_awm_c = "$Header: /usr/graph2/X11.3/contrib/windowmgrs/awm/RCS/awm.c,v 1.3 89/02/07 22:39:57 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 * 1.6 -- Various irritating changes. Support for WMSTATE..
X */
X
X#include <signal.h>
X#include "awm.h"
X#include <sys/ioctl.h>
X#include "X11/Xutil.h"
X#include "X11/cursorfont.h"
X
X#ifdef titan
X#include <sys/file.h>
X#endif
X
X#ifdef PCS
X#include <unistd.h>
X#include <bsd/sys/time.h>
X#endif
X#ifdef PROFIL
X#include <signal.h>
X/*
X * Dummy handler for profiling.
X */
Xptrap()
X{
X     exit(0);
X}
X#endif
X
XBoolean NeedRootInput=FALSE;
XMenuOptionsMask options;
Xchar *sfilename;
Xchar execfile[NAME_LEN]; /* Pointer to file to exec with -e */
XBoolean Snatched;
XBoolean desktop_execd = TRUE;
Xextern FILE *yyin;
Xextern int errorStatus;
Xextern int ErrorHandler();
Xextern XContext AwmContext;
X
X/*
X * Main program.
X */
Xmain(argc, argv, environ)
Xint argc;
Xchar **argv;
Xchar **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     unsigned int pop_width, pop_height; /* Pop up window width and height. */
X     int context;		/* Root, window, or icon context. */
X     unsigned 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 *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 root;		/* Root window for QueryPointer. */
X     AwmInfoPtr awi;
X     XEvent button_event; 	/* Button input event. */
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 = NULL;
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     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		    desktop_execd = FALSE; /* assume we have desktop to run */
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 += 2; argc -= 2;
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#ifdef CONSOLE
X     if (access("/dev/console", W_OK) == 0) {
X          freopen("/dev/console", "w", stderr);
X	  freopen("/dev/console", "w", stdout);
X     }
X#endif /* CONSOLE */
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
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#if defined(WMSTATE)
X     wm_state_atom = XInternAtom(dpy, "WM_STATE", False);
X#endif /* WMSTATE */
X
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	  extern char *getenv();
X	  char *home = getenv("HOME");
X	  if( !home )
X		  Error( "Cannot find home" );
X	  sfilename = rc_file = malloc(NAME_LEN);
X	  sprintf(rc_file, "%s/.awmrc", 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     /*
X      * Catch some of the basic signals so we don't get rudely killed without
X      * cleaning up first.
X      */
X#ifdef titan
X          signal(SIGHUP, Quit);
X     signal(SIGTERM, Quit);
X     signal(SIGQUIT, Quit);
X     signal(SIGINT, Quit);
X
X     /* ignore SIGTTOU */
X
X     signal(SIGTTOU, SIG_IGN);
X#else
X
X     if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
X	  signal(SIGHUP, Quit);
X     if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
X	  signal(SIGTERM, Quit);
X     if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
X	  signal(SIGTERM, Quit);
X     if (signal(SIGINT, SIG_IGN) != SIG_IGN)
X	  signal(SIGINT, Quit);
X#endif
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
X	  XFree(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	  Error("Error in gadget declarations. Exiting...\n");
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      * watch for initial window mapping and window destruction
X      */
X     
X     errorStatus = False;
X     swa.event_mask = (SubstructureRedirectMask | FocusChangeMask |
X		       (NeedRootInput ? EVENTMASK |
X			OwnerGrabButtonMask : 0));
X     XChangeWindowAttributes(dpy, RootWindow(dpy, scr), CWEventMask, &swa);
X     XSync(dpy, False);
X     if (errorStatus)
X	  Error("Hmmm.. Looks like you're running another window manager!\n");
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)) {
X	  int i;
X
X	  for (i = 0; i < (int)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->state |= ST_PLACED;
X		    /* Possibly add a frame */
X		    FDecorate(kiddies[i],0,0,0,0);
X		    event_mask = PropertyChangeMask | FocusChangeMask;
X		    if (!awi->frame || !FrameFocus)
X			 event_mask |= (EnterWindowMask | LeaveWindowMask);
X#ifndef RAINBOW
X		    SetBorderPixmaps(awi, GrayPixmap);
X#else
X		    SetBorderPixmaps(awi, awi->grayPixmap);
X#endif
X		    XSelectInput(dpy, kiddies[i], event_mask);
X	       }
X	  }
X	  if (kiddies && *kiddies)
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.font = IFontInfo->fid;
X     xgc.graphics_exposures = FALSE;
X     xgc.foreground = IForeground;
X     xgc.background = IBackground;
X     IconGC = XCreateGC(dpy, 
X			RootWindow(dpy, scr),
X			(GCForeground | GCBackground | GCGraphicsExposures |
X			 GCFont), &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 |
X			GCSubwindowMode, &xgc);
X
X     /*
X      * As our last "startup" task, invoke the execfile if was specified.
X      */
X     if (!desktop_execd) {
X	  if (access(execfile, X_OK) == 0) {
X	       if (fork() == 0) {
X		    setpgrp(0, getpid());
X		    signal(SIGHUP, SIG_DFL);
X		    signal(SIGQUIT, SIG_DFL);
X		    signal(SIGINT, SIG_DFL);
X		    execl("/bin/sh", "sh", "-c", execfile, 0);
X		    _exit(127);
X	       }
X	       else
X		    desktop_execd = TRUE;
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 == 0)
X	       continue;
X	  
X	  awi = GetAwmInfo(bwin);
X	  if (!awi)
X	       continue;
X
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	  /*
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		     * 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		    awi = GetAwmInfo(bwin);
X		    if (!awi)
X			 continue;
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		     * 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			 
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 == 0)
X			 break;
X
X		    /*
X		     * Determine the event window and context.
X		     */
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		     * 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 */
XGet_Defaults()
X{
X     /*
X      * Get the pixmap search path, if it exists.
X      */
X     awmPath = GetStringRes("path", (char *) NULL);
X
X     /* Default foreground/background colors (text) */
X     Foreground = GetStringRes("foreground", "black");
X     Background = GetStringRes("background", "white");
X     Reverse = GetBoolRes("reverse", FALSE);
X     
X     if (Reverse) { /* Swap the foreground and background */
X	  char *tmp;
X	  
X	  tmp = Foreground;
X	  Foreground = Background;
X          Background = tmp;
X     }
X     WBorder = GetStringRes("border.foreground", Foreground);
X     
X     Autoselect = GetBoolRes("autoselect", FALSE);
X     Autoraise = GetBoolRes("autoraise", FALSE);
X     Borders = GetBoolRes("borderContexts", FALSE);
X     ConstrainResize = GetBoolRes("constrainResize", FALSE);
X     FrameFocus = GetBoolRes("frameFocus", FALSE);
X     Freeze = GetBoolRes("freeze", FALSE);
X     Grid = GetBoolRes("grid", FALSE);
X     InstallColormap = GetBoolRes("installColormap", FALSE);
X     Titles = GetBoolRes("titles", FALSE);
X     IconLabels = GetBoolRes("icon.labels", FALSE);
X     ILabelTop = GetBoolRes("icon.labelTop", FALSE);
X     PushDown = GetBoolRes("title.push", FALSE);
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     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     HIconPad = GetIntRes("icon.hPad", DEF_ICON_PAD);
X     VIconPad = GetIntRes("icon.vPad", DEF_ICON_PAD);
X     RaiseDelay = GetIntRes("raiseDelay", DEF_RAISE_DELAY);
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
X     ForeColor = GetColorRes("foreground", BlackPixel(dpy, scr));
X     BackColor = GetColorRes("background", WhitePixel(dpy, scr));
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     /*
X      * Create and store the grey and solid pixmaps, and default icon pixmap
X      */
X     GrayPixmap = XCreatePixmapFromBitmapData(dpy, RootWindow(dpy, scr),
X					      gray_bits,
X					      gray_width, gray_height,
X					      ForeColor,
X					      BackColor,
X					      (unsigned)DefaultDepth(dpy,scr));
X
X     SolidPixmap = XCreatePixmapFromBitmapData(dpy, RootWindow(dpy, scr),
X					       solid_bits,
X					       solid_width, solid_height,
X					       ForeColor,
X					       BackColor,
X					       (unsigned)DefaultDepth(dpy,
X								      scr));
X     
X     IDefPixmap = XCreatePixmapFromBitmapData(dpy, RootWindow(dpy, scr),
X					       xlogo32_bits,
X					       xlogo32_width, xlogo32_height,
X					       IForeground,
X					       IBackground,
X					       (unsigned)DefaultDepth(dpy,
X								      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     
X     IBackPixmap = GetPixmapRes("icon.backpixmap", GrayPixmap, IForeground,
X				IBackground);
X     IDefPixmap =  GetPixmapRes("icon.defpixmap", IDefPixmap, 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 */
Xchar *GetStringRes(string, def_val)
Xchar *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 */
XBoolean GetBoolRes(string, def_val)
Xchar *string;
XBoolean 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 (Pred(cp) > 0)
X		def_val = TRUE;
X     Leave(def_val)
X}
X
X/*
X * Look up integer resource "string". If undefined or non-numeric,
X * return def_val.
X */
Xint GetIntRes(string, def_val)
Xchar *string;
Xint 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 */
Xchar *GetPixmapDataRes(string, wide, high)
Xchar *string;
Xunsigned 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 (XmuReadBitmapDataFromFile(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 */
XPixmap GetPixmapRes(string, def_pix, fg, bg)
Xchar *string;
XPixmap def_pix;
XPixel fg, bg;
X{
X     char *data;
X     Pixmap tmp;
X     unsigned 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					    (unsigned) DefaultDepth(dpy, scr));
X	  XFree(data);
X	  if (!tmp) {
X	       fprintf(stderr,
X		       "awm: Can't create pixmap '%s', using default.\n",
X		       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.This routine is only used for allocating colors from
X * the default colormap.
X */
XPixel GetColorRes(string, color)
Xchar *string;
XPixel color;
X{
X     char *cp;
X     Pixel tmp_color;
X     Boolean status;
X     extern Pixel LookupColor();
X     
X     Entry("GetColorRes")
X     
X     if ((cp = XGetDefault(dpy, NAME, string)) ||
X	 (cp = XGetDefault(dpy, CLASS, string))) {
X	  tmp_color = LookupColor(cp, DefaultColormap(dpy, scr), &status);
X	  if (!status) /* lookup succeeded */
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)
Xchar *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 if (dflt)
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
XAwmInfoPtr GetAwmInfo(w)
XWindow w;
X{
X     static AwmInfoPtr tmp;
X     
X     Entry("GetAwmInfo")
X     
X     if (!XFindContext(dpy, w, AwmContext, (caddr_t *) &tmp))
X	  Leave(tmp)
X     else
X	  Leave((AwmInfoPtr)NULL)
X}
X
XAwmInfoPtr RegisterWindow(w)
XWindow w;
X{
X     AwmInfoPtr tmp;
X     XClassHint clh;
X     XWMHints *wm_hints;
X     char *cp;
X
X     Entry("RegisterWindow")
X     
X     tmp = (AwmInfoPtr)malloc(sizeof(AwmInfo));
X     if (tmp == (AwmInfoPtr)NULL) {
X	  fprintf(stderr, "awm: Woe! No memory to register window.\n");
X	  Leave((AwmInfoPtr)NULL)
X     }
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 = ST_WINDOW;
X#ifdef WMSTATE
X     tmp->wm_state.icon=0;
X     tmp->wm_state.state=NormalState;
X     XChangeProperty(dpy,w,wm_state_atom,wm_state_atom,32,PropModeReplace,
X		     (char *) &tmp->wm_state,2);
X#endif /* WMSTATE */
X     tmp->winGC = XCreateGC(dpy, w, (unsigned long)0, (XGCValues *) NULL);
X     /*
X      * Determine attribute set by first turning on all attributes
X      * that are set by booleans and then (possibly) override them
X      * by checking to see what an individual window might want.
X      */
X     tmp->attrs = AT_NONE;
X     if (Titles)
X	  tmp->attrs |= AT_TITLE;
X     if (UseGadgets)
X	  tmp->attrs |= AT_GADGETS;
X     if (Borders)
X	  tmp->attrs |= AT_BORDER;
X     if (Autoraise)
X	  tmp->attrs |= AT_RAISE;
X     if (IconLabels)
X	  tmp->attrs |= AT_ICONLABEL;
X     if (wm_hints = XGetWMHints(dpy, w)) {
X	  if (wm_hints->input)
X     		tmp->attrs |= AT_INPUT;
X	  XFree(wm_hints);
X     }
X#ifdef RAINBOW
X     tmp->foreColor = ForeColor;
X     tmp->backColor = BackColor;
X     tmp->grayPixmap = GrayPixmap;
X     tmp->solidPixmap = SolidPixmap;
X#endif
X     clh.res_name = clh.res_class = (char *)NULL;
X     XGetClassHint(dpy, w, &clh);
X     if (clh.res_class) {
X#ifdef RAINBOW
X	  Pixel tmp_color;
X	  Boolean status;
X	  
X	  if (cp = (XGetDefault(dpy, clh.res_class, "wm_option.foreground"))){
X		  tmp_color = LookupColor( cp, DefaultColormap( dpy, scr ), & status );
X		  if( !status )
X			  tmp->foreColor = tmp_color;
X	  }
X
X	  if (cp = (XGetDefault(dpy, clh.res_class, "wm_option.background"))){
X		  tmp_color = LookupColor( cp, DefaultColormap( dpy, scr ), & status );
X		  if( !status )
X			  tmp->backColor = tmp_color;
X	  }
X#endif
X	  
X	  if (cp = (XGetDefault(dpy, clh.res_class, "wm_option.title")))
X	       tmp->attrs = SetOptFlag(tmp->attrs, AT_TITLE, Pred(cp));
X	  
X	  if (cp = (XGetDefault(dpy, clh.res_class, "wm_option.gadgets")))
X	       tmp->attrs = SetOptFlag(tmp->attrs, AT_GADGETS, Pred(cp));
X
X	  if (cp = (XGetDefault(dpy, clh.res_class,"wm_option.borderContext")))
X	       tmp->attrs = SetOptFlag(tmp->attrs, AT_BORDER, Pred(cp));
X
X	  if (cp = (XGetDefault(dpy, clh.res_class, "wm_option.autoRaise")))
X	       tmp->attrs = SetOptFlag(tmp->attrs, AT_RAISE, Pred(cp));
X
X	  if (cp = (XGetDefault(dpy, clh.res_class, "wm_option.icon.labels")))
X	       tmp->attrs = SetOptFlag(tmp->attrs, AT_ICONLABEL, Pred(cp));
X     }
X     if (clh.res_name) {
X#ifdef RAINBOW
X	  Pixel tmp_color;
X	  Boolean status;
X
X	  if (cp = (XGetDefault(dpy, clh.res_name, "wm_option.foreground"))){
X		  tmp_color = LookupColor( cp, DefaultColormap( dpy, scr ), & status );
X		  if( !status )
X			  tmp->foreColor = tmp_color;
X	  }
X
X	  if (cp = (XGetDefault(dpy, clh.res_name, "wm_option.background"))){
X		  tmp_color = LookupColor( cp, DefaultColormap( dpy, scr ), & status );
X		  if( !status )
X			  tmp->backColor = tmp_color;
X	  }
X#endif
X	  if (cp = (XGetDefault(dpy, clh.res_name, "wm_option.title")))
X	       tmp->attrs = SetOptFlag(tmp->attrs, AT_TITLE, Pred(cp));
X	  
X	  if (cp = (XGetDefault(dpy, clh.res_name, "wm_option.gadgets")))
X	       tmp->attrs = SetOptFlag(tmp->attrs, AT_GADGETS, Pred(cp));
X
X	  if (cp = (XGetDefault(dpy, clh.res_name, "wm_option.borderContext")))
X	       tmp->attrs = SetOptFlag(tmp->attrs, AT_BORDER, Pred(cp));
X
X	  if (cp = (XGetDefault(dpy, clh.res_name, "wm_option.autoRaise")))
X	       tmp->attrs = SetOptFlag(tmp->attrs, AT_RAISE, Pred(cp));
X
X	  if (cp = (XGetDefault(dpy, clh.res_name, "wm_option.icon.labels")))
X	       tmp->attrs = SetOptFlag(tmp->attrs, AT_ICONLABEL, Pred(cp));
X     }
X#ifdef RAINBOW
X     /* Has a different fore/back colour been given? */
X     if( (tmp->foreColor != ForeColor) || (tmp->backColor != BackColor) ){
X	  /*
X	   * Create and store the grey and solid pixmaps
X	   */
X	     tmp->grayPixmap = 
X	       XCreatePixmapFromBitmapData(dpy, RootWindow(dpy, scr),
X					   gray_bits,
X					   gray_width, gray_height,
X					   tmp->foreColor,
X					   tmp->backColor,
X					   (unsigned)DefaultDepth(dpy, scr));
X	     
X	     tmp->solidPixmap = 
X	       XCreatePixmapFromBitmapData(dpy, RootWindow(dpy, scr),
X					   solid_bits,
X					   solid_width, solid_height,
X					   tmp->foreColor,
X					   tmp->backColor,
X					   (unsigned)DefaultDepth(dpy, scr));
X	     
X     }
X#endif
X     XSaveContext(dpy, w, AwmContext, (caddr_t) tmp);
X     Leave(tmp)
X}
X
X/*
X * Sets bit "flag" conditionally, based on state of "mask" and
X * "predicate" (mask denotes current state, predicate denotes
X * whether change is desired).
X */
Xint SetOptFlag(mask, flag, predicate)
Xint mask, flag, predicate;
X{
X     Entry("SetOptFlag")
X
X     switch (predicate) {
X     case -1:
X	  Leave(mask)
X          break;
X
X     case 0:
X          if (mask & flag)
X	       Leave(mask ^ flag)
X          else
X	       Leave(mask)
X	  break;
X
X     case 1:
X	  Leave(mask | flag)
X	  break;
X     }
X     Leave(-1);
X}
X
X/*
X * check whether a string denotes an "on" or "off" value. Return 0
X * if "off", 1 if "on" and -1 if undefined (or null).
X */
XPred(s)
Xchar *s;
X{
X     int i, len;
X     char *tmp;
X     Boolean ret = -1;
X     Entry("Pred")
X
X     if (!s)
X	  Leave(-1)
X     len = strlen(s);
X     if (!len)
X	  Leave(-1)
X     tmp = (char *)malloc(len + 1);
X     if (!tmp) {
X	  fprintf(stderr, "awm: Pred: Can't allocate storage for '%s'!\n", s);
X	  Leave(-1)
X     }
X     strcpy(tmp, s);
X     for (i = 0; i < len; i++)
X	  if (tmp[i] >= 'A' && tmp[i] <= 'Z')
X	       tmp[i] += 32;
X     if (*tmp == 'y' || !strcmp(tmp, "on")
X	 || !strcmp(tmp, "true")
X	 || !strncmp(tmp, "enable", 6))
X	  ret = 1;
X     else if (*tmp == 'n' || !strcmp(tmp, "off")
X	      || !strcmp(tmp, "false")
X	      || !strncmp(tmp, "disable", 7))
X	  ret = 0;
X     free(tmp);
X     Leave(ret)
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 */
XInitBindings()
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 */
XCreate_Menus()
X{
X     Binding *bptr;
X     MenuInfo *minfo;
X     MenuLink *lnk;
X     extern MenuInfo *FindMenu();
X     extern RTLMenu create_menu();
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 = FindMenu(bptr->menuname))
X		    bptr->menu = 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
XGrab_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 */
XGrabAll(mask)
Xunsigned int mask;
X{
X     unsigned int junk, nkids;
X     Window *kiddies;
X     
X     Entry("GrabAll")
X     
X     if (XQueryTree(dpy, DefaultRootWindow(dpy), &junk, &junk, &kiddies,
X		    &nkids)) {
X	  int i;
X	  
X	  for (i = 0; i < (int)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	  Error("awm: Can't XQueryTree in GrabAll!\n");
X     Leave_void
X}
X
X/*
X * Grab a mouse button according to the given mask.
X */
XGrab(mask, w)
Xunsigned int mask;
XWindow 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 */
XResetCursor(button)
Xint 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 */
Xyyerror(s)
Xchar*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 */
Xyywarn(s)
Xchar*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 */
XUsage()
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 */
X/*ARGSUSED*/
XXIOError(dsp)
XDisplay *dsp;
X{
X     /* perror("awm"); */
X     exit(3);
X}
END_OF_FILE
if test 43072 -ne `wc -c <'awm.c'`; then
    echo shar: \"'awm.c'\" unpacked with wrong size!
fi
# end of 'awm.c'
fi
if test ! -d 'bitmaps' ; then
    echo shar: Creating directory \"'bitmaps'\"
    mkdir 'bitmaps'
fi
if test -f 'bitmaps/twm.gray.bm' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'bitmaps/twm.gray.bm'\"
else
echo shar: Extracting \"'bitmaps/twm.gray.bm'\" \(312 characters\)
sed "s/^X//" >'bitmaps/twm.gray.bm' <<'END_OF_FILE'
X/* @(#)gray.ic	X10/6.6	11/3/86 */
X#define gray_width 16
X#define gray_height 16
Xstatic char gray_bits[] = {
X   0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa,
X   0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa,
X   0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa,
X   0x55, 0x55, 0xaa, 0xaa, 0x55, 0x55, 0xaa, 0xaa};
END_OF_FILE
if test 312 -ne `wc -c <'bitmaps/twm.gray.bm'`; then
    echo shar: \"'bitmaps/twm.gray.bm'\" unpacked with wrong size!
fi
# end of 'bitmaps/twm.gray.bm'
fi
if test ! -d 'menus' ; then
    echo shar: Creating directory \"'menus'\"
    mkdir 'menus'
fi
echo shar: End of archive 1 \(of 12\).
cp /dev/null ark1isdone
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