mikew@wyse.wyse.com (Mike Wexler) (09/23/88)
Submitted-by: ken@cs.rochester.edu (Ken Yap) Posting-number: Volume 1, Issue 45 Archive-name: xplaces/part01 [xplaces doesn't seem to follow the draft ICCCM procedure of using the WM_COMMAND and WM_CLIENT_MACHINE to get the name and client machine that the process is running on.] #! /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 1)." # Contents: Makefile README default_setup patchlevel.h setenv.3 # setenv.c xplaces.c xtools.1 xtools.c # Wrapped by mikew@wyse on Thu Sep 22 15:22:57 1988 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'Makefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Makefile'\" else echo shar: Extracting \"'Makefile'\" \(791 characters\) sed "s/^X//" >'Makefile' <<'END_OF_FILE' XCFLAGS = -O -DDEFAULT_INITFILE=\"$(DEFAULT_INITFILE)\" -I/usr/include -L/usr/new/usr/lib/X11 XCONFDIR = /usr/new/usr/bin/X11 X# CFLAGS = -g -DDEFAULT_INITFILE=\"$(DEFAULT_INITFILE)\" X XDEFAULT_INITFILE = /usr/new/usr/lib/X11/xtools.defaults X X.SUFFIXES: .o .h .c .a X Xall: xtools xplaces X Xxtools: xtools.o setenv.o X cc $(CFLAGS) -o xtools xtools.o setenv.o X Xsetenv.o: setenv.c X Xxplaces: xplaces.o X cc $(CFLAGS) -o xplaces xplaces.o -lX X Xinstall: X install -m 755 xtools $(CONFDIR)/xtools X install -m 755 xplaces $(CONFDIR)/xplaces X cp default_setup $(DEFAULT_INITFILE) X cp xtools.1 /usr/man/mann/xtools.n X cp setenv.3 /usr/man/mann/setenv.n X# nroff -man xtools.1 > /usr/man/cat1/xtools.1 X# nroff -man setenv.3 > /usr/man/cat3/setenv.3 X Xclean: X rm -f *~* *.bak core *.o xtools xplaces END_OF_FILE if test 791 -ne `wc -c <'Makefile'`; then echo shar: \"'Makefile'\" unpacked with wrong size! fi # end of 'Makefile' fi if test -f 'README' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'README'\" else echo shar: Extracting \"'README'\" \(436 characters\) sed "s/^X//" >'README' <<'END_OF_FILE' X xtools allows one to create a personalized window Xconfiguration. xtools reads the startup file $HOME/.xtools (failing Xthat, $Xlibrary/xtools.defaults) and starts up the tools specified. XEach line of the file specifies a command to be executed. XLines beginning with # are comments. X xplaces prints on standard output the names of the tools Xand the geometry. The output, after a little editing, can be used Xin an initialization file. END_OF_FILE if test 436 -ne `wc -c <'README'`; then echo shar: \"'README'\" unpacked with wrong size! fi # end of 'README' fi if test -f 'default_setup' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'default_setup'\" else echo shar: Extracting \"'default_setup'\" \(123 characters\) sed "s/^X//" >'default_setup' <<'END_OF_FILE' Xxnwm -m Xxclock -analog =164x164+980+23 Xxterm -fn vtsingle -fb vtbold =80x65+1+23 Xxterm -C -fn 6x13 -fb 6x13 =80x24+661+555 END_OF_FILE if test 123 -ne `wc -c <'default_setup'`; then echo shar: \"'default_setup'\" unpacked with wrong size! fi # end of 'default_setup' fi if test -f 'patchlevel.h' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'patchlevel.h'\" else echo shar: Extracting \"'patchlevel.h'\" \(21 characters\) sed "s/^X//" >'patchlevel.h' <<'END_OF_FILE' X#define PATCHLEVEL 0 END_OF_FILE if test 21 -ne `wc -c <'patchlevel.h'`; then echo shar: \"'patchlevel.h'\" unpacked with wrong size! fi # end of 'patchlevel.h' fi if test -f 'setenv.3' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'setenv.3'\" else echo shar: Extracting \"'setenv.3'\" \(1041 characters\) sed "s/^X//" >'setenv.3' <<'END_OF_FILE' X.TH SETENV 3 "22 October 1985" X.SH NAME Xsetenv, delenv \- add/change/delete environment variables X.SH SYNOPSIS X.nf X.B setenv (name, value) X.B char *name, *value; X X.B delenv (name) X.B char *name; X.fi X.SH DESCRIPTION X.I Setenv Xallows a program to set environment variables. X.I Delenv Xallows a program to delete them. XThese routines follow on logically from X.IR getenv (3). X.SH EXAMPLES X.nf Xsetenv ("EDITOR", "/usr/ucb/ex"); Xdelenv ("EDITOR"); X.fi X.SH NOTES XThe third argument to routine X.B main Xstill points to the original environment after execution of these routines. XThe flag X.I \-lsjm Xneeds to be given to X.IR cc (1) Xor X.IR ld (1). X.SH "RETURN VALUES" X.I Setenv Xand X.I delenv Xboth return 0 on success and -1 if enough memory couldn't be allocated. X.I Delenv Xcan also return 1 meaning that the X.B name Xwasn't found in the current environment. XThe first call to X.I setenv Xor X.I delenv Xinitialises both routines. XAfter that, X.I delenv Xcannot return -1. X.SH "SEE ALSO" Xgetenv (3), execve (2) X.SH AUTHOR XStephen J. Muir, Lancaster University. END_OF_FILE if test 1041 -ne `wc -c <'setenv.3'`; then echo shar: \"'setenv.3'\" unpacked with wrong size! fi # end of 'setenv.3' fi if test -f 'setenv.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'setenv.c'\" else echo shar: Extracting \"'setenv.c'\" \(4480 characters\) sed "s/^X//" >'setenv.c' <<'END_OF_FILE' X/* Written by Stephen J. Muir, Computing Dept., Lancaster University */ X X# include <strings.h> X X/* This is the number of extra array elements to allocate each time it becomes X * necessary. X */ X# define INC 10 X Xextern char **environ, *malloc (); Xextern int free (); X Xstatic char **original, **current, **limit; X X/* This routine should be called only once (when either "setenv" or "delenv" is X * called for the first time). It would only be called again if it fails due X * to lack of memory. It makes a copy of the original environment because the X * original environment array and its elements were not obtained from "malloc" X * and the "free" routine cannot, therefore, be called with any of its X * elements. X * X * return values: X * 0: success X * -1: out of memory - nothing has changed X */ Xstatic /* this is a private routine */ Xinitialise () X { register char **old, **new_ptr, *tmp, **new_env; X X /* count number of existing strings */ X for (old = environ; *old; ++old) X ; X X /* make space for extra strings */ X if ((new_ptr = X new_env = X (char **)malloc (sizeof (char **) * ((old - environ) + INC + 1)) X ) X == 0 X ) X return (-1); X X /* "limit" points to the last element of the array -- it is used to X * decide when to recreate it X */ X limit = new_env + (old - environ) + INC; X X /* copy across old strings */ X for (old = environ; *old; ++old) X { if ((tmp = malloc (strlen (*old) + 1)) == 0) X { /* out of memory -- undo everything */ X while (new_ptr != new_env) X free (*--new_ptr); X free ((char *)new_ptr); X return (-1); X } X strcpy (tmp, *old); X *new_ptr++ = tmp; X } X /* "current" points to the null pointer at the end of the array */ X *(current = new_ptr) = 0; X X /* this is really just a flag to say it's initialised */ X original = environ; X /* overwrite old environment with new */ X environ = new_env; X return (0); X } X X/* This is a special routine to compare a string "name" of the form "NAME" with X * a string "name_value" of the form "NAME=VALUE". It returns zero if the X * comparison is successful X */ Xstatic /* this is a private routine */ Xdiffer (name, name_value) X char *name, *name_value; X { while (*name && *name_value) X if (*name++ != *name_value++) X return (1); X return (*name_value != '='); X } X X/* This routine deletes an environment variable, e.g. delenv ("SHELL"); X * X * return values: X * 0: success X * 1: environment variable not found X * -1: out of memory - nothing has changed X */ Xdelenv (name) X char *name; X { register char **ptr; X X /* initialise if necessary */ X if (original == 0 && initialise ()) X return (-1); X X /* attempt to find it */ X for (ptr = environ; *ptr && differ (name, *ptr); ++ptr) X ; X if (*ptr == 0) X return (1); /* not found */ X X /* delete it */ X free (*ptr); X *ptr = *--current; X *current = 0; X return (0); X } X X/* This routine sets a new environment variable, replacing an existing one X * where appropriate, e.g. setenv ("SHELL", "/bin/csh"); X * X * return values: X * 0: success X * -1: out of memory - nothing has changed X */ Xsetenv (name, value) X char *name, *value; X { register char **old, **new_ptr, *cp, *tmp, **new_env; X X /* initialise if necessary */ X if (original == 0 && initialise ()) X return (-1); X X /* allocate space for the new string */ X if ((cp = tmp = malloc (strlen (name) + strlen (value) + 2)) == 0) X return (-1); X X /* find an existing one if we can - we do this now as we will lose X * the original "name" pointer in the while loop following X */ X for (old = environ; *old && differ (name, *old); ++old) X ; X X /* make the new entry */ X while (*name) X *cp++ = *name++; X *cp++ = '='; X while (*value) X *cp++ = *value++; X *cp = '\0'; X X /* case 1: overwrite previous value */ X if (*old) X { free (*old); X *old = tmp; X } X X /* case 2: no previous value and no space left - allocate more */ X else if (current == limit) X { if ((new_ptr = X new_env = X (char **)malloc (sizeof (char **) * X ((old - environ) + INC + 1) X ) X ) == 0 X ) X { free (tmp); X return (-1); X } X limit = new_env + (old - environ) + INC; X for (old = environ; *old; ) X *new_ptr++ = *old++; X *new_ptr++ = tmp; X *(current = new_ptr) = 0; X free ((char *)environ); X environ = new_env; X } X X /* case 3: no previous value and there is enough space */ X else X { *current++ = tmp; X *current = 0; X } X return (0); X } END_OF_FILE if test 4480 -ne `wc -c <'setenv.c'`; then echo shar: \"'setenv.c'\" unpacked with wrong size! fi # end of 'setenv.c' fi if test -f 'xplaces.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'xplaces.c'\" else echo shar: Extracting \"'xplaces.c'\" \(2244 characters\) sed "s/^X//" >'xplaces.c' <<'END_OF_FILE' X/* X** A program to take a snapshot of the names and sizes of X** windows currently on the screen for use as an initialization spec. X** See manual page for further explaination. X** X** Ken Yap X** Placed in public domain X** Feb 1988 X*/ X X#include <stdio.h> X#include <X11/Xlib.h> X#include <X11/Xutil.h> X Xfatal(message) X char *message; X{ X fprintf(stderr, "%s\n", message); X exit(1); X} X Xmain(argc, argv) X int argc; X char *argv[]; X{ X register Display *d; X register int width, height; X int nchildren; X char *win_name; X Window root_win, parent_win, *child_list; X XWindowAttributes win_info; X XSizeHints hints; X X if ((d = XOpenDisplay(NULL)) == NULL) X fatal("Can't open display"); X X /* get a list of children of the root window */ X if (XQueryTree(d, DefaultRootWindow(d), &root_win, &parent_win, X &child_list, &nchildren) == 0) X fatal("Can't query window tree"); X /* scan list */ X for ( ; nchildren-- > 0; child_list++) X { X /* what is the name? */ X if (!XFetchName(d, *child_list, &win_name)) X continue; /* not fatal */ X X /* what do we know about it? */ X if (!XGetWindowAttributes(d, *child_list, &win_info)) X continue; X X if (win_info.class != InputOutput) X continue; /* only live windows desired */ X X if (!XGetNormalHints(d, *child_list, &hints)) X continue; X X /* need size either from user or program */ X if (!(hints.flags & (USSize || PSize))) X continue; X X /* if no increment then assume 1 */ X if (!(hints.flags & PResizeInc)) X hints.width_inc = hints.height_inc = 1; X X /* if no position then assume +0+0 */ X if (!(hints.flags & (USPosition || PPosition))) X hints.x = hints.y = 0; X X /* if no min width or height then assume 0 */ X if (!(hints.flags & PMinSize)) X hints.min_width = hints.min_height = 0; X X /* terminal windows sizes are in characters so this X will compute the geometry correctly */ X if (hints.width_inc > 1 && hints.height_inc > 1) X { X width = (hints.width - hints.min_width) / hints.width_inc; X height = (hints.height - hints.min_height) / hints.height_inc; X } X else X { X width = win_info.width; X height = win_info.height; X } X X if (win_name == NULL) X continue; /* ignore anonymous windows */ X printf("%s =%dx%d+%d+%d\n", win_name, X width, height, hints.x, hints.y); X } X} END_OF_FILE if test 2244 -ne `wc -c <'xplaces.c'`; then echo shar: \"'xplaces.c'\" unpacked with wrong size! fi # end of 'xplaces.c' fi if test -f 'xtools.1' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'xtools.1'\" else echo shar: Extracting \"'xtools.1'\" \(1937 characters\) sed "s/^X//" >'xtools.1' <<'END_OF_FILE' X.TH XTOOLS 1 "1 Feb 1988" "X Version 11" X.SH NAME Xxtools - start up personal X window configuration X.br Xxplaces - take snapshot of personal X window configuration X.SH SYNOPSIS X.B xtools X[ -f initfile ] X.br X.B xplaces X.SH DESCRIPTION X.I xtools Xallows one to create a personalized window configuration. X.I xtools Xreads the startup file $HOME/.xtools (failing that, $Xlibrary/xtools.defaults) Xand starts up the tools specified. XEach line of the file specifies a command to be executed. XLines beginning with # are comments. X.PP X.I xtools Xunderstands the following option: X.PP X.TP 8 X.B \-f \fIinitfile\fP X\fIinitfile\fP is the name of an alternate startup file. XIf this file cannot be found, $Xlibrary/xtools.defaults is used, if it exists. X.PP X.I Xtools Xplaces its own pid in the environment variable XTOOLSPID Xso that one can exit X at once by "kill $XTOOLSPID". XUpon receiving SIGTERM, X.I xtools Xwill send SIGTERM to each of the tools in turn before exiting. XThis command can also be taught to your favourite window manager. X.PP X.I xplaces Xprints on standard output the names of the tools and the geometry. XThe output, after a little editing, can be used Xin an initialization file. X.SH EXAMPLE XHere is a configuration example: X.sp X.nf Xxnwm -m Xxclock =53x53+981+23 Xxterm -C =80x24+3+29 Xxterm =80x24+3+576 Xxterm =80x24+659+576 X.fi X.sp X.I xtools Xwill start up a window manager, a clock and three terminal windows, Xone of which will receive redirected console output on Suns. X.PP XOn Suns, the recommended way of running X.I xtools Xis by ``xinit xtools''. XRemember to set the environment variable DISPLAY first! X.SH SEE ALSO Xxinit(1) X.SH FILES X$HOME/.xtools X.br X$Xlibrary/xtools.defaults X.SH DIAGNOSTICS XCan't find initialization file. X.SH BUGS X.I xplaces Xcan only print the name the tool wants to be known by. XThis is sometimes not the same as the name of the executable file Xso some hand editing of the output is required. X.SH AUTHOR XKen Yap END_OF_FILE if test 1937 -ne `wc -c <'xtools.1'`; then echo shar: \"'xtools.1'\" unpacked with wrong size! fi # end of 'xtools.1' fi if test -f 'xtools.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'xtools.c'\" else echo shar: Extracting \"'xtools.c'\" \(4452 characters\) sed "s/^X//" >'xtools.c' <<'END_OF_FILE' X/* X** A program to start up user preferences in X windows. X** Reads in specs from $HOME/.xtools or $Xlibrary/xtools. X** See manual page for further explaination. X** X** Ken Yap X** Placed in public domain X** Feb 1988 X*/ X X#include <stdio.h> X#include <signal.h> X#include <sys/wait.h> X X#ifndef DEFAULT_INITFILE X#define DEFAULT_INITFILE "/usr/new/lib/X11/xtools.defaults" X#endif X Xstatic char *progname; X X/* table of process id's */ Xstatic int procid[100] = { 0 }; X#define MAXPROCESS (sizeof(procid)/sizeof(procid[0])) X Xstatic quit() X/* X** Kill all children first X*/ X{ X register int i; X X /* send SIGTERM and SIGHUP to all children */ X for (i = 0; i < MAXPROCESS; i++) X if (procid[i] > 0) X { X (void)killpg(procid[i], SIGTERM); X (void)kill(procid[i], SIGTERM); X } X sleep(2); /* wait a decent interval */ X exit(0); X} X Xstatic char *skipblanks(p) X char *p; X/* X** Newline is whitespace too X*/ X{ X while (*p == ' ' || *p == '\t' || *p == '\n') X ++p; X return (p); X} X Xstatic char *skipword(p) X char *p; X/* X** But don't go past '\0' X*/ X{ X while (*p != ' ' && *p != '\t' && *p != '\n' && *p != '\0') X ++p; X return (p); X} X Xstatic int process(argv) X char **argv; X/* X** Fork and exec new process X*/ X{ X register int pid; X register char *procname; X char *rindex(); X X#ifdef DEBUG X while (*argv != 0) X (void)printf("'%s' ", *argv++); X (void)printf("\n"); X return (1); X#endif DEBUG X if ((pid = fork()) < 0) X return (pid); /* error occurred */ X if (pid > 0) /* I am parent */ X { X sleep(1); /* give child time to startup */ X (void)setpgrp(pid, pid); /* ignore errors, maybe child exited quickly */ X return (pid); X } X else /* I am child */ X { X if ((procname = rindex(*argv, '/')) == 0) X procname = *argv; X else X ++procname; /* last component */ X execvp(procname, argv); X perror("exec"); X exit(0); /* should never return unless error */ X /*NOTREACHED*/ X } X} X Xstatic execute(tool) X char *tool; X/* X** Chop up the command line and pass to process. X** Keep track of returned pid for later use. X*/ X{ X register char *cmd; X register int argcnt; X char *argvec[100]; X#define MAXARGS (sizeof(argvec)/sizeof(argvec[0])) X register int childpid, i; X char *malloc(); X X if (tool[0] == '#') X return; /* a comment */ X if ((cmd = malloc(strlen(tool) + 1)) == NULL) X return; /* no room */ X (void)strcpy(cmd, tool); /* copy command line */ X cmd = skipblanks(cmd); X for (argcnt = 0; argcnt < MAXARGS - 1 && *cmd != '\0'; argcnt++) X { X argvec[argcnt] = cmd; X cmd = skipword(cmd); X if (*cmd != '\0') X *cmd++ = '\0'; X cmd = skipblanks(cmd); X } X argvec[argcnt] = 0; X if (argcnt > 0 && (childpid = process(argvec)) > 0) X { X for (i = 0; i < MAXPROCESS; i++) /* find free slot */ X if (procid[i] == 0) X procid[i] = childpid; X } X} X Xcleanup() X/* X** Wait for zombies, if any X*/ X{ X register int i, pid; X X for (i = 0; i < MAXPROCESS; i++) X if (procid[i] > 0) X if (getpgrp(procid[i]) < 0) /* gone away */ X procid[i] = 0; /* clear entry */ X X while ((pid = wait((union wait *)0)) >= 0) /* get child */ X { X for (i = 0; i < MAXPROCESS; i++) /* remove entry */ X if (pid == procid[i]) X { X procid[i] = 0; X break; X } X } X} X Xstatic int readfile(filename) X char *filename; X/* X** Attempt to open initialization file. If sucessful, read lines X** and send to execute. X*/ X{ X register FILE *f; X char line[256]; X X if ((f = fopen(filename, "r")) == NULL) X return (0); X while (fgets(line, sizeof(line), f) != NULL) X execute(line); X (void)fclose(f); X return (1); X} X Xmain(argc, argv) X int argc; X char *argv[]; X{ X register int c; X register char *home; X char initfile[100], pidstring[20]; X extern int optind; X extern char *optarg; X char *getenv(); X X progname = argv[0]; X if ((home = getenv("HOME")) != NULL) /* if no home, use default */ X { X (void)strcpy(initfile, home); X (void)strcat(initfile, "/.xtools"); X } X else X (void)strcpy(initfile, DEFAULT_INITFILE); X X while ((c = getopt(argc, argv, "f:")) != EOF) X switch (c) X { X case 'f': X (void)strcpy(initfile, optarg); X break; X default: X exit(0); X } X X /* put own pid in environment so uwm can find it */ X (void)sprintf(pidstring, "%d", getpid()); X (void)setenv("XTOOLSPID", pidstring); X X /* arrange to exit nicely */ X (void)signal(SIGTERM, quit); X X /* try both places */ X if (!readfile(initfile) && !readfile(DEFAULT_INITFILE)) /* real loser */ X { X (void)fprintf(stderr, "Can't find initialization file\n"); X exit(1); X } X X cleanup(); X exit(0); /* if no more children */ X} END_OF_FILE if test 4452 -ne `wc -c <'xtools.c'`; then echo shar: \"'xtools.c'\" unpacked with wrong size! fi # end of 'xtools.c' fi echo shar: End of archive 1 \(of 1\). cp /dev/null ark1isdone MISSING="" for I in 1 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have the archive. rm -f ark[1-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0 -- Mike Wexler(wyse!mikew) Phone: (408)433-1000 x1330