
/*
 * $XConsortium: XOpenDis.c,v 11.69 88/09/30 14:03:15 jim Exp $
 */
/*
 * $Header: /cec/src/nestor/servers/R3/shXlib/XOpenDis.c,v 1.2 90/07/26 08:31:44 altenhof Exp $
 */

#include "copyright.h"
/* Copyright    Massachusetts Institute of Technology    1985, 1986	*/

/* Converted to V11 by jg */
/* Extended to allow multiplexing by ma */ 

#include <stdio.h>

#define  NEED_EVENTS    /* -- XmuXlibint.h refers to event structures -- */
#include "Xlibint.h"

/* -- additional includes -- */
#include "XmuXlibint.h"
#include "resources.h"

#include <X11/Xos.h>
#include <X11/Xatom.h>

#ifndef lint
static int lock;	/* get rid of ifdefs when locking implemented */
#endif

static int first_call = xTrue ;

static OutOfMemory( ) ;  /* to avoid gcc flag -traditional */

int _Xdebug = 0;
static xReq _dummy_request = {
	0, 0, 0
};

/* head of the linked list of open displays */
Display *_XHeadOfDisplayList = NULL;

extern Bool _XWireToEvent();
extern Status _XUnknownNativeEvent();
extern Bool _XUnknownWireEvent();

/* 
 * Connects to a server, creates a Display object and returns a pointer to
 * the newly created Display back to the caller.
 */

Display *XOpenDisplay (display)
	register char *display;
{
	register Display *dpy;		/* New Display object being created. */
	register int i;
	int j, k;			/* random iterator indexes */
	char *display_name;		/* pointer to display name */
	int indian;			/* to determine which indian. */
	xConnClientPrefix client;	/* client information */
	xConnSetupPrefix prefix;	/* prefix information */
	int vendorlen;			/* length of vendor string */
	char *setup;			/* memory allocated at startup */
	char displaybuf[256];		/* buffer to receive expanded name */
	char prop_name[256];		/* buffer to receive property name */
	int screen_num;			/* screen number */
	union {
		xConnSetup *setup;
		char *failure;
		char *vendor;
		xPixmapFormat *sf;
		xWindowRoot *rp;
		xDepth *dp;
		xVisualType *vp;
	} u;
	long setuplength;	/* number of bytes in setup message */

	extern int _XSendClientPrefix();
	extern int _XConnectDisplay();
	extern char *getenv();
	extern XID _XAllocID();
 
/*
 * -- Call XmuX initialisation routine on first call 
 */
	if( first_call )
	  XmuXInitialize( ) ;
	/*
	 * If the display specifier string supplied as an argument to this 
	 * routine is NULL or a pointer to NULL, read the DISPLAY variable.
	 */
	if (display == NULL || *display == '\0') {
		if ((display_name = getenv("DISPLAY")) == NULL) {
			/* Oops! No DISPLAY environment variable - error. */
			return(NULL);
		}
	}
	else {
		/* Display is non-NULL, copy the pointer */
		display_name = display;
	}

/*
 * Attempt to allocate a display structure. Return NULL if allocation fails.
 */
	LockMutex(&lock);
	if ((dpy = (Display *)Xcalloc(1, sizeof(Display))) == NULL) {
		errno = ENOMEM;
		UnlockMutex(&lock);
		return(NULL);
	}

/*
 * Call the Connect routine to get the network socket. If 0 is returned, the
 * connection failed. The connect routine will return the expanded display
 * name in displaybuf.
 */

	displaybuf[0] = prop_name[0] = '\0';
	if( ( dpy->fd = _XConnectDisplay( display_name, displaybuf, 
					    prop_name, &screen_num ) )
	     < 0 )
	{
		Xfree ((char *) dpy);
		UnlockMutex(&lock);
		return(NULL);		/* errno set by XConnectDisplay */
	}

/* 
 * -- Create default entry in Connection translation table
 * -- On success , return xTrue , otherwise xFalse
 * -- XXX values will be overwritten for multiplex connections outside of this
 */
	if( !CreateDefaultEntry( dpy ) )
	{
	    /* -- we've failed -- */
	    _XDisconnectDisplay( dpy->fd ) ;
	    _XFreeDisplayStructure( dpy ) ;
	    errno = ENOMEM ;
	    return( NULL ) ;
	}
/*
 * First byte is the byte order byte.
 * Authentication key is normally sent right after the connection.
 * This (in MIT's case) will be kerberos.
 */
	indian = 1;
	if (*(char *) &indian)
	    client.byteOrder = 'l';
	else
	    client.byteOrder = 'B';
	client.majorVersion = X_PROTOCOL;
	client.minorVersion = X_PROTOCOL_REVISION;
	_XSendClientPrefix (dpy, &client);
/*
 * Now see if connection was accepted...
 */
	_XRead (dpy, (char *)&prefix,(long)SIZEOF(xConnSetupPrefix));

	if (prefix.majorVersion < X_PROTOCOL) {
		(void) fputs ("Warning: Client built for newer server!\n", stderr);
	}
	if (prefix.minorVersion != X_PROTOCOL_REVISION) {
		(void) fputs (
		 "Warning: Protocol rev. of client does not match server!\n",
		  stderr);
	}

	setuplength = prefix.length << 2;
	if ( (u.setup = (xConnSetup *)(setup =  Xmalloc ((unsigned)setuplength)))
	    == NULL) {
		errno = ENOMEM;
		Xfree ((char *)dpy);
		UnlockMutex(&lock);
		return(NULL);
	}
	_XRead (dpy, (char *)u.setup, setuplength);
/*
 * If the connection was not accepted by the server due to problems,
 * give error message to the user....
 */
	if (prefix.success != xTrue) {
/*
		(void) fwrite (u.failure, (int)*u.failure, sizeof(char), stderr);
*/
		(void) fwrite (u.failure, sizeof(char),
			(int)prefix.lengthReason, stderr);
		(void) fwrite ("\n", sizeof(char), 1, stderr);
		Xfree ((char *)dpy);
		Xfree (setup);
		UnlockMutex(&lock);
		return (NULL);
	}

/*
 * We succeeded at authorization, so let us move the data into
 * the display structure.
 */
	dpy->next		= (Display *) NULL;
	dpy->proto_major_version= prefix.majorVersion;
	dpy->proto_minor_version= prefix.minorVersion;
	dpy->release 		= u.setup->release;
	dpy->resource_base	= u.setup->ridBase;
	dpy->resource_mask	= u.setup->ridMask;
	dpy->min_keycode	= u.setup->minKeyCode;
	dpy->max_keycode	= u.setup->maxKeyCode;
	dpy->keysyms		= (KeySym *) NULL;
	dpy->modifiermap	= NULL;
	dpy->lock_meaning	= NoSymbol;
	dpy->keysyms_per_keycode = 0;
	dpy->current		= None;
	dpy->xdefaults		= (char *)NULL;
	dpy->scratch_length	= 0L;
	dpy->scratch_buffer	= NULL;
	dpy->key_bindings	= NULL;
	/*
	 * -- we are not interested in handling motion buffers 
	 */
	dpy->motion_buffer	= 0 ; /* u.setup->motionBufferSize; */
	dpy->nformats		= u.setup->numFormats;
	dpy->nscreens		= u.setup->numRoots;
	dpy->byte_order		= u.setup->imageByteOrder;
	dpy->bitmap_unit	= u.setup->bitmapScanlineUnit;
	dpy->bitmap_pad		= u.setup->bitmapScanlinePad;
	dpy->bitmap_bit_order   = u.setup->bitmapBitOrder;
	dpy->max_request_size	= u.setup->maxRequestSize;
	dpy->ext_procs		= (_XExtension *)NULL;
	dpy->ext_data		= (XExtData *)NULL;
	dpy->ext_number 	= 0;
	dpy->event_vec[X_Error] = _XUnknownWireEvent;
	dpy->event_vec[X_Reply] = _XUnknownWireEvent;
	dpy->wire_vec[X_Error]  = _XUnknownNativeEvent;
	dpy->wire_vec[X_Reply]  = _XUnknownNativeEvent;
	for (i = KeyPress; i < LASTEvent; i++) {
	    dpy->event_vec[i] 	= _XWireToEvent;
	    dpy->wire_vec[i] 	= NULL;
	}
	for (i = LASTEvent; i < 128; i++) {
	    dpy->event_vec[i] 	= _XUnknownWireEvent;
	    dpy->wire_vec[i] 	= _XUnknownNativeEvent;
	}
	dpy->resource_id	= 0;
	dpy->resource_shift	= ffs(dpy->resource_mask) - 1;
	dpy->db 		= (struct _XrmHashBucketRec *)NULL;
	dpy->cursor_font	= None;
/* 
 * Initialize pointers to NULL so that XFreeDisplayStructure will
 * work if we run out of memory
 */

	dpy->screens = NULL;
	dpy->display_name = NULL;
	dpy->vendor = NULL;
	dpy->buffer = NULL;

/*
 * now extract the vendor string...  String must be null terminated,
 * padded to multiple of 4 bytes.
 */
	dpy->vendor = (char *) Xmalloc (u.setup->nbytesVendor + 1);
	vendorlen = u.setup->nbytesVendor;
	u.setup += 1;	/* can't touch information in XConnSetup anymore..*/
	(void) strncpy(dpy->vendor, u.vendor, vendorlen);
	u.vendor += (vendorlen + 3) & ~3;
/*
 * Now iterate down setup information.....
 */
	dpy->pixmap_format = 
	    (ScreenFormat *)Xmalloc(
		(unsigned) (dpy->nformats *sizeof(ScreenFormat)));
	if (dpy->pixmap_format == NULL) {
	        OutOfMemory (dpy, setup);
		UnlockMutex(&lock);
		return(NULL);
	}
/*
 * First decode the Z axis Screen format information.
 */
	for (i = 0; i < dpy->nformats; i++) {
	    register ScreenFormat *fmt = &dpy->pixmap_format[i];
	    fmt->depth = u.sf->depth;
	    fmt->bits_per_pixel = u.sf->bitsPerPixel;
	    fmt->scanline_pad = u.sf->scanLinePad;
	    fmt->ext_data = NULL;
	    u.sf += 1;
	}

/*
 * next the Screen structures.
 */
	dpy->screens = 
	    (Screen *)Xmalloc((unsigned) dpy->nscreens*sizeof(Screen));
	if (dpy->screens == NULL) {
	        OutOfMemory (dpy, setup);
		UnlockMutex(&lock);
		return(NULL);
	}
/*
 * Now go deal with each screen structure.
 */
	for (i = 0; i < dpy->nscreens; i++) {
	    register Screen *sp = &dpy->screens[i];
	    VisualID root_visualID = u.rp->rootVisualID;
	    sp->display	    = dpy;
	    sp->root 	    = u.rp->windowId;
	    sp->cmap 	    = u.rp->defaultColormap;
	    sp->white_pixel = u.rp->whitePixel;
	    sp->black_pixel = u.rp->blackPixel;
	    sp->root_input_mask = u.rp->currentInputMask;
	    sp->width	    = u.rp->pixWidth;
	    sp->height	    = u.rp->pixHeight;
	    sp->mwidth	    = u.rp->mmWidth;
	    sp->mheight	    = u.rp->mmHeight;
	    sp->min_maps    = u.rp->minInstalledMaps; 
	    sp->max_maps    = u.rp->maxInstalledMaps; 
	    sp->root_visual = NULL;  /* filled in later, when we alloc Visuals */
	    /*
	     * -- NO backing store 
	     */
	    sp->backing_store= NotUseful ; /* u.rp->backingStore; */
	    /*
	     * -- NO save unders 
	     */
	    sp->save_unders = False ; /*  u.rp->saveUnders; */
	    sp->root_depth  = u.rp->rootDepth;
	    sp->ndepths	    = u.rp->nDepths;
	    sp->ext_data   = NULL;
	    u.rp += 1;
/*
 * lets set up the depth structures.
 */
	    sp->depths = (Depth *)Xmalloc(
			(unsigned)sp->ndepths*sizeof(Depth));
	    if (sp->depths == NULL) {
		OutOfMemory (dpy, setup);
		UnlockMutex(&lock);
		return(NULL);
	    }
	    /*
	     * for all depths on this screen.
	     */
	    for (j = 0; j < sp->ndepths; j++) {
		Depth *dp = &sp->depths[j];
		dp->depth = u.dp->depth;
		dp->nvisuals = u.dp->nVisuals ; 
		u.dp += 1;
		dp->visuals = 
		  (Visual *)Xmalloc((unsigned)dp->nvisuals*sizeof(Visual));
		if (dp->visuals == NULL) {
		    OutOfMemory (dpy, setup);
		    UnlockMutex(&lock);
		    return(NULL);
		}
		for (k = 0; k < dp->nvisuals; k++) 
		{
			register Visual *vp = &dp->visuals[k];
			/* 
			 * -- RESTRICTION : No read/write color cells 
			 */
			vp->class	= u.vp->class;
/* --
			if( vp->class == GrayScale )
			    vp->class = StaticGray ;
			else
			    if( vp->class == PseudoColor )
				vp->class = StaticColor ;
			    else
				if( vp->class == DirectColor )
				    vp->class = TrueColor ;
-- */
			vp->bits_per_rgb= u.vp->bitsPerRGB;
			vp->map_entries	= u.vp->colormapEntries;
			vp->red_mask	= u.vp->redMask;
			vp->green_mask	= u.vp->greenMask;
			vp->blue_mask	= u.vp->blueMask;
			vp->ext_data	= NULL;
			vp->visualid = u.vp->visualID ;
			u.vp += 1;
		}
		if( !XmuXSortVisuals( dpy , dp->visuals , dp->nvisuals , 
				      dp->depth ) )
		{
		    errno = ENOMEM;
		    Xfree ((char *)dpy);
		    UnlockMutex(&lock);
		    return(NULL);
		}
		for (k = 0; k < dp->nvisuals; k++) 
		{
			register Visual *vp = &dp->visuals[k];

			if ( vp->visualid  == root_visualID )
			{  unsigned long black = sp->black_pixel ,
                                         white = sp->white_pixel ;
			   sp->root_visual = vp;
			   /*
			    * -- Create a colormap entry for screen's default
			    * -- Second last argument says 
			    * -- "no private colormap"
			    * -- and insert "black" and "white"
			    */
			   XmuXCreateColormapInfo( dpy , sp->cmap , 
						   vp , sp->root , False , 
						   AllocNone ) ;
			   XmuXUpdateColormapInfo( dpy , sp->cmap , 
						   &black , 1 , NULL , 0 ,
						   True , False ) ;
			   XmuXUpdateColormapInfo( dpy , sp->cmap ,
                                                   &white , 1 , NULL , 0 ,
						   True , False ) ;
		       }
		   }
	     }
	}
		

/*
 * Setup other information in this display structure.
 */
	dpy->vnumber = X_PROTOCOL;
	dpy->resource_alloc = _XAllocID;
	dpy->synchandler = NULL;
	dpy->request = 0;
	dpy->last_request_read = 0;
	dpy->default_screen = screen_num;  /* Value returned by ConnectDisplay */
	dpy->last_req = (char *)&_dummy_request;

	/* Salt away the host:display string for later use */
	if ((dpy->display_name = Xmalloc(
		(unsigned) (strlen(displaybuf) + 1))) == NULL) {
	        OutOfMemory (dpy, setup);
		UnlockMutex(&lock);
		return(NULL);
	}
	(void) strcpy (dpy->display_name, displaybuf);
 
	/* Set up the output buffers. */
	if ((dpy->bufptr = dpy->buffer = Xmalloc(BUFSIZE)) == NULL) {
	        OutOfMemory (dpy, setup);
		UnlockMutex(&lock);
		return(NULL);
	}
	dpy->bufmax = dpy->buffer + BUFSIZE;
 
	/* Set up the input event queue and input event queue parameters. */
	dpy->head = dpy->tail = NULL;
	dpy->qlen = 0;
 
/*
 * Now start talking to the server to setup all other information...
 */

	Xfree (setup);	/* all finished with setup information */

/*
 * Make sure default screen is legal.
 */
	if (screen_num >= dpy->nscreens) {
	    _XDisconnectDisplay (dpy->fd);
	    _XFreeDisplayStructure (dpy);
	    errno = EINVAL;
	    UnlockMutex(&lock);
	    return(NULL);
	}

/*
 * Set up other stuff clients are always going to use.
 */
	for (i = 0; i < dpy->nscreens; i++) {
	    register Screen *sp = &dpy->screens[i];
	    XGCValues values;
	    values.foreground = sp->black_pixel;
	    values.background = sp->white_pixel;
	    sp->default_gc = XCreateGC (dpy, sp->root,
			GCForeground|GCBackground, &values);
	}
/*
 * call into synchronization routine so that all programs can be
 * forced synchronize
 */
	(void) XSynchronize(dpy, _Xdebug);
/*
 * chain this stucture onto global list.
 */
	dpy->next = _XHeadOfDisplayList;
	_XHeadOfDisplayList = dpy;

/*
 *				 W A R N I N G
 *
 * This is experimental code for implementing pseudo-root windows as specified
 * by the Inter-Client Communications Conventions Manual.  The structures that
 * it provides should be considered private to the MIT implementation of Xlib
 * and are SUBJECT TO CHANGE WITHOUT NOTICE.  They should not be incorporated
 * into any toolkits or applications.  When they change, no effort will be
 * made to provide backwards compatibility.
 *
 */
	if (prop_name[0] != '\0') {
	    extern Status _XGetPseudoRoot();

	    /*
	     * If a bad property name is specified we want to fail so that
	     * the application doesn't get started up in the original root
	     * or, worse yet, in a messed up one.  Again, the interfaces to
	     * the pseudo root code are to be considered private to this 
	     * implementation of Xlib and should not be used in any toolkits
	     * or applications.
	     */
	    if (!_XGetPseudoRoot (dpy, prop_name)) {
		_XDisconnectDisplay (dpy);
		_XFreeDisplayStructure (dpy);
		errno = EINVAL;
		UnlockMutex(&lock);
		return (NULL);
	    }
	}

/*
 * and done mucking with the display
 */
	UnlockDisplay(dpy);		/* didn't exist, so didn't lock */
	UnlockMutex(&lock);

/*
 * get the resource manager database off the root window.
 */
	{
	    Atom actual_type;
	    int actual_format;
	    unsigned long nitems;
	    unsigned long leftover;
	    if (XGetWindowProperty(dpy, RootWindow(dpy, 0), 
		XA_RESOURCE_MANAGER, 0L, 100000000L, False, XA_STRING,
		&actual_type, &actual_format, &nitems, &leftover, 
		(unsigned char **) &dpy->xdefaults) != Success) {
			dpy->xdefaults = (char *) NULL;
		}
	    else {
	    if ( (actual_type != XA_STRING) ||  (actual_format != 8) ) {
		if (dpy->xdefaults != NULL) Xfree ( dpy->xdefaults );
		}
	    }
	}
	/*
	 * -- we must define some atoms
	 */
	XmuXDefineAtoms( dpy ) ;
	if(first_call){
	  first_call = xFalse ;
	  XmuXAddDisplays(dpy) ;
	}
	return( dpy ) ;
}


/* OutOfMemory is called if malloc fails.  XOpenDisplay returns NULL
   after this returns. */

static OutOfMemory (dpy, setup)
    Display *dpy;
    char *setup;
    {
    _XDisconnectDisplay (dpy->fd);
    _XFreeDisplayStructure (dpy);
    Xfree (setup);
    errno = ENOMEM;
    }


/* XFreeDisplayStructure frees all the storage associated with a 
 * Display.  It is used by XOpenDisplay if it runs out of memory,
 * and also by XCloseDisplay.   It needs to check whether all pointers
 * are non-NULL before dereferencing them, since it may be called
 * by XOpenDisplay before the Display structure is fully formed.
 * XOpenDisplay must be sure to initialize all the pointers to NULL
 * before the first possible call on this.
 */

_XFreeDisplayStructure(dpy)
	register Display *dpy;
{
	if (dpy->screens) {
	    register int i;

            for (i = 0; i < dpy->nscreens; i++) {
		Screen *sp = &dpy->screens[i];

		if (sp->depths) {
		   register int j;

		   for (j = 0; j < sp->ndepths; j++) {
			Depth *dp = &sp->depths[j];

			if (dp->visuals) {
			   register int k;

			   for (k = 0; k < dp->nvisuals; k++)
			     _XFreeExtData (dp->visuals[k].ext_data);
			   Xfree ((char *) dp->visuals);
			   }
			}

		   Xfree ((char *) sp->depths);
		   }

		_XFreeExtData (sp->ext_data);
		}

	    Xfree ((char *)dpy->screens);
	    }
	
	if (dpy->pixmap_format) {
	    register int i;

	    for (i = 0; i < dpy->nformats; i++)
	      _XFreeExtData (dpy->pixmap_format[i].ext_data);
            Xfree ((char *)dpy->pixmap_format);
	    }

	if (dpy->display_name)
	   Xfree (dpy->display_name);
	if (dpy->vendor)
	   Xfree (dpy->vendor);

        if (dpy->buffer)
	   Xfree (dpy->buffer);
	if (dpy->keysyms)
	   Xfree ((char *) dpy->keysyms);
	if (dpy->modifiermap)
	   XFreeModifiermap(dpy->modifiermap);
	if (dpy->xdefaults)
	   Xfree (dpy->xdefaults);
	if (dpy->key_bindings)
	   _XFreeKeyBindings(dpy);

	_XFreeExtData (dpy->ext_data);
        
	Xfree ((char *)dpy);
}
