/*****************************************************************
Copyright 1992 by Silicon Graphics Incorporated, Mountain View, CA,
and the Massachusetts Institute of Technology, Cambridge, Massachusetts.

                        All Rights Reserved

Permission to use, copy, modify, and distribute this software and its 
documentation for any purpose and without fee is hereby granted, 
provided that the above copyright notice appear in all copies and that
both that copyright notice and this permission notice appear in 
supporting documentation, and that the names of SGI or MIT not be
used in advertising or publicity pertaining to distribution of the
software without specific, written prior permission.  

SGI DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
SGI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
SOFTWARE.

******************************************************************/

/*
 * xmclient.c - X11/Motif client interface to hearts
 * 
 * Author:	Mike Yang (mikey@sgi.com)
 *		Silicon Graphics, Inc.
 * Date:	Fri Jan 3 1992
 * Copyright (c) 1992 Mike Yang
 */

#include <stdlib.h>
#include <malloc.h>
#include <sys/errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "misc.h"
#include "defs.h"
#include "local.h"
#include "client.h"
#include "gfx.h"
#ifdef SYSV
#include <sys/termio.h>
#endif
#include <X11/cursorfont.h>
#include <Xm/Form.h>
#include <Xm/Text.h>
#include <Xm/PushB.h>
#include <Xm/LabelG.h>
#include <Xm/DrawingA.h>
#include <Xm/RowColumn.h>
#include <Xm/Frame.h>
#include <Xm/BulletinB.h>

#define NUM_TABLES_ROWS	2
#define NUM_TABLES_COLS	4
#define NUM_TABLES	(NUM_TABLES_ROWS*NUM_TABLES_COLS)

static int count;
static Arg args[20];

typedef struct _CardInfo {
  int rank;
  int suit;
  struct _CardInfo *next;
} CardInfo;

typedef struct {
  CardInfo *head;
} SuitInfo;

SuitInfo my_hand[MAX_SUIT+1];

XtAppContext appContext;
Widget toplevel, form, displayFrame, displayArea, playArea, scoreArea;
Widget messageLabel, messageArea, messageEntry;
Widget commandArea, showButton = NULL, autoButton = NULL;
Widget quitButton, helpButton;
Widget displayLabels, roundLabel, leadLabel, textArea, playLabelArea;
Widget scorePlayer, scoreScore, scoreTotal;
Widget playerLabels[5], scoreLabels[5], totalLabels[5];
Widget playLabels[4];
Widget optionForm, helpDialog = NULL;
Widget gameBox, anotherGame, newGame, moreGames, quitGame, helpGame;
Widget gamesHeader, gamesFrame, gamesRC, gamesMessage;
Boolean showOld, *anotherPtr;
CardInfo playCards[4], lastCards[4];
char playNames[4][256], lastNames[4][256];
XtInputId distId = None, dealerId = None;
Boolean readingCard;
Cursor cardCursor = None;

Rank
convertRank(rank)
int rank;
{
  if (rank == 13) {
    return Ace;
  } else {
    return rank;
  }
}

Suit
convertSuit(suit)
int suit;
{
  Suit s;

  switch (suit) {
  case SPADES:
    s = Spade;
    break;
  case HEARTS:
    s = Heart;
    break;
  case DIAMONDS:
    s = Diamond;
    break;
  case CLUBS:
    s = Club;
    break;
  }
  return s;
}

void
showPlayArea(cards, names)
CardInfo *cards;
char names[4][256];
{
  int i;
  XmString xs;

  for (i=0; i<4; i++) {
    if (cards[i].rank) {
      paint_card(XtWindow(playArea), i*STACK_WIDTH, 0,
		 convertRank(cards[i].rank), convertSuit(cards[i].suit), 0);
    } else {
      XClearArea(XtDisplay(playArea), XtWindow(playArea), i*STACK_WIDTH, 0,
		 STACK_WIDTH, 0, False);
    }
    if (cards[i].rank) {
      xs = XmStringCreateSimple(names[i]);
    } else {
      xs = XmStringCreateSimple(" ");
    }
    count = 0;
    XtSetArg(args[count], XmNlabelString, xs);  count++;
    XtSetValues(playLabels[i], args, count);
    XmStringFree(xs);
  }
}

void
setShowOld(v)
Boolean v;
{
  if (showOld != v) {
    showOld = v;
    if (showOld) {
      showPlayArea(lastCards, lastNames);
    } else {
      showPlayArea(playCards, playNames);
    }
  }
}

void
setReadingCard(v)
Boolean v;
{
  if (readingCard != v) {
    readingCard = v;
    if (cardCursor == None) {
      cardCursor = XCreateFontCursor(XtDisplay(toplevel), XC_hand1);
    }
    if (XtIsRealized(displayArea)) {
      if (readingCard) {
	XDefineCursor(XtDisplay(displayArea), XtWindow(displayArea),
		      cardCursor);
      } else {
	XUndefineCursor(XtDisplay(displayArea), XtWindow(displayArea));
      }
      XFlush(XtDisplay(displayArea));
    }
    if (!readingCard && showOld) {
      setShowOld(False);
    }
  }
}

/**********************************************************************/

void
exposeDisplayArea(w, client_data, call_data)
Widget w;
XtPointer client_data;
XtPointer call_data;
{
  Suit suit;
  static Boolean first = True;

  for (suit=CLUBS; suit<=SPADES; suit++) {
    print_cards(suit);
  }
  if (first) {
    XmProcessTraversal(messageEntry, XmTRAVERSE_CURRENT);
    first = False;
  }
}

void
displaySelect(w, client_data, event)
Widget w;
XtPointer client_data;
XEvent *event;
{
  int suit, card, count;
  CardInfo *ptr, *cardSelected;
  char rch, sch;
  static char rnames[] = " 23456789TJQKA";

  cardSelected = NULL;
  if (readingCard &&
      event->type == ButtonPress && event->xbutton.button == Button1) {
    suit = (event->xbutton.x/STACK_WIDTH)+1;
    card = (event->xbutton.y/CARD_DELTA)+1;
    if (event->xbutton.x % STACK_WIDTH > CARD_WIDTH) {
      /* clicked on space between stacks */
    } else if (suit > 4) {
      /* clicked outside stacks */
    } else {
      ptr = my_hand[suit].head;
      count = 0;
      while (count < card && ptr->next) {
	count++;
	ptr = ptr->next;
      }
      if (count == card) {
	cardSelected = ptr;
      } else if (count < card &&
		 event->xbutton.y-(count-1)*CARD_DELTA < CARD_HEIGHT) {
	/* clicked on last card */
	cardSelected = ptr;
      } else {
	/* clicked below stack */
      }
      if (!ptr->rank) {
	cardSelected = NULL;
      }
    }
  }
  if (cardSelected) {
    rch = rnames[cardSelected->rank];
    switch (cardSelected->suit) {
    case SPADES:
      sch = 's';
      break;
    case HEARTS:
      sch = 'h';
      break;
    case DIAMONDS:
      sch = 'd';
      break;
    case CLUBS:
      sch = 'c';
      break;
    }
    send_card(rch, sch);
    setReadingCard(False);
    erase_window(TEXT_WINDOW);
  } else {
    XBell(XtDisplay(toplevel), 0);
  }
}

void
send_msg(w, client_data, call_data)
Widget w;
XtPointer client_data;
XtPointer call_data;
{
  char *msg;

  msg = XmTextGetString(messageEntry);
  XmTextSetString(messageEntry, "");
  send_message(msg);
  XtFree(msg);
}

void
show_button(w, client_data, call_data)
Widget w;
XtPointer client_data;
XtPointer call_data;
{
  XmProcessTraversal(messageEntry, XmTRAVERSE_CURRENT);
  if (readingCard) {
    setShowOld(!showOld);
  }
}

void
auto_play(w, client_data, call_data)
Widget w;
XtPointer client_data;
XtPointer call_data;
{
  XmProcessTraversal(messageEntry, XmTRAVERSE_CURRENT);
  if (readingCard) {
    send_auto();
    setReadingCard(False);
    erase_window(TEXT_WINDOW);
  }
}

void
quit_game(w, client_data, call_data)
Widget w;
XtPointer client_data;
XtPointer call_data;
{
  wimp_out();
}

void
help_me(w, client_data, call_data)
Widget w;
XtPointer client_data;
XtPointer call_data;
{
  Widget text, okButton, label;
  XmString xs;
  char filename[256];
  int fildes;
  struct stat buf;
  char *data;

  XmProcessTraversal(messageEntry, XmTRAVERSE_CURRENT);
  if (!helpDialog) {
    count = 0;
    XtSetArg(args[count], XmNtitle, "xmhearts help");  count++;
    helpDialog = XmCreateFormDialog(toplevel, "helpDialog", args, count);

    xs = XmStringCreateSimple("OK");
    count = 0;
    XtSetArg(args[count], XmNbottomAttachment, XmATTACH_FORM);  count++;
    XtSetArg(args[count], XmNbottomOffset, 10);  count++;
    XtSetArg(args[count], XmNrightAttachment, XmATTACH_FORM);  count++;
    XtSetArg(args[count], XmNrightOffset, 10);  count++;
    XtSetArg(args[count], XmNlabelString, xs);  count++;
    okButton = XmCreatePushButton(helpDialog, "helpOK", args, count);
    XtManageChild(okButton);
    XmStringFree(xs);

    xs = XmStringCreateSimple("Xmhearts, a Motif interface to hearts.  Mike Yang, Silicon Graphics, mikey@sgi.com");
    count = 0;
    XtSetArg(args[count], XmNleftAttachment, XmATTACH_FORM);  count++;
    XtSetArg(args[count], XmNrightAttachment, XmATTACH_WIDGET);  count++;
    XtSetArg(args[count], XmNrightWidget, okButton);  count++;
    XtSetArg(args[count], XmNtopAttachment,
	     XmATTACH_OPPOSITE_WIDGET);  count++;
    XtSetArg(args[count], XmNtopWidget, okButton);  count++;
    XtSetArg(args[count], XmNbottomAttachment,
	     XmATTACH_OPPOSITE_WIDGET);  count++;
    XtSetArg(args[count], XmNbottomWidget, okButton);  count++;
    XtSetArg(args[count], XmNalignment, XmALIGNMENT_CENTER);  count++;
    XtSetArg(args[count], XmNlabelString, xs);  count++;
    label = XmCreateLabelGadget(helpDialog, "label", args, count);
    XtManageChild(label);
    XmStringFree(xs);

    count = 0;
    XtSetArg(args[count], XmNtopAttachment, XmATTACH_FORM);  count++;
    XtSetArg(args[count], XmNbottomAttachment, XmATTACH_WIDGET);  count++;
    XtSetArg(args[count], XmNbottomWidget, okButton);  count++;
    XtSetArg(args[count], XmNbottomOffset, 10);  count++;
    XtSetArg(args[count], XmNleftAttachment, XmATTACH_FORM);  count++;
    XtSetArg(args[count], XmNrightAttachment, XmATTACH_FORM);  count++;
    XtSetArg(args[count], XmNwordWrap, True);  count++;
    XtSetArg(args[count], XmNscrollHorizontal, False);  count++;
    XtSetArg(args[count], XmNeditable, False);  count++;
    XtSetArg(args[count], XmNblinkRate, 0);  count++;
    XtSetArg(args[count], XmNrows, 24);  count++;
    XtSetArg(args[count], XmNcolumns, 80);  count++;
    XtSetArg(args[count], XmNeditMode, XmMULTI_LINE_EDIT);  count++;
    text = XmCreateScrolledText(helpDialog, "helpText", args, count);
    XtManageChild(text);

    sprintf(filename, "%s/%s", HEARTSLIB, INSTRUCT);
    if ((fildes = open(filename, O_RDONLY)) != -1) {
      fstat(fildes, &buf);
      data = (char *) malloc((size_t) buf.st_size+1);
      read(fildes, data, (unsigned) buf.st_size);
      data[buf.st_size] = '\0';
      close(fildes);
      XmTextSetString(text, data);
      free(data);
    } else {
      XmTextSetString(text, "Help file missing.\n");
    }
  }
  XtManageChild(helpDialog);
}

void
exposePlayArea(w, client_data, call_data)
Widget w;
XtPointer client_data;
XtPointer call_data;
{
  if (showOld) {
    showPlayArea(lastCards, lastNames);
  } else {
    showPlayArea(playCards, playNames);
  }
}

void
another_game(w, client_data, call_data)
Widget w;
XtPointer client_data;
XtPointer call_data;
{
  *anotherPtr = TRUE;
  if (!first_game) {
    joined = TRUE;
  }
}

void
new_game(w, client_data, call_data)
Widget w;
XtPointer client_data;
XtPointer call_data;
{
  start_new_game();
  joined = TRUE;
}

void
more_games(w, client_data, call_data)
Widget w;
XtPointer client_data;
XtPointer call_data;
{
  if (table_count > NUM_TABLES) {
    if ((cur_screen_table += NUM_TABLES) > table_count) {
      cur_screen_table = 1;
    }
    show_tables(cur_screen_table);
  }
}

void
tableSelect(w, client_data, event)
Widget w;
XtPointer client_data;
XEvent *event;
{
  int i;
  Widget *widgets;
  table_ptr cur_ptr;

  if (table_count && first_game &&
      event->type == ButtonPress && event->xbutton.button == Button1) {
    cur_ptr = first_table;
    for (i=0; i<table_count; i++) {
      if (cur_ptr->data && !cur_ptr->closed) {
	widgets = (Widget *) cur_ptr->data;
	if (w == widgets[1]) {
	  join_game(cur_ptr->table_id);
	  joined = TRUE;
	  return;
	}
      }
      cur_ptr = cur_ptr->next_table;
    }
  } else if (XtIsSensitive(anotherGame)) {
    another_game(w, NULL, NULL);
  }
}

/**********************************************************************/

void
dealerInput(client_data, source, id)
XtPointer client_data;
int *source;
XtInputId *id;
{
  fd_type read_fd;
  int nready;
  struct timeval timeout;

  timeout.tv_sec = 0;
  timeout.tv_usec = 0;
  fd_init(dealer_socket, &read_fd);
  while (dealerId &&
	 (nready = select(WIDTH, &read_fd, (fd_type *) 0, (fd_type *) 0,
			  &timeout)) && nready > 0) {
    do_socket();
  }
}

void
distInput(client_data, source, id)
XtPointer client_data;
int *source;
XtInputId *id;
{
  fd_type read_fd;
  int nready;
  struct timeval timeout;

  timeout.tv_sec = 0;
  timeout.tv_usec = 0;
  fd_init(dist_socket, &read_fd);
  while (distId &&
	 (nready = select(WIDTH, &read_fd, (fd_type *) 0, (fd_type *) 0,
			  &timeout)) && nready > 0) {
    do_dist();
  }
}

void
buildScoreLabels(parent, header, array)
Widget parent;
char *header;
Widget *array;
{
  Widget rc;
  XmString xs;
  int each;

  xs = XmStringCreateSimple(header);
  count = 0;
  XtSetArg(args[count], XmNorientation, XmVERTICAL);  count++;
  XtSetArg(args[count], XmNpacking, XmPACK_COLUMN);  count++;
  if (array == playerLabels) {
    XtSetArg(args[count], XmNentryAlignment, XmALIGNMENT_BEGINNING);  count++;
  } else {
    XtSetArg(args[count], XmNentryAlignment, XmALIGNMENT_END);  count++;
  }
  rc = XmCreateRowColumn(parent, "scoresColumn", args, count);
  XtManageChild(rc);
  count = 0;
  XtSetArg(args[count], XmNlabelString, xs);  count++;
  XtSetArg(args[count], XmNrecomputeSize, False);  count++;
  array[0] = XmCreateLabelGadget(rc, "header", args, count);
  XmStringFree(xs);
  xs = XmStringCreateSimple(" ");
  for (each=1; each<=4; each++) {
    count = 0;
    XtSetArg(args[count], XmNlabelString, xs);  count++; 
    XtSetArg(args[count], XmNrecomputeSize, False);  count++;
    array[each] = XmCreateLabelGadget(rc, "label", args, count);
  }
  XmStringFree(xs);
  XtManageChildren(array, 5);
}

void
buildScoreArea(parent)
Widget parent;
{
  Widget rc;

  count = 0;
  XtSetArg(args[count], XmNorientation, XmHORIZONTAL);  count++;
  XtSetArg(args[count], XmNpacking, XmPACK_COLUMN);  count++;
  rc = XmCreateRowColumn(parent, "scoreArea", args, count);
  XtManageChild(rc);
  buildScoreLabels(rc, "Player:      ", playerLabels);
  buildScoreLabels(rc, "Score:", scoreLabels);
  buildScoreLabels(rc, "Total:", totalLabels);
}

void
buildCommandArea(parent)
Widget parent;
{
  Widget rc;
  XmString xs;

  count = 0;
  XtSetArg(args[count], XmNorientation, XmHORIZONTAL);  count++;
  XtSetArg(args[count], XmNpacking, XmPACK_COLUMN);  count++; 
  XtSetArg(args[count], XmNentryAlignment, XmALIGNMENT_BEGINNING);  count++;
  rc = XmCreateRowColumn(parent, "commandArea", args, count);
  XtManageChild(rc);
  xs = XmStringCreateSimple("Toggle Last");
  count = 0;
  XtSetArg(args[count], XmNlabelString, xs);  count++;
  showButton = XmCreatePushButton(rc, "showButton", args, count);
  XtManageChild(showButton);
  XmStringFree(xs);
  XtAddCallback(showButton, XmNactivateCallback, show_button, NULL);
  xs = XmStringCreateSimple("Auto Play");
  count = 0;
  XtSetArg(args[count], XmNlabelString, xs);  count++;
  autoButton = XmCreatePushButton(rc, "autoButton", args, count);
  XtManageChild(autoButton);
  XtAddCallback(autoButton, XmNactivateCallback, auto_play, NULL);
  XmStringFree(xs);
  xs = XmStringCreateSimple("Quit");
  count = 0;
  XtSetArg(args[count], XmNlabelString, xs);  count++;
  quitButton = XmCreatePushButton(rc, "quitButton", args, count);
  XtManageChild(quitButton);
  XtAddCallback(quitButton, XmNactivateCallback, quit_game, NULL);
  XmStringFree(xs);
  xs = XmStringCreateSimple("Help");
  count = 0;
  XtSetArg(args[count], XmNlabelString, xs);  count++;
  helpButton = XmCreatePushButton(rc, "helpButton", args, count);
  XtManageChild(helpButton);
  XtAddCallback(helpButton, XmNactivateCallback, help_me, NULL);
  XmStringFree(xs);
}

void
buildInterface(parent)
Widget parent;
{
  Widget form;
  XmString xs;

  count = 0;
  XtSetArg(args[count], XmNtopAttachment, XmATTACH_FORM);  count++;
  XtSetArg(args[count], XmNtopOffset, 10);  count++;
  XtSetArg(args[count], XmNbottomAttachment, XmATTACH_FORM);  count++;
  XtSetArg(args[count], XmNbottomOffset, 10);  count++;
  XtSetArg(args[count], XmNleftAttachment, XmATTACH_FORM);  count++;
  XtSetArg(args[count], XmNleftOffset, 10);  count++;
  XtSetArg(args[count], XmNrightAttachment, XmATTACH_FORM);  count++;
  XtSetArg(args[count], XmNrightOffset, 10);  count++;
  form = XmCreateForm(parent, "form", args, count);
  XtManageChild(form);

  count = 0;
  XtSetArg(args[count], XmNtopAttachment, XmATTACH_FORM);  count++;
  XtSetArg(args[count], XmNleftAttachment, XmATTACH_FORM);  count++;
  XtSetArg(args[count], XmNshadowType, XmSHADOW_IN);  count++;
  XtSetArg(args[count], XmNmarginWidth, 10);  count++;
  XtSetArg(args[count], XmNmarginHeight, 10);  count++;
  displayFrame = XmCreateFrame(form, "displayFrame", args, count);
  XtManageChild(displayFrame);
  count = 0;
  XtSetArg(args[count], XmNwidth, 4*STACK_WIDTH-STACK_SPACING+2);  count++;
  XtSetArg(args[count], XmNheight, 12*CARD_DELTA+CARD_HEIGHT+2);  count++;
  XtSetArg(args[count], XmNshadowThickness, 0);  count++;
  displayArea = XmCreateDrawingArea(displayFrame, "displayArea",
				    args, count);
  XtManageChild(displayArea);
  XtAddCallback(displayArea, XmNexposeCallback, exposeDisplayArea, NULL);
  XtAddEventHandler(displayArea, ButtonPressMask, False, displaySelect, NULL);

  count = 0;
  XtSetArg(args[count], XmNtopAttachment, XmATTACH_WIDGET);  count++;
  XtSetArg(args[count], XmNtopWidget, displayFrame);  count++;
  XtSetArg(args[count], XmNtopOffset, 10);  count++;
  XtSetArg(args[count], XmNleftAttachment, XmATTACH_FORM);  count++;
/* adjust for display frame margin */
  XtSetArg(args[count], XmNleftOffset, 10);  count++;
  XtSetArg(args[count], XmNrightAttachment,
	   XmATTACH_OPPOSITE_WIDGET);  count++;
  XtSetArg(args[count], XmNrightWidget, displayFrame);  count++;
  XtSetArg(args[count], XmNheight, CARD_HEIGHT+2);  count++;
  XtSetArg(args[count], XmNshadowThickness, 0);  count++;
  playArea = XmCreateDrawingArea(form, "playArea", args, count);
  XtManageChild(playArea);
  XtAddCallback(playArea, XmNexposeCallback, exposePlayArea, NULL);

  count = 0;
  XtSetArg(args[count], XmNtopAttachment, XmATTACH_WIDGET);  count++;
  XtSetArg(args[count], XmNtopWidget, playArea);  count++;
  XtSetArg(args[count], XmNtopOffset, 10);  count++;
  XtSetArg(args[count], XmNleftAttachment, XmATTACH_FORM);  count++;
/* adjust for display frame margin */
  XtSetArg(args[count], XmNleftOffset, 10);  count++;
  XtSetArg(args[count], XmNrightAttachment,
	   XmATTACH_OPPOSITE_WIDGET);  count++;
  XtSetArg(args[count], XmNrightWidget, displayFrame);  count++;
  XtSetArg(args[count], XmNentryAlignment, XmALIGNMENT_CENTER);  count++;
  XtSetArg(args[count], XmNpacking, XmPACK_COLUMN);  count++;
  XtSetArg(args[count], XmNnumColumns, 1);  count++;
  XtSetArg(args[count], XmNorientation, XmHORIZONTAL);  count++;
  XtSetArg(args[count], XmNmarginWidth, 0);  count++;
  XtSetArg(args[count], XmNmarginHeight, 0);  count++;
  XtSetArg(args[count], XmNspacing, STACK_SPACING);  count++;
  playLabelArea = XmCreateRowColumn(form, "playLabelArea", args, count);
  XtManageChild(playLabelArea);

  xs = XmStringCreateSimple(" ");
  count = 0;
  XtSetArg(args[count], XmNlabelString, xs);  count++;
  XtSetArg(args[count], XmNwidth, CARD_WIDTH);  count++;
  XtSetArg(args[count], XmNmarginWidth, 0);  count++;
  XtSetArg(args[count], XmNrecomputeSize, False);  count++;
  playLabels[0] = XmCreateLabelGadget(playLabelArea, "playLabel", args, count);
  XtManageChild(playLabels[0]);
  playLabels[1] = XmCreateLabelGadget(playLabelArea, "playLabel", args, count);
  XtManageChild(playLabels[1]);
  playLabels[2] = XmCreateLabelGadget(playLabelArea, "playLabel", args, count);
  XtManageChild(playLabels[2]);
  playLabels[3] = XmCreateLabelGadget(playLabelArea, "playLabel", args, count);
  XtManageChild(playLabels[3]);
  XmStringFree(xs);

  count = 0;
  XtSetArg(args[count], XmNtopAttachment, XmATTACH_FORM);  count++;
  XtSetArg(args[count], XmNrightAttachment, XmATTACH_FORM);  count++;
  scoreArea = XmCreateFrame(form, "scoreArea", args, count);
  XtManageChild(scoreArea);
  buildScoreArea(scoreArea);

  count = 0;
  XtSetArg(args[count], XmNtopAttachment, XmATTACH_FORM);  count++;
  XtSetArg(args[count], XmNleftAttachment, XmATTACH_WIDGET);  count++;
  XtSetArg(args[count], XmNleftWidget, displayFrame);  count++;
  XtSetArg(args[count], XmNleftOffset, 10);  count++;
  XtSetArg(args[count], XmNrightAttachment, XmATTACH_WIDGET);  count++;
  XtSetArg(args[count], XmNrightWidget, scoreArea);  count++;
  XtSetArg(args[count], XmNorientation, XmVERTICAL);  count++;
  XtSetArg(args[count], XmNpacking, XmPACK_COLUMN);  count++;
  XtSetArg(args[count], XmNentryAlignment, XmALIGNMENT_BEGINNING);  count++;
  displayLabels = XmCreateRowColumn(form, "displayLabels", args, count);
  XtManageChild(displayLabels);

  xs = XmStringCreateSimple("New hand...");
  count = 0;
  XtSetArg(args[count], XmNlabelString, xs);  count++;
  XtSetArg(args[count], XmNrecomputeSize, False);  count++;
  roundLabel = XmCreateLabelGadget(displayLabels, "roundLabel", args, count);
  XtManageChild(roundLabel);
  XmStringFree(xs);

  xs = XmStringCreateSimple("Round: 1");
  count = 0;
  XtSetArg(args[count], XmNlabelString, xs);  count++;
  XtSetArg(args[count], XmNrecomputeSize, False);  count++;
  leadLabel = XmCreateLabelGadget(displayLabels, "leadLabel", args, count);
  XtManageChild(leadLabel);
  XmStringFree(xs);

  xs = XmStringCreateSimple(" ");
  count = 0;
  XtSetArg(args[count], XmNlabelString, xs);  count++;
  XtSetArg(args[count], XmNrecomputeSize, False);  count++;
  textArea = XmCreateLabelGadget(displayLabels, "textArea", args, count);
  XtManageChild(textArea);
  XmStringFree(xs);

  xs = XmStringCreateSimple("Messages:");
  count = 0;
  XtSetArg(args[count], XmNtopAttachment, XmATTACH_WIDGET);  count++;
  XtSetArg(args[count], XmNtopWidget, scoreArea);  count++;
  XtSetArg(args[count], XmNtopOffset, 10);  count++;
  XtSetArg(args[count], XmNleftAttachment, XmATTACH_WIDGET);  count++;
  XtSetArg(args[count], XmNleftWidget, displayFrame);  count++;
  XtSetArg(args[count], XmNleftOffset, 10);  count++;
  XtSetArg(args[count], XmNlabelString, xs);  count++;
  XtSetArg(args[count], XmNalignment, XmALIGNMENT_BEGINNING);  count++;
  messageLabel = XmCreateLabelGadget(form, "messageLabel", args, count);
  XtManageChild(messageLabel);
  XmStringFree(xs);

  count = 0;
  XtSetArg(args[count], XmNbottomAttachment, XmATTACH_FORM);  count++;
  XtSetArg(args[count], XmNrightAttachment, XmATTACH_FORM);  count++;
  commandArea = XmCreateForm(form, "commandArea", args, count);
  XtManageChild(commandArea);
  buildCommandArea(commandArea);

  count = 0;
  XtSetArg(args[count], XmNbottomAttachment, XmATTACH_WIDGET);  count++;
  XtSetArg(args[count], XmNbottomWidget, commandArea);  count++;
  XtSetArg(args[count], XmNbottomOffset, 10);  count++;
  XtSetArg(args[count], XmNleftAttachment, XmATTACH_WIDGET);  count++;
  XtSetArg(args[count], XmNleftWidget, displayFrame);  count++;
  XtSetArg(args[count], XmNleftOffset, 10);  count++;
  XtSetArg(args[count], XmNrightAttachment, XmATTACH_FORM);  count++;
  messageEntry = XmCreateText(form, "messageEntry", args, count);
  XtManageChild(messageEntry);
  XtAddCallback(messageEntry, XmNactivateCallback, send_msg, NULL);
  XmProcessTraversal(messageEntry, XmTRAVERSE_CURRENT);

  count = 0;
  XtSetArg(args[count], XmNtopAttachment, XmATTACH_WIDGET);  count++;
  XtSetArg(args[count], XmNtopWidget, messageLabel);  count++;
  XtSetArg(args[count], XmNbottomAttachment, XmATTACH_WIDGET);  count++;
  XtSetArg(args[count], XmNbottomWidget, messageEntry);  count++;
  XtSetArg(args[count], XmNbottomOffset, 5);  count++;
  XtSetArg(args[count], XmNleftAttachment, XmATTACH_WIDGET);  count++;
  XtSetArg(args[count], XmNleftWidget, displayFrame);  count++;
  XtSetArg(args[count], XmNleftOffset, 10);  count++;
  XtSetArg(args[count], XmNrightAttachment, XmATTACH_FORM);  count++;
  XtSetArg(args[count], XmNwordWrap, True);  count++;
  XtSetArg(args[count], XmNscrollHorizontal, False);  count++;
  XtSetArg(args[count], XmNeditable, False);  count++; 
  XtSetArg(args[count], XmNblinkRate, 0);  count++;
  XtSetArg(args[count], XmNcolumns, 70);  count++;
  XtSetArg(args[count], XmNeditMode, XmMULTI_LINE_EDIT);  count++;
  messageArea = XmCreateScrolledText(form, "messageArea", args, count);
  XtManageChild(messageArea);
}

void
buildOptionInterface(parent)
Widget parent;
{
  Widget header;
  XmString xs;

  count = 0;
  XtSetArg(args[count], XmNtopAttachment, XmATTACH_FORM);  count++;
  XtSetArg(args[count], XmNtopOffset, 10);  count++;
  XtSetArg(args[count], XmNbottomAttachment, XmATTACH_FORM);  count++;
  XtSetArg(args[count], XmNbottomOffset, 10);  count++;
  XtSetArg(args[count], XmNleftAttachment, XmATTACH_FORM);  count++;
  XtSetArg(args[count], XmNleftOffset, 10);  count++;
  XtSetArg(args[count], XmNrightAttachment, XmATTACH_FORM);  count++;
  XtSetArg(args[count], XmNrightOffset, 10);  count++;
  optionForm = XmCreateForm(parent, "optionForm", args, count);
  XtManageChild(optionForm);

  xs = XmStringCreateSimple("Welcome to the Game of Hearts");
  count = 0;
  XtSetArg(args[count], XmNtopAttachment, XmATTACH_FORM);  count++;
  XtSetArg(args[count], XmNleftAttachment, XmATTACH_FORM);  count++;
  XtSetArg(args[count], XmNrightAttachment, XmATTACH_FORM);  count++;
  XtSetArg(args[count], XmNlabelString, xs);  count++;
  XtSetArg(args[count], XmNalignment, XmALIGNMENT_CENTER);  count++;
  XtSetArg(args[count], XmNmarginHeight, 20);  count++;
  header = XmCreateLabelGadget(optionForm, "header", args, count);
  XtManageChild(header);
  XmStringFree(xs);

  if (MIKEYJ) {
    xs = XmStringCreateSimple("(the Jack of Diamonds scores -10)");
  } else {
    xs = XmStringCreateSimple("");
  }
  count = 0;
  XtSetArg(args[count], XmNtopAttachment, XmATTACH_WIDGET);  count++;
  XtSetArg(args[count], XmNtopWidget, header);  count++;
  XtSetArg(args[count], XmNleftAttachment, XmATTACH_FORM);  count++;
  XtSetArg(args[count], XmNrightAttachment, XmATTACH_FORM);  count++;
  XtSetArg(args[count], XmNlabelString, xs);  count++;
  XtSetArg(args[count], XmNalignment, XmALIGNMENT_CENTER);  count++;
  gamesMessage = XmCreateLabelGadget(optionForm, "gamesMessage", args, count);
  XtManageChild(gamesMessage);
  XmStringFree(xs);

  xs = XmStringCreateSimple("Current Games:");
  count = 0;
  XtSetArg(args[count], XmNtopAttachment, XmATTACH_WIDGET);  count++;
  XtSetArg(args[count], XmNtopWidget, gamesMessage);  count++;
  XtSetArg(args[count], XmNtopOffset, 10);  count++;
  XtSetArg(args[count], XmNleftAttachment, XmATTACH_FORM);  count++;
  XtSetArg(args[count], XmNlabelString, xs);  count++;
  XtSetArg(args[count], XmNalignment, XmALIGNMENT_BEGINNING);  count++;
  gamesHeader = XmCreateLabelGadget(optionForm, "gamesHeader", args, count);
  XtManageChild(gamesHeader);
  XmStringFree(xs);

  count = 0;
  XtSetArg(args[count], XmNbottomAttachment, XmATTACH_FORM);  count++;
  XtSetArg(args[count], XmNrightAttachment, XmATTACH_FORM);  count++;
  XtSetArg(args[count], XmNorientation, XmHORIZONTAL);  count++;
  XtSetArg(args[count], XmNpacking, XmPACK_COLUMN);  count++; 
  XtSetArg(args[count], XmNentryAlignment, XmALIGNMENT_BEGINNING);  count++;
  gameBox = XmCreateRowColumn(optionForm, "gameBox", args, count);
  XtManageChild(gameBox);

  xs = XmStringCreateSimple("Another Game");
  count = 0;
  XtSetArg(args[count], XmNlabelString, xs);  count++;
  anotherGame = XmCreatePushButton(gameBox, "anotherGame", args, count);
  XtManageChild(anotherGame);
  XtAddCallback(anotherGame, XmNactivateCallback, another_game, NULL);
  
  xs = XmStringCreateSimple("New Game");
  count = 0;
  XtSetArg(args[count], XmNlabelString, xs);  count++;
  newGame = XmCreatePushButton(gameBox, "newGame", args, count);
  XtManageChild(newGame);
  XtAddCallback(newGame, XmNactivateCallback, new_game, NULL);
  
  xs = XmStringCreateSimple("More Games");
  count = 0;
  XtSetArg(args[count], XmNlabelString, xs);  count++;
  moreGames = XmCreatePushButton(gameBox, "moreGames", args, count);
  XtManageChild(moreGames);
  XtAddCallback(moreGames, XmNactivateCallback, more_games, NULL);
  
  xs = XmStringCreateSimple("Quit");
  count = 0;
  XtSetArg(args[count], XmNlabelString, xs);  count++;
  quitGame = XmCreatePushButton(gameBox, "quitGame", args, count);
  XtManageChild(quitGame);
  XtAddCallback(quitGame, XmNactivateCallback, quit_game, NULL);

  xs = XmStringCreateSimple("Help");
  count = 0;
  XtSetArg(args[count], XmNlabelString, xs);  count++;
  helpGame = XmCreatePushButton(gameBox, "helpGame", args, count);
  XtManageChild(helpGame);
  XtAddCallback(helpGame, XmNactivateCallback, help_me, NULL);

  count = 0;
  XtSetArg(args[count], XmNtopAttachment, XmATTACH_WIDGET);  count++;
  XtSetArg(args[count], XmNtopWidget, gamesHeader);  count++;
  XtSetArg(args[count], XmNbottomAttachment, XmATTACH_WIDGET);  count++;
  XtSetArg(args[count], XmNbottomWidget, gameBox);  count++;
  XtSetArg(args[count], XmNbottomOffset, 10);  count++;
  XtSetArg(args[count], XmNleftAttachment, XmATTACH_FORM);  count++;
  XtSetArg(args[count], XmNrightAttachment, XmATTACH_FORM);  count++;
  XtSetArg(args[count], XmNshadowType, XmSHADOW_IN);  count++;
  gamesFrame = XmCreateFrame(optionForm, "gamesFrame", args, count);
  XtManageChild(gamesFrame);

  count = 0;
  XtSetArg(args[count], XmNorientation, XmVERTICAL);  count++;
  XtSetArg(args[count], XmNpacking, XmPACK_COLUMN);  count++;
  XtSetArg(args[count], XmNnumColumns, NUM_TABLES_COLS);  count++;
  XtSetArg(args[count], XmNadjustLast, False);  count++;
  XtSetArg(args[count], XmNmarginWidth, 10);  count++;
  XtSetArg(args[count], XmNmarginHeight, 10);  count++;
  XtSetArg(args[count], XmNspacing, 10);  count++;
  gamesRC = XmCreateRowColumn(gamesFrame, "gamesRC", args, count);
  XtManageChild(gamesRC);
}

init(argc_p, argv)
int *argc_p;
char **argv;
{
  char ch, *pager, buffer[128];
  int suit;
  CardInfo *card;

  toplevel = XtInitialize(argv[0], "Xmhearts", NULL, 0, argc_p, argv);
#ifdef USE_SCHEMES
  VkLoadScheme(XtDisplay(toplevel), argv[0], "Xmhearts");
#endif
  appContext = XtWidgetToApplicationContext(toplevel);

  count = 0;
  form = XmCreateForm(toplevel, "form", args, count);
  XtManageChild(form);

  buildInterface(form);
  buildOptionInterface(form);
  gfx_init(XtDisplay(toplevel), XScreenNumberOfScreen(XtScreen(toplevel)));

  XtRealizeWidget(toplevel);

  for (suit=CLUBS; suit<=SPADES; suit++) {
    card = (CardInfo *) malloc(sizeof(CardInfo));
    card->rank = card->suit = 0;
    card->next = NULL;
    my_hand[suit].head = card;
  }
  playCards[0].rank = 0;
  playCards[1].rank = 0;
  playCards[2].rank = 0;
  playCards[3].rank = 0;
  playNames[0][0] = '\0';
  playNames[1][0] = '\0';
  playNames[2][0] = '\0';
  playNames[3][0] = '\0';
  lastCards[0].rank = 0;
  lastCards[1].rank = 0;
  lastCards[2].rank = 0;
  lastCards[3].rank = 0;
  lastNames[0][0] = '\0';
  lastNames[1][0] = '\0';
  lastNames[2][0] = '\0';
  lastNames[3][0] = '\0';
  setReadingCard(False);
}

print_cards(suit)
int suit;
{
  CardInfo *ptr;
  int y;
  Rank r;
  Suit s;

  s = convertSuit(suit);
  ptr = my_hand[suit].head;
  y = 0;
  while (ptr->next) {
    ptr = ptr->next;
    r = convertRank(ptr->rank);
    paint_card(XtWindow(displayArea), (suit-1)*STACK_WIDTH, y, r, s,
	       ptr->next ? CARD_DELTA : 0);
    y += CARD_DELTA;
  }
  if (y) {
    XClearArea(XtDisplay(displayArea), XtWindow(displayArea),
	       (suit-1)*STACK_WIDTH, y+CARD_HEIGHT-CARD_DELTA+1 /* bw */,
	       STACK_WIDTH, 0, False);
  } else {
    XClearArea(XtDisplay(displayArea), XtWindow(displayArea),
	       (suit-1)*STACK_WIDTH, 0,
	       STACK_WIDTH, 0, False);
  }
}

void
displayMessage(msg)
char *msg;
{
  XmString xs;

  xs = XmStringCreateSimple(msg);
  count = 0;
  XtSetArg(args[count], XmNlabelString, xs);  count++;
  XtSetValues(textArea, args, count);
  XmStringFree(xs);
}

/**********************************************************************/

enter_card(rank, suit)
int rank, suit;
{
  CardInfo *card, *ptr;

  card = (CardInfo *) malloc(sizeof(CardInfo));
  card->rank = rank;
  card->suit = suit;
  ptr = my_hand[suit].head;
  while (ptr->next && ptr->next->rank > rank) {
    ptr = ptr->next;
  }
  card->next = ptr->next;
  ptr->next = card;
  print_cards(suit);
}

remove_card(rank, suit)
int rank, suit;
{
  CardInfo *card, *ptr;

  ptr = my_hand[suit].head;
  while (ptr->next) {
    if (ptr->next->rank == rank) {
      card = ptr->next;
      ptr->next = card->next;
      free((char *) card);
      break;
    } else {
      ptr = ptr->next;
    }
  }
  print_cards(suit);
}

erase_window(window_num)
int window_num;
{
  XmString xs;

  if (window_num == PLAY_WINDOW) {
/* if PLAY_WINDOW then save it for showing last */
    lastCards[0] = playCards[0];
    lastCards[1] = playCards[1];
    lastCards[2] = playCards[2];
    lastCards[3] = playCards[3];
    strcpy(lastNames[0], playNames[0]);
    strcpy(lastNames[1], playNames[1]);
    strcpy(lastNames[2], playNames[2]);
    strcpy(lastNames[3], playNames[3]);
    playCards[0].rank = 0;
    playCards[1].rank = 0;
    playCards[2].rank = 0;
    playCards[3].rank = 0;
    playNames[0][0] = '\0';
    playNames[1][0] = '\0';
    playNames[2][0] = '\0';
    playNames[3][0] = '\0';
    XClearArea(XtDisplay(playArea), XtWindow(playArea), 0, 0,
	       0, 0, False);
    xs = XmStringCreateSimple(" ");
    count = 0;
    XtSetArg(args[count], XmNlabelString, xs);  count++;
    XtSetValues(playLabels[0], args, count);
    XtSetValues(playLabels[1], args, count);
    XtSetValues(playLabels[2], args, count);
    XtSetValues(playLabels[3], args, count);
    XmStringFree(xs);
  } else if (window_num == TEXT_WINDOW) {
    displayMessage("");
  }
}

read_card()
{
  setReadingCard(True);
}

play_card(player, rch, sch, msg)
int player, rch, sch;
char *msg;
{
  XmString xs;

  playCards[player-1].rank = get_rank(rch);
  playCards[player-1].suit = get_suit(sch);
  if (!showOld) {
    paint_card(XtWindow(playArea), (player-1)*STACK_WIDTH, 0,
	       convertRank(playCards[player-1].rank),
	       convertSuit(playCards[player-1].suit),
	       0);
  }
  if (*msg != '\0') {
    strcpy(playNames[player-1], msg);
    if (!showOld) {
      xs = XmStringCreateSimple(msg);
      count = 0;
      XtSetArg(args[count], XmNlabelString, xs);  count++;
      XtSetValues(playLabels[player-1], args, count);
      XmStringFree(xs);
    }
  }
  XmUpdateDisplay(playArea);
  sleep(1);
}

score_points(player, pts, total_pts, msg)
int player, pts, total_pts;
char *msg;
{
  char str[256];
  XmString xs;

  xs = XmStringCreateSimple(msg);
  count = 0;
  XtSetArg(args[count], XmNlabelString, xs);  count++;
  XtSetValues(playerLabels[player], args, count);
  XmStringFree(xs);
  sprintf(str, "%d  ", pts);
  xs = XmStringCreateSimple(str);
  count = 0;
  XtSetArg(args[count], XmNlabelString, xs);  count++;
  XtSetValues(scoreLabels[player], args, count);
  XmStringFree(xs);
  sprintf(str, "%d  ", total_pts);
  xs = XmStringCreateSimple(str);
  count = 0;
  XtSetArg(args[count], XmNlabelString, xs);  count++;
  XtSetValues(totalLabels[player], args, count);
  XmStringFree(xs);
}

display_message(window_num, msg)
int window_num;
char *msg;
{
  XmString xs;
  char *str;

  if (window_num == MESG_WINDOW || window_num == PLAY_WINDOW) {
    XmTextInsert(messageArea, XmTextGetLastPosition(messageArea), msg);
    XmTextInsert(messageArea, XmTextGetLastPosition(messageArea), "\n");
    {
      short rows;
      Position x, y;
      
      count = 0;
      XtSetArg(args[count], XmNrows, &rows);  count++;
      XtGetValues(messageArea, args, count);
      if (rows <= 1) {
	XmTextShowPosition(messageArea, XmTextGetLastPosition(messageArea));
      } else {
	while (!XmTextPosToXY(messageArea, XmTextGetLastPosition(messageArea),
			      &x, &y)) {
	  XmTextScroll(messageArea, 1);
	}
      }
    }
  } else {
    xs = XmStringCreateSimple(msg);
    count = 0;
    XtSetArg(args[count], XmNlabelString, xs);  count++;
    if (window_num == TEXT_WINDOW) {
      XtSetValues(textArea, args, count);
    } else if (window_num == ROUND_WINDOW) {
      XtSetValues(roundLabel, args, count);
    } else if (window_num == LEAD_WINDOW) {
      XtSetValues(leadLabel, args, count);
    }
    XmStringFree(xs);
  }
}

game_is_over()
{
  XmString xs;
  Boolean buttonPressed;
  XEvent event;

  display_message(MESG_WINDOW,
		  "--------------------------------------------------------");
  display_message(MESG_WINDOW, "");
  display_message(MESG_WINDOW, "Click the left mouse button to continue...");
  XmUpdateDisplay(messageArea);

  buttonPressed = False;
  XGrabPointer(XtDisplay(messageArea), XtWindow(messageArea), True,
	       ButtonPressMask, GrabModeAsync, GrabModeAsync,
	       XtWindow(messageArea), None, CurrentTime);
  while (!buttonPressed) {
    if (XCheckTypedWindowEvent(XtDisplay(messageArea),
			       XtWindow(messageArea),
			       ButtonPress, &event)) {
      XtDispatchEvent(&event);
      XUngrabPointer(XtDisplay(messageArea), event.xbutton.time);
      XSync(XtDisplay(messageArea), False);
      buttonPressed = True;
    }
  }
}

start_game()
{
  XLowerWindow(XtDisplay(optionForm), XtWindow(optionForm));
  XmProcessTraversal(messageEntry, XmTRAVERSE_CURRENT);
  XSync(XtDisplay(optionForm), False);
  showOld = False;

  playCards[0].rank = 0;
  playCards[1].rank = 0;
  playCards[2].rank = 0;
  playCards[3].rank = 0;
  playNames[0][0] = '\0';
  playNames[1][0] = '\0';
  playNames[2][0] = '\0';
  playNames[3][0] = '\0';
  lastCards[0].rank = 0;
  lastCards[1].rank = 0;
  lastCards[2].rank = 0;
  lastCards[3].rank = 0;
  lastNames[0][0] = '\0';
  lastNames[1][0] = '\0';
  lastNames[2][0] = '\0';
  lastNames[3][0] = '\0';

  XmTextSetString(messageArea, "");
}

/*
 * Scan input for redraw screen requests or ':' messages.
 * Also scan socket for incoming commands.
 */
scan()
{
  static XEvent event;

  XtAppNextEvent(appContext, &event);
  XtDispatchEvent(&event);
}

terminate()
{
  XtDestroyWidget(toplevel);
}

/*
 * show_table - display table which is position table_pos on screen.
 */
show_table(cur_ptr, table_pos)
table_ptr	cur_ptr;
int		table_pos;
{
  Dimension width, height, marginWidth, marginHeight, spacing;
  Widget *widgets;
  XmString xs;
  char str[256];
  int each;

  count = 0;
  XtSetArg(args[count], XmNwidth, &width);  count++;
  XtSetArg(args[count], XmNheight, &height);  count++;
  XtSetArg(args[count], XmNmarginWidth, &marginWidth);  count++;
  XtSetArg(args[count], XmNmarginHeight, &marginHeight);  count++;
  XtSetArg(args[count], XmNspacing, &spacing);  count++;
  XtGetValues(gamesRC, args, count);

  if (!cur_ptr->data) {
    widgets = (Widget *) malloc(8*sizeof(Widget));
    count = 0;
    XtSetArg(args[count], XmNshadowType, XmSHADOW_OUT);  count++;
    widgets[0] = XmCreateFrame(gamesRC, "tableFrame", args, count);
    XtManageChild(widgets[0]);
    count = 0;
    XtSetArg(args[count], XmNorientation, XmVERTICAL);  count++;
    XtSetArg(args[count], XmNpacking, XmPACK_COLUMN);  count++;
    XtSetArg(args[count], XmNnumColumns, 1);  count++;
    XtSetArg(args[count], XmNentryAlignment, XmALIGNMENT_CENTER);  count++;
    XtSetArg(args[count], XmNmarginWidth, 0);  count++;
    widgets[1] = XmCreateRowColumn(widgets[0], "tableW", args, count);
    XtAddEventHandler(widgets[1], ButtonPressMask, False, tableSelect, NULL);
    xs = XmStringCreateSimple(" ");
    count = 0;
    XtSetArg(args[count], XmNlabelString, xs);  count++;
    XtSetArg(args[count], XmNrecomputeSize, False);  count++;
    for (each=0; each<6; each++) {
      widgets[each+2] = XmCreateLabelGadget(widgets[1], "tableLabel",
					    args, count);
    }
    XmStringFree(xs);
    XtManageChildren(widgets+2, 6);
    XtManageChild(widgets[1]);
    XtManageChild(widgets[0]);
    cur_ptr->data = (char *) widgets;
  } else {
    widgets = (Widget *) cur_ptr->data;
    XtManageChild(widgets[0]);
  }

  sprintf(str, "Table %d", table_pos+1);
  xs = XmStringCreateSimple(str);
  count = 0;
  XtSetArg(args[count], XmNlabelString, xs);  count++;
  XtSetValues(widgets[2], args, count);
  XmStringFree(xs);

  if (cur_ptr->closed) {
    xs = XmStringCreateSimple("<game over>");
    count = 0;
    XtSetArg(args[count], XmNlabelString, xs);  count++;
    XtSetValues(widgets[3], args, count);
    XmStringFree(xs);
    xs = XmStringCreateSimple(" ");
    count = 0;
    XtSetArg(args[count], XmNlabelString, xs);  count++;
    XtSetValues(widgets[4], args, count);
    XtSetValues(widgets[5], args, count);
    XtSetValues(widgets[6], args, count);
    XtSetValues(widgets[7], args, count);
    XmStringFree(xs);
  } else {
    if (!cur_ptr->hand) {
      sprintf(str, "<starting>");
    } else {
      sprintf(str, "Hand: %d  Round: %d", cur_ptr->hand, cur_ptr->round);
    }
    xs = XmStringCreateSimple(str);
    count = 0;
    XtSetArg(args[count], XmNlabelString, xs);  count++;
    XtSetValues(widgets[3], args, count);
    XmStringFree(xs);

    for (each=0; each<4; each++) {
      xs = XmStringCreateSimple(cur_ptr->player_name[each]);
      count = 0;
      XtSetArg(args[count], XmNlabelString, xs);  count++;
      XtSetValues(widgets[4+each], args, count);
      XmStringFree(xs);
    }
  }

  /* Make the row column the right width */
  count = 0;
  XtSetArg(args[count], XmNwidth,
	   (width-2*marginWidth-NUM_TABLES_COLS*4-
	    (NUM_TABLES_COLS-1)*spacing)/NUM_TABLES_COLS);  count++;
  XtSetValues(widgets[2], args, count);
}

/*
 * show_tables - display up to NUM_TABLES tables starting with table # start_id.
 */
show_tables(start_id)
int	start_id;
{
  table_ptr cur_ptr;
  int cur_id, i;
  char str[256];
  Widget *widgets;
  XmString xs;
  
  XtSetSensitive(moreGames, (table_count > 8));
  cur_ptr = first_table;
  for (i=0; i<table_count; i++) {
    if (cur_ptr->data) {
      widgets = (Widget *) cur_ptr->data;
      XtUnmanageChild(widgets[0]);
    }
    cur_ptr = cur_ptr->next_table;
  }
  if (table_count) {
    sprintf(str, "Current Games (page %d of %d):",
	    (start_id + NUM_TABLES-1) / NUM_TABLES,
	    (table_count + NUM_TABLES-1) / NUM_TABLES);
    xs = XmStringCreateSimple(str);
  } else {
    xs = XmStringCreateSimple("Current Games:");
  }
  count = 0;
  XtSetArg(args[count], XmNlabelString, xs);  count++;
  XtSetValues(gamesHeader, args, count);
  cur_ptr = first_table;
  for (cur_id = 1; cur_id < start_id; cur_id++) {
    cur_ptr = cur_ptr->next_table;
  }
  XtUnmanageChild(gamesRC);
  for (cur_id = 0; (cur_id < NUM_TABLES) && cur_ptr;
       cur_ptr = cur_ptr->next_table) {
    show_table(cur_ptr, cur_id++);
  }
  XtManageChild(gamesRC);
}

option_scan(another)
char *another;
{
  XEvent event;

  anotherPtr = another;
  *anotherPtr = FALSE;
  XtAppNextEvent(appContext, &event);
  XtDispatchEvent(&event);
}

option_init()
{
  if (distId) {
    XtRemoveInput(distId);
  }
  distId = XtAppAddInput(appContext, dist_socket,
			 (XtPointer) XtInputReadMask, distInput, NULL);
  XtSetSensitive(anotherGame, !first_game);
  XtSetSensitive(newGame, first_game);
  XRaiseWindow(XtDisplay(optionForm), XtWindow(optionForm));
  XSync(XtDisplay(optionForm), False);
}

init_socket()
{
  if (dealerId) {
    XtRemoveInput(dealerId);
  }
  dealerId = XtAppAddInput(appContext, dealer_socket,
			   (XtPointer) XtInputReadMask, dealerInput, NULL);
}

close_socket(s)
int s;
{
  if (s == dealer_socket && dealerId) {
    XtRemoveInput(dealerId);
    dealerId = None;
  } else if (s == dist_socket && distId) {
    XtRemoveInput(distId);
    distId = None;
  }
}

option_clear()
{
  table_ptr cur_ptr;
  int i;
  Widget *widgets;

  cur_ptr = first_table;
  for (i=0; i<table_count; i++) {
    if (cur_ptr->data) {
      widgets = (Widget *) cur_ptr->data;
      XtDestroyWidget(widgets[0]);
      cur_ptr->data = NULL;
    }
    cur_ptr = cur_ptr->next_table;
  }
}
