/*
 * Copyright 1988 by the Massachusetts Institute of Technology.
 * All rights reserved.
 * 
 * xwebster: An X11 desktop utility
 *
 * $Source: /afs/sipb.mit.edu/project/sipbsrc/src/webster/src/xwebster/RCS/xweb.c,v $
 * $Header: /afs/sipb.mit.edu/project/sipbsrc/src/webster/src/xwebster/RCS/xweb.c,v 1.27 94/07/06 01:33:49 svalente Exp $
 * $Author: svalente $
 *
 * Some portions of this code (derived from xyow.c):
 * Copyright (c) 1987 Siemens Corporate Research and Support, Inc.,
 * Princeton, NJ.
 *
 * Permission to use, copy, modify, and distribute this software and
 * its documentation for any purpose and without fee is hereby
 * granted, provided that the above copyright notice appear in all
 * copies and that both that copyright notice and this permission
 * notice appear in supporting documentation, and that the name of
 * Siemens not be used in advertising or publicity pertaining to
 * distribution of the software without specific, written prior
 * permission.  Siemens makes no representations about the
 * suitability of this software for any purpose.  It is provided "as
 * is" without express or implied warranty.
 * 
 */

#ifndef lint
static char rcsid_xweb_c[] = "$Header: /afs/sipb.mit.edu/project/sipbsrc/src/webster/src/xwebster/RCS/xweb.c,v 1.27 94/07/06 01:33:49 svalente Exp $";
#endif lint

#include <sys/types.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <netdb.h>
#include <sys/socket.h>
#include <sys/timeb.h>
#include <webster.h>

#include <closed.h>
#include <xwebster.h>

#ifdef _AIX
#include <sys/select.h>
#endif

#ifdef SUNRPC
#include <rpc/rpc.h>
#include <sunrpcweb.h>
#else !SUNRPC
#include <netinet/in.h>		/* included by <rpc/rpc.h> */
#endif SUNRPC

#ifdef HESIOD
#include <hesiod.h>
#endif HESIOD

#ifdef DEBUG
#include <sys/param.h>
char servername[MAXHOSTNAMELEN];
#endif DEBUG

#ifndef NeXT
extern char *malloc(), *realloc();
#endif

#define PROMPT "Word: "		/* prompt string in word window */
#define PROMPTLEN 6		/* why run strlen when I can count */
#define LEFT_MARGIN	5	/* 5-pixel left margin */
#define SHOW_SIZE		/* show the size of the window when resizing */

/* from init.c */
extern int rvflag;
extern int nohelpflag;
#ifdef SUNRPC
extern int RPC_exit_on_RPC_error;
#endif

/*
 * points to our current position in wwindows.definition, which is actually
 * the current word.
 */
char *curword = (char *) NULL;

/* deal with the strings of the definition we're working on */
char *curstash = (char *) NULL;
char *curptr = (char *) NULL;	
int howlong = 0;		/* length of definition so far,in characters */
int maxdeflen = 0;		/* how much memory have we allowed? */

/* display control */
int fontwidth;			/* maximum width of one char in the font */
int fontheight;			/* maximum height of one char in the font */
int current_x, current_y;	/* where we will print the next character */

#ifndef SUNRPC
FILE *WebsterSock;		/* for reading from the server	*/
#endif !SUNRPC

char *whoami;			/* argv[0], stripped of a pathname */
char **hostlist;		/* for hesiod hosts; if no hesiod, */
				/* list is only one host --        */
				/* WEBSTERHOST constant.           */

struct {
     int x, y;
     int xneg, yneg;
} initial_geometry;


/* Keep track of whether there is already a help window */
Window help_window = (Window) NULL;

struct sizes *popup();

void	RTLib_Initialize();
int	RTLib_border_width();
void	RTLib_Get_Initial_Geometry();
int	RTLib_Error_Handler();
Window	RTLib_Parent_Window();
void	RTLib_Parent_Size();
void	Webster_Set_Default_Geometry();
void	RTLib_Set_Initial_Geometry();
void	RTLib_Create_Window();
void	RTLib_Set_Properties();
void	RTLib_Set_GC();
Pixmap	RTLib_Create_Pixmap();
     
main(argc, argv)
	int argc;
	char *argv[];
{
     XEvent  ev;
     XEvent	*xevent;

#ifdef HESIOD
     char	**hes_resolve();
#endif HESIOD
#ifndef SUNRPC
     int	connectup();
#endif !SUNRPC
	
     whoami = (whoami = strrchr(argv[0], '/')) ? whoami + 1 : argv[0];

     RTLib_Initialize(whoami, &argc, argv);

#ifdef DEBUG
     XSetErrorHandler(RTLib_Error_Handler);
#endif

     if (!nohelpflag)
	  printf("For xwebster help, click the left mouse button on \
the xwebster window.\n");

     /* find the parent window and initialize its size. */
     parents.win = RTLib_Parent_Window();
     RTLib_Parent_Size(parents.win, &parents.cur_width,
		       &parents.cur_height);
	
     /* give me the context number, please */

     defwindow = XUniqueContext();
	
     RTLib_Set_GC();
     
     /* make the icon (master) window */

     Webster_Create_Icon(argc, argv);

     XSelectInput(dpy, icons.win,
		  ExposureMask | StructureNotifyMask |
		  ButtonPressMask | ButtonReleaseMask);

     XMapWindow(dpy, icons.win);
     /*
      * zero this out so that nothing will work until the user
      * requests a word window.
      */
     wwindows.win = 0;
	

#ifdef HESIOD
     /* who are we supposed to talk to? */
     if ((hostlist = hes_resolve("webster", "sloc")) == (char **) NULL) {
	  /*
	   * grab the first server and make it the one we talk
	   * to.
	   */
	  hostlist = (char **) malloc(sizeof (char *) * 2);
	  hostlist[0] = WEBSTERHOST;
	  hostlist[1] = (char *) NULL;
     }
#endif HESIOD
#ifdef DEBUG
     if (gethostname(servername, MAXHOSTNAMELEN)) {
	  fprintf(stderr, "Don't know what host name this is?!?!?");
	  exit(-1);
     }
     if (!hostlist)
	     hostlist = (char **) malloc(sizeof (char *) * 2);
     hostlist[0] = servername;
     hostlist[1] = (char *) NULL;
#endif DEBUG

#ifdef SUNRPC
     RPC_exit_on_RPC_error = 0;
#else
     /* say hello to the webster server: dealing with a timed-out */
     /* connection is left for later */
     connectup();
#endif !SUNRPC


     xevent = &ev;
     for (;;)
     {
	  Window ewindow;
	  struct sizes *stash;
	  int byebye();
	  Window Help();
	  void Punt_Window();
	  void New_Word_Window();
	  void Redisplay_Word();
	  void Typewriter();
	  void Webster_New_Character();
	  void Webster_Set_Current_Size();

	  XNextEvent(dpy, xevent);
	  ewindow = xevent->xany.window;

	  /*
	   * if we couldn't find the context, the window has
	   * probably already been destroyed.  Just keep going.
	   */
	  if (XFindContext(dpy, ewindow, defwindow, (char **)&stash)
	      != 0)
	       continue;
		
	  if (ewindow == icons.win)
	  {			/* do icons processing */
	       switch(xevent->type & 0x7f)
	       {
		    /*
		     * the & 0x7f is so that we don't
		     * distinguish between self-generated
		     * and server-sent events
		     */
	       case Expose:
		    if (xevent->xexpose.count == 0)
			 /*
			  * the background is repainted
			  * automagically.
			  */
			 break;

	       case ButtonRelease:
		    switch (((XButtonReleasedEvent *)
			     xevent)->button)
		    {
		    case Button1:
			 if (! help_window)
			      help_window = Help();
			 break;
		    case Button2:
			 /* new word window */
			 New_Word_Window(&wwindows);
			 break;

		    case Button3:
			 byebye();
			 break;

		    default:
			 break;
		    }
		    break;

	       case ConfigureNotify:
		    Webster_Set_Current_Size(xevent->xconfigure,
					     stash);
		    break;

	       default:
		    break;
				
	       }
	  }
	  else if (ewindow == wwindows.win)
	  {			/* do word window processing */
	       switch(xevent->type & 0x7f)
	       {
	       case Expose:
		    if (xevent->xexpose.count == 0)
			 Redisplay_Word(stash);
		    break;

	       case ButtonRelease:
		    switch (((XButtonReleasedEvent *)
			     xevent)->button)
		    {
		    case Button1:
		    case Button2:
		    case Button3:
			 Punt_Window(stash, True);
			 nuke_connection();
			 break;
		    default:
			 break;
		    }
		    break;
				
	       case ConfigureNotify:
		    Webster_Set_Current_Size(xevent->xconfigure,
					     stash);
		    break;
				
	       case KeyPress:
		    if (xevent->xany.window == wwindows.win)
			 Webster_New_Character(&(xevent->xkey));
		    break;
			
	       default:
		    break;
	       }
	  }
	  else {		/* must be a definition window */
	       switch(xevent->type & 0x7f)
	       {
	       case Expose:
					
		    if (xevent->xexpose.count == 0)
			 Typewriter(stash);
		    break;

	       case ButtonRelease:
		    switch (((XButtonReleasedEvent *)
			     xevent)->button)
		    {
		    case Button1:
		    case Button2:
		    case Button3:
			 Punt_Window(stash, False);
			 if (ewindow == help_window)
			      help_window = (Window) NULL;
			 break;
		    default:
			 break;
		    }
		    break;
	       case ConfigureNotify:
		    Webster_Set_Current_Size(xevent->xconfigure,
					     stash);
		    break;

	       default:
		    break;
	       }
	  }
     }
}


/* Set the minimum window size so that "str" can be completely
 *   shown in the font.
 *   default initial size to 2 * the minimum size,
 *   and the default initial position is (0,(parent_window_y - desired_height))
 */

void
Webster_Set_Default_Geometry(stash, width, height)
	struct sizes *stash;
	unsigned int width, height;
{
	stash->min_width = stash->desired_width = width;
	stash->min_height = stash->desired_height = height;

	stash->desired_x = 0;
	stash->desired_y = parents.cur_height - (stash->desired_height
						 + (2 * RTLib_border_width()));
}
 
/* Set the current window width and height
 *   based on information from the ConfigureNotify event
 */

void
Webster_Set_Current_Size(xconfigure, stash)
	XConfigureEvent  xconfigure;
	struct sizes *stash;
{
	stash->cur_width = xconfigure.width;
	stash->cur_height = xconfigure.height;
}

/*
 * Draw stash->definition (assumed to be one word), vertically
 * centered in the word window.
 */

void
Redisplay_Word(stash)
	struct sizes *stash;
{
	/* so that it's a null-terminated string, but don't increment,
	 * so that we can overwrite this when we get the next char. */
	*curword = '\0';
	/* looks like a handy time to recenter */
	current_y = stash->cur_height / 2;

	/* draw the prompt */
	XDrawString(dpy, stash->win, gc, LEFT_MARGIN, current_y,
		    PROMPT, PROMPTLEN);
	/* draw the word, if not null */
	if (*stash->definition != '\0')
		XDrawString(dpy, stash->win, gc, (LEFT_MARGIN +
						  (PROMPTLEN * fontwidth)),
			    current_y, stash->definition,
			    strlen(stash->definition));
}



clear_word()
{
     XClearWindow(dpy, wwindows.win);
     curword = wwindows.definition;
     XDrawString(dpy, wwindows.win, gc, LEFT_MARGIN,
		 current_y, PROMPT, PROMPTLEN);
     current_x = LEFT_MARGIN + (PROMPTLEN * fontwidth);
}



erase_character()
{
     char delt;
     
     /* Assumes fixed width font; Hell, the whole program does.  Fix */
     /* at some point in the future. 				     */
     if (curword - wwindows.definition) {
	  current_x -= fontwidth;
	  delt = *(--curword);
#ifdef DRAW_IMAGE_STRING
	  XDrawImageString(dpy, wwindows.win, erase_gc, current_x, current_y,
			   &delt, 1);
#else
	  XDrawString(dpy, wwindows.win, erase_gc, current_x, current_y,
		      &delt, 1);
#endif
     }
     else
	  XBell(dpy, 90);
}




/* this adds a new character to the word window */

void
Webster_New_Character(key)
	XKeyEvent *key;
{
	int i;
	char *st, askey[10], toscreen[2];
	void define();
	
	i = XLookupString(key, askey, sizeof(askey), NULL, NULL);

	if (i == 0)
		/* it's a zero-length string, so don't worry about it */
		return;
	
	for (st = askey; i > 0; i--)
	{
		/* stash it */
		toscreen[0] = *st++;
		toscreen[1] = '\0';
		/* Is it ^C?
		 * If so, clear the window,
		 * 	redraw the prompt,
		 * 	set curword back to the beginning of
		 * 	wwindows.definition, and reset current_x.
		 */
		if (toscreen[0] == '\003')
		     clear_word();
		/*
		 * If it's ^? (backspace):
		 * 	current_x -= width,
		 * 	if (rvflag is set)
		 * 		use our special gc (black foreground &
		 * 			background),
		 * 		print a blank,
		 * 	else
		 * 		print a blank,
		 * 	do NOT update current_x,
		 * 	decrement curword.
		 *
		 * We also make sure that we aren't trying to
		 * backspace off of the front end of wwindows.definition.
		 */
		else if (toscreen[0] == '\177')
		     erase_character();
		/* Is it \n or \r?
		 * If so, end the wwindows.definition with \0 and
		 * check the length.  If it's greater than 0,
		 * 	invoke webster, which pops up the window with
		 * 		the definition,
		 * 	then clear the word window and wwindows.definition,
		 * 	and reset current_x appropriately.
		 * else, fweep.
		 */
		else if ((toscreen[0] == '\n') || (toscreen[0] == '\r'))
		{
		        int len;
		     
			*curword = '\0';
			curword = wwindows.definition;
			/*
			 * Delete any blank spaces at the end of the
			 * word.
			 */
			while ((len = strlen(curword)) &&
			       (curword[len - 1] == ' '))
			     curword[len - 1] = '\0';
			if (strlen(curword))
			{
				define(curword);
				XClearWindow(dpy, wwindows.win);
				curword[0] = '\0';
				XDrawString(dpy, wwindows.win, gc, LEFT_MARGIN,
					    current_y, PROMPT, PROMPTLEN);
				current_x = LEFT_MARGIN +
					(PROMPTLEN * fontwidth);
				/*
				 * the old definition will be freed
				 * when its window is punted.
				 * curstash and curword should have
				 * already been reset, and will get
				 * more memory inside Define_Word, if
				 * they need it, so we don't deal with
				 * them here.
				 */
			} else
				XBell(dpy, 90);
		} 
		/* Is it an (upper- or lower-case) character?
		 * If so, add it to wwindows.definition,
		 * 	print it on the screen,
		 * 	and increment current_x appropriately.
		 */
		else if (isalpha(toscreen[0]) || toscreen[0] == '*' ||
			 toscreen[0] == '?' || toscreen[0] == '-' ||
			 toscreen[0] == ' ' || toscreen[0] == '\'')
		{
			*curword++ = toscreen[0];
			XDrawString(dpy, wwindows.win, gc, current_x,
				    current_y, toscreen, 1);
			current_x += fontwidth;
		} 
		/* Else, fweep. */
		else
			XBell(dpy, 90);

	} 
	return;
} 

/*
 * defarray is a pointer to a string, with linebreaks.  Pop up a
 * window just big enough to hold that text.
 *
 * defarray will not be freed until the window is punted.
 *
 */
struct sizes *
popup(word, defarray)
	char *word, *defarray;
{
	int i = 0;
	int memerror();
	void Typewriter();
	void RTLib_Set_Initial_Geometry();
	void RTLib_Create_Window();
	void RTLib_Set_Properties();
	register char *cp = defarray;
	struct sizes *newwin = (struct sizes *) malloc((unsigned)
						       sizeof(struct sizes));
	if (newwin == (struct sizes *) NULL)
		memerror();
	else {
		newwin->definition = malloc ((unsigned) sizeof (char *));
		if (newwin->definition == (char *) NULL)
			memerror();
	}

	/*
	 * figure out how many lines (\n) there are in defarray.
	 * Multiply by max_height of font to get the height.  No line
	 * is more than 80 chars long, so 80 + (2 * LEFT_MARGIN) is
	 * the width.  default_x_pos is 0; default_y_pos is
	 * parent_height - icon_window_height - desired_height (ie,
	 * stack the definition just above the default icon window
	 * position).
	 */
	while ((cp = strchr(cp, '\n')) != (char *) NULL)
	       {
		       i++;
		       cp++;
	       }
	/* i + 2, for 1 blank line at the top and one at the bottom */
	newwin->desired_height = newwin->min_height = (i + 2)
		* fontheight;
	newwin->desired_width = newwin->min_width = (80 * fontwidth)
		+ (2 * LEFT_MARGIN);

	/* Give this the same geometry as the icon, offset so as not */
	/* to block it.						     */
	
	if (initial_geometry.xneg)
	     newwin->desired_x = parents.cur_width - newwin->min_width -
		  - initial_geometry.x - 2 * RTLib_border_width();
	else
	     newwin->desired_x = initial_geometry.x;

	if (initial_geometry.yneg)
	     newwin->desired_y = parents.cur_height - newwin->min_height -
		  icons.cur_height - initial_geometry.y -
		       4 * RTLib_border_width();
	else
	     newwin->desired_y =  initial_geometry.y + icons.cur_height +
		  2 * RTLib_border_width();
	
	/* Now make sure as much as possible is on the screen. */
	on_screen(newwin);
	newwin->definition = defarray;
	newwin->win_name = word;

	/* go and do thou likewise */
	RTLib_Set_Initial_Geometry(newwin);
	RTLib_Create_Window(newwin);
	RTLib_Set_Properties((char **)NULL, 0, newwin, (Pixmap *) NULL, True);
	XSelectInput(dpy, newwin->win, ExposureMask | StructureNotifyMask
		     | ButtonPressMask | ButtonReleaseMask);
	XMapWindow(dpy, newwin->win);
	Typewriter(newwin);

	/* clean up the old definition */
	howlong = maxdeflen = 0;
	curstash = (char *) NULL;

	return(newwin);
} 

void
Typewriter(stash)
	struct sizes *stash;
{
	int memerror();
	register char *cp, *print, *scrap;
	register int cur_x, cur_y;
	
	scrap = malloc((unsigned) sizeof (char)
		       * (strlen(stash->definition) + 1));
	if (scrap == (char *) NULL)
		memerror();
	
	(void)strcpy(scrap, stash->definition);
	
	cp = print = scrap;
	cur_x = LEFT_MARGIN;
	/*
	 * fontheight * 2; once for the font, and once for the blank
	 * line.  Sometimes I'd like to hang the person who created
	 * X11's notion of geometry from the highest yardarm available.
	 */
	cur_y = fontheight * 2;
	/*
	 * Don't bother clearing the window -- the first expose event will do
	 * that for us.
	 */
	while ((cp = strchr(cp, '\n')) != (char *) NULL)
	{
		*cp++ = '\0';
		XDrawString(dpy, stash->win, gc, cur_x, cur_y,
			    print, strlen(print));
		print = cp;
		cur_y += fontheight;
	}
	free(scrap);
}

/*
 * if flag is true, we are dealing with a non-malloc'ed structure (ie,
 * wwindows), and may not free it.
 */
void
Punt_Window(stash, flag)
	struct sizes *stash;
	int flag;
{
	if (stash->definition) {
		free(stash->definition);
		stash->definition = (char *) NULL;
	}
	XDeleteContext(dpy, stash->win, defwindow);
	if (stash->win) {
		XDestroyWindow(dpy, stash->win);
		stash->win = 0;
	}
	if (!flag)
		free((char *)stash);
}

on_screen(stash)
struct sizes *stash;
{
     if ((stash->desired_x + stash->desired_width + 2 * RTLib_border_width())
	 > parents.cur_width) {
	  stash->desired_x = parents.cur_width - stash->min_width -
	       2 * RTLib_border_width();
	  stash->desired_width = stash->min_width;
     }
     if ((stash->desired_y + stash->desired_height + 2 * RTLib_border_width())
	 > parents.cur_height) {
	  stash->desired_y = parents.cur_height - stash->min_height -
	       2 * RTLib_border_width();
	  stash->desired_height = stash->min_height;
     }
     if (stash->desired_x < 0) {
	  stash->desired_x = 0;
	  stash->desired_width = stash->min_width;
     }
     if (stash->desired_y < 0) {
	  stash->desired_y = 0;
	  stash->desired_height = stash->min_height;
     }
}


Window
Help()
{
     struct sizes *retwin;
     
     int memerror();
     /* carefully set up beforehand, you bet */	
     char *string, *message = "XWEBSTER INSTRUCTIONS:\n\nIn the icon window:\n      Clicking the left button will get you this help message;\n      Clicking the middle button will pop up a 'word window';\n      Clicking the right button will cause xwebster to exit.\n\nIn the word window:\n      Type in your word.  Control-C will clear everything you've\n      entered, and the backspace key works normally.  Hit Return when\n      you're done entering the word.  xwebster will pop up a\n      'definition window' with the definition of your word.\n\n      Clicking any button in the word window will cause it to disappear.\n\nIn the definition window:\n\n      Clicking any button in the definition window will cause it to\n      disappear.\n\nIf you're using an RT, which has no middle button, press both the\nbuttons simultaneously instead.\n\nClicking any button in this window will cause it to disappear.\n\n";

     string = malloc((unsigned) sizeof (char *) * (strlen(message) + 1));
     if (string == (char *) NULL)
	  memerror();
	
     strcpy(string, message);
	
     retwin = popup("Help", string);
     return (retwin ? retwin->win : (Window) NULL);
}

void
New_Word_Window(stash)
	struct sizes *stash;
{
	void Punt_Window();
	int memerror();
	unsigned int width, height;

	if (stash->win != 0)
		/*
		 * lost it, forgot it, something.  Anyway, punt it and
		 * start fresh.
		 */
		Punt_Window(stash, True);


	/*
	 * never let the word window get too small for a
	 * 20-letter word (really not that big), plus the prompt, plus
	 * a 10-pixel margin.
	 */
	{
		char *str = "20202020202020202020";
			
		width = 10 + XTextWidth(fontp, str, strlen(str)) +
			XTextWidth(fontp, PROMPT, PROMPTLEN);
		height = 10 + fontheight;
	}

	stash->min_width = stash->desired_width = width;
	stash->min_height = stash->desired_height = height;
	
	/* Put the word window to the right of the icon if the icon is */
	/* based at the left margin, or to the left of the icon if the */
	/* icon is based at the right margin.			       */

	if (initial_geometry.xneg)
	     stash->desired_x = parents.cur_width - width -
		  icons.cur_width - initial_geometry.x -
		       4 * RTLib_border_width();
	else
	     stash->desired_x = initial_geometry.x + icons.cur_width +
		  2 * RTLib_border_width();

	/* If the icon is based at the top margin, align the word */
	/* window with the top of the icon; if it is based at the */
	/* bottom, align the word with the bottom.		  */
	if (initial_geometry.yneg)
	     stash->desired_y = parents.cur_height - initial_geometry.y -
		  height - 2 * RTLib_border_width();
	else
	     stash->desired_y = initial_geometry.y;

	/* Now make sure it's totally on-screen */

	on_screen(stash);
	
	/*
	 * fiddle a bit with stash->desired_x; we want it to be to the
	 * right of the icon window.
	 */
	RTLib_Set_Initial_Geometry(stash);
	current_x = LEFT_MARGIN;
	current_y = stash->cur_height - (fontheight / 2);

	/* set the "name" of the window, for the icon */
	stash->win_name = "Word Window";
	
	/* 1024 characters ought to be enough for any word */
	curword = wwindows.definition = malloc((unsigned) sizeof(char *)
					      * BUFSIZ);
	if (curword == (char *) NULL)
		memerror();
	
	RTLib_Create_Window(stash);
	RTLib_Set_Properties((char **) NULL, 0, stash, (Pixmap *) NULL, True);

	XSelectInput(dpy, stash->win, ExposureMask |
		     StructureNotifyMask | ButtonPressMask |
		     ButtonReleaseMask | KeyPressMask);
	XMapWindow(dpy, stash->win);
	XDrawString(dpy, stash->win, gc, current_x, current_y,
		    PROMPT, PROMPTLEN);
	current_x = LEFT_MARGIN + (PROMPTLEN * fontwidth);
}


Webster_Create_Icon(argc, argv)
int argc;
char **argv;
{
     Pixmap iconpix;

     /* Get the geometry parameters specified on the command line */
     RTLib_Get_Initial_Geometry(&initial_geometry.x,
				&initial_geometry.y,
				&initial_geometry.xneg,
				&initial_geometry.yneg);
     
     /* used as the icon window's tile and icon */
     iconpix = RTLib_Create_Pixmap(closed_bits, (unsigned int) closed_width,
				   (unsigned int) closed_height);

     /* Deal with the default initial geometry */

     /* make the icon window exactly the size of its tile */

     icons.min_width = icons.desired_width = closed_width;
     icons.min_height = icons.desired_height = closed_height;

     if (initial_geometry.xneg)
	  icons.desired_x = parents.cur_width - icons.desired_width -
	       2 * RTLib_border_width() - initial_geometry.x;
     else
	  icons.desired_x = initial_geometry.x;

     if (initial_geometry.yneg)
	  icons.desired_y = parents.cur_height - icons.desired_height -
	       2 * RTLib_border_width() - initial_geometry.y;
     else
	  icons.desired_y = initial_geometry.y;

     /* Make sure it stays on screen */

     if ((icons.desired_x + icons.desired_width + 2 * RTLib_border_width())
	 > parents.cur_width) {
	  icons.desired_x = parents.cur_width - icons.min_width -
	       2 * RTLib_border_width();
	  icons.desired_width = icons.min_width;
	  if (initial_geometry.xneg)
	       initial_geometry.x = 0;
	  else
	       initial_geometry.x = icons.desired_x;
     }
     if ((icons.desired_y + icons.desired_height + 2 * RTLib_border_width())
	 > parents.cur_height) {
	  icons.desired_y = parents.cur_height - icons.min_height -
	       2 * RTLib_border_width();
	  icons.desired_height = icons.min_height;
	  if (initial_geometry.yneg)
	       initial_geometry.y = 0;
	  else
	       initial_geometry.y = icons.desired_y;
     }
     
     if (icons.desired_x < 0) {
	  icons.desired_x = 0;
	  icons.desired_width = icons.min_width;
	  if (initial_geometry.xneg)
	       initial_geometry.x = parents.cur_width -
		    icons.desired_x - 2 * RTLib_border_width();
	  else
	       initial_geometry.x = 0;
     }
     if (icons.desired_y < 0) {
	  icons.desired_y = 0;
	  icons.desired_height = icons.min_height;
	  if (initial_geometry.yneg)
	       initial_geometry.y = parents.cur_height -
		    icons.desired_y - 2 * RTLib_border_width();
	  else
	       initial_geometry.y = 0;
     }
     
     RTLib_Set_Initial_Geometry(&icons);
     RTLib_Create_Window(&icons);
     RTLib_Set_Properties(argv, argc, &icons, &iconpix, False);

     XSetWindowBackgroundPixmap(dpy, icons.win, iconpix);
}
