[crossfire] [PATCH (big)] Basic X11 client overhaul

Edgar Toernig froese at gmx.de
Sun Mar 12 12:21:42 CST 2006


Hi all!

The standard font in the basic X11 client (8x13) was too small
for my taste and when trying to use a bigger one I noticed, that
this is not really supported.  I decided to fix that.

What started as a simple patch to support arbitrary font sizes
became a major overhaul of the drawing routines of clclient.
The resulting features: arbitrary font sizes, proper window
resizing, dedicated input box with history, non-square map
sizes, sorted resistancies/skills, X11 window classes, and a
couple of minor tweaks.  On the way I cleaned up the code a
little bit.

As far as I can tell, the only lost feature is the non-scrolling
info window.  The patch shouldn't break anything - if it does,
holler.

Sorry that the patch got that big.

Ciao, ET.

PS: At the moment I'm reading the ml via gmane.  mailman.metalforge.org
    seems to be down.


 common/client.c   |   10
 common/commands.c |   20
 common/external.h |    1
 common/p_cmd.c    |    2
 x11/xutil.c       |    8
 x11/x11.h         |    2
 x11/x11proto.h    |    3
 x11/x11.c         | 2289 +++++++++++++++++++-------------------------
 8 files changed, 1051 insertions(+), 1284 deletions(-)


diff -rup crossfire-client-1.9.0-orig/common/client.c crossfire-client-1.9.0/common/client.c
--- crossfire-client-1.9.0-orig/common/client.c	2006-02-26 08:45:46 +0100
+++ crossfire-client-1.9.0/common/client.c	2006-03-02 02:01:01 +0100
@@ -61,11 +61,11 @@ Client_Player cpl;
 ClientSocket csocket;
 
 const char *const resists_name[NUM_RESISTS] = {
-"armor", "magic", "fire", "elec",
-"cold", "conf", "acid", "drain",
-"ghit", "pois", "slow", "para",
-"t undead", "fear", "depl","death",
-"hword", "blind"};
+"Armor", "Magic", "Fire", "Elec",
+"Cold", "Conf", "Acid", "Drain",
+"GhHit", "Pois", "Slow", "Para",
+"TUnd", "Fear", "Depl","Death",
+"HWord", "Blind"};
 
 typedef void (*CmdProc)(unsigned char *, int len);
 
diff -rup crossfire-client-1.9.0-orig/common/commands.c crossfire-client-1.9.0/common/commands.c
--- crossfire-client-1.9.0-orig/common/commands.c	2006-02-26 08:45:46 +0100
+++ crossfire-client-1.9.0/common/commands.c	2006-03-09 20:06:18 +0100
@@ -442,13 +442,11 @@ void DrawInfoCmd(char *data, int len)
 	LOG(LOG_WARNING,"common::DrawInfoCmd","got no data");
 	buf="";
     }
-    else buf++;
-    if (color!=NDI_BLACK)
-	draw_color_info(color, buf);
     else
-	draw_info(buf,NDI_BLACK);
-
+	buf++;
+    draw_info(buf, color);
 }
+
 TextManager* firstTextManager = NULL;
 
 void setTextManager(int type, ExtTextManager callback){
@@ -634,7 +632,7 @@ void StatsCmd(unsigned char *data, int l
 
 void handle_query (char *data, int len)
 {
-    char *buf,*cp;
+    char *buf,*cp=0;
     uint8 flags = atoi(data);
 
     (void)len; /* __UNUSED__ */
@@ -649,16 +647,16 @@ void handle_query (char *data, int len)
 
     /* The actual text is optional */
     buf = strchr(data,' ');
-    if (buf) buf++;
 
     /* If we just get passed an empty string, why draw this? */
     if (buf) {
-	cp = buf;
+	cp = ++buf;
 	while ((buf=strchr(buf,'\n'))!=NULL) {
 	    *buf++='\0';
 	    draw_info(cp, NDI_BLACK);
 	    cp = buf;
 	}
+    }
     /* Yes/no - don't do anything with it now */
     if (flags & CS_QUERY_YESNO) {}
 
@@ -668,10 +666,10 @@ void handle_query (char *data, int len)
     else
 	cpl.input_state = Reply_Many;
 
-    if (cp) draw_prompt(cp);
-    }
+    cpl.input_text[0] = 0;
+    draw_prompt(cp ? cp : "");
 
-      LOG(0,"commands.c","Received query.  Input state now %d\n", cpl.input_state);
+    LOG(0,"commands.c","Received query.  Input state now %d\n", cpl.input_state);
 }
 
 /* Sends a reply to the server.  text contains the null terminated
diff -rup crossfire-client-1.9.0-orig/common/external.h crossfire-client-1.9.0/common/external.h
--- crossfire-client-1.9.0-orig/common/external.h	2006-02-19 04:26:53 +0100
+++ crossfire-client-1.9.0/common/external.h	2006-03-09 20:07:33 +0100
@@ -46,7 +46,6 @@ extern void draw_magic_map(void);
 
 /* Info related functions */
 extern void draw_info(const char *str, int color);
-extern void draw_color_info(int colr, const char *buf);
 extern void draw_prompt(const char *str);
 extern void x_set_echo(void);
 extern void set_scroll(const char *s);
diff -rup crossfire-client-1.9.0-orig/common/p_cmd.c crossfire-client-1.9.0/common/p_cmd.c
--- crossfire-client-1.9.0-orig/common/p_cmd.c	2006-02-19 04:26:53 +0100
+++ crossfire-client-1.9.0/common/p_cmd.c	2006-03-02 02:01:15 +0100
@@ -405,7 +405,7 @@ static void do_resist(const char * ignor
         int i;
         char buf[256];
         for (i=0; i<NUM_RESISTS; i++) {
-            sprintf(buf,"%-20s %+4d",
+            sprintf(buf,"%-10s %+4d",
                     resists_name[i], cpl.stats.resists[i]);
             draw_info(buf, NDI_BLACK);
         }
diff -rup crossfire-client-1.9.0-orig/x11/xutil.c crossfire-client-1.9.0/x11/xutil.c
--- crossfire-client-1.9.0-orig/x11/xutil.c	2006-02-26 08:45:47 +0100
+++ crossfire-client-1.9.0/x11/xutil.c	2006-03-12 16:14:23 +0100
@@ -419,7 +419,7 @@ void parse_keybind_line(char *buf, int l
          * it may be able to use it in the future.  As such, don't throw
          * it away, but at least print a warning message.
          */
-        if (keycode==0) {
+        if (0) if (keycode==0) {
 	    LOG(LOG_WARNING,"x11::parse_keybind_line","could not convert keysym %s into keycode, ignoring",
 		buf);
 	}
@@ -584,9 +584,10 @@ void parse_key(char key, KeyCode keycode
     char buf[MAX_BUF];
 
     if (keycode == commandkey && keysym==commandkeysym) {
-	draw_prompt(">");
 	cpl.input_state = Command_Mode;
+	cpl.input_text[0] = 0;
 	cpl.no_echo=FALSE;
+	draw_prompt(">");
 	return;
     }
     if (keycode == firekey[0] || keysym==firekeysym[0] ||
@@ -640,8 +641,7 @@ void parse_key(char key, KeyCode keycode
    	    gtk_entry_set_text(GTK_ENTRY(entrytext),buf);
 	    gtk_widget_grab_focus (GTK_WIDGET(entrytext));
 #else
-	    sprintf(buf,">%s", cpl.input_text);
-	    draw_prompt(buf);
+	    draw_prompt(">");
 #endif
 	    return;
 	}
diff -rup crossfire-client-1.9.0-orig/x11/x11.h crossfire-client-1.9.0/x11/x11.h
--- crossfire-client-1.9.0-orig/x11/x11.h	2005-09-06 08:39:17 +0200
+++ crossfire-client-1.9.0/x11/x11.h	2006-03-07 19:53:13 +0100
@@ -40,7 +40,7 @@ struct PixmapInfo {
 
 extern struct PixmapInfo *pixmaps[MAXPIXMAPNUM];
 extern Display *display;
-extern uint8   image_size;
+extern int image_size;
 extern Window win_root,win_game;
 extern GC gc_game;
 extern Colormap colormap;
diff -rup crossfire-client-1.9.0-orig/x11/x11proto.h crossfire-client-1.9.0/x11/x11proto.h
--- crossfire-client-1.9.0-orig/x11/x11proto.h	2006-02-15 09:03:14 +0100
+++ crossfire-client-1.9.0/x11/x11proto.h	2006-03-09 20:07:11 +0100
@@ -15,10 +15,8 @@ extern void SoundCmd(unsigned char *data
 extern int error_handler(Display *dp, XErrorEvent *xe);
 extern void event_loop(void);
 extern void end_windows(void);
-extern void write_ch(char key);
 extern void draw_prompt(const char *str);
 extern void draw_info(const char *str, int color);
-extern void draw_color_info(int colr, const char *buf);
 extern void draw_stats(int redraw);
 extern void draw_message_window(int redraw);
 extern void open_container(item *op);
@@ -40,7 +38,6 @@ extern void x_set_echo(void);
 extern void display_map_doneupdate(int redraw, int notice);
 extern int display_mapscroll(int dx, int dy);
 extern int associate_cache_entry(Cache_Entry *ce, int pixnum);
-extern void redisplay_stats(void);
 extern void display_map_startupdate(void);
 extern void draw_magic_map(void);
 extern void magic_map_flash_pos(void);
diff -rup crossfire-client-1.9.0-orig/x11/x11.c crossfire-client-1.9.0/x11/x11.c
--- crossfire-client-1.9.0-orig/x11/x11.c	2006-02-26 08:45:47 +0100
+++ crossfire-client-1.9.0/x11/x11.c	2006-03-12 17:57:57 +0100
@@ -37,6 +37,7 @@ const char *rcsid_x11_x11_c =
  */
 
 #define X_PROG_NAME "cfclient"
+#define X_CLASS "CFClient"
 
 /* Most functions in this file are private.  Here is a list of
  * the global functions:
@@ -83,6 +84,7 @@ const char *rcsid_x11_x11_c =
 
 #include <X11/Xlib.h>
 #include <X11/Xutil.h>
+#include <X11/keysym.h>
 
 #include "mapdata.h"
 #include "x11proto.h"
@@ -120,126 +122,137 @@ typedef struct {
     GC gc_icon;
     GC gc_status;
 
-    uint8 show_icon:1;	  /* show status icons */
-    uint8 show_weight:1;  /* show item's weight */
+    int show_icon:1;	  /* show status icons */
+    int show_weight:1;	  /* show item's weight */
 
     char format_nw[20];	  /* sprintf-format for text (name and weight) */
     char format_nwl[20];  /* sprintf-format for text (name, weight, limit) */
     char format_n[20];	  /* sprintf-format for text (only name) */
-    sint16 text_len;	  /* How wide the text-field is */
 
-    sint16 width;	  /* How wide the window is in pixels */
-    sint16 height;	  /* How height the window is in pixels */
+    int width;		  /* How wide the window is in pixels */
+    int height;		  /* How height the window is in pixels */
 
-    sint16 item_pos;	  /* The sequence number of the first drawn item */
-    sint16 item_used;	  /* How many items actually drawn. (0 - size) */
+    int item_pos;	  /* The sequence number of the first drawn item */
+    int item_used;	  /* How many items actually drawn. (0 - size) */
 
-    sint16 size;	  /* How many items there is room to display */
-    sint16 *faces;	  /* [size] */
-    sint8 *icon1;	  /* status icon : locked */
-    sint8 *icon2;	  /* status icon : applied / unpaid */
-    sint8 *icon3;	  /* status icon : magic */
-    sint8 *icon4;	  /* status icon : damned / cursed */
+    int size;		  /* How many items there is room to display */
+    int *faces;		  /* [size] */
+    char *icon1;	  /* status icon : locked */
+    char *icon2;	  /* status icon : applied / unpaid */
+    char *icon3;	  /* status icon : magic */
+    char *icon4;	  /* status icon : damned / cursed */
     char **names;	  /* [size][NAME_LEN] */
 
     /* The scrollbar */
-    sint16 bar_length; 	  /* the length of scrollbar in pixels */
-    sint16 bar_size;	  /* the current size of scrollbar in pixels */
-    sint16 bar_pos;	  /* the starting position of scrollbar in pixels */
+    int bar_length; 	  /* the length of scrollbar in pixels */
+    int bar_size;	  /* the current size of scrollbar in pixels */
+    int bar_y;		  /* the starting position of scrollbar in pixels */
+
     inventory_show show_what;	/* What to show in inventory */
-    uint32  weight_limit;   /* Weight limit for this list - used for title */
+    int weight_limit;	  /* Weight limit for this list - used for title */
 } itemlist;
 
-int noautorepeat = FALSE;	/* turn off autorepeat detection */
-
-static char *font_name="8x13",	**gargv;
-
-#define SCROLLBAR_WIDTH	16	/* +2+2 for border on each side */
-#define INFOCHARS 50
-#define INFOLINES 36
-/* Perhaps decent defaults, but not quite right */
-static int  FONTWIDTH= 8;
-static int FONTHEIGHT= 13;
-#define MAX_INFO_WIDTH 80
-#define MAXNAMELENGTH 50
-
 /* What follows is various constants (or calculations) for various
  * window sizes.
  */
 
-/* Width (and height) of the game window */
-#define GAME_WIDTH  (image_size * use_config[CONFIG_MAPWIDTH] + 5)
+#define GAP	3	/* spacing between windows */
+#define BW	3	/* internal border width */
+
+#define SCROLLBAR_WIDTH	14	/* total width including border */
+
+/* status bars (+2 for each border) */
+#define BAR_WIDTH	10
+#define BAR_HEIGHT	(MSG_HEIGHT - BW - BW - 4)
+#define BAR_TOTAL_WIDTH	(FONT_WIDTH + 2 + BAR_WIDTH+4 + FONT_WIDTH)
+
+static int FONT_WIDTH = 8;
+static int FONT_HEIGHT = 13;
+static int FONT_BASE = 13; /* offset from top to baseline - aka ascent */
+
+#define GAME_WIDTH  (image_size * use_config[CONFIG_MAPWIDTH])
+#define GAME_HEIGHT  (image_size * use_config[CONFIG_MAPHEIGHT])
+
+#define STAT_HEIGHT	(BW + 10 * FONT_HEIGHT + BW)
+#define STAT_WIDTH	(BW + 29 * FONT_WIDTH + BW)
+
+#define MSG_HEIGHT	(BW + 5*FONT_HEIGHT + BW)
+#define MSG_WIDTH	(BW + 4*BAR_TOTAL_WIDTH + 16*FONT_WIDTH + BW)
+
+#define INPUT_HEIGHT	(1 + BW + FONT_HEIGHT + BW)
+
+#define INFO_WIDTH	(BW + 50*FONT_WIDTH + BW)
+#define INFO_HEIGHT	(STAT_HEIGHT + GAP + GAME_HEIGHT + GAP + MSG_HEIGHT)
+#define INFO_CHARS	80	/* max chars per line */
 
-#define STAT_HEIGHT 140
 
 /* Width of the inventory and look window */
-#define INV_WIDTH   300
-/* spacing between windows */
-#define WINDOW_SPACING	3
-/* Height of the master (root) window */
-#define ROOT_HEIGHT	522
+#define INV_WIDTH (BW + image_size + 24 + 21*FONT_WIDTH + BW+SCROLLBAR_WIDTH+BW)
 
-static int gargc, old_mapx=11, old_mapy=11;
+static int gargc;
+static char **gargv;
+
+static int noautorepeat = FALSE;	/* turn off autorepeat detection */
+
+static char *font_name="8x13";
+
+static int old_mapx=11, old_mapy=11;
 
 Display *display;
 static Window def_root;	/* default root window */
 static long def_screen;	/* default screen number */
 static unsigned long foreground,background;
-Window win_stats,win_message;
-Window win_root,win_game;
+static Window win_stats, win_message;
+Window win_root, win_game;
 Colormap colormap;
 static XColor discolor[16];
 static XFontStruct *font;	/* Font loaded to display in the windows */
 static XEvent event;
-static XSizeHints messagehint, roothint;
+static XSizeHints roothint;
 static Atom wm_delete_window;
 
 /* This struct contains the information to draw 1 line of data. */
 typedef struct {
-    char	*info;		/* Actual character data for a line */
-    uint8	color;		/* Color to draw that line */
+    char	text[INFO_CHARS+1];	/* Actual character data for a line */
+    uint8	color;			/* Color to draw that line */
 } InfoLine;
 
 /* This contains all other information for the info window */
 typedef struct {
-    uint16	info_chars;	/* width in chars of info window */
-    uint16	max_info_chars;	/* Max value of info_chars */
-    uint16	infopos;	/* Where in the info arry to put new data */
-    uint16	infoline;	/* Where on the window to draw the line */
-    uint16	scroll_info_window:1;  /* True if we should scroll the window */
-    uint16	numlines;	/* How many have been stored the array */
-    uint16	maxlines;	/* Maxlines (how large the array below is) */
-    uint16	maxdisp;	/* How many lines can be displayed at once */
-    uint8	lastcolor;	/* Last color text was drawn in */
-    InfoLine	*data;		/* An array of lines */
-    Window	win_info;	/* Actual info window */
-    GC		gc_info;	/* GC for this window */
+    int	width,height;	/* width and height of window (pixels) */
+    int cwidth, cheight;/* width and height in characters */
+    int lines;		/* number of lines in line[] */
+    int pos;		/* 'current' line in line[], always at bottom of win */
+    InfoLine *line;	/* An array of lines */
+
+    Window win;		/* Actual info window */
+    GC gc;		/* GC for this window */
+
     /* The scrollbar */
-    sint16 bar_length; 	  /* the max length of scrollbar in pixels */
-    sint16 bar_size;	  /* the current size (length) of scrollbar in pixels */
-    sint16 bar_pos;	  /* the starting position of scrollbar.  This is
-			   * an offset, which is the number of lines from
-			   * 0 for the text to end out.*/
-    sint16 bar_y;	  /* X starting position of scrollbar */
-    uint16	has_scrollbar:1;/* True if there is a scrollbar in the window */
-    sint16	width,height; /* Width and height of window */
+    int bar_length;	/* the max length of scrollbar in pixels */
+    int bar_pos;	/* when bar_pos==pos bar is at the bottom */
+
+    char prompt[INFO_CHARS+1];	/* the current prompt */
 } InfoData;
 
-InfoData infodata = {0, 0, 0, 0, 0, 0, INFOLINES, INFOLINES, NDI_BLACK,
-	NULL, 0, 0,0,0,0,0,0,0,0};
+static InfoData info;
 
-uint8	image_size=24;
+#define HISTORY_SIZE	100	/* number of history lines */
+static struct {
+    int pos;
+    char *line[HISTORY_SIZE];
+} history;
 
 
+int	image_size=24;
 
-static char stats_buff[7][600];
 struct PixmapInfo *pixmaps[MAXPIXMAPNUM];
+
 /* Off the 'free' space in the window, this floating number is the
  * portion that the info takes up.
  */
 static float info_ratio=0;
 
-#define INFOLINELEN 500
 #define XPMGCS 100
 
 enum {
@@ -262,11 +275,31 @@ static GC gc_copy;		/* used for copying 
 static itemlist look_list, inv_list;
 
 /* Used to know what stats has changed */
-static Stats last_stats = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+static Stats last_stats;
+
+/*********************************************************************/
 
-/* info win */
-#define INFOCHARS 50
+static void *
+xmalloc(size_t size)
+{
+    void *x;
 
+    x = malloc(size ? size : 1);
+    if (x)
+	return x;
+    fprintf(stderr, "Not enough memory to allocate %ud bytes\n", size);
+    exit(1);
+}
+
+/* XDrawRectangle draws to x+w/y+h inclusive - not what one expects. */
+#define DrawRectangle(dpy, d, gc, x, y, w, h) \
+		    XDrawRectangle((dpy), (d), (gc), (x), (y), (w)-1, (h)-1)
+
+static void
+DrawText(Drawable d, GC gc, int x, int y, const char *str)
+{
+    XDrawImageString(display, d, gc, x, y + FONT_BASE, str, strlen(str));
+}
 
 /* This is the loop that the client goes through once all the
  * initialization is done.  Basically, it checks for input and
@@ -278,8 +311,6 @@ static Stats last_stats = {0,0,0,0,0,0,0
  * check_x_events takes all the events that are waiting.
  */
 
-extern int maxfd;
-
 /* Handle errors.  I really needed this when debugging
  * the crashes with the big image stuff - I need to know
  * what function is causing the crash.
@@ -301,6 +332,7 @@ int error_handler(Display *dp, XErrorEve
 void event_loop()
 {
     fd_set tmp_read;
+    int maxfd;
     int pollret;
     struct timeval timeout;
 
@@ -311,7 +343,8 @@ void event_loop()
     }
     maxfd = csocket.fd + 1;
     while (1) {
-	if (csocket.fd==-1) return;
+	if (csocket.fd==-1)
+	    return;
 
 	/* Do a quick check here for better performance */
 	check_x_events();
@@ -368,7 +401,7 @@ static void gen_draw_face(Drawable where
 	total++;
 	mask = pixmaps[face]->mask;
 	/* Lets see if we can find a stored mask with matching gc */
-	for(gcnum=0;gcnum<XPMGCS;gcnum++) {
+	for (gcnum=0;gcnum<XPMGCS;gcnum++) {
 	    if (xpm_masks[gcnum] == mask)
 		break;
 	}
@@ -384,7 +417,7 @@ static void gen_draw_face(Drawable where
 	 * at position 0.  Thus, the one in the last position was the least
 	 * used entry
 	 */
-	for(i=gcnum-1;i>=0;i--) {
+	for (i=gcnum-1;i>=0;i--) {
 	    xpm_masks[i+1] = xpm_masks[i];
 	    gc_xpm[i+1] = gc_xpm[i];
 	}
@@ -406,7 +439,7 @@ void end_windows()
     XFreeGC(display, gc_game);
     XFreeGC(display, gc_copy);
     XFreeGC(display, gc_stats);
-    XFreeGC(display, infodata.gc_info);
+    XFreeGC(display, info.gc);
     XFreeGC(display, inv_list.gc_text);
     XFreeGC(display, inv_list.gc_icon);
     XFreeGC(display, inv_list.gc_status);
@@ -431,20 +464,18 @@ void end_windows()
 
 static int get_game_display(void) {
     XSizeHints gamehint;
+    XClassHint classhint;
     int i;
    
-    gamehint.x=INV_WIDTH + WINDOW_SPACING;
-    gamehint.y=STAT_HEIGHT + WINDOW_SPACING;
-
-    gamehint.width=GAME_WIDTH;
-    gamehint.height=gamehint.width;
-
-    gamehint.max_width=gamehint.min_width=gamehint.width;
-    gamehint.max_height=gamehint.min_height=gamehint.height;
+    gamehint.x = INV_WIDTH + GAP;
+    gamehint.y = STAT_HEIGHT + GAP;
+    gamehint.width = GAME_WIDTH;
+    gamehint.height = GAME_HEIGHT;
     gamehint.flags=PPosition | PSize;
+
     win_game=XCreateSimpleWindow(display,win_root,
-	gamehint.x,gamehint.y,gamehint.width,gamehint.height,2,
-	background,foreground);
+	gamehint.x,gamehint.y,gamehint.width,gamehint.height,0,
+	foreground,foreground);
     icon=XCreateBitmapFromData(display,win_game,
 	(_Xconst char *) crossfire_bits,
 	(unsigned int) crossfire_width, (unsigned int)crossfire_height);
@@ -456,8 +487,11 @@ static int get_game_display(void) {
     } else
 	XSetWindowColormap(display, win_game, colormap);
 
-    XSetStandardProperties(display,win_game,X_PROG_NAME, X_PROG_NAME,
-	icon,gargv,gargc, &(gamehint));
+    XSetStandardProperties(display,win_game,"Crossfire - map", "crossmap",
+			   icon,gargv,gargc, &gamehint);
+    classhint.res_name = "map";
+    classhint.res_class = X_CLASS;
+    XSetClassHint(display, win_game, &classhint);
 
     gc_game=XCreateGC(display,win_game,0,0);
     XSetForeground(display,gc_game,discolor[0].pixel);
@@ -465,7 +499,7 @@ static int get_game_display(void) {
 
     XSetGraphicsExposures(display, gc_game, False);
     gc_copy=XCreateGC(display,win_game,0,0);
-    XSetGraphicsExposures(display, gc_game, True);
+    XSetGraphicsExposures(display, gc_copy, True);
     gc_floor = XCreateGC(display,win_game,0,0);
     XSetGraphicsExposures(display, gc_floor, False);
     gc_blank = XCreateGC(display,win_game,0,0);
@@ -502,599 +536,300 @@ static int get_game_display(void) {
 
 static int get_info_display(void) {
     XSizeHints infohint;
+    XClassHint classhint;
     int i;
 
-    /* The following could happen if bad values are given. */
-    if (infodata.maxlines<INFOLINES) infodata.maxlines=INFOLINES;
-    infohint.x=INV_WIDTH + GAME_WIDTH + WINDOW_SPACING*2;
-    infohint.y=0;
-    infohint.width=infodata.width=6+INFOCHARS*FONTWIDTH;
-    infohint.height=infodata.height=roothint.height;
-    infodata.maxdisp = roothint.height/FONTHEIGHT;
-
-    infohint.min_width=100;
-    infohint.min_height=30;
+    infohint.x = INV_WIDTH + GAP + GAME_WIDTH + GAP;
+    infohint.y = 0;
+    infohint.width = info.width = INFO_WIDTH;
+    infohint.height = info.height = INFO_HEIGHT;
     infohint.flags=PPosition | PSize;
-    infodata.win_info=XCreateSimpleWindow(display, win_root,
-	infohint.x,infohint.y,infohint.width,infohint.height,2,
+
+    info.win=XCreateSimpleWindow(display, win_root,
+	infohint.x,infohint.y,infohint.width,infohint.height,0,
 	foreground,background);
-    XSetWindowColormap(display, infodata.win_info, colormap);
-    icon=XCreateBitmapFromData(display,infodata.win_info,
+    XSetWindowColormap(display, info.win, colormap);
+    icon=XCreateBitmapFromData(display,info.win,
 	(_Xconst char *) crossfire_bits,
 	(unsigned int) crossfire_width, (unsigned int)crossfire_height);
-    XSetStandardProperties(display,infodata.win_info,"Crossfire - text",
+    XSetStandardProperties(display,info.win,"Crossfire - text",
 	"Crosstext",icon,gargv,gargc,&(infohint));
-    infodata.gc_info=XCreateGC(display,infodata.win_info,0,0);
-    XSetForeground(display,infodata.gc_info,foreground);
-    XSetBackground(display,infodata.gc_info,background);
+    classhint.res_name = "text";
+    classhint.res_class = X_CLASS;
+    XSetClassHint(display, info.win, &classhint);
 
-    XSetFont(display,infodata.gc_info,font->fid);
+    info.gc=XCreateGC(display,info.win,0,0);
+    XSetForeground(display,info.gc,foreground);
+    XSetBackground(display,info.gc,background);
 
-    XSelectInput(display,infodata.win_info,
+    XSetFont(display,info.gc,font->fid);
+
+    XSelectInput(display,info.win,
 	ButtonPressMask|KeyPressMask|KeyReleaseMask|ExposureMask|
 	StructureNotifyMask);
-    XSetWMProtocols(display, infodata.win_info, &wm_delete_window, 1);
-    XMapRaised(display,infodata.win_info);
-    if (infodata.maxlines>infodata.maxdisp) infodata.has_scrollbar=1;
-    infodata.info_chars = (infohint.width/FONTWIDTH)-1;
-    if (infodata.has_scrollbar) infodata.info_chars -=3;
-    infodata.max_info_chars=infodata.info_chars;
-    infodata.data=(InfoLine *) malloc(sizeof(InfoLine) * infodata.maxlines);
-    infodata.bar_length=infodata.height - 8;
-    for (i=0; i<infodata.maxlines; i++) {
-	infodata.data[i].info = malloc(sizeof(char)* (infodata.info_chars+1));
-	infodata.data[i].info[0]='\0';
-	infodata.data[i].color=0;
+    XSetWMProtocols(display, info.win, &wm_delete_window, 1);
+    XMapRaised(display,info.win);
+
+    info.bar_length = info.height-BW-BW-INPUT_HEIGHT-4;
+    info.cheight = (info.height-BW-BW-INPUT_HEIGHT) / FONT_HEIGHT;
+    info.cwidth = (info.width-BW-BW-SCROLLBAR_WIDTH-BW)/FONT_WIDTH;
+    if (info.cwidth > INFO_CHARS)
+	info.cwidth = INFO_CHARS;
+
+    if (info.lines < 4*info.cheight)
+	info.lines = 4*info.cheight;
+    info.line = xmalloc(sizeof(InfoLine) * info.lines);
+    for (i=0; i<info.lines; i++) {
+	info.line[i].text[0] = '\0';
+	info.line[i].text[INFO_CHARS] = '\0';
+	info.line[i].color = 0;
     }
+    info.pos = info.bar_pos = 0;
 
     return 0;
 }
 
-static void delete_ch(void) {
-    if(strlen(cpl.input_text)==0)
-	return;
-    cpl.input_text[strlen(cpl.input_text)-1] = '\0';
+static int
+DrawInfoText(int y, const char *str)
+{
+    int l = strlen(str);
 
-    /* If not on the first line but backspacing to the front, we need to
-     * do some special handling.
-     */
-    if ((strlen(cpl.input_text)>3) &&
-      strlen(infodata.data[infodata.infopos].info)<3) {
-        int line=infodata.infopos-1;
-        if (line<0) line=infodata.numlines;
-        strcpy(infodata.data[infodata.infopos].info, 
-	       infodata.data[line].info);
-        infodata.data[infodata.infopos].info[
-	    strlen(infodata.data[infodata.infopos].info)-1]=0;
-	XDrawImageString(display,infodata.win_info,infodata.gc_info,
-		FONTWIDTH, (infodata.infoline+1)*FONTHEIGHT,
-		infodata.data[infodata.infopos].info,
-		strlen(infodata.data[infodata.infopos].info));
-    } else {
-        infodata.data[infodata.infopos].info[
-	    strlen(infodata.data[infodata.infopos].info)-1]=0;
-	XDrawImageString(display,infodata.win_info,infodata.gc_info,
-		(strlen(infodata.data[infodata.infopos].info)+1)*FONTWIDTH,
-		(infodata.infoline+1)*FONTHEIGHT," ",1);
-    }
+    if (l > info.cwidth) /* clip to avoid overwriting scroll bar */
+	l = info.cwidth;
+    XDrawImageString(display, info.win, info.gc,
+			BW, BW + FONT_BASE + y*FONT_HEIGHT, str, l);
+    return l * FONT_WIDTH;
 }
 
-/* Writes one character to the screen.  Used when player is typing
- * stuff we that we want to appear, or used to give prompts.
- */
-
-void write_ch(char key)
+static void
+DrawInput(void)
 {
-    char c2[2];
+    int x = BW;
+    int y = info.height - BW - FONT_HEIGHT;
+    int width = (info.width - BW - BW) / FONT_WIDTH;
+    const char *str = cpl.input_text;
+    int l1 = strlen(info.prompt);
+    int l2 = strlen(str);
+    int o;
 
-    /* Sort of a gross hack, but this gets it so that we actually put
-     * the command into the buffer.
-     */
-    if (key==13) {
-        /* We turn off command mode for the draw_info call, because
-         * it has special handling for normal output during command
-         * mode; but we do this manually now. 
-	 */
-        Input_State old_state = cpl.input_state;
-        cpl.input_state = Playing;
-	draw_info(infodata.data[infodata.infopos].info,NDI_BLACK);
-        cpl.input_state = old_state;
-	return;
-    }
-
-    if (infodata.lastcolor!=NDI_BLACK) {
-	XSetForeground(display,infodata.gc_info,discolor[NDI_BLACK].pixel);
-	infodata.lastcolor=NDI_BLACK;
-    }
-
-    if (key == 9) { /* Tab */
-	const char *str = complete_command(infodata.data[infodata.infopos].info);
-
-	/* +1 so that we keep our > at start of line.  Don't
-	 * recopy the data on top of ourself.
-	 */
-	if (str != (infodata.data[infodata.infopos].info+1)) {
-	    strcpy(infodata.data[infodata.infopos].info+1, str);
-	    strcpy(cpl.input_text,str);
-	}
-    } else {
-
-	if ((key < 32 || (unsigned char) key > 127) && key != 8)
-	    return;
-	c2[0] = key;
-	c2[1] ='\0';
+    XSetForeground(display,info.gc,discolor[NDI_BLACK].pixel);
+    XDrawLine(display, info.win, info.gc,
+				    x, y-BW-1, info.width-BW-1, y-BW-1);
 
+    if (cpl.input_state != Metaserver_Select &&
+	cpl.input_state != Reply_One &&
+	cpl.input_state != Reply_Many &&
+	cpl.input_state != Command_Mode)
+	goto clear; 
 
-	if(key==8||key==127) {
-	    /* By backspacking enough, let them get out of command mode */
-	    if (cpl.input_text[0]=='\0' && cpl.input_state==Command_Mode) {
-		cpl.input_state=Playing;
-		/* Erase the prompt */
-		XDrawImageString(display,infodata.win_info,infodata.gc_info,
-				 FONTWIDTH,(infodata.infoline+1)*FONTHEIGHT," ",1);
-	    }
-	    delete_ch();
-	    return;
-	}
-	/* Give some leeway here */
-	if(strlen(cpl.input_text)>=(MAX_BUF-15))
-	    return;
-
-	strcat(cpl.input_text,c2);
+    if (cpl.no_echo) {
+	static const char noecho[] = "????????????????????????????????????????"
+				     "????????????????????????????????????????";
+	if (l2 > sizeof(noecho)-1)
+	    l2 = sizeof(noecho)-1;
+	str = noecho + sizeof(noecho)-1 - l2;
     }
-    
-    if(strlen(infodata.data[infodata.infopos].info)>=(infodata.info_chars-2)) {
-        /* Draw the currently line and scroll down one */
 
-        /* We turn off command mode for the draw_info call, because
-         * it has special handling for normal output during command
-         * mode; but we do this manually now. 
-	 */
-        cpl.input_state = Playing;
-	draw_info(infodata.data[infodata.infopos].info,NDI_BLACK);
-        cpl.input_state = Command_Mode;
-	infodata.data[infodata.infopos].info[0]=(((strlen(cpl.input_text)/ 
-	    infodata.info_chars))%10)+49;
-        infodata.data[infodata.infopos].info[1]='>';
-	infodata.data[infodata.infopos].info[2]=0;
-	XDrawImageString(display,infodata.win_info,infodata.gc_info,
-		FONTWIDTH,(infodata.infoline+1)*FONTHEIGHT,
-		infodata.data[infodata.infopos].info,
-		strlen(infodata.data[infodata.infopos].info));
+    o = l1 + l2 + 1 - width;
+    if (o < 0)
+	o = 0;
+    if (o < l1) {
+	XSetForeground(display, info.gc, discolor[NDI_NAVY].pixel);
+	DrawText(info.win, info.gc, x, y, info.prompt + o);
+	x += (l1 - o) * FONT_WIDTH;
+	o = l1;
     }
+    o -= l1;
+    if (o < l2) {
+	XSetForeground(display, info.gc, discolor[NDI_BLACK].pixel);
+	DrawText(info.win, info.gc, x, y, str + o);
+	x += (l2 - o) * FONT_WIDTH;
+    }
+    /*cursor*/
+    XSetForeground(display, info.gc, discolor[NDI_RED].pixel);
+    XFillRectangle(display, info.win, info.gc, x, y, 2, FONT_HEIGHT);
+    x += 2;
 
-    if (key != 9 ) strcat(infodata.data[infodata.infopos].info,(cpl.no_echo? "?": c2));
-
-    XDrawImageString(display,infodata.win_info,infodata.gc_info,
-	FONTWIDTH,(infodata.infoline+1)*FONTHEIGHT,
-	infodata.data[infodata.infopos].info,
-	strlen(infodata.data[infodata.infopos].info));
+  clear:
+    XClearArea(display, info.win, x, y, info.width-x, FONT_HEIGHT, False);
 }
 
-
-
-/* This is similar to draw_info below, but doesn't advance to a new
- * line.  Generally, queries use this function to draw the prompt for
- * the name, password, etc.
- * This also starts from character position 0.  Thus, only 1 call of this
- * per a given line is useful
- */
-
-void draw_prompt(const char *str)
+void
+draw_prompt(const char *str)
 {
-    if (infodata.lastcolor!=NDI_BLACK) {
-	XSetForeground(display,infodata.gc_info,discolor[NDI_BLACK].pixel);
-	infodata.lastcolor=NDI_BLACK;
-    }
-
-    strncpy(infodata.data[infodata.infopos].info,str,infodata.info_chars);
-    infodata.data[infodata.infopos].info[infodata.info_chars] = '\0';
-    infodata.data[infodata.infopos].color=NDI_BLACK;
-    XDrawImageString(display,infodata.win_info,
-	infodata.gc_info,FONTWIDTH,(infodata.infoline+1)*FONTHEIGHT,
-	infodata.data[infodata.infopos].info,
-	strlen(infodata.data[infodata.infopos].info));
+    strncpy(info.prompt, str, INFO_CHARS);
+    info.prompt[INFO_CHARS] = 0;
+    history.pos = 0;
+    DrawInput();
 }
 
-/* If redarew is true, draw the scrollbar no matter what */
-static void draw_info_scrollbar(int redraw)
+static void
+draw_info_scrollbar(int redraw)
 {
-    static int last_length=0, last_y=0;
+    static int last_size = -1, last_y = -1;
+    int pos, size, y;
 
-    if (!infodata.has_scrollbar) return;
+    pos = info.bar_pos - info.pos - info.cheight;
+    pos = (pos + 2*info.lines) % info.lines;
 
-    if (infodata.numlines <infodata.maxdisp) {
-	infodata.bar_size=infodata.bar_length;
-	infodata.bar_y=0;
-    }
-    else {
-	infodata.bar_size=infodata.bar_length*infodata.maxdisp/infodata.numlines;
-	infodata.bar_y=infodata.bar_length*(infodata.bar_pos-infodata.maxdisp)/infodata.numlines;
-	if (infodata.bar_y<0) infodata.bar_y=0;
-    }
-/*
-    if ((infodata.bar_size+infodata.bar_y)>infodata.bar_length) {
-	    infodata.bar_y=infodata.bar_length-infodata.bar_size;
-    }
-*/
-    if (!redraw && last_length==infodata.bar_size && last_y==infodata.bar_y) return;
+    size = (info.bar_length * info.cheight + info.lines-1) / info.lines;
+    y = info.bar_length * pos / info.lines;
 
-    last_y=infodata.bar_y;
-    last_length=infodata.bar_size;
+    if (size < 1)
+	size = 1;
 
-    /* Note - with the way this is set up, it wouldn't be too hard to make
-     * the scrollbar color customizable
-     */
-    if (infodata.lastcolor!=NDI_BLACK) {
-      XSetForeground(display,infodata.gc_info,discolor[NDI_BLACK].pixel);
-      infodata.lastcolor=NDI_BLACK;
-    }
-	
-    XDrawRectangle(display, infodata.win_info,
-	infodata.gc_info, infodata.width-SCROLLBAR_WIDTH-6,
-		   3, 20,
-		   infodata.height -6);
-    XClearArea(display, infodata.win_info, 
-		   infodata.width-SCROLLBAR_WIDTH-4, 4, 16, 
-		   infodata.bar_length, False);
-
-    XFillRectangle(display, infodata.win_info, infodata.gc_info,
-	infodata.width - SCROLLBAR_WIDTH-4,4+infodata.bar_y,
-	16, infodata.bar_size);
-}
+    if (!redraw && last_size == size && last_y == y)
+	return;
 
-/* draw_info adds a line to the info window. */
+    last_y = y;
+    last_size = size;
 
-void draw_info(const char *str, int color) {
-  char *cp;
-  uint16 new_infopos = (infodata.infopos+1)% infodata.maxlines ;
+    XSetForeground(display, info.gc, discolor[NDI_BLACK].pixel);
 
-  if(str == (char *) NULL) {
-    draw_info("[NULL]",color);
-    return;
-  }
+    DrawRectangle(display, info.win, info.gc,
+		   info.width-BW-SCROLLBAR_WIDTH, BW,
+		   SCROLLBAR_WIDTH, info.bar_length+4);
+    XClearArea(display, info.win, 
+		   info.width-BW-SCROLLBAR_WIDTH+2, BW+2,
+		   SCROLLBAR_WIDTH-4, info.bar_length, False);
+
+    XFillRectangle(display, info.win, info.gc,
+	info.width-BW-SCROLLBAR_WIDTH+2, BW+2+y,
+	SCROLLBAR_WIDTH-4, size);
+}
 
-  if((cp=strchr(str,'\n'))!=NULL) {
-    /* 4096 is probably way overkill, but 1024 could very well be too small.
-     * And I don't see the need to malloc and then free this either -
-     * this is a single user program.
-     */
-    char obuf[4096],*buf = obuf;
+/* draw_info adds a line to the info window. */
 
-    strncpy(buf,str, 4095);
-    do {
-      if ((cp = strchr(buf, '\n'))) {
-	*cp='\0';
-	draw_info(buf,color);
-	buf = cp +1;
-      } else
-	draw_info(buf,color);
-    } while (cp!=NULL);
-    return;
-  }
+void
+draw_info(const char *str, int color)
+{
+    char *p, buf[256];
+    InfoLine *lp;
+    int l;
 
-  /* Lets do the word wrap for messages - MSW */
-  if ((int)strlen(str) >= infodata.info_chars) {
-	int i=infodata.info_chars-1;
-
-	/* i=last space (or ')' for armor.  Wrap armor, because
-	otherwise, the two sets of ()() can be about half the line */
-	while ((str[--i]!=' ') && (str[i]!=')') && (i!=0)) ;
-	/* if i==0, string has no space.  Just let it be truncated */
-	if (i!=0) {
-	    char *buf = (char *)malloc(sizeof(char)*(i+2));
-	    int j;
-
-	    i++;	/* want to keep the ')'.  This also keeps
-			the space, but that really doesn't matter */
-	    strncpy(buf, str, i);
-	    buf[i]='\0';
-	    draw_info(buf,color);
-	    free(buf);
-
-	    for (j=i; j < (int)strlen(str); j++) /* if the wrap portion is */
-		if (str[j]!=' ') break;		/* only space, don't wrap it*/
-	    if ((((strlen(str)-i)!=1) || (str[i]!='.')) && (j!=strlen(str)))
-		draw_info((str+i),color);
-	    return;
+    if (str == NULL)
+	str = "[NULL]";
+
+    /* split lines */
+    while ((p = strchr(str,'\n'))) {
+	if (p - str < sizeof(buf)) {
+	  memcpy(buf, str, p - str);
+	  buf[p - str] = 0;
+	  draw_info(buf, color);
 	}
-  }
-  
-  /* This is the real code here - stuff above is just formating and making
-   * it look nice.  This stuff here is actually drawing the code
-   */
-
-  /* clear the new last line in window */
-  memset(infodata.data[new_infopos].info, 32, infodata.info_chars-1);
-  if(cpl.input_state == Command_Mode)
-  {
-      /* we copy the last command line to the new last line in window */
-      strcpy(infodata.data[new_infopos].info, infodata.data[infodata.infopos].info);
-  }
-  infodata.data[new_infopos].info[infodata.info_chars] = '\0';
-  
-  strncpy(infodata.data[infodata.infopos].info,str,infodata.info_chars);
-  infodata.data[infodata.infopos].info[infodata.info_chars] = '\0';
-  infodata.data[infodata.infopos].color=color;
-
-  /* This area is for scrollbar handling.  The first check is to see if
-   * the scrollbar is at the very end, if it is, then we don't care about this.
-   * IF not at the end, then see if it is at the end of the window.  If
-   * so, increase the bar position so that that view area keeps up with what
-   * is being drawn.  If we are not at the end of the buffer, then decrease
-   * the bar position - in this way, we keep the same viewable area visible
-   * for redraws.
-   *
-   * A couple notes:  If jump to end was desired on output, then this
-   * code just needs to be replaced with a line like infodata.bar_pos=
-   * infodata.numlines.
-   * If it is desired for the window to scroll up as new output is printed
-   * out, then the second case would need to be removed, and a draw_all_info
-   * call added instead.
-   */
-  if (infodata.bar_pos<infodata.maxlines) {
-	if (infodata.bar_pos==infodata.numlines) {
-		infodata.bar_pos++;
-	}
-	else if (infodata.numlines==infodata.maxlines) {
-	    infodata.bar_pos--;
-	    if (infodata.bar_pos<infodata.maxdisp)
-		infodata.bar_pos=infodata.maxdisp;
-	}
-  }
-  if (infodata.numlines<infodata.maxlines) infodata.numlines++;
-
-  /* Basically, if we don't have a scrollbar, or we are at the end of it,
-   * then do the drawing stuff, otherwise don't.
-   */
-  if (!infodata.has_scrollbar || infodata.bar_pos>=infodata.numlines) {
-    /*
-     * The XDrawImageString draws the line.
-     */
-    if (infodata.lastcolor!=color) {
-      XSetForeground(display,infodata.gc_info,discolor[color].pixel);
-      infodata.lastcolor=color;
+	str = p + 1;
     }
-  
-    XDrawImageString(display,infodata.win_info,
-      infodata.gc_info,FONTWIDTH,(infodata.infoline+1)*FONTHEIGHT,
-      infodata.data[infodata.infopos].info,
-      strlen(infodata.data[infodata.infopos].info));
 
-    /* Now it gets potentially more complicated - now we have to handle
-     * wrapping and stuff like that.
-     */
+    /* word wrap */
+    while (strlen(str) > info.cwidth) {
+	int i = info.cwidth;
 
-    if(++(infodata.infoline)>=infodata.maxdisp){
-      if (infodata.scroll_info_window) {
-  	XCopyArea(display,infodata.win_info,infodata.win_info,
-  	    infodata.gc_info,0,FONTHEIGHT,infodata.info_chars*FONTWIDTH,
-  	    infodata.maxdisp*FONTHEIGHT,0,0);
-  	infodata.infoline--;
-      }
-      else
-   	infodata.infoline=0;
-    }
-  }
+	/* split at last ' ' or ')' */
+	while (i && str[i] != ' ' && str[i-1] != ')')
+	    i--;
 
-  infodata.infopos = new_infopos;
+	if (i == 0) /* no split point -> hard break */
+	    i = info.cwidth;
 
-  if (!infodata.has_scrollbar || infodata.bar_pos>=infodata.numlines) {
-        if(cpl.input_state == Command_Mode)
-        {
-                uint8 endpos = strlen(infodata.data[infodata.infopos].info);
-
-                infodata.data[infodata.infopos].info[endpos] = ' ';
-                XDrawImageString(display,infodata.win_info,
-	        infodata.gc_info,FONTWIDTH,(infodata.infoline+1)*FONTHEIGHT,
-	        infodata.data[infodata.infopos].info, infodata.info_chars-1);
-                infodata.data[infodata.infopos].info[endpos] = '\0';
-        }
-        else
-        {
-                XDrawImageString(display,infodata.win_info,
-	        infodata.gc_info,FONTWIDTH,(infodata.infoline+1)*FONTHEIGHT,
-	        infodata.data[infodata.infopos].info, infodata.info_chars-1);
-        }
-  }
-
-  /* If in a reply state, grab the input buffer and store it.
-   */
-  if (cpl.input_state==Reply_Many) {
-    strncpy(infodata.data[infodata.infopos].info, cpl.input_text, 
-	    infodata.info_chars);
-    infodata.data[infodata.infopos].info[infodata.info_chars] = '\0';
-     
-    XDrawImageString(display,infodata.win_info,infodata.gc_info,
-	FONTWIDTH,(infodata.infoline+1)*FONTHEIGHT,
-	infodata.data[infodata.infopos].info, 
-	strlen(infodata.data[infodata.infopos].info));
-  }
-  /* We should have some intelligent checks so it is not drawn unnecessarily */
-  draw_info_scrollbar(FALSE);
-}
+	if (i < sizeof(buf)) {
+	    memcpy(buf, str, i);
+	    buf[i] = 0;
+	    draw_info(buf, color);
+	}
+	str += i;
+	while (*str == ' ')
+	    str++;
 
-/* This is pretty much print_message, but the name is changed, and some
- * unnecessary code has been removed.
- */
+	/* if the rest of the line is empty or only a single '.' abort */
+	if (*str == 0 || (*str == '.' && str[1] == 0))
+	    return;
+    }
 
-void draw_color_info(int colr, const char *buf){
-    draw_info(buf,colr);
-}
+    /* This is the real code here - stuff above is just formating and making
+     * it look nice.  This stuff here is actually drawing the code
+     */
 
+    /* insert new line */
+    info.pos = (info.pos + 1) % info.lines;
+    strncpy(info.line[info.pos].text,str,INFO_CHARS);
+    info.line[info.pos].color=color;
+
+    /* adjust scrollbar position */
+    info.bar_pos = (info.bar_pos + 1) % info.lines;
+
+    /* scroll up */
+    XCopyArea(display, info.win, info.win, info.gc,
+	BW, BW+FONT_HEIGHT,
+	info.cwidth*FONT_WIDTH, (info.cheight - 1) * FONT_HEIGHT,
+	BW, BW);
+
+    /* redraw the bottom line */
+    lp = info.line + info.bar_pos;
+    l = strlen(lp->text);
+    if (l < info.cwidth) // have to redraw the whole line, fill it up
+	memset(lp->text + l, ' ', info.cwidth - l);
+    XSetForeground(display, info.gc, discolor[lp->color].pixel);
+    DrawInfoText(info.cheight - 1, lp->text);
+    if (l < info.cwidth)
+	lp->text[l] = 0;
+}
 
 /*
  * draw_all_info is only needed for redraws, which includes scrollbar
  * movement
  */
 
+static void
+draw_all_info(void)
+{
+    int i;
 
-static void draw_all_info(void) {
-  int i;
-
-  XClearWindow(display,infodata.win_info);
-  if (infodata.numlines>=infodata.maxdisp) {
-     int startline=infodata.infopos-infodata.maxdisp-
-	(infodata.numlines-infodata.bar_pos)+1,displine=0;
-
-     if (startline<0) startline+=infodata.maxlines;
-
-     /* If we are scrolling back (bar_pos<numlines), then we want to
-      * start drawing from the top, and want to keep displine 0.
-      */
-     if (!infodata.scroll_info_window) {
-	if (infodata.bar_pos>=infodata.numlines) {
-		displine=(infodata.infoline+1) % infodata.maxdisp;
-		/* So that when we now that we have scrolled back */
-		
-	}
-	else infodata.infoline=infodata.maxdisp-1;
-     }
+    XClearWindow(display,info.win);
 
-     for (i=0; i<infodata.maxdisp; i++) {
-	if (infodata.lastcolor!=infodata.data[startline].color) {
-		XSetForeground(display,infodata.gc_info,
-			       discolor[infodata.data[startline].color].pixel);
-		infodata.lastcolor=infodata.data[startline].color;
-	}
-	XDrawImageString(display,infodata.win_info,
-	    infodata.gc_info,FONTWIDTH,(displine+1)*FONTHEIGHT,
-	    infodata.data[startline].info,
-	    strlen(infodata.data[startline].info));
-	startline++;
-	startline %= infodata.maxlines;
-	displine++;
-	displine %= infodata.maxdisp;
-     }
-  }
-  else  {
-      for(i=0;i<=infodata.numlines;i++) {
-	if (infodata.lastcolor!=infodata.data[i].color)  {
-		XSetForeground(display,infodata.gc_info,
-			       discolor[infodata.data[i].color].pixel);
-		infodata.lastcolor=infodata.data[i].color;
-	}
-	XDrawImageString(display,infodata.win_info,
-	    infodata.gc_info,FONTWIDTH,(i+1)*FONTHEIGHT,
-	    infodata.data[i].info,strlen(infodata.data[i].info));
-      }
-  }
-  draw_info_scrollbar(TRUE);
+    for (i = 0; i < info.cheight; ++i) {
+	InfoLine *lp = info.line + (info.bar_pos - info.cheight + 1 + i
+						+ info.lines) % info.lines;
+	XSetForeground(display,info.gc,discolor[lp->color].pixel);
+	DrawInfoText(i, lp->text);
+    }
+    DrawInput();
+    draw_info_scrollbar(TRUE);
 }
 
-static void resize_win_message(int width, int height) {
-    messagehint.width = width;
-    messagehint.height = height;
-}
 
 static void resize_win_info(int width, int height) {
-    int chars=(width/FONTWIDTH)-1;
-    int lines=(height/FONTHEIGHT)-1;
-    int i;
-    InfoLine	*newlines;
-
-    if (infodata.width==width &&
-	infodata.height==height) return;
-
-    if(chars<3 || lines<3)
-	return;
-
-    infodata.width=width;
-    infodata.height=height;
-    infodata.bar_length=infodata.height - 8;
-    if (infodata.has_scrollbar) chars-=3;
-
+    int chars, lines, i;
 
-    /* We have a scrollback buffer.  All we need to change then is maxdisp */
-    if (infodata.maxdisp != infodata.maxlines && lines<infodata.maxlines) {
-	/* Move insert line to bottom of the screen if we are already there
-	 * or it would otherwise be off the screen.
-	 */
-	if (((infodata.infoline+1) == infodata.maxdisp) ||
-	    (infodata.infoline >= lines)) infodata.infoline = lines - 1;
-	infodata.maxdisp=lines;
-    }
-    /* The window has changed size, but the amount of data we can display
-     * has not.  so just redraw the window and return.
-     */
-    if (chars == infodata.info_chars && lines == infodata.maxdisp) {
-	draw_all_info();
-	return;
-    }	
+    if (width < BW + 3*FONT_WIDTH + BW + SCROLLBAR_WIDTH + BW)
+	width = BW + 3*FONT_WIDTH + BW + SCROLLBAR_WIDTH + BW;
+    if (height < BW + 2*FONT_HEIGHT + BW + INPUT_HEIGHT)
+	height = BW + 2*FONT_HEIGHT + BW + INPUT_HEIGHT;
 
-    /* Either we have a scrollbar (as above), or the window has not
-     * changed in height, so we just need to change the size of the
-     * buffers.
-     */
-    if (lines == infodata.maxdisp) {
-	for (i=0; i<infodata.maxlines; i++) {
-	    if (chars>infodata.max_info_chars) {
-		infodata.data[i].info= realloc(infodata.data[i].info, sizeof(char) * (chars+1));
-	    }
-	    /* Terminate buffer in both cases */
-	    infodata.data[i].info[chars]='\0';
-	}
-	infodata.info_chars=chars;
-	draw_all_info();
+    if (info.width == width && info.height == height)
 	return;
-    }
-    /* IF we get here, the window has grown or shrunk, and we don't have
-     * a scrollbar.  This code is a lot simpler than what was here before,
-     * but probably is not as efficient (But with the number of resize
-     * events likely, this should not be a big deal).
-     */
 
-    /* First, allocate new storage */
-    newlines = malloc(sizeof(InfoLine) * lines);
-    for (i=0; i<lines; i++) {
-	newlines[i].info = malloc(sizeof(char) * (chars +1));
-	newlines[i].info[0]='\0';
-	newlines[i].color=0;
-    }
-    /* First case - we can keep all the old data.  Note that the old
-     * buffer could have been filled up, so we still need to do some
-     * checking to find the start
-     */
-    if (infodata.numlines <= lines) {
-	int start=0,k;
-
-	/* Buffer was full, so the start could be someplace else */
-	if (infodata.numlines == infodata.maxlines) {
-	    start = infodata.infopos+1;
-	}
-	for (i=0; i<infodata.numlines; i++) {
-	    k= (start+i) % infodata.maxlines;
-	    strncpy(newlines[i].info, infodata.data[k].info, chars);
-	    newlines[i].info[chars]=0;
-	    newlines[i].color = infodata.data[k].color;
+    lines = (height - BW - BW - INPUT_HEIGHT) / FONT_HEIGHT;
+    chars = (width - BW - BW - SCROLLBAR_WIDTH - BW) / FONT_WIDTH;
+    if (chars > INFO_CHARS)
+	chars = INFO_CHARS;
+
+    info.width = width;
+    info.height = height;
+    info.bar_length = height - BW - BW - INPUT_HEIGHT - 4;
+    info.cwidth = chars;
+    info.cheight = lines;
+
+    if (lines > info.lines) { /* grow scrollback buffer */
+	lines *= 4;
+	info.line = realloc(info.line, sizeof(InfoLine) * lines);
+	for (i = info.lines; i < lines; ++i) {
+	    info.line[i].text[0] = '\0';
+	    info.line[i].text[INFO_CHARS] = '\0';
+	    info.line[i].color = 0;
 	}
+	info.lines = lines;
     }
-    else {
-	/* We have to lose data, so keep the most recent. */
 
-	int start=infodata.infopos-lines,k;
-
-	if (start<0) start += infodata.maxlines;
-	for (i=0; i<lines; i++) {
-	    k= (start+i) % infodata.maxlines;
-	    strncpy(newlines[i].info, infodata.data[k].info, chars);
-	    newlines[i].info[chars]=0;
-	    newlines[i].color = infodata.data[k].color;
-	}
-	infodata.infopos = 0;
-	newlines[0].info[0] = '\0';
-	infodata.infoline = lines-1;
-	infodata.numlines = lines;
-	infodata.bar_pos = lines;
-    }
-    infodata.maxdisp = lines;
-    for (i=0; i<infodata.maxlines; i++) {
-	free(infodata.data[i].info);
-    }
-    free(infodata.data);
-    infodata.data = newlines;
-    infodata.maxlines = lines;
-    infodata.info_chars=chars;
     draw_all_info();
 }
 
@@ -1109,16 +844,16 @@ static void resize_win_info(int width, i
 
 static int get_stats_display(void) {
     XSizeHints stathint;
+    XClassHint classhint;
 
-    stathint.x=INV_WIDTH + WINDOW_SPACING;
-    stathint.y=0;
-    stathint.width=GAME_WIDTH;
-    stathint.height=STAT_HEIGHT;
-    stathint.min_width=stathint.max_width=stathint.width;
-    stathint.min_height=stathint.max_height=stathint.height;
+    stathint.x = INV_WIDTH + GAP;
+    stathint.y = 0;
+    stathint.width = STAT_WIDTH;
+    stathint.height = STAT_HEIGHT;
     stathint.flags=PPosition | PSize;
+
     win_stats=XCreateSimpleWindow(display,win_root,
-	stathint.x,stathint.y,stathint.width,stathint.height,2,
+	stathint.x,stathint.y,stathint.width,stathint.height,0,
 	foreground,background);
     XSetWindowColormap(display, win_stats, colormap);
     icon=XCreateBitmapFromData(display,win_stats,
@@ -1126,6 +861,9 @@ static int get_stats_display(void) {
 	(unsigned int) crossfire_width, (unsigned int)crossfire_height);
     XSetStandardProperties(display,win_stats,"Crossfire - status",
 	"crosstatus",icon,gargv,gargc, &(stathint));
+    classhint.res_name = "status";
+    classhint.res_class = X_CLASS;
+    XSetClassHint(display, win_stats, &classhint);
 
     gc_stats=XCreateGC(display,win_stats,0,0);
     XSetForeground(display,gc_stats,foreground);
@@ -1137,6 +875,25 @@ static int get_stats_display(void) {
    return 0;
 }
 
+static int
+sort_skills(const void *_a, const void *_b)
+{
+    int a = *(int *)_a;
+    int b = *(int *)_b;
+    int x;
+
+    x = cpl.stats.skill_exp[b] - cpl.stats.skill_exp[a];
+    if (x == 0)
+	x = strcasecmp(skill_names[a], skill_names[b]);
+    return x;
+}
+
+static void
+DrawStatText(int y, const char *str)
+{
+    DrawText(win_stats, gc_stats, BW, BW + y*FONT_HEIGHT, str);
+}
+
 /* This draws the stats window.  If redraw is true, it means
  * we need to redraw the entire thing, and not just do an
  * updated.
@@ -1148,40 +905,35 @@ void draw_stats(int redraw) {
   int i;
   char *s;
 
-    if (strcmp(cpl.title, last_name) || redraw) {
+    if (redraw || strcmp(cpl.title, last_name)) {
 	strcpy(last_name,cpl.title);
 	strcpy(buff,cpl.title);
  	strcat(buff,"                     ");
-	XDrawImageString(display,win_stats,
-	    gc_stats,10,10, buff,strlen(buff));
+	DrawStatText(0, buff);
     }
 
-    if(redraw || cpl.stats.exp!=last_stats.exp ||
+    if (redraw || cpl.stats.exp!=last_stats.exp ||
       cpl.stats.level!=last_stats.level) {
-	sprintf(buff,"Score: %5lld  Level: %d",cpl.stats.exp,
-	    cpl.stats.level);
- 	strcat(buff,"                     ");
-	XDrawImageString(display,win_stats,
-	    gc_stats,10,24, buff,strlen(buff));
+	sprintf(buff,"Score: %lld  Level: %d            ",
+						cpl.stats.exp, cpl.stats.level);
+	DrawStatText(1, buff);
 
 	last_stats.exp = cpl.stats.exp;
 	last_stats.level = cpl.stats.level;
       }
 
-    if(redraw || 
+    if (redraw || 
        cpl.stats.hp!=last_stats.hp || cpl.stats.maxhp!=last_stats.maxhp ||
        cpl.stats.sp!=last_stats.sp || cpl.stats.maxsp!=last_stats.maxsp ||
        cpl.stats.grace!=last_stats.grace || 
        cpl.stats.maxgrace!=last_stats.maxgrace) {
 
-	sprintf(buff,"Hp %d/%d  Sp %d/%d Gr %d/%d",
+	sprintf(buff,"Hp %d/%d  Sp %d/%d  Gr %d/%d                 ",
 	    cpl.stats.hp, cpl.stats.maxhp,
 	    cpl.stats.sp, cpl.stats.maxsp,
 	    cpl.stats.grace, cpl.stats.maxgrace);
 
- 	strcat(buff,"                     ");
-	XDrawImageString(display,win_stats,
-	    gc_stats,10,38, buff,strlen(buff));
+	DrawStatText(2, buff);
 	last_stats.hp=cpl.stats.hp;
 	last_stats.maxhp=cpl.stats.maxhp;
 	last_stats.sp=cpl.stats.sp;
@@ -1190,19 +942,17 @@ void draw_stats(int redraw) {
 	last_stats.maxgrace=cpl.stats.maxgrace;
     }
 
-    if(redraw || cpl.stats.Dex!=last_stats.Dex ||
+    if (redraw || cpl.stats.Dex!=last_stats.Dex ||
       cpl.stats.Con!=last_stats.Con || cpl.stats.Str!=last_stats.Str ||
       cpl.stats.Int!=last_stats.Int || cpl.stats.Wis!=last_stats.Wis ||
       cpl.stats.Cha!=last_stats.Cha || cpl.stats.Pow!=last_stats.Pow) {
 
-	sprintf(buff,"S%2d D%2d Co%2d I%2d W%2d P%2d Ch%2d",
+	sprintf(buff,"S%-2d D%-2d Co%-2d I%-2d W%-2d P%-2d Ch%-2d            ",
 	    cpl.stats.Str,cpl.stats.Dex,cpl.stats.Con,
 	    cpl.stats.Int,cpl.stats.Wis,cpl.stats.Pow,
 	    cpl.stats.Cha);
 
- 	strcat(buff,"                     ");
-	XDrawImageString(display,win_stats,
-	    gc_stats,10,52, buff,strlen(buff));
+	DrawStatText(3, buff);
 
 	last_stats.Str=cpl.stats.Str;
 	last_stats.Con=cpl.stats.Con;
@@ -1213,17 +963,15 @@ void draw_stats(int redraw) {
 	last_stats.Pow=cpl.stats.Pow;
       }
 
-    if(redraw || cpl.stats.wc!=last_stats.wc ||
+    if (redraw || cpl.stats.wc!=last_stats.wc ||
       cpl.stats.ac!=last_stats.ac ||
       cpl.stats.resists[0]!=last_stats.resists[0] ||
       cpl.stats.dam!=last_stats.dam) {
 
-	sprintf(buff,"Wc:%3d Dam:%3d Ac:%3d Arm:%3d",
-	    cpl.stats.wc,cpl.stats.dam,cpl.stats.ac,
+	sprintf(buff,"Wc:%3d Dam:%3d Ac:%3d Arm:%3d             ",
+	    cpl.stats.wc, cpl.stats.dam, cpl.stats.ac,
 	    cpl.stats.resists[0]);
- 	strcat(buff,"                     ");
-	XDrawImageString(display,win_stats,
-	    gc_stats,10,66, buff,strlen(buff));
+	DrawStatText(4, buff);
 
 	last_stats.wc=cpl.stats.wc;
 	last_stats.ac=cpl.stats.ac;
@@ -1231,7 +979,7 @@ void draw_stats(int redraw) {
 	last_stats.resists[0] = cpl.stats.resists[0];
       }
 
-  if(redraw || last_stats.speed!=cpl.stats.speed ||
+  if (redraw || last_stats.speed!=cpl.stats.speed ||
      cpl.stats.food!=last_stats.food ||
      cpl.stats.weapon_sp != last_stats.weapon_sp) {
 	/* since both speed and weapon speed have been multiplied by
@@ -1242,28 +990,27 @@ void draw_stats(int redraw) {
 	double weap_sp;
 
 	/* Seems that weapon_sp can be 0 in some cases which caused SIGFPE's */
-	if (cpl.stats.weapon_sp ==0) weap_sp = 0;
-	else weap_sp = (float) cpl.stats.speed/	((float)cpl.stats.weapon_sp);
+	if (cpl.stats.weapon_sp == 0)
+	    weap_sp = 0;
+	else
+	    weap_sp = (float)cpl.stats.speed / (float)cpl.stats.weapon_sp;
 
 	/* The following is generating an FPE on alpha systems - changed
 	 * everything to be doubles to see if that might make some
 	 * difference.
 	 */
-	if(cpl.stats.food<100 && (cpl.stats.food&4)) {
-	    sprintf(buff,"Speed: %3.2f (%1.2f) Food: *%d* HUNGRY!",
-		(double)cpl.stats.speed/FLOAT_MULTF,
-		weap_sp,cpl.stats.food);
-	    if (use_config[CONFIG_FOODBEEP] && (cpl.stats.food%4==3)) XBell(display, 0);
+	if (cpl.stats.food<100 && (cpl.stats.food&4)) {
+	    sprintf(buff,"Speed: %3.2f (%1.2f) Food: *%d* HUNGRY!            ",
+		(double)cpl.stats.speed/FLOAT_MULTF, weap_sp, cpl.stats.food);
+	    if (use_config[CONFIG_FOODBEEP] && cpl.stats.food%4==3)
+		XBell(display, 0);
 	} else {
-	    sprintf(buff,"Speed: %3.2f (%1.2f)  Food: %3d",
-		(float)cpl.stats.speed/FLOAT_MULTF,
-		weap_sp, cpl.stats.food);
-	    if (use_config[CONFIG_FOODBEEP] && cpl.stats.food<1) XBell(display,100);
+	    sprintf(buff,"Speed: %3.2f (%1.2f)  Food: %3d                    ",
+		(double)cpl.stats.speed/FLOAT_MULTF, weap_sp, cpl.stats.food);
+	    if (use_config[CONFIG_FOODBEEP] && cpl.stats.food<1)
+		XBell(display,100);
 	}
-
- 	strcat(buff,"                     ");
-	XDrawImageString(display,win_stats,
-	    gc_stats,10,80, buff,strlen(buff));
+	DrawStatText(5, buff);
 
 	last_stats.food=cpl.stats.food;
 	last_stats.speed = cpl.stats.speed;
@@ -1272,45 +1019,44 @@ void draw_stats(int redraw) {
     if (redraw || strcmp(cpl.range, last_range)) {
 	strcpy(last_range, cpl.range);
 	strcpy(buff,cpl.range);
- 	strcat(buff,"                     ");
-	XDrawImageString(display,win_stats,
-	    gc_stats,10,94, buff,strlen(buff));
+ 	strcat(buff,"                           ");
+	DrawStatText(6, buff);
     }
 
-    if (redraw) {
+    if (redraw)
       i = 0;
-    } else {
+    else
       for (i=0; i<MAX_SKILL; i++) {
 	if ((cpl.stats.skill_level[i] != last_stats.skill_level[i] ||
 	    cpl.stats.skill_exp[i] != last_stats.skill_exp[i]) &&
 	    skill_names[i] && cpl.stats.skill_exp[i])
 	  break;
       }
-    }
 
     if (i < MAX_SKILL) {
-	int on_skill=0;
+	int map[MAX_SKILL], n;
+
+	for (i = n = 0; i < MAX_SKILL; ++i)
+	    if (skill_names[i] && cpl.stats.skill_exp[i])
+		map[n++] = i;
+	qsort(map, n, sizeof(int), sort_skills);
 
-	*buff = '\0';
 	s = buff;
-	for (i=0; i<MAX_SKILL; i++) {
-	    if (!skill_names[i] || !cpl.stats.skill_exp[i]) continue;
+	for (i = 0; i < n; ++i) {
+	    int j = map[i];
 
-	    last_stats.skill_level[i] = cpl.stats.skill_level[i];
-	    last_stats.skill_exp[i] = cpl.stats.skill_exp[i];
-	    s += sprintf(s,"%.3s: %7lld (%d) ", skill_names[i], cpl.stats.skill_exp[i],
-		cpl.stats.skill_level[i]);
-	    if ((on_skill % 2) == 1) {
-		XDrawImageString(display,win_stats,gc_stats,10,
-				108 + (14 * (on_skill / 2)), buff,strlen(buff));
-		*buff = '\0';
+	    last_stats.skill_level[j] = cpl.stats.skill_level[j];
+	    last_stats.skill_exp[j] = cpl.stats.skill_exp[j];
+	    s += sprintf(s,"%c%.2s:%6lld (%d) ",
+		    skill_names[j][0] & ~0x20, skill_names[j]+1,
+		    cpl.stats.skill_exp[j], cpl.stats.skill_level[j]);
+	    if (i & 1) {
+		DrawStatText(7 + i/2, buff);
 		s = buff;
 	    }
-	    on_skill++;
 	}
-	if (*buff) 
-	    XDrawImageString(display,win_stats,gc_stats,10,
-			108 + (14 * (on_skill / 2)), buff,strlen(buff));
+	if (i & 1) 
+	    DrawStatText(7 + i/2, buff);
     }
 }
 
@@ -1321,25 +1067,27 @@ void draw_stats(int redraw) {
 ***********************************************************************/
 
 static int get_message_display(void) {
+    XSizeHints messagehint;
+    XClassHint classhint;
 
-    messagehint.x=INV_WIDTH + WINDOW_SPACING;
-    /* Game window is square so we can use the width */
-    messagehint.y=GAME_WIDTH + STAT_HEIGHT+WINDOW_SPACING*2;
-    messagehint.width=GAME_WIDTH;
-    messagehint.height=roothint.height - messagehint.y;
-    messagehint.max_width=messagehint.min_width=messagehint.width;
-    messagehint.max_height=STAT_HEIGHT;
-    messagehint.min_height=messagehint.height;
+    messagehint.x = INV_WIDTH + GAP;
+    messagehint.y = STAT_HEIGHT + GAP + GAME_HEIGHT + GAP;
+    messagehint.width = MSG_WIDTH;
+    messagehint.height = MSG_HEIGHT;
     messagehint.flags=PPosition | PSize;
+
     win_message=XCreateSimpleWindow(display,win_root,
 	messagehint.x,messagehint.y,messagehint.width,
-	messagehint.height,2,foreground,background);
+	messagehint.height,0,foreground, background);
     XSetWindowColormap(display, win_message, colormap);
     icon=XCreateBitmapFromData(display,win_message,
 	(_Xconst char *) crossfire_bits,
 	(unsigned int) crossfire_width, (unsigned int)crossfire_height);
     XSetStandardProperties(display,win_message,"Crossfire - vitals",
-	"crossvitals",icon, gargv,gargc,&(messagehint));
+	"crossvitals",icon, gargv,gargc,&messagehint);
+    classhint.res_name = "vitals";
+    classhint.res_class = X_CLASS;
+    XSetClassHint(display, win_message, &classhint);
     gc_message=XCreateGC(display,win_message,0,0);
     XSetForeground(display,gc_message,foreground);
     XSetBackground(display,gc_message,background);
@@ -1351,34 +1099,64 @@ static int get_message_display(void) {
    return 0;
 }
 
-static void xwritedown(const char *txt, int x) {
-  int y=13;
-  for(;*txt!='\0';txt++,y+=13)
-    XDrawImageString(display,win_message,
-		     look_list.gc_text,x,y,txt,1);
+static void resize_win_message(int width, int height) {
 }
 
-#define MAX_BARS_MESSAGE 80
+static void
+draw_stat_bar(int bar_nr, int val, int maxval, int *lastval, int force,
+								    char *label)
+{
+    int height = BAR_HEIGHT;
+    int alert = val <= maxval/4;
+    int x = BW + BAR_TOTAL_WIDTH * bar_nr;
+    int y = BW;
+    int h;
+
+    if (val < maxval)
+	height = (val * BAR_HEIGHT) / maxval;
+    if (height < 0)
+	height = 0;
+    if (height == *lastval && !force)
+	return;
+    *lastval = height;
 
-static void draw_stat_bar(int bar_pos, int height, int is_alert)
-{
-  if(height!=MAX_BARS_MESSAGE)	/* clear the top of the bar */
-    XClearArea(display,win_message, bar_pos, 4,
-	10, MAX_BARS_MESSAGE-height, 0);
+    if (alert)
+	XSetForeground(display,look_list.gc_text, discolor[3].pixel);
 
-  if(height==0)			/* empty bar */
-    return;
+    h = BAR_HEIGHT - height;
+    if (h)
+	XClearArea(display,win_message,
+		x + FONT_WIDTH+2 + 2, y + 2, BAR_WIDTH, h, 0);
+    if (height)
+	XFillRectangle(display,win_message, look_list.gc_text,
+		x + FONT_WIDTH+2 + 2, y + 2 + h, BAR_WIDTH, height);
+
+    if (alert)
+	XSetForeground(display,look_list.gc_text, foreground);
+
+    if (force) {
+	char buf[2];
+	DrawRectangle(display,win_message, look_list.gc_text,
+	    x + FONT_WIDTH+2, y, BAR_WIDTH + 4, BAR_HEIGHT + 4);
+	buf[1] = 0;
+	while ((buf[0] = *label++)) {
+	    DrawText(win_message, look_list.gc_text, x, y, buf);
+	    y += FONT_BASE+1; //FONT_HEIGHT is too much.
+	}
+    }
+}
+
+static int
+sort_resists(const void *_a, const void *_b)
+{
+    int a = *(int *)_a;
+    int b = *(int *)_b;
+    int x;
 
-  if(is_alert) /* this should have its own gc */
-	XSetForeground(display,look_list.gc_text,
-			discolor[3].pixel);
-
-  XFillRectangle(display,win_message,
-	 look_list.gc_text, bar_pos, 4+MAX_BARS_MESSAGE-height, 10, height);
-
-  if(is_alert)
-	 XSetForeground(display,look_list.gc_text,
-			foreground);
+    x = cpl.stats.resists[b] - cpl.stats.resists[a];
+    if (x == 0)
+	x = strcasecmp(resists_name[a], resists_name[b]);
+    return x;
 }
 
 
@@ -1387,140 +1165,53 @@ static void draw_stat_bar(int bar_pos, i
  */
 
 void draw_message_window(int redraw) {
-    int bar,is_alert,flags;
-    static uint16 oldflags=0;
-    static uint16 scrollsize_hp=0, scrollsize_sp=0, scrollsize_food=0,
-	scrollsize_grace=0;
-    static uint8 scrollhp_alert=FALSE, scrollsp_alert=FALSE,
-	scrollfood_alert=FALSE, scrollgrace_alert=FALSE;
-
-    /* draw hp bar */
-    if(cpl.stats.maxhp>0)
-    {
-	bar=(cpl.stats.hp*MAX_BARS_MESSAGE)/cpl.stats.maxhp;
-	if(bar<0)
-	    bar=0;
-	is_alert=(cpl.stats.hp <= cpl.stats.maxhp/4);
-    }
-    else
-    {
-	bar=0;
-	is_alert=0;
-    }
-    if (redraw || scrollsize_hp!=bar || scrollhp_alert!=is_alert)
-	draw_stat_bar(20, bar, is_alert);
-    scrollsize_hp=bar;
-    scrollhp_alert=is_alert;
-
-    /* draw sp bar.  spellpoints can go above max
-     * spellpoints via supercharging with the transferrance spell,
-     * or taking off items that raise max spellpoints.
-     */
-    if (cpl.stats.sp>cpl.stats.maxsp)
-	bar = MAX_BARS_MESSAGE;
-    else
-	bar=(cpl.stats.sp*MAX_BARS_MESSAGE)/cpl.stats.maxsp;
-    if(bar<0) 
-	bar=0;
-
-    is_alert=(cpl.stats.sp <= cpl.stats.maxsp/4);
-
-    if (redraw || scrollsize_sp!=bar || scrollsp_alert!=is_alert)
-	draw_stat_bar(60, bar, is_alert);
-
-    scrollsize_sp=bar;
-    scrollsp_alert=is_alert;
-
-    /* draw sp bar. grace can go above max or below min */
-    if (cpl.stats.grace>cpl.stats.maxgrace)
-	bar = MAX_BARS_MESSAGE;
-    else
-	bar=(cpl.stats.grace*MAX_BARS_MESSAGE)/cpl.stats.maxgrace;
-    if(bar<0) 
-	bar=0;
-
-    is_alert=(cpl.stats.grace <= cpl.stats.maxgrace/4);
-
-    if (redraw || scrollsize_grace!=bar || scrollgrace_alert!=is_alert)
-	draw_stat_bar(100, bar, is_alert);
-
-    scrollsize_grace=bar;
-    scrollgrace_alert=is_alert;
-  
-    /* draw food bar */
-    bar=(cpl.stats.food*MAX_BARS_MESSAGE)/999;
-    if(bar<0) 
-	bar=0;
-    is_alert=(cpl.stats.food <= 999/4);
-
-    if (redraw || scrollsize_food!=bar || scrollfood_alert!=is_alert)
-	draw_stat_bar(140, bar, is_alert);
-
-    scrollsize_food=bar;
-    scrollfood_alert=is_alert;
+    static int oldflags=0;
+    static int hp = -1, sp = -1, gr = -1, food = -1;
+    int flags;
+    int x = BW + 4 * BAR_TOTAL_WIDTH;
+    int y = BW;
+    char buf[64];
+
+    draw_stat_bar(0, cpl.stats.hp, cpl.stats.maxhp, &hp, redraw, "HP");
+    draw_stat_bar(1, cpl.stats.sp, cpl.stats.maxsp, &sp, redraw, "Mana");
+    draw_stat_bar(2, cpl.stats.grace, cpl.stats.maxgrace, &gr, redraw, "Grace");
+    draw_stat_bar(3, cpl.stats.food, 999, &food, redraw, "Food");
 
     flags = cpl.stats.flags;
-
     if (cpl.fire_on) flags |= SF_FIREON;
     if (cpl.run_on) flags |= SF_RUNON;
-
-    if ((flags & SF_FIREON ) != (oldflags & SF_FIREON)) {
-	if (flags & SF_FIREON)
-	    XDrawImageString(display, win_message,
-			     look_list.gc_text, 180, 15, "Fire On", 7);
-	else
-	    XClearArea(display, win_message,
-                   180, 0, 60, 15, False);
-    }
-    if ((flags & SF_RUNON ) != (oldflags & SF_RUNON)) {
-	if (flags & SF_RUNON)
-	    XDrawImageString(display, win_message,
-			     look_list.gc_text, 180, 30, "Run On", 6);
-	else
-	    XClearArea(display, win_message,
-                   180, 15, 60, 15, False);
+    if (redraw || flags != oldflags) {
+	DrawText(win_message, look_list.gc_text,
+			 x + 12*FONT_WIDTH, y,
+			 (flags & SF_FIREON) ? "Fire" : "    ");
+	DrawText(win_message, look_list.gc_text,
+			 x + 12*FONT_WIDTH, y + FONT_HEIGHT,
+			 (flags & SF_RUNON) ? "Run" : "   ");
+	oldflags = flags;
     }
-    oldflags = flags;
+
     if (redraw || cpl.stats.resist_change) {
-	int x=180, y=45,i;
-	char buf[40];
+	int i, j, map[NUM_RESISTS];
 
-	cpl.stats.resist_change=0;
-	XClearArea(display, win_message, 180, 30, messagehint.width-180, messagehint.height-30, False);
-	for (i=0; i<NUM_RESISTS; i++) {
-	    if (cpl.stats.resists[i]) {
-		XDrawImageString(display, win_message,
-			 look_list.gc_text, x, y, resists_name[i],
-			 strlen(resists_name[i]));
-		sprintf(buf,"%+4d", cpl.stats.resists[i]);
-		XDrawImageString(display, win_message,
-			 look_list.gc_text, x+40, y, buf, strlen(buf));
-		y+=15;
-		/* Move to the next draw position.  If we run
-		 * out of space, just break out of the function.
-		 */
-		if (y>messagehint.height) break;
-	    } /* If we have a resistance with value */
-	} /* For loop of resistances */
-    } /* If we need to draw the resistances */
+	for (i = 0; i < NUM_RESISTS; ++i)
+	    map[i] = i;
+	qsort(map, NUM_RESISTS, sizeof(int), sort_resists);
+
+	for (i = 0; i < NUM_RESISTS && cpl.stats.resists[j = map[i]]; ++i) {
+	    sprintf(buf, "%-5.5s%+4d", resists_name[j],
+				       cpl.stats.resists[j]);
+	    DrawText(win_message, look_list.gc_text, x, y, buf);
+	    y += FONT_HEIGHT;
+	}
+	XClearArea(display, win_message, x, y, 10*FONT_WIDTH, 999, False);
+	cpl.stats.resist_change = 0;
+    }
 }
     
 
-static void draw_all_message(void) {
-
+static void draw_all_message(void)
+{
   XClearWindow(display,win_message);
-  xwritedown("HP",06);
-  XDrawRectangle(display,win_message,
-		 look_list.gc_text,18,2,14,MAX_BARS_MESSAGE+4);
-  xwritedown("Mana",46);
-  XDrawRectangle(display,win_message,
-		 look_list.gc_text,58,2,14,MAX_BARS_MESSAGE+4);
-  xwritedown("Grace",86);
-  XDrawRectangle(display,win_message,
-		 look_list.gc_text,98,2,14,MAX_BARS_MESSAGE+4);
-  xwritedown("Food",126);
-  XDrawRectangle(display,win_message,
-		 look_list.gc_text,138,2,14,MAX_BARS_MESSAGE+4);
   draw_message_window(1);
 }
 
@@ -1578,7 +1269,8 @@ static void create_status_icons(void)
     int x, y;
     GC tmpgc;
 
-    if (hasinit) return;
+    if (hasinit)
+	return;
     hasinit=1;
 
 #define CREATEPM(name,data) \
@@ -1619,139 +1311,142 @@ static void create_status_icons(void)
 	     * adjacent dark2 image.  dark3 results in diagonal stripes.  OTOH, these will
 	     * change depending on the image size.
 	     */
-	    if ((x+y) % 2) {
+	    if ((x+y) % 2)
 		XDrawPoint(display, dark1, tmpgc, x, y);
-	    }
-	    if ((x+y) %3) {
+	    if ((x+y) % 3)
 		XDrawPoint(display, dark2, tmpgc, x, y);
-	    }
-	    if ((x+y) % 4) {
+	    if ((x+y) % 4)
 		XDrawPoint(display, dark3, tmpgc, x, y);
-	    }
 	}
     }
     XFreeGC(display, tmpgc);
 }
 
+
 /*
  *  draw_list redraws changed item to the window and updates a scrollbar
  */
 static void draw_list (itemlist *l)
 {
-    int i, items, size, pos;
+    int i, items, size;
     item *tmp;
     char buf[MAX_BUF], buf2[MAX_BUF];
+    int y = BW;
 
     /* draw title */
     strcpy(buf2, l->title);
     if (l->show_what & show_mask) {
-	strcat(buf2," (");
-	if (l->show_what & show_applied) strcat(buf2,"applied, ");
-	if (l->show_what & show_unapplied) strcat(buf2,"unapplied, ");
-	if (l->show_what & show_unpaid) strcat(buf2,"unpaid, ");
-	if (l->show_what & show_cursed) strcat(buf2,"cursed, ");
-	if (l->show_what & show_magical) strcat(buf2,"magical, ");
-	if (l->show_what & show_nonmagical) strcat(buf2,"nonmagical, ");
-	if (l->show_what & show_locked) strcat(buf2,"locked, ");
-	if (l->show_what & show_unlocked) strcat(buf2,"unlocked, ");
+	strcpy(buf2,"(");
+	if (l->show_what & show_applied)	strcat(buf2,"applied, ");
+	if (l->show_what & show_unapplied)	strcat(buf2,"unapplied, ");
+	if (l->show_what & show_unpaid)		strcat(buf2,"unpaid, ");
+	if (l->show_what & show_cursed)		strcat(buf2,"cursed, ");
+	if (l->show_what & show_magical)	strcat(buf2,"magical, ");
+	if (l->show_what & show_nonmagical)	strcat(buf2,"nonmagical, ");
+	if (l->show_what & show_locked)		strcat(buf2,"locked, ");
+	if (l->show_what & show_unlocked)	strcat(buf2,"unlocked, ");
 	/* want to kill the comma we put in above.  Replace it with the paren */
 	buf2[strlen(buf2)-2]=')';
 	buf2[strlen(buf2)-1]='\0';
     }
-    if(l->env->weight < 0 || l->show_weight == 0)
-	sprintf (buf, l->format_n, buf2);
+    if (l->env->weight < 0 || l->show_weight == 0)
+	sprintf(buf, l->format_n, buf2);
     else if (!l->weight_limit)
-	sprintf (buf, l->format_nw, buf2, l->env->weight);
+	sprintf(buf, l->format_nw, buf2, l->env->weight);
     else
-	sprintf(buf, l->format_nwl, buf2, l->env->weight,
-		l->weight_limit/1000);
+	sprintf(buf, l->format_nwl, buf2, l->env->weight, l->weight_limit);
 
-    if (strcmp (buf, l->old_title)) {
-	XCopyPlane(display, icons[l->env->open ? close_icon : no_icon], 
-			    l->win, l->gc_status, 0,0, image_size,13, 2,2, 1);
+    if (strcmp(buf, l->old_title)) {
 	strcpy (l->old_title, buf);
-	XDrawImageString(display, l->win, l->gc_text, 
-			 (l->show_icon ? image_size+24+4 : image_size+4),
-			 13, buf, strlen(buf));
+	XCopyPlane(display, icons[l->env->open ? close_icon : no_icon], 
+			    l->win, l->gc_status, 0,0, 24,13,
+			    BW, y + (FONT_HEIGHT-13)/2, 1);
+	DrawText(l->win, l->gc_text, 
+			 BW + image_size + (l->show_icon ? 24 : 0), y, buf);
     }
 
     /* Find how many objects we should draw. */
 
-    for(tmp = l->env->inv, items=0; tmp ;tmp=tmp->next)
-	if (show_object(tmp, l->show_what)) items++;
+    for (tmp = l->env->inv, items=0; tmp ;tmp=tmp->next)
+	if (show_object(tmp, l->show_what))
+	    items++;
 
-    if(l->item_pos > items - l->size)
+    if (l->item_pos > items - l->size)
 	l->item_pos = items - l->size;
-    if(l->item_pos < 0)
+    if (l->item_pos < 0)
 	l->item_pos = 0;
 
     /* Fast forward to the appropriate item location */
 
-    for(tmp = l->env->inv, i=l->item_pos; tmp && i; tmp=tmp->next)
-	if (show_object(tmp, l->show_what)) i--;
-
-    for(i=0; tmp && i < l->size; tmp=tmp->next) {
-	if (!show_object(tmp, l->show_what)) continue;
+    for (tmp = l->env->inv, i=l->item_pos; tmp && i; tmp=tmp->next)
+	if (show_object(tmp, l->show_what))
+	    i--;
+
+    y += FONT_HEIGHT;
+    for (i=0; tmp && i < l->size; tmp=tmp->next) {
+	if (!show_object(tmp, l->show_what))
+	    continue;
 	/* draw face */
-	if(l->faces[i] != tmp->face) {
+	if (l->faces[i] != tmp->face) {
 	    l->faces[i] = tmp->face;
-	    XClearArea(display, l->win, 4, 16 + image_size * i, 
-		       image_size, image_size, False);
-	    gen_draw_face (l->win, tmp->face,4, 16 + image_size * i, 0, 0);
+	    XClearArea(display, l->win, BW, y, image_size, image_size, False);
+	    gen_draw_face(l->win, tmp->face, BW, y, 0, 0);
 	}
 	/* draw status icon */
 	if (l->show_icon) {
-	    sint8 tmp_icon;
+	    int tmp_icon;
 	    tmp_icon = tmp->locked ? locked_icon : no_icon;
 	    if (l->icon1[i] != tmp_icon) {
 		l->icon1[i] = tmp_icon;
-		draw_status_icon (l, image_size+4, 16 + image_size * i, tmp_icon);
+		draw_status_icon(l, BW + image_size, y, tmp_icon);
 	    }
 	    tmp_icon = tmp->applied ? applied_icon :
 		       tmp->unpaid  ? unpaid_icon : no_icon;
 	    if (l->icon2[i] != tmp_icon) {
 		l->icon2[i] = tmp_icon;
-		draw_status_icon (l, image_size+4, 22 + image_size * i, tmp_icon);
+		draw_status_icon(l, BW + image_size, y + 6, tmp_icon);
 	    }
 	    tmp_icon = tmp->magical ? magic_icon : no_icon;
 	    if (l->icon3[i] != tmp_icon) {
 		l->icon3[i] = tmp_icon;
-		draw_status_icon (l, image_size+4, 28 + image_size * i, tmp_icon);
+		draw_status_icon(l, BW + image_size, y + 12, tmp_icon);
 	    }
 	    tmp_icon = tmp->damned ? damned_icon : 
 		       tmp->cursed ? cursed_icon : no_icon;
 	    if (l->icon4[i] != tmp_icon) {
 		l->icon4[i] = tmp_icon;
-		draw_status_icon (l, image_size+4, 34 + image_size * i, tmp_icon);
+		draw_status_icon(l, BW + image_size, y + 18, tmp_icon);
 	    }
 	}
 	/* draw name */
-	strcpy (buf2, tmp->d_name);
+	strcpy(buf2, tmp->d_name);
 	if (l->show_icon == 0)
-	    strcat (buf2, tmp->flags);
+	    strcat(buf2, tmp->flags);
 
-	if(tmp->weight < 0 || l->show_weight == 0)
+	if (tmp->weight < 0 || l->show_weight == 0)
 	    sprintf(buf, l->format_n, buf2);
 	else 
 	    sprintf(buf, l->format_nw, buf2, tmp->nrof * tmp->weight);
 
-	if(!l->names[i] || strcmp(buf, l->names[i])) {
+	if (!l->names[i] || strcmp(buf, l->names[i])) {
 	    copy_name (l->names[i], buf);
-	    XDrawImageString(display, l->win, l->gc_text, 
-			     (l->show_icon?image_size+24+4:image_size+4),
-			     34 + image_size * i, buf, strlen(buf));
+	    DrawText(l->win, l->gc_text, 
+			    BW + image_size + (l->show_icon ? 24 : 0),
+			    y + (image_size - FONT_HEIGHT)/2,
+			    buf);
 	}
 	i++;
+	y += image_size;
     }
 
     /* If there are not enough items to fill in the display area,
      * then set the unused ares to nothing.
      */
-    if(items < l->item_used) {
-	XClearArea(display, l->win, 0, 16 + image_size * i, l->width - 23,
-		   image_size * (l->size - i) , False);
+    if (items < l->item_used) {
+	XClearArea(display, l->win, 0, y,
+			l->width - BW - SCROLLBAR_WIDTH, l->height - y, False);
 	while (i < l->item_used) {
-	    copy_name (l->names[i], "");
+	    copy_name(l->names[i], "");
 	    l->faces[i] = 0;
 	    l->icon1[i] = l->icon2[i] = l->icon3[i] = l->icon4[i] = 0;
 	    i++;
@@ -1760,21 +1455,22 @@ static void draw_list (itemlist *l)
     l->item_used = items > l->size ? l->size : items;
 
     /* draw the scrollbar now */
-    if(items < l->size)
+    if (items < l->size)
 	items = l->size;
 
     size = (long) l->bar_length * l->size / items;
-    pos = (long) l->bar_length * l->item_pos / items;
-
-    if(l->bar_size != size || pos != l->bar_pos) {
+    y = (long) l->bar_length * l->item_pos / items;
 
-	XClearArea(display, l->win, l->width-20, 17 + l->bar_pos, 16, 
-		   l->bar_size, False);
+    if (l->bar_size != size || y != l->bar_y) {
+	XClearArea(display, l->win,
+		    l->width-BW-SCROLLBAR_WIDTH+2, BW+FONT_HEIGHT+2 + l->bar_y,
+		    SCROLLBAR_WIDTH-4, l->bar_size, False);
 	l->bar_size = size;
-	l->bar_pos  = pos;
+	l->bar_y  = y;
 
-	XFillRectangle(display, l->win, l->gc_text, l->width - 20,
-		       17 + l->bar_pos, 16, l->bar_size);
+	XFillRectangle(display, l->win, l->gc_text,
+		    l->width-BW-SCROLLBAR_WIDTH+2, BW+FONT_HEIGHT+2 + l->bar_y,
+		    SCROLLBAR_WIDTH-4, l->bar_size);
     }
 }
 
@@ -1788,7 +1484,7 @@ static void draw_all_list(itemlist *l)
 
     strcpy (l->old_title, "");
 
-    for(i=0; i<l->size; i++) {
+    for (i=0; i<l->size; i++) {
 	copy_name(l->names[i], "");
 	l->faces[i] = 0;
 	l->icon1[i] = 0;
@@ -1798,8 +1494,9 @@ static void draw_all_list(itemlist *l)
     }
 
     XClearWindow(display, l->win);
-    XDrawRectangle(display, l->win, l->gc_text, l->width - 22, 15, 20,
-		   l->bar_length + 4);
+    DrawRectangle(display, l->win, l->gc_text,
+		    l->width - BW - SCROLLBAR_WIDTH, BW + FONT_HEIGHT,
+		    SCROLLBAR_WIDTH, l->bar_length + 4);
 
 #if 0
     /* Don't reset these - causes window position to reset too often */
@@ -1837,63 +1534,50 @@ void close_container (item *op) 
 
 static void resize_list_info(itemlist *l, int w, int h)
 {
-    int i;
+    int i, len;
 
-    if (l->faces) 
-	free(l->faces);
-    if (l->icon1) 
-	free(l->icon1);
-    if (l->icon2) 
-	free(l->icon2);
-    if (l->icon3) 
-	free(l->icon3);
-    if (l->icon4) 
-	free(l->icon4);
+    if (w < BW + image_size + 24 + 4*FONT_WIDTH + BW + SCROLLBAR_WIDTH + BW)
+	w = BW + image_size + 24 + 4*FONT_WIDTH + BW + SCROLLBAR_WIDTH + BW;
+    if (h < BW + FONT_HEIGHT + image_size + BW)
+	h = BW + FONT_HEIGHT + image_size + BW;
+
+    free(l->faces);
+    free(l->icon1);
+    free(l->icon2);
+    free(l->icon3);
+    free(l->icon4);
     if (l->names) {
 	for (i=0; i < l->size; i++)
-	    if (l->names[i])
-		free(l->names[i]);
+	    free(l->names[i]);
 	free(l->names);
     }
     l->width  = w;
     l->height = h;
-    l->size = (l->height - FONTHEIGHT - 8) / image_size;
-    l->text_len = (l->width - (l->show_icon ? 84 : 60)) / FONTWIDTH;
-    l->bar_length = l->size * image_size;
-    sprintf (l->format_nw, "%%-%d.%ds%%6.1f", l->text_len-6, l->text_len-6);
-    sprintf (l->format_nwl, "%%-%d.%ds%%6.1f/%%4d", l->text_len-11, l->text_len-11);
-    sprintf (l->format_n, "%%-%d.%ds", l->text_len, l->text_len);
+    l->size = (l->height - BW - FONT_HEIGHT - BW) / image_size;
+    l->bar_length = l->size * image_size - 4;
+
+    len = (l->width - BW - image_size - (l->show_icon ? 24 : 0)
+		    - BW - SCROLLBAR_WIDTH - BW) / FONT_WIDTH;
+    sprintf(l->format_n, "%%-%d.%ds", len, len);
+    if (len > 6)
+	sprintf(l->format_nw, "%%-%d.%ds%%6.1f", len - 6, len - 6);
+    else
+	strcpy(l->format_nw, l->format_n);
+    if (len > 11)
+	sprintf(l->format_nwl, "%%-%d.%ds%%6.1f/%%4d", len - 11, len - 11);
+    else
+	strcpy(l->format_nwl, l->format_nw);
+
+    l->faces = xmalloc(sizeof(*l->faces) * l->size);
+    l->icon1 = xmalloc(sizeof(*l->icon1) * l->size);
+    l->icon2 = xmalloc(sizeof(*l->icon2) * l->size);
+    l->icon3 = xmalloc(sizeof(*l->icon3) * l->size);
+    l->icon4 = xmalloc(sizeof(*l->icon4) * l->size);
+    l->names = xmalloc(sizeof(*l->names) * l->size);
+
+    for (i=0; i < l->size; i++)
+	l->names[i] = xmalloc(NAME_LEN);
 
-    if ((l->faces = malloc (sizeof (*(l->faces)) * l->size )) == NULL) {
-	printf ("Can't allocate memory.\n");
-	exit (0);
-    }
-    if ((l->icon1 = malloc (sizeof (*(l->icon1)) * l->size )) == NULL) {
-	printf ("Can't allocate memory.\n");
-	exit (0);
-    }
-    if ((l->icon2 = malloc (sizeof (*(l->icon2)) * l->size )) == NULL) {
-	printf ("Can't allocate memory.\n");
-	exit (0);
-    }
-    if ((l->icon3 = malloc (sizeof (*(l->icon3)) * l->size )) == NULL) {
-	printf ("Can't allocate memory.\n");
-	exit (0);
-    }
-    if ((l->icon4 = malloc (sizeof (*(l->icon4)) * l->size )) == NULL) {
-	printf ("Can't allocate memory.\n");
-	exit (0);
-    }
-    if ((l->names = malloc (sizeof (char *) * l->size )) == NULL) {
-	printf ("Can't allocate memory.\n");
-	exit (0);
-    }
-    for (i=0; i < l->size; i++) {
-	if ((l->names[i] = malloc (NAME_LEN)) == NULL) {
-	    printf ("Can't allocate memory.\n");
-	    exit (0);
-	}
-    }
     draw_all_list(l);	/* this also initializes above allocated tables */
 }
 
@@ -1901,6 +1585,7 @@ static void get_list_display(itemlist *l
 		   const char *t, const char *s)
 {
     XSizeHints hint;
+    XClassHint classhint;
 
     l->faces=NULL;
     l->names=NULL;
@@ -1908,17 +1593,19 @@ static void get_list_display(itemlist *l
     hint.y = y;
     hint.width  = w;
     hint.height = h;
-    hint.min_width  = 60 + 10 * FONTWIDTH;
-    hint.min_height = FONTHEIGHT + 8 + image_size * 2;
     hint.flags = PPosition | PSize;
+
     l->win = XCreateSimpleWindow(display, win_root, hint.x, hint.y, hint.width,
-			       hint.height, 2, foreground, background);
+			       hint.height, 0, foreground, background);
     XSetWindowColormap(display, l->win, colormap);
     icon = XCreateBitmapFromData(display, l->win, 
 			       (_Xconst char *) crossfire_bits,
 			       (unsigned int) crossfire_width, 
 			       (unsigned int)crossfire_height);
     XSetStandardProperties(display, l->win, t, s, icon, gargv, gargc, &(hint));
+    classhint.res_name = (char *)s;
+    classhint.res_class = X_CLASS;
+    XSetClassHint(display, l->win, &classhint);
     l->gc_text = XCreateGC (display, l->win, 0, 0);
     l->gc_icon = XCreateGC (display, l->win, 0, 0);
     l->gc_status = XCreateGC (display, l->win, 0, 0);
@@ -1942,14 +1629,14 @@ static void get_list_display(itemlist *l
 static int get_inv_display(void)
 {
     inv_list.env = cpl.ob;
-    strcpy (inv_list.title, ""/*ET: too long: "Inventory:"*/);
+    strcpy (inv_list.title, "Inventory:");
     inv_list.show_weight = 1;
     inv_list.show_what = show_all;
     inv_list.weight_limit=0;
-    get_list_display ( &inv_list, 0, 0, INV_WIDTH, 
-		      2*(roothint.height - WINDOW_SPACING) / 3,
-		      "Crossfire - inventory",
-		      "crossinventory");
+    get_list_display( &inv_list, 0, 0,
+		      INV_WIDTH, 
+		      2*(roothint.height - GAP) / 3,
+		      "Crossfire - inventory", "crossinventory");
     return 0;
 }
 
@@ -1959,11 +1646,11 @@ static int get_look_display(void)
     strcpy (look_list.title, "You see:");
     look_list.show_weight = 1;
     look_list.show_what = show_all;
-    inv_list.weight_limit = 0;
-    get_list_display ( &look_list, 0, 
-	      (2*(roothint.height - WINDOW_SPACING) / 3) + WINDOW_SPACING,
+    look_list.weight_limit = 0;
+    get_list_display( &look_list, 0, 
+	      (2*(roothint.height - GAP) / 3) + GAP,
 		      INV_WIDTH, 
-		      (roothint.height - WINDOW_SPACING) / 3,
+		      (roothint.height - GAP) / 3,
 		      "Crossfire - look",
 		    "crosslook");
     return 0;
@@ -2009,23 +1696,12 @@ void set_show_weight (const char *s)
 
 void set_weight_limit (uint32 wlim)
 {
-    inv_list.weight_limit = wlim;
+    inv_list.weight_limit = wlim / 1000;
 }
 
 void set_scroll(const char *s)
 {
-    if (!infodata.scroll_info_window) {
-	infodata.scroll_info_window=1;
-	if (infodata.numlines>=infodata.maxdisp) {
-	    infodata.infoline=infodata.maxdisp-1;
-	}
-	draw_all_info();
-	draw_info("Scroll is enabled", NDI_BLACK);
-    }
-    else {
-	draw_info("Scroll is disabled", NDI_BLACK);
-	infodata.scroll_info_window=0;
-    }
+    draw_info("Scroll cannot be disabled", NDI_BLACK);
 }
 
 void set_autorepeat(const char *s)
@@ -2037,7 +1713,7 @@ void set_autorepeat(const char *s)
 
 int get_info_width()
 {
-    return infodata.info_chars;
+    return info.cwidth;
 }
 
 void menu_clear(void)
@@ -2072,7 +1748,9 @@ void item_event_item_changed(item * it) 
  */
 int sync_display = 0;
 
-static int get_root_display(char *display_name) {
+static int get_root_display(char *display_name)
+{
+    XClassHint classhint;
     char *cp;
 
     display=XOpenDisplay(display_name);
@@ -2118,7 +1796,7 @@ static int get_root_display(char *displa
 	    use_config[CONFIG_ECHO] = FALSE;
     }
     if ((cp=XGetDefault(display,X_PROG_NAME, "scrollLines"))!=NULL) {
-	infodata.maxlines=atoi(cp);
+	info.lines=atoi(cp);
     }
     if ((cp=XGetDefault(display,X_PROG_NAME,"font")) != NULL) {
 	font_name = strdup_local(cp);
@@ -2129,29 +1807,24 @@ static int get_root_display(char *displa
 	fprintf(stderr,"Could not load font %s\n", font_name);
 	exit(1);
     }
-    FONTWIDTH=font->max_bounds.width;
-    FONTHEIGHT=font->max_bounds.ascent + font->max_bounds.descent;
+    FONT_WIDTH=font->max_bounds.width;
+    FONT_HEIGHT=font->max_bounds.ascent + font->max_bounds.descent;
+    FONT_BASE=font->max_bounds.ascent;
 
     background=WhitePixel(display,def_screen);
     foreground=BlackPixel(display,def_screen);
+
     roothint.x=0;
     roothint.y=0;
-    roothint.width=582+6+INFOCHARS*FONTWIDTH;
-    roothint.height=ROOT_HEIGHT;
-    /* Make up for the extra size of the game window.  88 is
-     * 11 tiles * 8 pixels/tile bigger size.
-     */
-    roothint.width += 88;
-    roothint.height+= 88;
-    init_pngx_loader(display);
-
-    roothint.max_width=roothint.min_width=roothint.width;
-    roothint.max_height=roothint.min_height=roothint.height;
+    roothint.width = INV_WIDTH +GAP+ GAME_WIDTH +GAP+ INFO_WIDTH;
+    roothint.height = STAT_HEIGHT +GAP+ GAME_HEIGHT +GAP+ MSG_HEIGHT;
     roothint.flags=PSize; /*ET: no PPosition. let window manager handle that. */
 
-    if(!want_config[CONFIG_SPLITWIN]) {
+    init_pngx_loader(display);
+
+    if (!want_config[CONFIG_SPLITWIN]) {
 	win_root=XCreateSimpleWindow(display,def_root,
-	    roothint.x,roothint.y,roothint.width,roothint.height,2,
+	    roothint.x,roothint.y,roothint.width,roothint.height,0,
 	    background,foreground);
 
 	allocate_colors(display, win_root, def_screen, &colormap, discolor);
@@ -2160,8 +1833,11 @@ static int get_root_display(char *displa
 	icon=XCreateBitmapFromData(display,win_root,
 	    (_Xconst char *) crossfire_bits,
 	    (unsigned int) crossfire_width, (unsigned int)crossfire_height);
-	XSetStandardProperties(display,win_root,X_PROG_NAME,X_PROG_NAME,
-	    icon,gargv,gargc,&(roothint));
+	XSetStandardProperties(display,win_root,"Crossfire X11 Client V"
+			     VERSION, "crossfire", icon,gargv,gargc,&roothint);
+	classhint.res_name = "root";
+	classhint.res_class = X_CLASS;
+	XSetClassHint(display, win_root, &classhint);
 	gc_root=XCreateGC(display,win_root,0,0);
 	XSetForeground(display,gc_root,foreground);
 	XSetBackground(display,gc_root,background);
@@ -2169,64 +1845,67 @@ static int get_root_display(char *displa
 	XSelectInput(display,win_root,KeyPressMask|
 	     KeyReleaseMask|ExposureMask|StructureNotifyMask);
 	XMapRaised(display,win_root);
-	XNextEvent(display,&event);	/*ET: this is bogus */
-    XSetWMProtocols(display, win_root, &wm_delete_window, 1);
+	XSetWMProtocols(display, win_root, &wm_delete_window, 1);
     }
     else
 	win_root = def_root;
     return 0;
 }
 
-static void resize_win_root(XEvent *event) {
-    int width, inv_width, info_width;
+static void resize_win_root(int width, int height)
+{
+    int info_width, inv_width, inv_height, stat_height, msg_height;
+    int x;
 
     if (want_config[CONFIG_SPLITWIN]) {
 	fprintf(stderr,"Got a resize root window in split windows mode\n");
 	return;
     }
 
-    /* The middle 3 windows don't really benefit from the resize, so keep
-     * them the same size, and use the leftover equally between the left
-     * and right windows.
-     */
-    width = (event->xconfigure.width - GAME_WIDTH -WINDOW_SPACING*2);
-    info_width = width * info_ratio;
-    inv_width = width - info_width;
-
-    /* With png (and 32x32 images), the message window can get scrunched,
-     * so lets make it taller if we can - there is no reason not to, as otherwise
-     * that space is lost anyways.
-     */
-    XMoveResizeWindow(display, win_message, inv_width + WINDOW_SPACING, 
-		GAME_WIDTH + STAT_HEIGHT + WINDOW_SPACING*2, GAME_WIDTH,
-		event->xconfigure.height - GAME_WIDTH + STAT_HEIGHT + WINDOW_SPACING*2);
-    messagehint.width=GAME_WIDTH;
-    messagehint.height=event->xconfigure.height - GAME_WIDTH + STAT_HEIGHT + WINDOW_SPACING*2;
-
-    /* These windows just need to be relocated.  The y constants are
-     * hardcoded - those windows don't really benefit from being resized
-     * (actually, no code in place to currently do it), so no reason
-     * to get trick with those just now.
-     */
-
-    XMoveWindow(display, win_game, inv_width + WINDOW_SPACING, STAT_HEIGHT + WINDOW_SPACING);
-    XMoveWindow(display, win_stats, inv_width + WINDOW_SPACING, 0);
-
-    /* Resize the info window */
-    XMoveResizeWindow(display, infodata.win_info,  
-	inv_width + GAME_WIDTH + WINDOW_SPACING * 2, 0,
-	info_width, event->xconfigure.height);
-
-
-    /* Resize the inventory, message window */
-    XResizeWindow(display, inv_list.win, inv_width, 
-		  2 * (event->xconfigure.height - WINDOW_SPACING) / 3);
-
-
-    XMoveResizeWindow(display, look_list.win, 0, 
-	      (2*(event->xconfigure.height - WINDOW_SPACING) / 3) + WINDOW_SPACING,
-		      inv_width, 
-		      (event->xconfigure.height - WINDOW_SPACING) / 3);
+    /* some sanity checks to make sure all sizes stay positive */
+    if (width < 6*BW + 2*GAP + GAME_WIDTH + 20*FONT_WIDTH)
+	width = 6*BW + 2*GAP + GAME_WIDTH + 20*FONT_WIDTH;
+    if (height < 2*GAP + STAT_HEIGHT + GAME_HEIGHT)
+	height = 2*GAP + STAT_HEIGHT + GAME_HEIGHT;
+
+    x = width - GAP - GAME_WIDTH - GAP;
+    info_width = x * info_ratio;
+    inv_width = x - info_width;
+
+    x = height - BW - FONT_HEIGHT - BW - GAP - BW - FONT_HEIGHT - BW;
+    inv_height = BW + FONT_HEIGHT + x / image_size * 2/3 * image_size + BW;
+
+    x = height - STAT_HEIGHT - GAP - GAME_HEIGHT - GAP - MSG_HEIGHT;
+    if (x < 0)
+	x = 0;
+    stat_height = STAT_HEIGHT + x / 2;
+
+    msg_height = height - stat_height - GAP - GAME_HEIGHT - GAP;
+    if (msg_height < MSG_HEIGHT)
+	msg_height = MSG_HEIGHT;
+
+    XResizeWindow(display, inv_list.win,
+	    inv_width, inv_height);
+
+    XMoveResizeWindow(display, look_list.win,
+	    0, inv_height + GAP,
+	    inv_width, height - inv_height - GAP);
+
+    XMoveResizeWindow(display, win_stats,
+	    inv_width + GAP, 0,
+	    GAME_WIDTH, stat_height);
+
+    XMoveResizeWindow(display, win_game,
+	    inv_width + GAP, stat_height + GAP,
+	    GAME_WIDTH, GAME_HEIGHT);
+
+    XMoveResizeWindow(display, win_message,
+	    inv_width + GAP, GAME_HEIGHT + GAP + stat_height + GAP,
+	    GAME_WIDTH, msg_height);
+
+    XMoveResizeWindow(display, info.win,  
+	    inv_width + GAP + GAME_WIDTH + GAP, 0,
+	    info_width, height);
 
     /* The Resize requests will generate events.  As such, we don't call
      * the resize functions here - the event handler would get those anyways,
@@ -2245,12 +1924,12 @@ static void parse_game_button_press(int 
 {
     int dx, dy, i, xmidl, xmidh, ymidl, ymidh;
 
-    dx = (x-2)/image_size-use_config[CONFIG_MAPWIDTH]/2;
-    dy= (y-2)/image_size-use_config[CONFIG_MAPHEIGHT]/2;
-    xmidl=(use_config[CONFIG_MAPWIDTH]/2) * image_size;
-    xmidh=(use_config[CONFIG_MAPWIDTH]/2 + 1) * image_size;
-    ymidl=(use_config[CONFIG_MAPHEIGHT]/2) * image_size;
-    ymidh=(use_config[CONFIG_MAPHEIGHT]/2 + 1) * image_size;
+    dx = x/image_size - use_config[CONFIG_MAPWIDTH]/2;
+    dy = y/image_size - use_config[CONFIG_MAPHEIGHT]/2;
+    xmidl = (use_config[CONFIG_MAPWIDTH]/2) * image_size;
+    xmidh = (use_config[CONFIG_MAPWIDTH]/2 + 1) * image_size;
+    ymidl = (use_config[CONFIG_MAPHEIGHT]/2) * image_size;
+    ymidh = (use_config[CONFIG_MAPHEIGHT]/2 + 1) * image_size;
 
     switch (button) {
 	case 1:
@@ -2258,17 +1937,22 @@ static void parse_game_button_press(int 
 	    /* Its unlikely this will happen, but if the window is
 	     * resized, its possible to be out of bounds.
 	     */
-	    if(dx<(-use_config[CONFIG_MAPWIDTH]/2)||dx>(use_config[CONFIG_MAPWIDTH]/2)||dy<(-use_config[CONFIG_MAPHEIGHT]/2)||dy>(use_config[CONFIG_MAPHEIGHT]/2)) return;
+	    if (dx < -use_config[CONFIG_MAPWIDTH]/2 ||
+		dx > use_config[CONFIG_MAPWIDTH]/2 ||
+		dy < -use_config[CONFIG_MAPHEIGHT]/2 ||
+		dy > use_config[CONFIG_MAPHEIGHT]/2)
+		return;
 	    look_at(dx,dy);
+	    break;
 	}
-	break;
 	case 2:
 	case 3:
 	    if (x<xmidl)
 		i = 0;
 	    else if (x>xmidh)
 	       i = 6;
-	    else i =3;
+	    else
+		i = 3;
 
 	    if (y>ymidh)
 	      i += 2;
@@ -2330,7 +2014,7 @@ static void do_key_press(int repeated)
 	cpl.showmagic=0;
 	display_map_doneupdate(TRUE, FALSE);
     }
-    if(!XLookupString(&event.xkey,text,10, &gkey,NULL)) {
+    if (!XLookupString(&event.xkey,text,10, &gkey,NULL)) {
 /*
  *	This happens quite a bit - most modifier keys (shift, control, etc)
  *	can not be mapped to a value.
@@ -2343,12 +2027,10 @@ static void do_key_press(int repeated)
     }
     switch(cpl.input_state) {
 	case Playing:
-	    parse_key(text[0],event.xkey.keycode,gkey,repeated);
+	    parse_key(text[0] & 0xff, event.xkey.keycode, gkey, repeated);
 	    break;
 
 	case Reply_One:
-	/* Don't send modifier keys as reply to query. Tries to prevent
-	 * from getting into the "...state is not ST_PLAYING" state. */
 	    if (text[0]) {
 		text[1]='\0';
 		send_reply(text);
@@ -2363,31 +2045,71 @@ static void do_key_press(int repeated)
 	case Reply_Many:
 	case Command_Mode:
 	case Metaserver_Select:
-	    if (text[0]==13) {
-		enum Input_State old_state=cpl.input_state;
-		if (cpl.input_state==Metaserver_Select) {
-		    cpl.input_state=Playing;
-		    return;
-		}
-		if (cpl.input_state==Reply_Many)
+	    if (text[0] == 13 || text[0] == 10) {
+		if (*cpl.input_text && !cpl.no_echo) /* add to history */
+		    if (!history.line[1] ||	/* but no dups */
+			strcmp(history.line[1], cpl.input_text))
+		    {
+			free(history.line[HISTORY_SIZE-1]);
+			memmove(history.line+2, history.line+1,
+					    (HISTORY_SIZE-2) * sizeof(char *));
+			history.line[1] = strdup(cpl.input_text);
+		    }
+		if (cpl.input_state == Metaserver_Select) {
+		    cpl.input_state = Playing;
+		} else if (cpl.input_state == Reply_Many) {
+		    cpl.input_state = Playing;
 		    send_reply(cpl.input_text);
-		else {
-		    write_ch(13);
+		} else {
+		    cpl.input_state = Playing;
+		    draw_info(cpl.input_text, NDI_RED);
 		    extended_command(cpl.input_text);
 		}
-		/* Only set state to playing if the state has otherwise
-		 * not changed - this check is needed because 'bind
-		 * changes the state, and we don't want to change to playing
-		 * again.
-		 */
-		if (old_state==cpl.input_state)
+		cpl.no_echo = 0;  /* By default, start echoing thing again */
+		history.pos = 0;
+	    } else if (text[0] == 8 || text[0] == 127) {
+		int l = strlen(cpl.input_text);
+		if (l)
+		    cpl.input_text[l-1] = 0;
+		else if (cpl.input_state == Command_Mode)
 		    cpl.input_state = Playing;
-		cpl.input_text[0]='\0';
-		cpl.no_echo=0;	/* By default, start echoing thing again */
-	    }
-	    else {
-		write_ch(text[0]);
+		else
+		    XBell(display, 100);
+	    } else if (text[0] == 9 && cpl.input_state == Command_Mode) {
+		const char *str = complete_command(cpl.input_text);
+		if (str != cpl.input_text) {
+		    strcpy(cpl.input_text, str);
+		    strcat(cpl.input_text, " ");
+		} else
+		    XBell(display, 100);
+	    } else if (text[0] == 27) {
+		cpl.input_text[0] = 0;
+		if (cpl.input_state == Command_Mode)
+		    cpl.input_state = Playing;
+	    } else if (gkey == XK_Up || text[0] == ('P' & 0x1f)) {
+		if (history.pos == 0) { // save current line
+		    free(history.line[0]);
+		    history.line[0] = strdup(cpl.input_text);
+		}
+		if (history.pos+1 < HISTORY_SIZE && history.line[history.pos+1])
+		    strcpy(cpl.input_text, history.line[++history.pos]);
+		else
+		    XBell(display, 100);
+	    } else if (gkey == XK_Down || text[0] == ('N' & 0x1f)) {
+		if (history.pos > 0)
+		    strcpy(cpl.input_text, history.line[--history.pos]);
+		else
+		    XBell(display, 100);
+	    } else if (text[0] >= 32 && (text[0] & 0xff) <= 127) {
+		int l = strlen(cpl.input_text);
+		if (l < MAX_BUF - 15) {
+		    cpl.input_text[l++] = text[0];
+		    cpl.input_text[l] = 0;
+		}
+		else
+		    XBell(display, 100);
 	    }
+	    DrawInput();
 	    break;
 
 	default:
@@ -2398,47 +2120,47 @@ static void do_key_press(int repeated)
 
 static void buttonpress_in_info(XButtonEvent *xbutton)
 {
-    int y = xbutton->y-16, x=xbutton->x, button = xbutton->button,dy,pos=0;
+    int y = xbutton->y - BW - 2;
+    int x = xbutton->x;
+    int button = xbutton->button;
+    int dy, pos;
 
-    if (!infodata.has_scrollbar)
+    if (button < 4 && x < info.width-BW-SCROLLBAR_WIDTH)
 	return;
 
-    if (button < 4 && x <= infodata.width-SCROLLBAR_WIDTH-4)
-	return;
+    dy = y / FONT_HEIGHT > 0 ? y / FONT_HEIGHT : 1;
 
-    dy = y / FONTHEIGHT > 0 ? y / FONTHEIGHT : 1;
+    pos = (info.pos - info.bar_pos + info.lines) % info.lines;
       
     switch(button) {
 	  case 1:
-	    pos = infodata.bar_pos - dy;
+	    pos += dy;
 	    break;
 
 	  case 2:
-	    pos = y * infodata.numlines / infodata.bar_length;
+	    pos = info.lines-info.cheight/2 - y * info.lines / info.bar_length;
 	    break;
 
 	  case 3:
-	    pos = infodata.bar_pos + dy;
+	    pos -= dy;
 	    break;
 
 	  case 4:
-	    pos = infodata.bar_pos - 1;
+	    pos++;
 	    break;
 
 	  case 5:
-	    pos = infodata.bar_pos + 1;
+	    pos--;
 	    break;
 
     }
-    if (pos<infodata.maxdisp) {
-	if (infodata.numlines<infodata.maxdisp)
-	    pos=infodata.numlines;
-	else
-	    pos=infodata.maxdisp;
-    }
-    if (pos>infodata.numlines) pos=infodata.numlines;
-    if (pos != infodata.bar_pos) {
-	infodata.bar_pos = pos;
+    if (pos < 0)
+	pos = 0;
+    if (pos > info.lines - info.cheight)
+	pos = info.lines - info.cheight;
+    pos = (info.pos - pos + info.lines) % info.lines;
+    if (pos != info.bar_pos) {
+	info.bar_pos = pos;
 	draw_all_info();
     }
 }
@@ -2454,11 +2176,13 @@ static void buttonpress_in_info(XButtonE
 static int buttonpress_in_list (itemlist *l, XButtonEvent *xbutton)
 {
     item *tmp;
-    int y = xbutton->y - 16, x=xbutton->x, button = xbutton->button;
+    int y = xbutton->y - BW - FONT_HEIGHT - 2;
+    int x = xbutton->x;
+    int button = xbutton->button;
     int items, pos=0, dy;
 
     if (y < 0 && l->env->open) /* close the sack */
-	client_send_apply (l->env->tag);
+	client_send_apply(l->env->tag);
  
     if (y < 0 || y > image_size * l->size)
 	return 1;
@@ -2473,8 +2197,9 @@ static int buttonpress_in_list (itemlist
 	return 1;
     }
 
-    if (x > l->width-23) {    /* scrollbar */
+    if (x >= l->width - BW - SCROLLBAR_WIDTH) {    /* scrollbar */
 
+	y -= 2;
 	dy = y / image_size > 0 ? y / image_size : 1;
       
 	switch(button) {
@@ -2483,7 +2208,7 @@ static int buttonpress_in_list (itemlist
 	    break;
 
 	  case 2:
-	    for(tmp=l->env->inv, items=0; tmp; tmp=tmp->next)
+	    for (tmp=l->env->inv, items=0; tmp; tmp=tmp->next)
 		items++;
 	    pos = y * items / l->bar_length;
 	    break;
@@ -2501,9 +2226,11 @@ static int buttonpress_in_list (itemlist
     }
 
     pos = l->item_pos + y / image_size;
-    for(tmp=l->env->inv, items=0; tmp; tmp=tmp->next) {
-	if (show_object(tmp, l->show_what)) items++;
-	if (items>pos) break;
+    for (tmp=l->env->inv, items=0; tmp; tmp=tmp->next) {
+	if (show_object(tmp, l->show_what))
+	    items++;
+	if (items>pos)
+	    break;
     }
     if (tmp) {
 	switch(button) {
@@ -2542,23 +2269,15 @@ static int buttonpress_in_list (itemlist
  */
 char *get_metaserver()
 {
-    static char ret_buf[MAX_BUF];
-
     cpl.input_state = Metaserver_Select;
+    cpl.input_text[0] = 0;
     draw_prompt(":");
     while (cpl.input_state == Metaserver_Select) {
 	check_x_events();
 	usleep(50000);	/* 1/20 sec */
     } /* while input state is metaserver select. */
 
-    /* We need to clear out cpl.input_text - otherwise the next
-     * long input (like player name) won't work right.
-     * so copy it to a private buffer and return.
-     */
-    strncpy(ret_buf, cpl.input_text, MAX_BUF-1);
-    ret_buf[MAX_BUF-1]=0;
-    cpl.input_text[0]=0;
-    return ret_buf;
+    return cpl.input_text;
 }
 
 
@@ -2592,7 +2311,8 @@ void check_x_events() {
 	if (want_config[CONFIG_CACHE] && lastupdate>5 && newimages) {
 	    update_icons_list(&inv_list);
 	    update_icons_list(&look_list);
-	    if (!cpl.showmagic) display_map_doneupdate(TRUE, FALSE);
+	    if (!cpl.showmagic)
+		display_map_doneupdate(TRUE, FALSE);
 	    newimages=0;
 	    lastupdate=0;
 	}
@@ -2609,53 +2329,64 @@ void check_x_events() {
 	XNextEvent(display,&event);
 	switch(event.type) {
 
-	    case ConfigureNotify:
-		if(event.xconfigure.window==infodata.win_info)
-		    resize_win_info(event.xconfigure.width, event.xconfigure.height);
-		else if(event.xconfigure.window==inv_list.win)
-		    resize_list_info(&inv_list, event.xconfigure.width,
-			 event.xconfigure.height);
-		else if(event.xconfigure.window==look_list.win)
-		    resize_list_info(&look_list, event.xconfigure.width,
-			 event.xconfigure.height);
-		else if(event.xconfigure.window==win_root)
-		    resize_win_root(&event);
-		else if(event.xconfigure.window==win_message)
-		    resize_win_message(event.xconfigure.width, event.xconfigure.height);
+	    case ConfigureNotify: {
+		int win = event.xconfigure.window;
+		int w = event.xconfigure.width;
+		int h = event.xconfigure.height;
+
+		if (win == info.win)
+		    resize_win_info(w, h);
+		else if (win == inv_list.win)
+		    resize_list_info(&inv_list, w, h);
+		else if (win == look_list.win)
+		    resize_list_info(&look_list, w, h);
+		else if (win == win_root)
+		    resize_win_root(w, h);
+		else if (win == win_message)
+		    resize_win_message(w, h);
 		break;
-
-	    case Expose:
-	    /* No point redrawing windows if there are more Expose's to
-	     * come.
-	     */
-	    if (event.xexpose.count!=0) continue;
-	    if(event.xexpose.window==win_stats) {
-		XClearWindow(display,win_stats);
-		draw_stats(1);
-	    } else if(event.xexpose.window==infodata.win_info)
-		draw_all_info();
-	    else if(event.xexpose.window==inv_list.win)
-		draw_all_list(&inv_list);
-	    else if(event.xexpose.window==look_list.win)
-		draw_all_list(&look_list);
-	    else if(event.xexpose.window==win_message)
-		draw_all_message();
-	    else if(event.xexpose.window==win_game) {
-		if (cpl.showmagic) draw_magic_map();
-		else display_map_doneupdate(TRUE, FALSE);
-	    } else if(want_config[CONFIG_SPLITWIN]==FALSE && event.xexpose.window==win_root) {
-		XClearWindow(display,win_root);
 	    }
-	    break;
+	    case Expose:
+		/* No point redrawing windows if there are more Expose's to
+		 * come.
+		 */
+		if (event.xexpose.count!=0)
+		    continue;
+
+		if (event.xexpose.window==win_stats) {
+		    XClearWindow(display,win_stats);
+		    draw_stats(1);
+		} else if (event.xexpose.window==info.win)
+		    draw_all_info();
+		else if (event.xexpose.window==inv_list.win)
+		    draw_all_list(&inv_list);
+		else if (event.xexpose.window==look_list.win)
+		    draw_all_list(&look_list);
+		else if (event.xexpose.window==win_message)
+		    draw_all_message();
+		else if (event.xexpose.window==win_game) {
+		    if (cpl.showmagic)
+			draw_magic_map();
+		    else
+			display_map_doneupdate(TRUE, FALSE);
+		} else if (want_config[CONFIG_SPLITWIN]==FALSE &&
+					    event.xexpose.window==win_root) {
+		    XClearWindow(display,win_root);
+		}
+		break;
 
 	    case GraphicsExpose:
 		/* No point redrawing windows if there are more GraphicExpose's
 		 * to come.
 		 */
-		if (event.xgraphicsexpose.count!=0) continue;
-		if(event.xgraphicsexpose.drawable==win_game) {
-		    if (cpl.showmagic) draw_magic_map();
-		    else display_map_doneupdate(TRUE, FALSE);
+		if (event.xgraphicsexpose.count!=0)
+		    continue;
+
+		if (event.xgraphicsexpose.drawable==win_game) {
+		    if (cpl.showmagic)
+			draw_magic_map();
+		    else
+			display_map_doneupdate(TRUE, FALSE);
 		}
 		break;
 
@@ -2665,25 +2396,23 @@ void check_x_events() {
 
 
 	    case ButtonPress:
-		/* Most of these will try to send requests to the server - since we
-		 * are not connected, this will probably fail in some bad way.
+		/*
+		 * Most of these will try to send requests to the server.
+		 * Since we are not connected, this will probably fail in
+		 * some bad way.
 		 */
-		if (cpl.input_state != Metaserver_Select) {
-
-		    if(event.xbutton.window==win_game) {
-			parse_game_button_press(event.xbutton.button,event.xbutton.x,
-						event.xbutton.y);
-		    } else if(event.xbutton.window==inv_list.win) {
+		if (event.xbutton.window==info.win)
+		    buttonpress_in_info(&event.xbutton);
+		else if (cpl.input_state != Metaserver_Select) {
+		    if (event.xbutton.window==win_game)
+			parse_game_button_press(event.xbutton.button,
+					    event.xbutton.x, event.xbutton.y);
+		    else if (event.xbutton.window==inv_list.win)
 			buttonpress_in_list(&inv_list, &event.xbutton);
-
-		    } else if(event.xbutton.window==look_list.win) {
+		    else if (event.xbutton.window==look_list.win)
 			buttonpress_in_list(&look_list, &event.xbutton);
-		    }
-		    else if (event.xbutton.window==infodata.win_info) {
-			buttonpress_in_info(&event.xbutton);
-		    }
-		    break;
 		}
+		break;
 
 	    case KeyRelease:
 		parse_key_release(event.xkey.keycode, gkey);
@@ -2699,12 +2428,13 @@ void check_x_events() {
 		else
 		    do_key_press(0);	/* regular key */
 		break;
+
         case ClientMessage:
-            if(event.xclient.data.l[0] == wm_delete_window){
+            if (event.xclient.data.l[0] == wm_delete_window) {
                 LOG(LOG_INFO,"x11::check_x_events","Window closed. Exiting.");
                 exit(0);
             }
-        break;
+	    break;
 	}
     }
     /* Below does not apply if we're not connected */
@@ -2718,7 +2448,8 @@ void check_x_events() {
 	 */
 
 	/* Need to do this to show the players position */
-	if (cpl.showmagic) magic_map_flash_pos();
+	if (cpl.showmagic)
+	    magic_map_flash_pos();
 	clear_fire_run();
     }
     /* a good place to check for childs */
@@ -2828,7 +2559,8 @@ int init_windows(int argc, char **argv)
 	    }
 	    x = atoi(argv[on_arg]);
 	    for (cp = argv[on_arg]; *cp!='\0'; cp++)
-		if (*cp == 'x' || *cp == 'X') break;
+		if (*cp == 'x' || *cp == 'X')
+		    break;
 
 	    if (*cp==0) {
 		fprintf(stderr,"-mapsize requires both and X and Y value (ie, XxY - note the\nx in between.\n");
@@ -2920,7 +2652,7 @@ int init_windows(int argc, char **argv)
 		fprintf(stderr,"-scrolllines requires a number\n");
 		return 1;
 	    }
-	    infodata.maxlines = atoi(argv[on_arg]);
+	    info.lines = atoi(argv[on_arg]);
 	    continue;
 	}
 	else if (!strcmp(argv[on_arg],"-font")) {
@@ -2953,6 +2685,13 @@ int init_windows(int argc, char **argv)
 	    return 1;
 	}
     }
+
+#ifndef HAVE_LIBPNG
+    fprintf(stderr,"Client not configured with Png display mode enabled\n");
+    fprintf(stderr,"Install the png library and try recompiling.\n");
+    exit(1);
+#endif
+
     /* Moving processing and setting of display attributes down here.
      * This is because a default display mode may also require special
      * handling.
@@ -2960,14 +2699,8 @@ int init_windows(int argc, char **argv)
      * we just fall back to pixmap mode.  But I don't really want to get into
      * a big nest of #ifdefs checking/setting modes.
      */
-#ifndef HAVE_LIBPNG
-    fprintf(stderr,"Client not configured with Png display mode enabled\n");
-    fprintf(stderr,"Install the png library and try recompiling.\n");
-    exit(1);
-#else
-    image_size=32;
-#endif
 
+    image_size=32;
     mapdata_init();
 
     /* Finished parsing all the command line options.  Now start
@@ -2988,7 +2721,8 @@ int init_windows(int argc, char **argv)
     init_keys();
     init_cache_data();
     set_window_pos();
-    info_ratio=(float) infodata.width/ (float) (infodata.width + INV_WIDTH);
+    info_ratio = (float)info.width / (float)(info.width + INV_WIDTH);
+    XFlush(display);
     return 0;
 }
 
@@ -3079,16 +2813,18 @@ void resize_map_window(int x, int y)
 	 * but does a reasonable job.  Don't do shrinks
 	 */
 
-	if (use_config[CONFIG_MAPWIDTH] > old_mapx) width = (use_config[CONFIG_MAPWIDTH] - old_mapx)* image_size;
+	if (use_config[CONFIG_MAPWIDTH] > old_mapx)
+	    width = (use_config[CONFIG_MAPWIDTH] - old_mapx) * image_size;
 
-	if (use_config[CONFIG_MAPHEIGHT] > old_mapy) height = (use_config[CONFIG_MAPHEIGHT] - old_mapy)* image_size;
+	if (use_config[CONFIG_MAPHEIGHT] > old_mapy)
+	    height = (use_config[CONFIG_MAPHEIGHT] - old_mapy) * image_size;
 
 	/* if somethign to do */
-	if (width>0 || height > 0) {
+	if (width > 0 || height > 0) {
 	    XGetWindowAttributes(display, win_root, &attrib);
 	    width += attrib.width;  
 	    height += attrib.height;
-	    XResizeWindow(display, win_game, x*image_size, y*image_size);
+	    // resize other windows via configure root event
 	    XResizeWindow(display, win_root, width, height);
 	}
 	old_mapx=use_config[CONFIG_MAPWIDTH];
@@ -3112,9 +2848,8 @@ void display_map_doneupdate(int redraw, 
 {
     int ax,ay, mx, my;
 
-    if(notice) {
+    if (notice)
 	return;
-    }
 
     if (cpl.showmagic) {
 	magic_map_flash_pos();
@@ -3122,8 +2857,8 @@ void display_map_doneupdate(int redraw, 
     }
 
     XSetClipMask(display,gc_floor,None);
-    for(ax=0;ax<use_config[CONFIG_MAPWIDTH];ax++) {
-	for(ay=0;ay<use_config[CONFIG_MAPHEIGHT];ay++) { 
+    for (ax=0;ax<use_config[CONFIG_MAPWIDTH];ax++) {
+	for (ay=0;ay<use_config[CONFIG_MAPHEIGHT];ay++) { 
 	    mx = pl_pos.x+ax;
 	    my = pl_pos.y+ay;
 	    if (redraw || the_map.cells[mx][my].need_update)  {
@@ -3147,10 +2882,10 @@ int display_mapscroll(int dx, int dy)
     dsty = dy < 0 ? image_size : 0;
 
     w = use_config[CONFIG_MAPWIDTH];
-    if(dx != 0)
+    if (dx != 0)
         w--;
     h = use_config[CONFIG_MAPHEIGHT];
-    if(dy != 0)
+    if (dy != 0)
         h--;
     XCopyArea(display, win_game, win_game, gc_copy,
         srcx, srcy,
@@ -3173,16 +2908,6 @@ int associate_cache_entry(Cache_Entry *c
     return 0;
 }
 
-void redisplay_stats()
-{
-  int i;
-  for(i=0;i<7;i++) {
-    XDrawImageString(display,win_stats,
-		   gc_stats,10,i*14+10, stats_buff[i],strlen(stats_buff[i]));
-}
-  XFlush(display);
-}
-
 void display_map_startupdate()
 {
 }
@@ -3213,8 +2938,8 @@ void draw_magic_map()
      */
     XClearWindow(display,win_game);
 
-    cpl.mapxres = (win_info.width-4)/cpl.mmapx;
-    cpl.mapyres = (win_info.height-4)/cpl.mmapy;
+    cpl.mapxres = win_info.width/cpl.mmapx;
+    cpl.mapyres = win_info.height/cpl.mmapy;
     if (cpl.mapxres < 1 || cpl.mapyres<1) {
 	fprintf(stderr,"magic map resolution less than 1, map is %dx%d\n",
 		cpl.mmapx, cpl.mmapy);
@@ -3224,8 +2949,10 @@ void draw_magic_map()
      * it probably makes sense to keep them the same value.
      * Need to take the smaller value.
      */
-    if (cpl.mapxres>cpl.mapyres) cpl.mapxres=cpl.mapyres;
-    else cpl.mapyres=cpl.mapxres;
+    if (cpl.mapxres>cpl.mapyres)
+	cpl.mapxres=cpl.mapyres;
+    else
+	cpl.mapyres=cpl.mapxres;
 
     if (cpl.mapxres>24) {
 	cpl.mapxres=24;
@@ -3236,7 +2963,7 @@ void draw_magic_map()
      */
     for (y = 0; y < cpl.mmapy; y++) {
 	for (x = 0; x < cpl.mmapx; x++) {
-	    uint8 val = cpl.magicmap[y*cpl.mmapx + x];
+	    int val = cpl.magicmap[y*cpl.mmapx + x];
 	    XSetForeground(display,gc_game,
 		discolor[val&FACE_COLOR_MASK].pixel);
 	    XFillRectangle(display,win_game,
@@ -3248,7 +2975,8 @@ void draw_magic_map()
 /* Basically, this just flashes the player position on the magic map */
 void magic_map_flash_pos()
 {
-    if (!cpl.showmagic) return;
+    if (!cpl.showmagic)
+	return;
     cpl.showmagic ^=2;
     if (cpl.showmagic & 2) {
 	XSetForeground(display, gc_game, foreground);
@@ -3332,7 +3060,7 @@ void save_winpos()
     fprintf(fp,"win_game: %d %d %d %d\n", wx,wy, w, h);
     get_window_coord(win_stats, &x,&y, &wx,&wy,&w,&h);
     fprintf(fp,"win_stats: %d %d %d %d\n", wx,wy, w, h);
-    get_window_coord(infodata.win_info, &x,&y, &wx,&wy,&w,&h);
+    get_window_coord(info.win, &x,&y, &wx,&wy,&w,&h);
     fprintf(fp,"win_info: %d %d %d %d\n", wx,wy, w, h);
     get_window_coord(inv_list.win, &x,&y, &wx,&wy,&w,&h);
     fprintf(fp,"win_inv: %d %d %d %d\n", wx,wy, w, h);
@@ -3355,14 +3083,17 @@ void set_window_pos()
     char buf[MAX_BUF],*cp;
     FILE *fp;
 
-    if (!want_config[CONFIG_SPLITWIN]) return;
+    if (!want_config[CONFIG_SPLITWIN])
+	return;
 
     sprintf(buf,"%s/.crossfire/winpos", getenv("HOME"));
-    if (!(fp=fopen(buf,"r"))) return;
+    if (!(fp=fopen(buf,"r")))
+	return;
 
     while(fgets(buf,MAX_BUF-1, fp)!=NULL) {
 	buf[MAX_BUF-1]='\0';
-	if (!(cp=strchr(buf,' '))) continue;
+	if (!(cp=strchr(buf,' ')))
+	    continue;
 	*cp++='\0';
 	if (sscanf(cp,"%d %d %d %d",&xwc.x,&xwc.y,&xwc.width,&xwc.height)!=4)
 	    continue;
@@ -3371,7 +3102,7 @@ void set_window_pos()
 	if (!strcmp(buf,"win_stats:")) 
 	    XConfigureWindow(display,win_stats,xwc_mask, &xwc);
 	if (!strcmp(buf,"win_info:")) 
-	    XConfigureWindow(display,infodata.win_info,xwc_mask, &xwc);
+	    XConfigureWindow(display,info.win,xwc_mask, &xwc);
 	if (!strcmp(buf,"win_inv:")) 
 	    XConfigureWindow(display,inv_list.win,xwc_mask, &xwc);
 	if (!strcmp(buf,"win_look:")) 
@@ -3390,14 +3121,17 @@ void load_defaults()
     FILE *fp;
 
     sprintf(path,"%s/.crossfire/defaults", getenv("HOME"));
-    if ((fp=fopen(path,"r"))==NULL) return;
+    if ((fp=fopen(path,"r"))==NULL)
+	return;
     while (fgets(inbuf, MAX_BUF-1, fp)) {
 	inbuf[MAX_BUF-1]='\0';
 	inbuf[strlen(inbuf)-1]='\0';	/* kill newline */
 
-	if (inbuf[0]=='#') continue;
+	if (inbuf[0]=='#')
+	    continue;
 	/* IF no colon, then we certainly don't have a real value, so just skip */
-	if (!(cp=strchr(inbuf,':'))) continue;
+	if (!(cp=strchr(inbuf,':')))
+	    continue;
 	*cp='\0';
 	cp+=2;	    /* colon, space, then value */
 
@@ -3410,32 +3144,60 @@ void load_defaults()
 	    continue;
 	}
 	if (!strcmp(inbuf,"cacheimages")) {
-	    if (!strcmp(cp,"True")) want_config[CONFIG_CACHE]=TRUE;
-	    else want_config[CONFIG_CACHE]=FALSE;
+	    if (!strcmp(cp,"True"))
+		want_config[CONFIG_CACHE]=TRUE;
+	    else
+		want_config[CONFIG_CACHE]=FALSE;
 	    continue;
 	}
 	if (!strcmp(inbuf,"split")) {
-	    if (!strcmp(cp,"True")) want_config[CONFIG_SPLITWIN]=TRUE;
-	    else want_config[CONFIG_SPLITWIN]=FALSE;
+	    if (!strcmp(cp,"True"))
+		want_config[CONFIG_SPLITWIN]=TRUE;
+	    else
+		want_config[CONFIG_SPLITWIN]=FALSE;
 	    continue;
 	}
 	if (!strcmp(inbuf,"showicon")) {
-	    if (!strcmp(cp,"True")) inv_list.show_icon=TRUE;
-	    else inv_list.show_icon=FALSE;
+	    if (!strcmp(cp,"True"))
+		inv_list.show_icon=TRUE;
+	    else
+		inv_list.show_icon=FALSE;
+	    continue;
+	}
+	if (!strcmp(inbuf,"showicon.look")) {
+	    if (!strcmp(cp,"True"))
+		look_list.show_icon=TRUE;
+	    else
+		look_list.show_icon=FALSE;
+	    continue;
+	}
+	if (!strcmp(inbuf,"showweight")) {
+	    if (!strcmp(cp,"True"))
+		inv_list.show_weight=TRUE;
+	    else
+		inv_list.show_weight=FALSE;
+	    continue;
+	}
+	if (!strcmp(inbuf,"showweight.look")) {
+	    if (!strcmp(cp,"True"))
+		look_list.show_weight=TRUE;
+	    else
+		look_list.show_weight=FALSE;
 	    continue;
 	}
 	if (!strcmp(inbuf,"scrolllines")) {
-	    infodata.maxlines = atoi(cp);
+	    info.lines = atoi(cp);
 	    continue;
 	}
 	if (!strcmp(inbuf,"scrollinfo")) {
-	    if (!strcmp(cp,"True")) infodata.scroll_info_window=TRUE;
-	    else infodata.scroll_info_window=FALSE;
+	    /* silently ignored */
 	    continue;
 	}
 	if (!strcmp(inbuf,"sound")) {
-	    if (!strcmp(cp,"True")) want_config[CONFIG_SOUND]=TRUE;
-	    else want_config[CONFIG_SOUND]=FALSE;
+	    if (!strcmp(cp,"True"))
+		want_config[CONFIG_SOUND]=TRUE;
+	    else
+		want_config[CONFIG_SOUND]=FALSE;
 	    continue;
 	}
 	if (!strcmp(inbuf,"command_window")) {
@@ -3445,19 +3207,31 @@ void load_defaults()
 	    continue;
 	}
 	if (!strcmp(inbuf,"foodbeep")) {
-	    if (!strcmp(cp,"True")) use_config[CONFIG_FOODBEEP]=TRUE;
-	    else use_config[CONFIG_FOODBEEP]=FALSE;
+	    if (!strcmp(cp,"True"))
+		use_config[CONFIG_FOODBEEP]=TRUE;
+	    else
+		use_config[CONFIG_FOODBEEP]=FALSE;
 	    continue;
 	}
 	if (!strcmp(inbuf,"noautorepeat")) {
-	    if (!strcmp(cp,"True")) noautorepeat=TRUE;
-	    else noautorepeat=FALSE;
+	    if (!strcmp(cp,"True"))
+		noautorepeat=TRUE;
+	    else
+		noautorepeat=FALSE;
 	    continue;
 	}
 	if (!strcmp(inbuf,"font")) {
 	    font_name = strdup_local(cp);
 	    continue;
 	}
+	if (!strcmp(inbuf,"mapsize")) {
+	    int w,h;
+	    if (sscanf(cp, "%dx%d", &w, &h) == 2) {
+		want_config[CONFIG_MAPWIDTH] = w;
+		want_config[CONFIG_MAPHEIGHT] = h;
+	    }
+	    continue;
+	}
 	fprintf(stderr,"Got line we did not understand: %s: %s\n", inbuf, cp);
     }
     fclose(fp);
@@ -3485,11 +3259,15 @@ void save_defaults()
     fprintf(fp,"port: %d\n", use_config[CONFIG_PORT]);
     fprintf(fp,"server: %s\n", server);
     fprintf(fp,"font: %s\n", font_name);
+    fprintf(fp,"mapsize: %dx%d\n", want_config[CONFIG_MAPWIDTH],
+				   want_config[CONFIG_MAPHEIGHT]);
     fprintf(fp,"cacheimages: %s\n", want_config[CONFIG_CACHE]?"True":"False");
     fprintf(fp,"split: %s\n", want_config[CONFIG_SPLITWIN]?"True":"False");
     fprintf(fp,"showicon: %s\n", inv_list.show_icon?"True":"False");
-    fprintf(fp,"scrolllines: %d\n", infodata.maxlines);
-    fprintf(fp,"scrollinfo: %s\n", infodata.scroll_info_window?"True":"False");
+    fprintf(fp,"showicon.look: %s\n", look_list.show_icon?"True":"False");
+    fprintf(fp,"showweight: %s\n", inv_list.show_weight?"True":"False");
+    fprintf(fp,"showweight.look: %s\n", look_list.show_weight?"True":"False");
+    fprintf(fp,"scrolllines: %d\n", info.lines);
     fprintf(fp,"sound: %s\n", want_config[CONFIG_SOUND]?"True":"False");
     fprintf(fp,"command_window: %d\n", use_config[CONFIG_CWINDOW]);
     fprintf(fp,"foodbeep: %s\n", use_config[CONFIG_FOODBEEP]?"True":"False");
@@ -3510,8 +3288,9 @@ void save_defaults()
 
 void command_show (const char *params)
 {
-    if(!params) {
-	if (inv_list.show_what==show_all) inv_list.show_what = show_applied;
+    if (!params) {
+	if (inv_list.show_what==show_all)
+	    inv_list.show_what = show_applied;
 	else { /* rotate the bit.  If no valid bits are set, start over */
 	    inv_list.show_what = inv_list.show_what << 1;
 	    if (!(inv_list.show_what & show_mask))
@@ -3552,26 +3331,26 @@ void command_show (const char *params)
 int main(int argc, char *argv[])
 {
     int sound,got_one=0;
-    int i;
 
-#ifdef HAS_COMMON_RCSID
-    INIT_COMMON_RCSID;
-#endif
-#ifdef HAS_X11_RCSID
-    INIT_X11_RCSID;
-#endif
 /*
  * output some version informations on LOG.
  * usefull when reporting a bug.
  */
-
 #ifdef HAS_COMMON_RCSID
-    for (i=0;common_rcsid[i];i++)
-        LOG(LOG_INFO,"Version::common","%s",common_rcsid[i]);
+    {
+	INIT_COMMON_RCSID;
+	int i;
+	for (i=0;common_rcsid[i];i++)
+	    LOG(LOG_INFO,"Version::common","%s",common_rcsid[i]);
+    }
 #endif
 #ifdef HAS_X11_RCSID
-    for (i=0;x11_rcsid[i];i++)
-        LOG(LOG_INFO,"Version::x11   ","%s",x11_rcsid[i]);
+    {
+	INIT_X11_RCSID;
+	int i;
+	for (i=0;x11_rcsid[i];i++)
+	    LOG(LOG_INFO,"Version::x11   ","%s",x11_rcsid[i]);
+    }
 #endif
 
     /* This needs to be done first.  In addition to being quite quick,
@@ -3592,13 +3371,7 @@ int main(int argc, char *argv[])
 	fprintf(stderr,"Failure to init windows.\n");
 	exit(1);
     }
-    csocket.inbuf.buf=malloc(MAXSOCKBUF);
-
-#ifdef HAVE_SYSCONF
-    maxfd = sysconf(_SC_OPEN_MAX);
-#else
-    maxfd = getdtablesize();
-#endif
+    csocket.inbuf.buf = xmalloc(MAXSOCKBUF);
 
     sound = init_sounds();
 



More information about the crossfire mailing list