v04i082: xconf -- X-based conferencing tool, Part01/05

Dan Heller argv at island.uu.net
Tue Jul 25 18:10:11 AEST 1989


Submitted-by: Jon Crowcroft <J.Crowcroft at Cs.Ucl.AC.UK>
Posting-number: Volume 4, Issue 82
Archive-name: xconf/part01

[ This seems to be sun-specific since it uses sun rpc's.  I didn't look
  at the code to be sure, tho.  It compiled fine using the Makefile tho
  I had to modify it to point to a place where IntrinsicI.h is used (it
  is no longer in the X11 include files as it was in R2; it's now in the
  lib/Xt dir in the R3 source tree).  Also, Text.c was too big so I hadda
  split it up into 3 parts (Text.c.a[abc] -- be sure to glue them back
  together before trying to make).  By its description, it seems like a
  useful program.  --argv ]

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then feed it
# into a shell via "sh file" or similar.  To overwrite existing files,
# type "sh file -c".
# The tool that generated this appeared in the comp.sources.unix newsgroup;
# send mail to comp-sources-unix at uunet.uu.net if you want that tool.
# If this archive is complete, you will see the following message at the end:
#		"End of archive 1 (of 5)."
# Contents:  xconf/HELP xconf/Text.c.aa xconf/xconf.c
# Wrapped by argv at sumatra on Tue Jul 25 01:01:04 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'xconf/HELP' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'xconf/HELP'\"
else
echo shar: Extracting \"'xconf/HELP'\" \(2603 characters\)
sed "s/^X//" >'xconf/HELP' <<'END_OF_FILE'
XDESCRIPTION...
XXconf is a simple text based conferencing program.
X
XIt works by opening multiple windows, one per conferee, one on each
Xconferees displays (does not pre-empt user being in multiple
Xconferences though).
X
XIt sets up a top level window with quit/help/accept buttons.
XAccept popups a box widget with multiple asciiTextwidget's (one per
Xconferee). One is for input, the rest show what every one is typeing
Xon their input windows...
X
XNote that the ascii widget is like a jove edit window, and that edit
Xcommands typed in it will have the same effect on the output windows
Xon each other conferees display as on your input window. [Try typing
XCtl-V to go down a page, Meta-V to go up].
X
XOne user starts the conference, specifying all the users (including
Xthemselves) at startup.
XUsers may choose not to accept the conference, by quiting immediately.
XWhen the last person quits, the conference terminates.
X
XA User is specified by user name. This may be optionally appended by
Xa machine (user at machine) and also by a display
X(user at machine:Display#). if the user name appears alone, it can be
Xused to find where the user is logged in, and which of possibly many
Xlogins is least recently idle. If the machine/display is specified,
Xthe user name is ignored, and used simply as a tag for their
Xconference windows.
X
XThere is no floor control at present, so it is a "free for all" 
Xconference, just like an n-way talk.
X
X
XNOTE BENE: 
X
XUnder twm, you need to set NoTitleFocus in your .twmrc file, else
Xkeyboard input never gets focused properly - a sort of feature of twm
X- not really a bug in xconf though...
X
XUSAGE...
XTo run, type
X
Xxconf <user at machine>+ [-typicalXArgs]
X
Xe.g. 
Xxconf jon at perky pp at lagavulin steve at lion -fg green -bg blue
X
XA box appears on each users display, with three command buttons:
X
XQuit
XQuits now, or at any point in the conference.
X
XHelp
XPopups a help window with soem assistance displayed, and a subsidery
Xquit button.
X
XAccept
XAccepts the conference, Popups a new box, with a text window for this
Xuser to type in, and other users input to be output on. The windows
Xare labelled to show whose is whose. If you quit, all the windows
Xvanish on your display, and your output window vanishes onm each other
Xpersons display.
X
XYou type at the widnow marked <= in.
X
XBUGS...
XCurrently there are some odd problems with some window managers.
X
XIf the user who started the conference kills the program, the
Xconference terminates for everyone else [although they may just quit
Xwithout this happening].
X
XWhen you quit, you output window on other conferees display is
Xdestroyed, but not the label.
END_OF_FILE
if test 2603 -ne `wc -c <'xconf/HELP'`; then
    echo shar: \"'xconf/HELP'\" unpacked with wrong size!
fi
# end of 'xconf/HELP'
fi
if test -f 'xconf/Text.c.aa' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'xconf/Text.c.aa'\"
else
echo shar: Extracting \"'xconf/Text.c.aa'\" \(30780 characters\)
sed "s/^X//" >'xconf/Text.c.aa' <<'END_OF_FILE'
X#ifndef lint
Xstatic char Xrcsid[] = "$XConsortium: Text.c,v 1.77 88/10/25 00:14:46 jim Exp $";
X#endif
X
X
X/***********************************************************
XCopyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
Xand the Massachusetts Institute of Technology, Cambridge, Massachusetts.
X
X                        All Rights Reserved
X
XPermission to use, copy, modify, and distribute this software and its 
Xdocumentation for any purpose and without fee is hereby granted, 
Xprovided that the above copyright notice appear in all copies and that
Xboth that copyright notice and this permission notice appear in 
Xsupporting documentation, and that the names of Digital or MIT not be
Xused in advertising or publicity pertaining to distribution of the
Xsoftware without specific, written prior permission.  
X
XDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
XALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
XDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
XANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
XWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
XARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
XSOFTWARE.
X
X******************************************************************/
X
X#include <X11/IntrinsicP.h>
X#include <X11/StringDefs.h>
X#include <X11/Shell.h>
X#include <X11/Xatom.h>
X#include <X11/Xmu.h>
X#include <X11/Cardinals.h>
X#include <X11/Label.h>
X#include <X11/Command.h>
X#include <X11/Dialog.h>
X#include <X11/Scroll.h>
X#include "TextP.h"
X
XAtom FMT8BIT = NULL;
X
Xextern void bcopy();
Xextern void LowerCase();
Xextern int errno, sys_nerr;
Xextern char* sys_errlist[];
X
X#define abs(x)	(((x) < 0) ? (-(x)) : (x))
X#define min(x,y)	((x) < (y) ? (x) : (y))
X#define max(x,y)	((x) > (y) ? (x) : (y))
X#define GETLASTPOS  (*ctx->text.source->Scan) (ctx->text.source, 0, XtstAll, XtsdRight, 1, TRUE)
X
X#define zeroPosition ((XtTextPosition) 0)
X#define BIGNUM ((Dimension)32023)
X
Xstatic void BuildLineTable ();
Xstatic void ScrollUpDownProc();
Xstatic void ThumbProc();
X
X/****************************************************************
X *
X * Full class record constant
X *
X ****************************************************************/
X
Xstatic XtTextSelectType defaultSelectTypes[] = {
X	XtselectPosition,
X	XtselectWord,
X	XtselectLine,
X	XtselectParagraph,
X	XtselectAll,
X	XtselectNull
X};
X
Xstatic caddr_t defaultSelectTypesPtr = (caddr_t)defaultSelectTypes;
Xextern char defaultTextTranslations[];	/* fwd ref */
Xstatic Dimension defWidth = 100;
Xstatic Dimension defHeight = DEFAULT_TEXT_HEIGHT;
X
X#define offset(field) XtOffset(TextWidget, field)
Xstatic XtResource resources[] = {
X    {XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension),
X        offset(core.width), XtRDimension, (caddr_t)&defWidth},
X    {XtNcursor, XtCCursor, XtRCursor, sizeof(Cursor),
X	offset(simple.cursor), XtRString, "xterm"},
X    {XtNheight, XtCHeight, XtRDimension, sizeof(Dimension),
X        offset(core.height), XtRDimension, (caddr_t)&defHeight},
X    {XtNtextOptions, XtCTextOptions, XtRInt, sizeof (int),
X        offset(text.options), XtRImmediate, (caddr_t)0},
X    {XtNdialogHOffset, XtCMargin, XtRInt, sizeof(int),
X	 offset(text.dialog_horiz_offset), XtRImmediate, (caddr_t)0},
X    {XtNdialogVOffset, XtCMargin, XtRInt, sizeof(int),
X	 offset(text.dialog_vert_offset), XtRImmediate, (caddr_t)0},
X    {XtNdisplayPosition, XtCTextPosition, XtRInt,
X	 sizeof (XtTextPosition), offset(text.lt.top), XtRImmediate, (caddr_t)0},
X    {XtNinsertPosition, XtCTextPosition, XtRInt,
X        sizeof(XtTextPosition), offset(text.insertPos), XtRImmediate, (caddr_t)0},
X    {XtNleftMargin, XtCMargin, XtRDimension, sizeof (Dimension),
X        offset(text.client_leftmargin), XtRImmediate, (caddr_t)2},
X    {XtNselectTypes, XtCSelectTypes, XtRPointer,
X        sizeof(XtTextSelectType*), offset(text.sarray),
X	XtRPointer, (caddr_t)&defaultSelectTypesPtr},
X    {XtNtextSource, XtCTextSource, XtRPointer, sizeof (caddr_t),
X         offset(text.source), XtRPointer, NULL},
X    {XtNtextSink, XtCTextSink, XtRPointer, sizeof (caddr_t),
X         offset(text.sink), XtRPointer, NULL},
X    {XtNselection, XtCSelection, XtRPointer, sizeof(caddr_t),
X	 offset(text.s), XtRPointer, NULL},
X#ifdef JON
X    {XtNcallback, XtCCallback, XtRCallback, sizeof(caddr_t),
X	 offset(text.callbacks), XtRCallback, (caddr_t)NULL},
X#endif JON
X};
X#undef offset
X
X  
X#define done(address, type) \
X        { toVal->size = sizeof(type); toVal->addr = (caddr_t) address; }
X
X/* EditType enumeration constants */
X
Xstatic  XrmQuark  XtQTextRead;
Xstatic  XrmQuark  XtQTextAppend;
Xstatic  XrmQuark  XtQTextEdit;
X
X/* ARGSUSED */
Xstatic void CvtStringToEditMode(args, num_args, fromVal, toVal)
X    XrmValuePtr args;		/* unused */
X    Cardinal	*num_args;	/* unused */
X    XrmValuePtr	fromVal;
X    XrmValuePtr	toVal;
X{
X    static XtTextEditType editType;
X    XrmQuark    q;
X    char        lowerName[1000];
X
X/* ||| where to put LowerCase */
X    LowerCase((char *)fromVal->addr, lowerName);
X    q = XrmStringToQuark(lowerName);
X    if (q == XtQTextRead ) {
X        editType = XttextRead;
X        done(&editType, XtTextEditType);
X        return;
X    }
X    if (q == XtQTextAppend) {
X        editType = XttextAppend;
X        done(&editType, XtTextEditType);
X        return;
X    }
X    if (q == XtQTextEdit) {
X        editType = XttextEdit;
X        done(&editType, XtTextEditType);
X        return;
X    }
X    toVal->size = 0;
X    toVal->addr = NULL;
X};
X
X
Xstatic void ClassInitialize()
X{
X    XtQTextRead   = XrmStringToQuark(XtEtextRead);
X    XtQTextAppend = XrmStringToQuark(XtEtextAppend);
X    XtQTextEdit   = XrmStringToQuark(XtEtextEdit);
X
X    XtAddConverter(XtRString, XtREditMode, CvtStringToEditMode, NULL, 0);
X}
X
Xstatic void CreateScrollbar(w)
X    TextWidget w;
X{
X    Arg args[1];
X    Dimension bw;
X    Widget sbar;
X
X    XtSetArg(args[0], XtNheight, w->core.height);
X    w->text.sbar = sbar =
X	    XtCreateWidget("scrollbar", scrollbarWidgetClass, w, args, ONE);
X    XtAddCallback( sbar, XtNscrollProc, ScrollUpDownProc, (caddr_t)w );
X    XtAddCallback( sbar, XtNjumpProc, ThumbProc, (caddr_t)w );
X    w->text.leftmargin += sbar->core.width + (bw = sbar->core.border_width);
X    XtMoveWidget( sbar, -(Position)bw, -(Position)bw );
X}
X
X/* ARGSUSED */
Xstatic void Initialize(request, new)
X Widget request, new;
X{
X    TextWidget ctx = (TextWidget) new;
X
X    if (!FMT8BIT)
X        FMT8BIT = XInternAtom(XtDisplay(new), "FMT8BIT", False);
X
X    if (ctx->core.height == DEFAULT_TEXT_HEIGHT) {
X        ctx->core.height = (2*yMargin) + 2;
X        if (ctx->text.sink)
X	    ctx->core.height += (*ctx->text.sink->MaxHeight)(new, 1);
X    }
X
X    ctx->text.lt.lines = 0;
X    ctx->text.lt.info = NULL;
X    ctx->text.s.left = ctx->text.s.right = 0;
X    ctx->text.s.type = XtselectPosition;
X    ctx->text.s.selections = NULL;
X    ctx->text.s.atom_count = ctx->text.s.array_size = 0;
X    ctx->text.sbar = ctx->text.outer = NULL;
X    ctx->text.lasttime = 0; /* ||| correct? */
X    ctx->text.time = 0; /* ||| correct? */
X    ctx->text.showposition = TRUE;
X    ctx->text.lastPos = ctx->text.source ? GETLASTPOS : 0;
X    ctx->text.dialog = NULL;
X    ctx->text.updateFrom = (XtTextPosition *) XtMalloc((unsigned)1);
X    ctx->text.updateTo = (XtTextPosition *) XtMalloc((unsigned)1);
X    ctx->text.numranges = ctx->text.maxranges = 0;
X    ctx->text.gc = DefaultGCOfScreen(XtScreen(ctx));
X    ctx->text.hasfocus = FALSE;
X    ctx->text.leftmargin = ctx->text.client_leftmargin;
X    ctx->text.update_disabled = False;
X    ctx->text.old_insert = -1;
X
X    if (ctx->text.options & scrollVertical)
X	CreateScrollbar(ctx);
X}
X
Xvoid ForceBuildLineTable();
X
Xstatic void Realize( w, valueMask, attributes )
X   Widget w;
X   Mask *valueMask;
X   XSetWindowAttributes *attributes;
X{
X   TextWidget ctx = (TextWidget)w;
X
X   *valueMask |= CWBitGravity;
X   attributes->bit_gravity =
X       (ctx->text.options & wordBreak) ? ForgetGravity : NorthWestGravity;
X
X   (*textClassRec.core_class.superclass->core_class.realize)
X       (w, valueMask, attributes);
X
X   if (ctx->text.sbar) {
X       XtRealizeWidget(ctx->text.sbar);
X       XtMapWidget(ctx->text.sbar);
X   }
X   ForceBuildLineTable(ctx);
X}
X
X
Xstatic /*void*/ _CreateCutBuffers(d)
X    Display *d;
X{
X    static struct _DisplayRec {
X	struct _DisplayRec *next;
X	Display *dpy;
X    } *dpy_list = NULL;
X    struct _DisplayRec *dpy_ptr;
X
X    for (dpy_ptr = dpy_list; dpy_ptr != NULL; dpy_ptr = dpy_ptr->next) {
X	if (dpy_ptr->dpy == d) return;
X    }
X
X    dpy_ptr = XtNew(struct _DisplayRec);
X    dpy_ptr->next = dpy_list;
X    dpy_ptr->dpy = d;
X    dpy_list = dpy_ptr;
X
X#define Create(buffer) \
X    XChangeProperty(d, RootWindow(d, 0), buffer, XA_STRING, 8, \
X		    PropModeAppend, NULL, 0 );
X
X    Create( XA_CUT_BUFFER0 );
X    Create( XA_CUT_BUFFER1 );
X    Create( XA_CUT_BUFFER2 );
X    Create( XA_CUT_BUFFER3 );
X    Create( XA_CUT_BUFFER4 );
X    Create( XA_CUT_BUFFER5 );
X    Create( XA_CUT_BUFFER6 );
X    Create( XA_CUT_BUFFER7 );
X
X#undef Create
X}
X
X/* Utility routines for support of Text */
X
X
X/*
X * Procedure to manage insert cursor visibility for editable text.  It uses
X * the value of ctx->insertPos and an implicit argument. In the event that
X * position is immediately preceded by an eol graphic, then the insert cursor
X * is displayed at the beginning of the next line.
X*/
Xstatic void InsertCursor (w, state)
X  Widget w;
X  XtTextInsertState state;
X{
X    TextWidget ctx = (TextWidget)w;
X    Position x, y;
X    int dy, line, visible;
X    XtTextBlock text;
X
X    if (ctx->text.lt.lines < 1) return;
X    visible = LineAndXYForPosition(ctx, ctx->text.insertPos, &line, &x, &y);
X    if (line < ctx->text.lt.lines)
X	dy = (ctx->text.lt.info[line + 1].y - ctx->text.lt.info[line].y) + 1;
X    else
X	dy = (ctx->text.lt.info[line].y - ctx->text.lt.info[line - 1].y) + 1;
X
X    /** If the insert position is just after eol then put it on next line **/
X    if (x > ctx->text.leftmargin &&
X	ctx->text.insertPos > 0 &&
X	ctx->text.insertPos >= ctx->text.lastPos) {
X	   /* reading the source is bogus and this code should use scan */
X	   (*ctx->text.source->Read) (ctx->text.source, ctx->text.insertPos - 1, &text, 1);
X	   if (text.ptr[0] == '\n') {
X	       x = ctx->text.leftmargin;
X	       y += dy;
X	   }
X    }
X    y += dy;
X    if (visible)
X	(*ctx->text.sink->InsertCursor)(w, x, y, state);
X    ctx->text.ev_x = x;
X    ctx->text.ev_y = y;
X}
X
X
X/*
X * Procedure to register a span of text that is no longer valid on the display
X * It is used to avoid a number of small, and potentially overlapping, screen
X * updates. [note: this is really a private procedure but is used in
X * multiple modules].
X*/
X_XtTextNeedsUpdating(ctx, left, right)
X  TextWidget ctx;
X  XtTextPosition left, right;
X{
X    int     i;
X    if (left < right) {
X	for (i = 0; i < ctx->text.numranges; i++) {
X	    if (left <= ctx->text.updateTo[i] && right >= ctx->text.updateFrom[i]) {
X		ctx->text.updateFrom[i] = min(left, ctx->text.updateFrom[i]);
X		ctx->text.updateTo[i] = max(right, ctx->text.updateTo[i]);
X		return;
X	    }
X	}
X	ctx->text.numranges++;
X	if (ctx->text.numranges > ctx->text.maxranges) {
X	    ctx->text.maxranges = ctx->text.numranges;
X	    i = ctx->text.maxranges * sizeof(XtTextPosition);
X	    ctx->text.updateFrom = (XtTextPosition *) 
X   	        XtRealloc((char *)ctx->text.updateFrom, (unsigned) i);
X	    ctx->text.updateTo = (XtTextPosition *) 
X		XtRealloc((char *)ctx->text.updateTo, (unsigned) i);
X	}
X	ctx->text.updateFrom[ctx->text.numranges - 1] = left;
X	ctx->text.updateTo[ctx->text.numranges - 1] = right;
X    }
X}
X
X
X/*
X * Procedure to read a span of text in Ascii form. This is purely a hack and
X * we probably need to add a function to sources to provide this functionality.
X * [note: this is really a private procedure but is used in multiple modules].
X*/
Xchar *_XtTextGetText(ctx, left, right)
X  TextWidget ctx;
X  XtTextPosition left, right;
X{
X    char   *result, *tempResult;
X    int length, resultLength;
X    XtTextBlock text;
X    XtTextPosition end, nend;
X    
X    resultLength = right - left + 10;	/* Bogus? %%% */
X    result = (char *)XtMalloc((unsigned) resultLength);
X    end = (*ctx->text.source->Read)(ctx->text.source, left, &text, right - left);
X    (void) strncpy(result, text.ptr, text.length);
X    length = text.length;
X    while (end < right) {
X        nend = (*ctx->text.source->Read)(ctx->text.source, end, &text, right - end);
X	tempResult = result + length;
X        (void) strncpy(tempResult, text.ptr, text.length);
X	length += text.length;
X        end = nend;
X    }
X    result[length] = 0;
X    return result;
X}
X
X
X
X/* 
X * This routine maps an x and y position in a window that is displaying text
X * into the corresponding position in the source.
X */
Xstatic XtTextPosition PositionForXY (ctx, x, y)
X  TextWidget ctx;
X  Position x,y;
X{
X /* it is illegal to call this routine unless there is a valid line table! */
X    int     width, fromx, line;
X    XtTextPosition position, resultstart, resultend;
X
X    /*** figure out what line it is on ***/
X    if (ctx->text.lt.lines == 0) return 0;
X
X    for (line = 0; line < ctx->text.lt.lines - 1; line++) {
X	if (y <= ctx->text.lt.info[line + 1].y)
X	    break;
X    }
X    position = ctx->text.lt.info[line].position;
X    if (position >= ctx->text.lastPos)
X	return ctx->text.lastPos;
X    fromx = ctx->text.lt.info[line].x;	/* starting x in line */
X    width = x - fromx;			/* num of pix from starting of line */
X    (*ctx->text.sink->Resolve) (ctx, position, fromx, width,
X	    &resultstart, &resultend);
X    if (resultstart >= ctx->text.lt.info[line + 1].position)
X	resultstart = (*ctx->text.source->Scan)(ctx->text.source,
X		ctx->text.lt.info[line + 1].position, XtstPositions, XtsdLeft, 1, TRUE);
X    return resultstart;
X}
X
X/*
X * This routine maps a source position in to the corresponding line number
X * of the text that is displayed in the window.
X*/
Xstatic int LineForPosition (ctx, position)
X  TextWidget ctx;
X  XtTextPosition position;
X  /* it is illegal to call this routine unless there is a valid line table!*/
X{
X    int     line;
X
X    if (position <= ctx->text.lt.info[0].position)
X	return 0;
X    for (line = 0; line < ctx->text.lt.lines; line++)
X	if (position < ctx->text.lt.info[line + 1].position)
X	    break;
X    return line;
X}
X
X/*
X * This routine maps a source position into the corresponding line number
X * and the x, y coordinates of the text that is displayed in the window.
X*/
Xstatic int LineAndXYForPosition (ctx, pos, line, x, y)
X  TextWidget ctx;
X  XtTextPosition pos;
X  int *line;
X  Position *x, *y;
X  /* it is illegal to call this routine unless there is a valid line table!*/
X{
X    XtTextPosition linePos, endPos;
X    int     visible, realW, realH;
X
X    *line = 0;
X    *x = ctx->text.leftmargin;
X    *y = yMargin;
X    visible = IsPositionVisible(ctx, pos);
X    if (visible) {
X	*line = LineForPosition(ctx, pos);
X	*y = ctx->text.lt.info[*line].y;
X	*x = ctx->text.lt.info[*line].x;
X	linePos = ctx->text.lt.info[*line].position;
X	(*ctx->text.sink->FindDistance)((Widget)ctx, linePos,
X                                     *x, pos, &realW, &endPos, &realH);
X	*x = *x + realW;
X    }
X    return visible;
X}
X
X/*
X * This routine builds a line table. It does this by starting at the
X * specified position and measuring text to determine the staring position
X * of each line to be displayed. It also determines and saves in the
X * linetable all the required metrics for displaying a given line (e.g.
X * x offset, y offset, line length, etc.).
X*/
Xstatic void BuildLineTable (ctx, position)
X  TextWidget ctx;
X  XtTextPosition position;
X{
X    Position x, y;
X    int width, realW, realH;
X    int line, lines;
X    XtTextPosition startPos, endPos;
X    Boolean     rebuild;
X
X    rebuild = (Boolean) (position != ctx->text.lt.top);
X    lines = (*ctx->text.sink->MaxLines)((Widget)ctx, ctx->core.height);
X    if (ctx->text.lt.info != NULL && lines != ctx->text.lt.lines) {
X	XtFree((char *) ctx->text.lt.info);
X	ctx->text.lt.info = NULL;
X    }
X    if (ctx->text.lt.info == NULL) {
X	ctx->text.lt.info = (XtTextLineTableEntry *)
X	    XtCalloc((unsigned)lines + 1, (unsigned)sizeof(XtTextLineTableEntry));
X	rebuild = TRUE;
X    }
X    if (rebuild) {
X	XtTextLineTableEntry *lt;
X	int options = ctx->text.options;
X	int (*FindPosition)() = ctx->text.sink->FindPosition;
X	int (*Scan)() = ctx->text.source->Scan;
X	ctx->text.lt.top = position;
X	ctx->text.lt.lines = lines;
X	startPos = position;
X	x = ctx->text.leftmargin;
X	y = yMargin;
X	for (line = 0, lt = ctx->text.lt.info; line <= ctx->text.lt.lines;
X	     line++, lt++) {
X	    lt->x = x;
X	    lt->y = y;
X	    lt->position = startPos;
X	    if (startPos <= ctx->text.lastPos) {
X		width = (options & resizeWidth) ? BIGNUM : ctx->core.width - x;
X		(*FindPosition)((Widget)ctx, startPos, x,
X				width, (options & wordBreak),
X				&endPos, &realW, &realH);
X		if (!(options & wordBreak) && endPos < ctx->text.lastPos) {
X		    endPos = (*Scan)(ctx->text.source, startPos,
X				     XtstEOL, XtsdRight, 1, TRUE);
X		    if (endPos == startPos)
X			endPos = ctx->text.lastPos + 1;
X		}
X		lt->endX = realW + x;
X		startPos = endPos;
X	    }
X	    else lt->endX = x;
X	    y = y + realH;
X	}
X    }
X}
X
X/*
X * This routine is used to re-display the entire window, independent of
X * its current state.
X*/
Xvoid ForceBuildLineTable(ctx)
X    TextWidget ctx;
X{
X    XtTextPosition position;
X
X    position = ctx->text.lt.top;
X    ctx->text.lt.top++; /* ugly, but it works */
X    BuildLineTable(ctx, position);
X}
X
X/*
X * This routine is used by Text to notify an associated scrollbar of the
X * correct metrics (position and shown fraction) for the text being currently
X * displayed in the window.
X*/
Xstatic void SetScrollBar(ctx)
X    TextWidget ctx;
X{
X    float   first, last;
X    if (ctx->text.sbar) {
X	if ((ctx->text.lastPos > 0)  &&  (ctx->text.lt.lines > 0)) {
X	    first = ctx->text.lt.top;
X	    first /= ctx->text.lastPos; 
X					/* Just an approximation */
X	    last = ctx->text.lt.info[ctx->text.lt.lines].position;
X	    last /= ctx->text.lastPos;
X	}
X	else {
X	    first = 0.0;
X	    last = 1.0;
X	}
X	XtScrollBarSetThumb(ctx->text.sbar, first, last - first);
X    }
X}
X
X
X/*
X * The routine will scroll the displayed text by lines.  If the arg  is
X * positive, move up; otherwise, move down. [note: this is really a private
X * procedure but is used in multiple modules].
X*/
X_XtTextScroll(ctx, n)
X  TextWidget ctx;
X  int n;			/* assumed <= ctx->text.lt.lines */
X{
X    XtTextPosition top, target;
X    if (n >= 0) {
X	top = min(ctx->text.lt.info[n].position, ctx->text.lastPos);
X	BuildLineTable(ctx, top);
X	if (top >= ctx->text.lastPos)
X	    DisplayTextWindow(ctx);
X	else {
X	    XCopyArea(XtDisplay(ctx), XtWindow(ctx), XtWindow(ctx), ctx->text.gc,
X		      0, ctx->text.lt.info[n].y, (int)ctx->core.width,
X		      (int)ctx->core.height - ctx->text.lt.info[n].y,
X		      0, ctx->text.lt.info[0].y);
X	    (*ctx->text.sink->ClearToBackground)(ctx, 0,
X		ctx->text.lt.info[0].y + ctx->core.height - ctx->text.lt.info[n].y,
X		(int)ctx->core.width, (int)ctx->core.height);
X	    if (n < ctx->text.lt.lines) n++; /* update descenders at bottom */
X	    _XtTextNeedsUpdating(ctx,
X		    ctx->text.lt.info[ctx->text.lt.lines - n].position, ctx->text.lastPos);
X	    SetScrollBar(ctx);
X	}
X    } else {
X	int tempHeight;
X	n = -n;
X	target = ctx->text.lt.top;
X	top = (*ctx->text.source->Scan)(ctx->text.source, target, XtstEOL,
X				     XtsdLeft, n+1, FALSE);
X	BuildLineTable(ctx, top);
X	if (ctx->text.lt.info[n].position == target) {
X	    tempHeight = ctx->text.lt.info[ctx->text.lt.lines-n].y - 1;
X	    XCopyArea(XtDisplay(ctx), XtWindow(ctx), XtWindow(ctx), ctx->text.gc,
X		      0, ctx->text.lt.info[0].y, (int)ctx->core.width, tempHeight,
X		      0, ctx->text.lt.info[n].y);
X	    (*ctx->text.sink->ClearToBackground)(ctx, 0,
X		ctx->text.lt.info[0].y,
X		(int)ctx->core.width, ctx->text.lt.info[n].y - 1);
X	    _XtTextNeedsUpdating(ctx, 
X		    ctx->text.lt.info[0].position, ctx->text.lt.info[n].position);
X	    SetScrollBar(ctx);
X	} else if (ctx->text.lt.top != target) DisplayTextWindow(ctx);
X    }
X}
X
X/*
X * The routine will scroll the displayed text by pixels.  If the arg is
X * positive, move up; otherwise, move down.
X*/
X/*ARGSUSED*/
Xstatic void ScrollUpDownProc (w, closure, callData)
X    Widget w;
X    caddr_t closure;		/* TextWidget */
X    caddr_t callData;		/* #pixels */
X{
X    TextWidget ctx = (TextWidget)closure;
X    int     apix, line;
X    _XtTextPrepareToUpdate(ctx);
X    apix = abs((int)callData);
X    for (line = 1;
X	    line < ctx->text.lt.lines && apix > ctx->text.lt.info[line + 1].y;
X	    line++);
X    if (((int)callData) >= 0)
X	_XtTextScroll(ctx, line);
X    else
X	_XtTextScroll(ctx, -line);
X    _XtTextExecuteUpdate(ctx);
X}
X
X/*
X * The routine "thumbs" the displayed text. Thumbing means reposition the
X * displayed view of the source to a new position determined by a fraction
X * of the way from beginning to end. Ideally, this should be determined by
X * the number of displayable lines in the source. This routine does it as a
X * fraction of the first position and last position and then normalizes to
X * the start of the line containing the position.
X*/
X/*ARGSUSED*/
Xstatic void ThumbProc (w, closure, callData)
X    Widget w;
X    caddr_t closure;		/* TextWidget */
X    float *callData;
X  /* BUG/deficiency: The normalize to line portion of this routine will
X   * cause thumbing to always position to the start of the source.
X   */
X{
X    TextWidget ctx= (TextWidget)closure;
X    XtTextPosition position, old_top, old_bot;
X    _XtTextPrepareToUpdate(ctx);
X    old_top = ctx->text.lt.top;
X    old_bot = ctx->text.lt.info[ctx->text.lt.lines-1].position;
X    position = *callData * ctx->text.lastPos;
X    position = (*ctx->text.source->
X		Scan)(ctx->text.source, position, XtstEOL, XtsdLeft, 1, FALSE);
X    if (position >= old_top && position <= old_bot) {
X	int line;
X	for (line = 0; line < ctx->text.lt.lines &&
X		       position > ctx->text.lt.info[line].position; line++);
X	if (line)
X	    _XtTextScroll(ctx, line);
X    }
X    else {
X	BuildLineTable(ctx, position);
X	if (old_top >= ctx->text.lt.top &&
X	    old_top <= ctx->text.lt.info[ctx->text.lt.lines-1].position) {
X	    int line;
X	    for (line = 0;
X		 line < ctx->text.lt.lines &&
X		 old_top > ctx->text.lt.info[line].position; line++);
X	    BuildLineTable(ctx, old_top);
X	    if (line)
X		_XtTextScroll(ctx, -line);
X	}
X	else {
X	    DisplayTextWindow(ctx);
X	}
X    }
X    _XtTextExecuteUpdate(ctx);
X}
X
X
Xstatic Boolean ConvertSelection(w, selection, target,
X				type, value, length, format)
X  Widget w;
X  Atom *selection, *target, *type;
X  caddr_t *value;
X  unsigned long *length;
X  int *format;
X{
X    Display* d = XtDisplay(w);
X    TextWidget ctx = (TextWidget)w;
X
X    if (*target == XA_TARGETS(d)) {
X	Atom* targetP;
X	Atom* std_targets;
X	unsigned long std_length;
X	if (ctx->text.source->ConvertSelection == NULL ||
X	    !(*ctx->text.source->
X	      ConvertSelection) (d, ctx->text.source, selection, target,
X				 type, value, length, format)) {
X	    *value = NULL;
X	    *length = 0;
X	}
X	XmuConvertStandardSelection(w, ctx->text.time, selection, target, type,
X				   (caddr_t*)&std_targets, &std_length, format);
X	*value = XtRealloc(*value, sizeof(Atom)*(std_length + 6 + *length));
X	targetP = *(Atom**)value + *length;
X	*length += std_length + 5;
X	if (ctx->text.source->edit_mode == XttextEdit)
X	    (*length)++;
X	*targetP++ = XA_STRING;
X	*targetP++ = XA_TEXT(d);
X	*targetP++ = XA_LENGTH(d);
X	*targetP++ = XA_LIST_LENGTH(d);
X	*targetP++ = XA_CHARACTER_POSITION(d);
X	if (ctx->text.source->edit_mode == XttextEdit)
X	    *targetP++ = XA_DELETE(d);
X	bcopy((char*)std_targets, (char*)targetP, sizeof(Atom)*std_length);
X	XtFree((char*)std_targets);
X	*type = XA_ATOM;
X	*format = 32;
X	return True;
X    }
X
X    if (ctx->text.source->ConvertSelection != NULL &&
X	(*ctx->text.source->
X	 ConvertSelection) (d, ctx->text.source, selection,
X			    target, type, value, length, format))
X	return True;
X
X    if (*target == XA_STRING || *target == XA_TEXT(d)) {
X	*type = XA_STRING;
X	*value = _XtTextGetText(ctx, ctx->text.s.left, ctx->text.s.right);
X	*length = strlen(*value);
X	*format = 8;
X	return True;
X    }
X    if (*target == XA_LIST_LENGTH(d)) {
X	*value = XtMalloc(4);
X	if (sizeof(long) == 4)
X	    *(long*)*value = 1;
X	else {
X	    long temp = 1;
X	    bcopy( ((char*)&temp)+sizeof(long)-4, (char*)*value, 4);
X	}
X	*type = XA_INTEGER;
X	*length = 1;
X	*format = 32;
X	return True;
X    }
X    if (*target == XA_LENGTH(d)) {
X	*value = XtMalloc(4);
X	if (sizeof(long) == 4)
X	    *(long*)*value = ctx->text.s.right - ctx->text.s.left;
X	else {
X	    long temp = ctx->text.s.right - ctx->text.s.left;
X	    bcopy( ((char*)&temp)+sizeof(long)-4, (char*)*value, 4);
X	}
X	*type = XA_INTEGER;
X	*length = 1;
X	*format = 32;
X	return True;
X    }
X    if (*target == XA_CHARACTER_POSITION(d)) {
X	*value = XtMalloc(8);
X	(*(long**)value)[0] = ctx->text.s.left + 1;
X	(*(long**)value)[1] = ctx->text.s.right;
X	*type = XA_SPAN(d);
X	*length = 2;
X	*format = 32;
X	return True;
X    }
X    if (*target == XA_DELETE(d)) {
X	void KillCurrentSelection();
X	KillCurrentSelection(ctx, (XEvent*)NULL);
X	*value = NULL;
X	*type = XA_NULL(d);
X	*length = 0;
X	*format = 32;
X	return True;
X    }
X    if (XmuConvertStandardSelection(w, ctx->text.time, selection, target, type,
X				    value, length, format))
X	return True;
X
X    /* else */
X    return False;
X}
X
X
Xstatic void LoseSelection(w, selection)
X  Widget w;
X  Atom *selection;
X{
X    TextWidget ctx = (TextWidget)w;
X    Boolean update_in_progress = (ctx->text.old_insert >= 0);
X    register Atom* atomP;
X    int i, empty;
X
X    _XtTextPrepareToUpdate(ctx);
X
X    for (i = 0, atomP = ctx->text.s.selections;
X	 i < ctx->text.s.atom_count; i++, atomP++)
X    {
X	if (*selection == *atomP) *atomP = (Atom)0;
X	switch (*atomP) {
X	  case XA_CUT_BUFFER0:
X	  case XA_CUT_BUFFER1:
X	  case XA_CUT_BUFFER2:
X	  case XA_CUT_BUFFER3:
X	  case XA_CUT_BUFFER4:
X	  case XA_CUT_BUFFER5:
X	  case XA_CUT_BUFFER6:
X	  case XA_CUT_BUFFER7:	*atomP = (Atom)0;
X	}
X    }
X
X    for (i = ctx->text.s.atom_count; i; i--) {
X	if (ctx->text.s.selections[i-1] != 0) break;
X    }
X    ctx->text.s.atom_count = i;
X
X    for (i = 0, atomP = ctx->text.s.selections;
X	 i < ctx->text.s.atom_count; i++, atomP++)
X    {
X	if (*atomP == (Atom)0) {
X	    *atomP = ctx->text.s.selections[--ctx->text.s.atom_count];
X	}
X    }
X
X    if (ctx->text.s.atom_count == 0)
X	_XtTextSetNewSelection(ctx, ctx->text.insertPos, ctx->text.insertPos,
X			       NULL, ZERO);
X
X    if (!update_in_progress) {
X	_XtTextExecuteUpdate(ctx);
X    }
X}
X
X
Xstatic int _XtTextSetNewSelection(ctx, left, right, selections, count)
X  TextWidget ctx;
X  XtTextPosition left, right;
X  Atom *selections;
X  Cardinal count;
X{
X    XtTextPosition pos;
X    void (*nullProc)() = NULL;
X
X    if (left < ctx->text.s.left) {
X	pos = min(right, ctx->text.s.left);
X	_XtTextNeedsUpdating(ctx, left, pos);
X    }
X    if (left > ctx->text.s.left) {
X	pos = min(left, ctx->text.s.right);
X	_XtTextNeedsUpdating(ctx, ctx->text.s.left, pos);
X    }
X    if (right < ctx->text.s.right) {
X	pos = max(right, ctx->text.s.left);
X	_XtTextNeedsUpdating(ctx, pos, ctx->text.s.right);
X    }
X    if (right > ctx->text.s.right) {
X	pos = max(left, ctx->text.s.right);
X	_XtTextNeedsUpdating(ctx, pos, right);
X    }
X
X    ctx->text.s.left = left;
X    ctx->text.s.right = right;
X    if (ctx->text.source->SetSelection != nullProc) {
X	(*ctx->text.source->SetSelection) (ctx->text.source,
X					   left, right,
X					   count ? selections[0] : NULL);
X    }
X    if (left < right) {
X	int buffer;
X	while (count) {
X	    Atom selection = selections[--count];
X	    switch (selection) {
X	      case XA_CUT_BUFFER0: buffer = 0; break;
X	      case XA_CUT_BUFFER1: buffer = 1; break;
X	      case XA_CUT_BUFFER2: buffer = 2; break;
X	      case XA_CUT_BUFFER3: buffer = 3; break;
X	      case XA_CUT_BUFFER4: buffer = 4; break;
X	      case XA_CUT_BUFFER5: buffer = 5; break;
X	      case XA_CUT_BUFFER6: buffer = 6; break;
X	      case XA_CUT_BUFFER7: buffer = 7; break;
X	      default:		   buffer = -1;
X	    }
X	    if (buffer >= 0) {
X		char *ptr =
X		    _XtTextGetText(ctx, ctx->text.s.left, ctx->text.s.right);
X		if (buffer == 0) {
X		    _CreateCutBuffers(XtDisplay((Widget)ctx));
X		    XRotateBuffers(XtDisplay((Widget)ctx), 1);
X		}
X		XStoreBuffer(XtDisplay((Widget)ctx), ptr,
X			     min(strlen(ptr), MAXCUT), buffer);
X		XtFree (ptr);
X	    } else {
X		XtOwnSelection((Widget)ctx, selection, ctx->text.time,
X			       ConvertSelection, LoseSelection, NULL);
X	    }
X	}
X    }
X}
X
X
X
X/*
X * This internal routine deletes the text from pos1 to pos2 in a source and
X * then inserts, at pos1, the text that was passed. As a side effect it
X * "invalidates" that portion of the displayed text (if any).
X*/
Xstatic
Xint ReplaceText (ctx, pos1, pos2, text)
X  TextWidget ctx;
X  XtTextPosition pos1, pos2;
X  XtTextBlock *text;
X
X /* it is illegal to call this routine unless there is a valid line table!*/
X{
X    int i, line1, visible, delta, error;
X    Position x, y;
X    int realW, realH, width;
X    XtTextPosition startPos, endPos, updateFrom;
X    int (*Scan)() = ctx->text.source->Scan;
X
X    /* the insertPos may not always be set to the right spot in XttextAppend */
X    if ((pos1 == ctx->text.insertPos) &&
X	(ctx->text.source->edit_mode == XttextAppend)) {
X      ctx->text.insertPos = ctx->text.lastPos;
X      pos2 = pos2 - pos1 + ctx->text.insertPos;
X      pos1 = ctx->text.insertPos;
X    }
X    updateFrom = (*Scan)(ctx->text.source, pos1, XtstWhiteSpace, XtsdLeft,
X	    1, TRUE);
X    updateFrom = (*Scan)(ctx->text.source, updateFrom, XtstPositions, XtsdLeft,
X	    1, TRUE);
X    startPos = max(updateFrom, ctx->text.lt.top);
X    visible = LineAndXYForPosition(ctx, startPos, &line1, &x, &y);
X    error = (*ctx->text.source->Replace)(ctx->text.source, pos1, pos2, text);
X    if (error) return error;
X    ctx->text.lastPos = GETLASTPOS;
X    if (ctx->text.lt.top >= ctx->text.lastPos) {
X	BuildLineTable(ctx, ctx->text.lastPos);
X	ClearWindow(ctx);
X	SetScrollBar(ctx);
X	return error;
X    }
X    delta = text->length - (pos2 - pos1);
X    if (delta < ctx->text.lastPos) {
X	pos2 += delta;
X	for (i = 0; i < ctx->text.numranges; i++) {
X	    if (ctx->text.updateFrom[i] > pos1)
X		ctx->text.updateFrom[i] += delta;
X	    if (ctx->text.updateTo[i] >= pos1)
X		ctx->text.updateTo[i] += delta;
X	}
X    }
X
X    /* 
X     * fixup all current line table entries to reflect edit.
X     * %%% it is not legal to do arithmetic on positions.
X     * using Scan would be more proper.
X     */
X    if (delta) {
X	XtTextLineTableEntry *lineP;
X	int line2 = LineForPosition(ctx, pos1) + 1;
X	for (i = line2, lineP = ctx->text.lt.info + line2;
X	     i <= ctx->text.lt.lines; i++, lineP++)
X	    lineP->position += delta;
X    }
X
X    /*
X     * Now process the line table and fixup in case edits caused
X     * changes in line breaks. If we are breaking on word boundaries,
X     * this code checks for moving words to and from lines.
X    */
END_OF_FILE
if test 30780 -ne `wc -c <'xconf/Text.c.aa'`; then
    echo shar: \"'xconf/Text.c.aa'\" unpacked with wrong size!
fi
# end of 'xconf/Text.c.aa'
fi
if test -f 'xconf/xconf.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'xconf/xconf.c'\"
else
echo shar: Extracting \"'xconf/xconf.c'\" \(18989 characters\)
sed "s/^X//" >'xconf/xconf.c' <<'END_OF_FILE'
X#include "xconf.h"
X#ifndef lint
Xstatic char *rcsid = "$Header: $";
X#endif
X
X/*
X * Written By Jon Crowcroft, May 1989
X * yours to do with as you wish
X *
X * I do not claim it has any value whatsoever... 
X *
X * TOFIX
X * Unsatisfactory nature of the conference starter having to name
X * themselves in the argument list.
X *
X */
X
Xchar *usage = "user at host user at host ... [-e] [-X typicalXargs]";
X
X/*
X * For help, click help
X */
Xextern char defaultTextTranslations[];
X/*
X * Some dimensions for the conference windows.
X */
Xstatic int widthb = DEFWIDTHB, heightb = DEFHEIGHTB;
Xstatic int widthw = DEFWIDTHW, heightw = DEFHEIGHTB;
X
X
X/*
X * The conference/window desription structures as far as xa is concerned
X * These are xa private structures, not X-Windows ones...
X */
Xxconf_t Conference[MAXCONF];
Xstatic XtAppContext context;
Xstatic int numberofthem = 0;
Xstatic int numberlive = 0;
X
Xstatic Arg args[10];
Xstatic Cardinal nargs;
X
Xstatic char **saved_argv;
Xstatic int saved_argc; 
X
Xstatic int firsttime = True;
Xstatic int exptl = False;
X
X
Xmain(argc, argv)
Xchar *argv[];
X{
X	int i, max;
X/*
X * Must be talking to at least one person 
X */
X 	if (argc < 2) {
X		(void)fprintf(stderr, "%s %s\n", argv[0], usage);
X		exit(-1);
X	}
X
X/*
X * Parse cmd line args
X * [User[@host[:Display#]]]+ -X TypicalXArgs
X * and count number of users...
X */
X	max = (argc-1 > MAXCONF) ? MAXCONF : argc-1;
X	for(i = 1; i <= max; i++) {
X/*
X * ignore real X args here
X */
X		if (strcmp(argv[i], "-X") == 0)
X			break;
X		if (strcmp(argv[i], "-e") == 0) {
X			exptl = True;
X			continue;
X		}
X		ParseUserDisplay(&Conference[numberofthem], argv[i]);
X		numberofthem += 1;
X	}
X
X	if (numberofthem <= 0) {
X		(void)fprintf(stderr, "No confederates?\n");
X		exit(-1);
X	}
X
X/*
X * Start talking Xt
X * Create Application Context
X */
X	XtToolkitInitialize();	
X	context = XtCreateApplicationContext();
X
X/*
X * For each user(display), 
X * 	there is 1 display which we open a window for their input, 
X * 	on which is for each other user
X *		a window for their output
X *
X * TODO:
X * Should invite user first - could ask them simply to 
X * do xhost <confhost>
X *	where <confhost> is the conference chair...
X */
X	for(i = 0; i < numberofthem; i++) 
X		(void)StartConference(context,
X				i,
X				Conference,
X				numberofthem,
X				argc, 
X				argv);
X	firsttime = False;
X	numberlive = i;
X/*
X * And let X take over
X */
X	XtAppMainLoop(context);
X}
X
XParseUserDisplay(conf, arg)
Xxconf_t *conf;
Xchar *arg;
X{
X	char *cp, *FindMostRecentActiveLogin();
X	(void)strcpy(conf->user, arg);
X	if ((cp = strchr(arg, '@')) == NULL) {
X#ifdef SUNRPC
X		(void)strcpy(conf->display, FindMostRecentActiveLogin(arg));
X#else SUNRPC
X		(void)strcpy(conf->display, "");
X#endif SUNRPC
X	} else {
X		cp += 1;
X		(void)strcpy(conf->display, cp);
X		if (strchr(arg, ':') == NULL) 
X			  (void)strcat(conf->display, ":0"); 
X	}
X}
X
X
X/*
X * This is called by X, when someone clicks on the qb (QUIT)
X * TODO: Fix box to re-layout after conferee exits
X */
X
X/* ARGSUSED */
Xvoid Alldone(widget, data, event)
XWidget widget;
Xcaddr_t data, event;
X{
X	int i, j, someleft = 0;
X	int w,h;
X	XtGeometryResult res;
X	XtWidgetGeometry preferred, intended;
X	int foundsize = False;
X
X	for(i=0; i < numberofthem; i++) {
X		if (Conference[i].qb == widget)  {
X			XtDestroyWidget(Conference[i].toplevel);
X			Conference[i].live = False;
X			for(j=0; j< numberofthem; j++) {
X				if (j != i && Conference[j].live) {
X				    XtDestroyWidget(Conference[j].them[i].v);
X				    if (!foundsize) {
X					    intended.request_mode = 
X						preferred.request_mode = 
X						XtCWQueryOnly|CWWidth|CWHeight;
X					    intended.width = intended.height = 1000;
X					    res = XtQueryGeometry(Conference[j].box, 
X						&intended, &preferred);
X					    w = preferred.width;
X					    h = preferred.height;
X					    foundsize = True;
X				    }
X				    XtSetArg(args[0], XtNwidth, w);
X				    XtSetArg(args[1], XtNheight, h);
X				    XtSetValues(Conference[j].pop, args, TWO);
X				    XtResizeWindow(Conference[j].pop);
X
X				    XtSetArg(args[0], XtNwidth, w);
X				    XtSetArg(args[1], XtNheight, h);
X				    XtSetValues(Conference[j].box, args, TWO);
X				    XtResizeWindow(Conference[j].box);
X				}
X			}
X			(void)fprintf(stderr,"%s has left the conference\n", 
X				Conference[i].user);
X			numberlive--;
X		}
X		if (XtIsRealized(Conference[i].toplevel))
X			someleft++;
X	}
X	if (!someleft || numberlive <= 0) {
X		(void)fprintf(stderr, "The Conference is now Closed\n");
X		exit(0);
X	}
X}
X
X/*
X * Call back to accept conference and pop up all windows
X */
X/* ARGSUSED */
Xvoid Accept(widget, data, event)
XWidget widget;
Xcaddr_t data, event;
X{
X	xconf_t *conf = (xconf_t *)data;
X	XtPopup(conf->pop, XtGrabNone);
X	XtSetKeyboardFocus(conf->box, XtNameToWidget(conf->box, "value"));
X}
X
X/*
X * Call back to pop up add conferee thingy
X */
X/* ARGSUSED */
Xvoid Add(widget, data, event)
XWidget widget;
Xcaddr_t data, event;
X{
X	xconf_t *conf = (xconf_t *)data;
X	XtPopup(conf->npop, XtGrabNone);
X}
X
X/*
X * Actually add the new conferee
X */
X/* ARGSUSED */
Xvoid AddOk(widget, data, event)
XWidget widget;
Xcaddr_t data, event;
X{
X        int i, j;
X	char *cp;
X	xconf_t *conf = (xconf_t *)data;
X	int newconf = numberofthem;
X	int w,h;
X	XtGeometryResult res;
X	XtWidgetGeometry preferred, intended;
X
X	cp = XtDialogGetValueString(conf->nap);
X	ParseUserDisplay(&Conference[newconf], cp);
X	numberofthem++;
X	if (!StartConference(context, 
X			newconf, 
X			Conference, 
X			numberofthem,
X			0,
X			NO(char **))) {
X		numberofthem--;
X		XtSetArg(args[0], XtNvalue, "Cannot find User");
X		XtSetValues(conf->nap, args, ONE);
X		return;
X	}
X
X/*
X * set size of old conferences by new one i.e. let
X * box choose size for this number of children
X */
X	intended.request_mode = 
X		preferred.request_mode = 
X		XtCWQueryOnly|CWWidth|CWHeight;
X	intended.width = intended.height = 1000;
X	res = XtQueryGeometry(Conference[newconf].box, 
X		&intended, &preferred);
X	w = preferred.width;
X	h = preferred.height;
X
X/*
X * And add output for everyone else, resizing as we go
X */
X	for(j=0; j<numberofthem; j++) {
X		if (Conference[j].live && j != newconf) {
X			place(&Conference[j], 
X				Conference[newconf].user, 
X				newconf, j);
X/*
X * Seems to be that you cannot just resize one or the other, 
X * and expect them to "do the right thing"
X */
X			XtSetArg(args[0], XtNwidth, w);
X			XtSetArg(args[1], XtNheight, h);
X			XtSetValues(Conference[j].pop, args, TWO);
X			XtResizeWindow(Conference[j].pop);
X
X			XtSetArg(args[0], XtNwidth, w);
X			XtSetArg(args[1], XtNheight, h);
X			XtSetValues(Conference[j].box, args, TWO);
X			XtResizeWindow(Conference[j].box);
X		}
X	}
X	numberlive++;
X	XtPopdown(conf->npop);
X}
X/* ARGSUSED */
Xvoid AddQuit(widget, data, event)
XWidget widget;
Xcaddr_t data, event;
X{
X	xconf_t *conf = (xconf_t *)data;
X	XtPopdown(conf->npop);
X}
X
X/* ARGSUSED */
Xvoid KeyIn(widget, data, event)
XWidget widget;
Xcaddr_t data;
XXEvent *event;
X{
X        int i,j;
X	Widget w;
X
X	for(i=0; i<numberofthem; i++) {
X		if (Conference[i].me.w == widget) {
X			for(j=0; j<numberofthem; j++) {
X				if ((j != i) && Conference[j].live) {
X					static XEvent ev;
X					w = Conference[j].them[i].w;
X					ev = *event;
X					ev.xany.display = XtDisplay(w);
X					ev.xany.window = XtWindow(w);
X					XtDispatchEvent(&ev);
X				}
X			}
X			return;
X		}
X	}
X	(void)fprintf(stderr,"input from nobody\n");
X}
X
X/* ARGSUSED */
Xvoid Help(widget, data, event)
XWidget widget;
Xcaddr_t data, event;
X{
X	xconf_t *conf = (xconf_t *)data;
X	XtPopup(conf->hpop, XtGrabNone);
X	XtSetKeyboardFocus(conf->hap, XtNameToWidget(conf->hap, "value"));
X}
X
X
X/* ARGSUSED */
Xvoid HelpQuit(widget, data, event)
XWidget widget;
Xcaddr_t data, event;
X{
X	xconf_t *conf = (xconf_t *)data;
X	XtPopdown(conf->hpop);
X}
X
X/* ARGSUSED */
Xvoid Hapropos(widget, data, event)
XWidget widget;
Xcaddr_t data, event;
X{
X	xconf_t *conf = (xconf_t *)data;
X	Arg arg[1];
X	char *cp = "", *dohap();
X
X	cp = XtDialogGetValueString(conf->hap);
X	XtSetArg(arg[0], XtNlabel, dohap(cp));
X	XtSetValues(conf->hapres, arg, ONE);
X}
X
X/*
X * Extract string from default text translations - need
X * to hack round the newlines, tabs and colons to get
X * out a normal looking string
X */
Xchar *
Xdohap(cp)
Xchar *cp;
X{
X	char *dp = defaultTextTranslations, *cdp;
X	static char buf[80], *cb = buf;
X
X	if (cp != '\0') {
X		while(*dp != '\0') {
X			if (strncmp(cp, dp, strlen(cp)) == 0) {
X				cdp = dp;
X				while((*cdp != '\0') && (*cdp != '\n'))
X					cdp--;
X				cdp++;
X				while (*cdp != ':')
X					*cb++ = *cdp++;
X				*cb = '\0';
X				return buf;
X			}
X			dp++;
X		}
X	}
X	return "Nothing Apt";
X}
X
X#ifdef JOKE
Xvoid Joke(widget, data, event)
XWidget widget;
Xcaddr_t data, event;
X{
X	Arg arg[1];
X	XtSetArg(arg[0], XtNlabel, "I told you Not to");
X	XtSetValues(widget, arg, ONE);
X}
X#endif JOKE
X
X 
X#ifdef EXPTL
X/*
X * Call backs for assertion etc...
X */
X/* ARGSUSED */
Xassert(widget, data, event)
XWidget widget;
Xcaddr_t data, event;
X{
X	int i;
X/*
X * Assertion = This fact is the case...
X * Bell for Assertion
X */
X	for(i=0;i<numberofthem; i++)
X		if(Conference[i].live)
X			XBell(XtDisplay(Conference[i].toplevel), 50);
X}
X
X/* ARGSUSED */
Xcommit(widget, data, event)
XWidget widget;
Xcaddr_t data, event;
X{
X/*
X * Committing = I will do this...
X */
X}
X
X/* ARGSUSED */
Xdirect(widget, data, event)
XWidget widget;
Xcaddr_t data, event;
X{
X/*
X * Direction = You will do this...
X */
X}
X
X/* ARGSUSED */
Xdeclare(widget, data, event)
XWidget widget;
Xcaddr_t data, event;
X{
X/*
X * Declaration = Varialbe <- Value, from now on...
X */
X}
X
X/* ARGSUSED */
Xexpress(widget, data, event)
XWidget widget;
Xcaddr_t data, event;
X{
X/*
X * Expression = This is how i feel about this
X *
X * This one really needs a scale most of all
X * color might be used to express here
X */
X}
X#endif EXPTL
X
X/*
X *******************************************************************
X * Set up a toplevel and sub windows on each conf display...
X *******************************************************************
X */
XStartConference(context, nth, confs, nconf, argc, argv)
XXtAppContext context;
Xint	nth;
Xxconf_t *confs;
Xint 	nconf;
Xint 	argc;
Xchar 	*argv[];
X{
X	Screen *scrn;
X	int i;
X	xconf_t *conf = &confs[nth];
X	char *ptr = "";
X
X/*
X * Tie to approprate display, copy args to saved_args 
X */
X	saved_argc = argc;
X	saved_argv = (char **) XtCalloc(
X		(unsigned) ((argc) + 1), (unsigned)sizeof(*saved_argv));
X	for(i=0; i<argc; i++)
X		saved_argv[i] = argv[i];
X	saved_argv[i] = NULL;
X	conf->dpy = XtOpenDisplay(context,
X				      conf->display,
X				      "xconf",
X				      "XConf",
X					NULL, 0,
X				      &saved_argc, saved_argv);
X
X	if (conf->dpy == NO(Display *)) {
X		(void)fprintf(stderr,"oops, cannot open display %s\n",
X				conf->display);
X/*
X * maye we should continue with less people...
X*/
X		if (firsttime)
X			exit(-1);
X		else
X			return False;
X	}
X/*
X * Find right screen for the toplevel... 
X * And do some scaling
X * Note, after this, added conferees may clutter the screen...nis
X */
X	if (firsttime) 
X		Scale(conf->dpy, nconf, &widthb, &heightb, &widthw, &heightw);
X
X/*
X * Create a shell widget to put all the others in
X */
X	nargs = 0;
X	scrn = DefaultScreenOfDisplay(conf->dpy);
X	XtSetArg(args[nargs], XtNscreen, scrn); nargs++;
X	XtSetArg(args[nargs], XtNargc, saved_argc); nargs++;
X	XtSetArg(args[nargs], XtNargv, saved_argv); nargs++;
X	conf->toplevel = XtAppCreateShell("xconf",
X					"XConf",
X#ifdef OVERRIDE
X					overrideShellWidgetClass,
X#else OVERRIDE
X					applicationShellWidgetClass,
X#endif OVERRIDE
X					conf->dpy,
X					args,
X					nargs);
X/*
X * Request Box...
X */
X	conf->tbox = XtCreateManagedWidget("ConfCtlBox", 
X			boxWidgetClass, conf->toplevel, NO(Arg *), ZERO);
X/*
X * And a quit command
X */
X        conf->qb = XtCreateManagedWidget("Quit Conference",  
X			commandWidgetClass, conf->tbox, NO(Arg *), ZERO);
X	XtAddCallback(conf->qb, XtNcallback, Alldone, (caddr_t) conf);
X/*
X * And an add conferee button
X */
X        conf->nb = XtCreateManagedWidget("Add Conferee",  
X			commandWidgetClass, conf->tbox, NO(Arg *), ZERO);
X	XtAddCallback(conf->nb, XtNcallback, Add, (caddr_t) conf);
X	conf->npop = XtCreatePopupShell("AddConf",
X			topLevelShellWidgetClass, conf->toplevel, NULL, ZERO);
X/*
X * and the rest to do conferee adding...
X */
X	conf->nbox = XtCreateManagedWidget("ABox",
X                        boxWidgetClass, conf->npop, NO(Arg *), ZERO);
X	XtSetArg(args[0], XtNlabel, "Add: ");
X	XtSetArg(args[1], XtNvalue, ptr);
X	conf->nap = XtCreateManagedWidget("AddPop",
X			dialogWidgetClass, conf->nbox, args, TWO);
X	conf->nok = XtCreateManagedWidget("Add ok?",
X			commandWidgetClass, conf->nap, NO(Arg *), ZERO);
X	XtAddCallback(conf->nok, XtNcallback, AddOk, (caddr_t)conf);
X	conf->nq = XtCreateManagedWidget("Add Quit?",
X			commandWidgetClass, conf->nap, NO(Arg *), ZERO);
X	XtAddCallback(conf->nq, XtNcallback, AddQuit, (caddr_t)conf);
X
X/*
X * And a accept command
X */
X        conf->ab = XtCreateManagedWidget("Accept Conference",  
X			commandWidgetClass, conf->tbox, NO(Arg *), ZERO);
X	XtAddCallback(conf->ab, XtNcallback, Accept, (caddr_t)conf);
X/*
X * And a Help Button
X */
X	conf->hb = XtCreateManagedWidget("Help",
X                        commandWidgetClass, conf->tbox, NO(Arg *), ZERO);
X	XtAddCallback(conf->hb, XtNcallback, Help, (caddr_t)conf);
X
X/*
X * Do each conf as a popup application window...
X */
X	XtSetArg(args[0], XtNallowResize, True);
X	conf->pop = XtCreatePopupShell("xonferee",
X			topLevelShellWidgetClass, conf->toplevel, args, ONE);
X/*
X * Make a box, with dimensions
X */
X	XtSetArg(args[0], XtNallowResize, True);
X	conf->box = XtCreateManagedWidget("confereebox", 
X			boxWidgetClass, conf->pop, args, ONE);
X
X/*
X * And a popup help window
X */
X	conf->hpop = XtCreatePopupShell("HelpPop",
X			topLevelShellWidgetClass, conf->toplevel, NULL, ZERO);
X/*
X * was topLevel
X */
X	conf->hbox = XtCreateManagedWidget("HelpBox", 
X			boxWidgetClass, conf->hpop, args, TWO);
X/*
X * Why the following?, coz of defects in X{t}whatever
X * it doesnt quite work as we'd like
X */
X	XtAppAddConverter(context, XtRString, XtROrientation, 
X			XmuCvtStringToOrientation, NULL, (Cardinal)0 );
X
X	XtSetArg(args[0], XtNfile, (XtArgVal)HELPFILE);
X	XtSetArg(args[1], XtNtextOptions, scrollVertical|wordBreak);
X	XtSetArg(args[2], XtNwidth, widthw);
X	XtSetArg(args[3], XtNheight, heightw);
X	XtSetArg(args[4], XtNeditType, (XtArgVal)XttextEdit); 
X	conf->htxt = XtCreateManagedWidget("Help", 
X			asciiDiskWidgetClass, conf->hbox, args, FIVE);
X	XtSetArg(args[0], XtNlabel, "Hapropos: ");
X	XtSetArg(args[1], XtNvalue, ptr);
X	conf->hap = XtCreateManagedWidget("Hapropos",
X			dialogWidgetClass, conf->hbox, args, TWO);
X	conf->hapok = XtCreateManagedWidget("apropos ok?",
X			commandWidgetClass, conf->hap, NO(Arg *), ZERO);
X	XtAddCallback(conf->hapok, XtNcallback, Hapropos, (caddr_t)conf);
X	conf->hapres = XtCreateManagedWidget("apropos res:",
X			labelWidgetClass, conf->hbox, NO(Arg *), ZERO);
X	conf->hq = XtCreateManagedWidget("Quit Help",
X                        commandWidgetClass, conf->hbox, NO(Arg *), ZERO);
X	XtAddCallback(conf->hq, XtNcallback, HelpQuit, (caddr_t)conf);
X
X#ifdef JOKE
X	conf->jb = XtCreateManagedWidget("Do Not Press This Button",
X		commandWidgetClass, conf->tbox, NULL, 0);
X	XtAddCallback(conf->jb, XtNcallback, Joke, (caddr_t)conf);
X#endif JOKE
X
X/* 
X * Now the windows for user typing in, and
X * others output
X */
X	conf->live = True;
X	for(i=0; i < nconf; i++) 
X		if (firsttime || Conference[i].live)
X			place(conf, Conference[i].user, i, nth);
X
X/*
X * And realize this conferees top level
X */
X	XtRealizeWidget(conf->toplevel);
X	XBell(XtDisplay(conf->toplevel), 50);
X
X	return True;
X}
X
X/*
X * Set up a ascii String class widget, (called lotsaa times, once per
X * conferee
X */
Xplace(conf, name, j, nth)
Xxconf_t *conf;
Xchar *name;
Xint j;
Xint nth;
X{
X	int i;
X	char nb[80];
X	xwin_t *ww = &(conf->them[j]);
X/*
X * Set Xt ascii string class arguments such as
X * 	string
X *	edit style
X * 	text options for scollbar and word breaking
X *	width and height
X */
X
X	nargs = 0;
X	XtSetArg(args[nargs], XtNallowResize, True);
X	nargs++;
X	XtSetArg(args[nargs], XtNwidth, widthw+16);
X	nargs++;
X	XtSetArg(args[nargs], XtNheight, heightw+16);
X	nargs++;
X	ww->v = XtCreateManagedWidget("win", vPanedWidgetClass, 
X			conf->box, args, nargs);
X
X	for(i=0; i<BUFFSIZE; i++)
X		ww->buff[i] = ' ';
X	nargs = 0;
X	XtSetArg(args[nargs], XtNstring, (XtArgVal)ww->buff); 
X	nargs++;
X	XtSetArg(args[nargs], XtNtextSource, ww->source);
X	nargs++;
X	XtSetArg(args[nargs], XtNeditType, (XtArgVal)XttextEdit); 
X	nargs++;
X	XtSetArg(args[nargs], XtNwidth, widthw); 
X	nargs++;
X        XtSetArg(args[nargs], XtNheight, heightw); 
X	nargs++;
X	XtSetArg(args[nargs], XtNtextOptions, scrollVertical|wordBreak); 
X	nargs++;
X/*  
X * Distinguish input and output windows by reverse video
X */
X	if ( j != nth ) {
X		XtSetArg(args[nargs], XtNbackground, XtDefaultForeground); 
X		nargs++;
X		XtSetArg(args[nargs], XtNforeground, XtDefaultBackground); 
X		nargs++;
X	}
X
X/*
X * Note could be asciiDiskWidgetClass, with tmp fil nam, top record procedings
X */
X	ww->w = XtCreateManagedWidget("win", asciiStringWidgetClass, 
X			ww->v, args, nargs);
X	if (ww->w == NULL) {
X		(void)fprintf(stderr, "win create failed...\n");
X		exit(-1);
X	}
X
X/*
X * and our funky text widget callback
X */
X	if (j == nth) {
X		Conference[nth].me.w = ww->w;
X		XtAddCallback(ww->w, XtNcallback, KeyIn, (caddr_t)conf);
X		(void)sprintf(nb, "<- In  %10s", name);
X	} else {
X		(void)sprintf(nb, "<- Out %10s", name);
X	}
X
X	XtTextSetLastPos(ww->w, 0);
X	XtTextEnableRedisplay(ww->w);
X/*
X * And a label to say who we are
X */
X	XtSetArg(args[0], XtNlabel, (XtArgVal)nb);
X	XtSetArg(args[1], XtNallowResize, True);
X	XtSetArg(args[2], XtNheight, 12);
X	ww->lab = XtCreateManagedWidget(name, labelWidgetClass,
X			ww->v, args, THREE);
X
X#ifdef EXPTL
X/*
X * And a bunch of illocutionary buttons (see Searle)
X */
X	if (exptl && (j == nth)) {
X		ww->assert = XtCreateManagedWidget("Assert",
X				commandWidgetClass,
X				ww->v, NO(Arg *), ZERO);
X		XtAddCallback(ww->assert, XtNcallback, assert, (caddr_t)conf);
X		
X		ww->commit = XtCreateManagedWidget("Commit",
X				commandWidgetClass,
X				ww->v, NO(Arg *), ZERO);
X		XtAddCallback(ww->commit, XtNcallback, commit, (caddr_t)conf);
X				
X		ww->direct = XtCreateManagedWidget("Direct",
X				commandWidgetClass,
X				ww->v, NO(Arg *), ZERO);
X		XtAddCallback(ww->direct, XtNcallback, direct, (caddr_t)conf);
X
X		ww->declare = XtCreateManagedWidget("Declare",
X				commandWidgetClass,
X				ww->v, NO(Arg *), ZERO);
X		XtAddCallback(ww->declare, XtNcallback, declare, (caddr_t)conf);
X
X		ww->express = XtCreateManagedWidget("Express",
X				commandWidgetClass,
X				ww->v, NO(Arg *), ZERO);
X		XtAddCallback(ww->express, XtNcallback, express, (caddr_t)conf);
X	}
X#endif EXPTL
X/*
X * Get round munge mess that box widget seems to get into if sizeing
X * in a popup
X	{
X	int foo;
X        XtSetArg(args[0], XtNheight, &foo);
X	XtGetValues(conf->box, args, ONE);
X        XtSetArg(args[0], XtNheight, foo);
X	XtSetValues(ww->v, args, ONE);
X	}
X */
X}
X
X
XScale(d, n, wb, hb, ww, hw)
XDisplay *d;
Xint n;
Xint *wb, *hb, *ww, *hw;
X{
X	Dimension w, h;
X	int s = DefaultScreen(d);
X
X	w = DisplayWidth(d, s);
X	h = DisplayHeight(d, s);
X
X	*wb = (w * 5) / 6;
X	*hb = (h * 5) / 6;
X
X	*ww = (*wb) / (n+2);  
X	*hw = (*hb) / (n+2); 
X}
X/*
X * EOF :-)
X */
END_OF_FILE
if test 18989 -ne `wc -c <'xconf/xconf.c'`; then
    echo shar: \"'xconf/xconf.c'\" unpacked with wrong size!
fi
# end of 'xconf/xconf.c'
fi
echo shar: End of archive 1 \(of 5\).
cp /dev/null ark1isdone
MISSING=""
for I in 1 2 3 4 5 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 5 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0



More information about the Comp.sources.x mailing list