/**********************************************************************/
/*                                                                    */
/*	CRISP - Programmable editor                                   */
/*	===========================                                   */
/*                                                                    */
/*  File:          xdsp.c                                             */
/*  Author:        P. D. Fox                                          */
/*  Created:       3 Jun 1991                      		      */
/*                                                                    */
/*  Copyright (c) 1990, 1991 Paul Fox                                 */
/*                All Rights Reserved.                                */
/*                                                                    */
/*                                                                    */
/*--------------------------------------------------------------------*/
/*  Description:  X11 display handler for CRISP                       */
/*                                                                    */
/*   This  file  has  only  just  started  so dont believe any of it  */
/*   until I say so.						      */
/**********************************************************************/
/*
static char sccs_id[] = "%Z% %M% %R%.%L%";
*/
# include	<list.h>
# include	<X11/Xlib.h>
# include	<X11/Xutil.h>
# include	<X11/Xos.h>
# include	<X11/Xatom.h>
# include	<X11/Intrinsic.h>
# include	<X11/Shell.h>
# include	<X11/StringDefs.h>
# include	"x11r3.h"
# include	"crwin.h"


# if !defined(TRUE)
#	define	TRUE	1
#	define	FALSE	0
# endif
/**********************************************************************/
/*   Connection to X-server.					      */
/**********************************************************************/
Display	*dpy;
char	*display_name;
int	screen_num = 0;
int	xdebug;

static String fallback_resources[] = {
	/***********************************************/
	/*   Default  geometry  gives  us a 80 column  */
	/*   wide screen for the 7x13 font.	       */
	/***********************************************/
	"Crisp*geometry:	562x408",
	"Crisp*font:		7x13",
	"Crisp*background:	black",
	"Crisp*input:	True",
	NULL
	};

# if !defined(X11r3)
XtAppContext	app_con;
# endif

XEvent	event;

Arg	wargs[20];
Widget main_widget;
Widget child;

/***********************************************/
/*   Map  the  line  drawing graphics. We can  */
/*   only  use  those  fonts  that  have  the  */
/*   line drawing character set available.     */
/***********************************************/
char	remap_graphics[] = 
	{0x12, 0x19, 0x0d, 0x0c, 0x0e, 0x0b, 0x18, 0x17, 0x16, 0x15, 0x0f};
# define	REMAP_CHAR(x)	\
	if ((unsigned char) (x) >= CH_HORIZONTAL) \
		x = remap_graphics[(unsigned char) x - CH_HORIZONTAL];

/**********************************************************************/
/*   Variables defined in display.c				      */
/**********************************************************************/
vbyte_t   **pscreen;
extern fd_set	sel_bits;

void	event_proc();
int	x11_read();
void	x11_window_size();
void	x11_empty_input_queue();
void	x11_show_cursor();
void	x11_update_region PROTO((int, int, int, int));
void	x11_print_string PROTO((int, int, int, vbyte_t *));
int	x11_event_pending PROTO((void));
void	x11_set_names();
void	x11_flush PROTO((void));
void	x11_cursor();

int	x11_select();
void	x11_beep PROTO((void));
void	x_trace_event PROTO((XEvent *));
void
x11_init(argcp, argv)
int	*argcp;
char	**argv;
{

	xdebug = getenv("XDEBUG") != NULL;
	/***********************************************/
	/*   Set up hook routines for CRISP.	       */
	/***********************************************/
	scrfn.scr_window_size = x11_window_size;
	scrfn.scr_show_cursor = x11_show_cursor;
	scrfn.scr_print_string = x11_print_string;
	scrfn.scr_select = x11_select;
	scrfn.scr_event_pending = x11_event_pending;
	scrfn.scr_beep = x11_beep;
	scrfn.scr_read = x11_read;
	scrfn.scr_flush = (int (*)()) x11_flush;
/*	scrfn.scr_flush = x11_flush; */
	scrfn.scr_set_names = (int (*)()) x11_set_names;
	scrfn.scr_cursor = x11_cursor;

	main_widget = XtAppInitialize(&app_con, "Crisp", NULL, 0,
		argcp, argv, fallback_resources, NULL, 0);
	child = XtCreateManagedWidget("", 
			crwinWidgetClass,
			main_widget, NULL, 0);
	
	dpy = XtDisplay(main_widget);
	screen_num = DefaultScreen(dpy);

/*	XtSetArg(wargs[0], XtNallowShellResize, 1);*/
/*	XtSetArg(wargs[1], XtNmappedWhenManaged, 1);*/
/*	XtSetArg(wargs[2], XtNsensitive, 1);*/
/*	XtSetValues(main_widget, wargs, 3);*/

	XtRealizeWidget(main_widget);
	
	/***********************************************/
	/*   We  are  dirty  here but theres no other  */
	/*   way  to  do  it. We want to have control  */
	/*   over  the  structure  of our code -- not  */
	/*   XtAppMainLoop().   So   we   allow   the  */
	/*   getkey()   code  to  select()  on  X11's  */
	/*   socket  descriptor.  We  must  make sure  */
	/*   that  the  event  loop  is  empty before  */
	/*   doing   the   select  otherwise  we  may  */
	/*   deadlock.				       */
	/***********************************************/
	FD_SET(dpy->fd, &sel_bits);
	x11_empty_input_queue();

	x11_window_size(&nrow, &ncol);
}
/**********************************************************************/
/*   Function to update the whole display.			      */
/**********************************************************************/
void
x11_update()
{
	x11_update_region(0, 0, nrow, ncol);
}
/**********************************************************************/
/*   Update window within a specific rectangle.			      */
/**********************************************************************/
void

x11_update_region(start_line, start_col, end_line, end_col)
int	start_line;
int	start_col;
int	end_line;
int	end_col;
{	int	r;
	vbyte_t	*vp;

	if (end_line > nrow)
		end_line = nrow;
	if (end_col > ncol)
		end_col = ncol;
	for (r = start_line; r < end_line; r++) {
		vp = pscreen[r] + start_col;
		x11_print_string(r, start_col, end_col - start_col, vp);
		}
}
void
event_proc(w, client_data, event, continue_to_dispatch)
Widget	w;
XtPointer	client_data;
XEvent	*event;
Boolean	*continue_to_dispatch;
{
	printf("*** event func*****\n");
}
/**********************************************************************/
/*   Function called to empty the received X event queue.	      */
/**********************************************************************/
void
x11_empty_input_queue()
{

	while (XtAppPending(app_con)) {
		XtAppNextEvent(app_con, &event);
		if (xdebug)
			x_trace_event(&event);
		XtDispatchEvent(&event);
		}
	update();
}
/**********************************************************************/
/*   Function  called  to  check to see if there is an event pending  */
/*   from X windows.						      */
/**********************************************************************/
int
x11_event_pending()
{
	if (XtAppPending(app_con)) {
		x11_empty_input_queue();
		}
/*     the following line doesn't seem to be necessary for XFree86  */
/*	return crwin_getkey(child, FALSE); */
	return(0);
}
void
pretend_select(rbits, wbits, ebits)
fd_set	*rbits;
fd_set	*wbits;
fd_set	*ebits;
{
	if (rbits)
		FD_ZERO(rbits);
	if (wbits)
		FD_ZERO(wbits);
	if (ebits)
		FD_ZERO(ebits);
	FD_SET(TTY_FD, rbits);
}
int
x11_select(nfds, rbits, wbits, ebits, tmo)
int	nfds;
fd_set	*rbits;
fd_set	*wbits;
fd_set	*ebits;
struct timeval	*tmo;
{	int	n;
	
	x11_empty_input_queue();
	/***********************************************/
	/*   If  we've  got  a  keystroke in the push  */
	/*   back   buffer,  then  pretend  that  the  */
	/*   select has worked.			       */
	/***********************************************/
	if (crwin_getkey(child, FALSE) != 0) {
		pretend_select(rbits, wbits, ebits);
		return 1;
		}
	XFlush(dpy);
	n = select(nfds, rbits, wbits, ebits, tmo);
	if (n <= 0)
		return n;
	/***********************************************/
	/*   If  we  got  some  X  events to process,  */
	/*   then  go  do  those  and check if any of  */
	/*   them looked like a keystroke event.       */
	/***********************************************/
	if (FD_ISSET(dpy->fd, &sel_bits)) {
		x11_empty_input_queue();
		if (crwin_getkey(child, FALSE) != 0) {
			pretend_select(rbits, wbits, ebits);
			return 1;
			}
		}
	return n;
}
/**********************************************************************/
/*   Routine to get the current window size in rows and columns.      */
/**********************************************************************/
void
x11_window_size(row, col)
u_int16	*row;
u_int16	*col;
{	int	r, c;

	crwin_get_window_size(child, &r, &c);
	*row = r;
	*col = c;
}
/**********************************************************************/
/*   Function called to cause the cursor to show up in the window.    */
/**********************************************************************/
void
x11_show_cursor(row, col)
int	row;
int	col;
{	char	buf[1];
	static int last_cursor_row = -1;
	static int last_cursor_col = -1;
	vbyte_t	b;
	extern int imode;

	/***********************************************/
	/*   If  we've  already  got  a cursor on the  */
	/*   screen  then  redraw  it  back to how it  */
	/*   was,  otherwise  we  leave  a  trail  of  */
	/*   cursors on the screen.		       */
	/***********************************************/
	if (last_cursor_row >= 0) {
		x11_update_region(last_cursor_row, last_cursor_col,
				  last_cursor_row + 1, last_cursor_col + 1);
		}
	last_cursor_row = row;
	last_cursor_col = col;
	b =  pscreen[row][col];
	buf[0] = (char) b;
	REMAP_CHAR(buf[0]);
	crwin_show_cursor(child, row, col, imode, 
		buf, (b & BG_COLOR) >> BG_SHIFT);
}
/**********************************************************************/
/*   Function   called   by   display  code  to  draw  a  string  of  */
/*   characters   at  a  certain  position  on  the  screen.  String  */
/*   doesn't extend over line boundaries.			      */
/**********************************************************************/
void
x11_print_string(row, col, len, vp)
int	row;
int	col;
int	len;
vbyte_t	*vp;
{	char	buf[80];
	char	*end_buf;
	char	*bp;
	int	fg, bg;
	int	c;
	int	end_col = col + len;

	for (c = col; c < end_col; ) {
		vbyte_t	attr = *vp & COLOR_MASK;
		/***********************************************/
		/*   Draw  as  many consecutive characters as  */
		/*   we can until we hit a color change.       */
		/***********************************************/
		bp = buf;
		if (end_col - c > sizeof buf)
			end_buf = &buf[sizeof buf];
		else
			end_buf = &buf[end_col - c];
		while ((*vp & COLOR_MASK) == attr && bp < end_buf) {
			*bp = (char) *vp++;
			REMAP_CHAR(*bp);
			bp++;
			}
		fg = (attr & FG_COLOR) >> FG_SHIFT;
		bg = (attr & BG_COLOR) >> BG_SHIFT;
		crwin_draw_string(child, row, c, buf, bp - buf, 
			x11_colors[fg], x11_colors[bg]);
		c += bp - buf;
		}
}
/**********************************************************************/
/*   Function to sound a bell or flash window.			      */
/**********************************************************************/
void
x11_beep()
{
	XBell(dpy, 100);
	XFlush(dpy);
}
/**********************************************************************/
/*   Function   called   to   read  a  buffered  keystroke  (16  bit  */
/*   quantity) from our internal pushback buffer.		      */
/**********************************************************************/
int
x11_read()
{
	return crwin_getkey(child, TRUE);
}
/**********************************************************************/
/*   Routine to flush output to window.				      */
/**********************************************************************/
void
x11_flush()
{
	XFlush(dpy);
}
/**********************************************************************/
/*   Function to set the window and/or icon name.		      */
/**********************************************************************/
void
x11_set_names(win_name, icon_name)
char	*win_name;
char	*icon_name;
{	int	i = 0;

	if (win_name) {
		XtSetArg(wargs[i], XtNtitle, win_name); i++;
		}
	if (icon_name) {
		XtSetArg(wargs[i], XtNiconName, icon_name); i++;
		}
	XtSetValues(main_widget, wargs, i);
	
}
/**********************************************************************/
/*   Function  to  set  the  color  of  the  cursor depending on the  */
/*   input mode.						      */
/**********************************************************************/
void
x11_cursor(insmode, virtual_space)
int	insmode;
int	virtual_space;
{
}
