/**********************************************************************/
/*                                                                    */
/*	CRISP - Programmable editor                                   */
/*	===========================                                   */
/*                                                                    */
/*  File:          mouse.c                                            */
/*  Author:        P. D. Fox                                          */
/*  Created:       20 Apr 1990                     		      */
/*                                                                    */
/*  Copyright (c) 1990 Paul Fox                                       */
/*                All Rights Reserved.                                */
/*                                                                    */
/*                                                                    */
/*--------------------------------------------------------------------*/
/*  Description:  Mouse support code.                                 */
/*                                                                    */
/**********************************************************************/

/*static char sccs_id[] = "%Z% %M% %R%.%L%";*/

# include	"list.h"
# include	"tty.h"

/**********************************************************************/
/*   Definitions for where the mouse is on the screen.		      */
/**********************************************************************/
# define	LEFT_EDGE	1
# define	RIGHT_EDGE	2
# define	TOP_EDGE	3
# define	BOTTOM_EDGE	4
# define	INSIDE_WINDOW	5
# define	TITLE		6

# define	MAX_X	1000
# define	MAX_Y	300

char	*mouse_dev = NULL;	/* Device name of mouse.	*/
int	mouse_fd = -1;		/* File descriptor of mouse dev if available */

int	mouse_x = 0;		/* Current mouse co-ords.	*/
int	mouse_y = 0;
int	mouse_oldx = 0, 
	mouse_oldy = 0;		/* Old co-ords.			*/
	
int	x_pitch;
int	y_pitch;
	
extern	fd_set	sel_bits;	
/**********************************************************************/
/*   Current status of buttons.					      */
/**********************************************************************/
int	but1;
int	but2;
int	but3;

/**********************************************************************/
/*   Prototypes							      */
/**********************************************************************/
void	mouse_draw_icon();
WINDOW	*mouse_pos PROTO((int, int, int *, int *));

# if !defined(HAVE_MOUSE)
void
mouse_init(dev)
char	*dev;
{
}
# else

/**********************************************************************/
/*   Function  to  try  and  initialise mouse device. Called only if  */
/*   -mouse flag set. Called with name of device for accessing.	      */
/**********************************************************************/
void
mouse_init(dev)
char	*dev;
{	struct termio mouse_term;
	char	*cp = getenv("BMOUSE");
	
	dev = cp ? cp : "/dev/tty00";
	/***********************************************/
	/*   Open  mouse  --  if  open fails, then no  */
	/*   mouse   support   is   available.   Fail  */
	/*   quietly  so  we  can  use  same  aliases  */
	/*   with or without mouse support.	       */
	/***********************************************/
	mouse_fd = open(dev, O_RDONLY | O_EXCL);
	if (mouse_fd < 0)
		return;
		
	/***********************************************/
	/*   Make mouse device into raw mode, etc.     */
	/***********************************************/
	ioctl(mouse_fd, TCGETA, &mouse_term);
	mouse_term.c_lflag &= ~(ICANON | ECHO);
	mouse_term.c_iflag &= ~ICRNL;
	mouse_term.c_oflag = 0;
	mouse_term.c_cflag &= ~(PARENB | CBAUD);
	mouse_term.c_cflag |= (CS8 | B1200);
	mouse_term.c_cc[VMIN] = 0;
	mouse_term.c_cc[VTIME] = 1;
	ioctl(mouse_fd, TCSETA, &mouse_term);
	
	add_input_device(mouse_fd);
	
}
int
mouse_active()
{
	return mouse_fd >= 0;
}
int
mouse_poll(fd_bits)
fd_set	*fd_bits;
{	unsigned char	mbuf[3];
	char	buf[120];
	int	n;
	int	buts_changed;
	int	b1;
	int	b2;
	int	b3;
	static	int	max_x;
	static	int	max_y;
	
	if (mouse_fd < 0 || !FD_ISSET(mouse_fd, fd_bits))
		return FALSE;

	b1 = but1;
	b2 = but2;
	b3 = but3;

	if (x_pitch == 0) {
		x_pitch = MAX_X / ncol;
		y_pitch = MAX_Y / nrow;
		max_x = x_pitch * (ncol - 1);
		max_y = y_pitch * (nrow - 1);
		}
	while (1) {	
			
		/***********************************************/
		/*   Make  sure  we  get  3  bytes  from  the  */
		/*   mouse  and  make  sure  that  we haven't  */
		/*   lost sync.				       */
		/***********************************************/
		n = read(mouse_fd, mbuf, 1);
		if (n != 1 || (mbuf[0] & 0xc0) != 0xc0) {
			return FALSE;
			}
		if (read(mouse_fd, mbuf+1, 1) != 1)
			return FALSE;
		if (read(mouse_fd, mbuf+2, 1) != 1)
			return FALSE;
		if (mbuf[1] != 0x80) {
			int d = mbuf[1] & 0x3f;
			if (mbuf[0] & 0x03)
				mouse_x -= 0x40 - d;
			else
				mouse_x += d;
			}
		if (mbuf[2] != 0x80) {
			int d = mbuf[2] & 0x3f;
			if (mbuf[0] & 0x0c)
				mouse_y -= 0x40 -d;
			else
				mouse_y += d;
			}
			
		b1 = (mbuf[0] & 0x20) != 0;
		b2 = (mbuf[0] & 0x10) != 0;
		
		/***********************************************/
		/*   Make sure mouse stays on screen.	       */
		/***********************************************/
		if (mouse_y < 0)
			mouse_y = 0;
		if (mouse_x < 0)
			mouse_x = 0;
		if (mouse_y >= max_y)
			mouse_y = max_y - 1;
		if (mouse_x > max_x)
			mouse_x = max_x;
			
		/***********************************************/
		/*   Dont   let   mouse  touch  bottom  right  */
		/*   corner   of   screen   otherwise  screen  */
		/*   might scroll.			       */
		/***********************************************/
		if (mouse_x == max_x - 1 && mouse_y == max_y - 1)
			mouse_x--;
		if (mouse_y != mouse_oldy || mouse_x != mouse_oldx) {
			mouse_draw_icon(mouse_y / y_pitch, mouse_x / x_pitch, 
					mouse_oldy / y_pitch, mouse_oldx / x_pitch);
			mouse_oldy = mouse_y;
			mouse_oldx = mouse_x;
			}
		buts_changed = b1 ^ but1 || b2 ^ but2 || b3 ^ but3;
		if (buts_changed || (b1 | b2 | b3)) {
			int	x = mouse_x / x_pitch;
			int	y = mouse_y / y_pitch;
			static int ox, oy;
			int	win_id, where;
			WINDOW	*wp;
			if (buts_changed || x != ox || y != oy) {
				ox = x;
				oy = y;
				
				wp = mouse_pos(x, y, &win_id, &where);
				if (wp) {
					x -= wp->w_x;
					y -= wp->w_y;
					}
				sprintf(buf, "mouse %d %d %d %d %d %d %d", 
					win_id, where,
					x, y, b1, b2, b3);
				str_exec(buf);
				}
			}
		but1 = b1;
		but2 = b2;
		but3 = b3;
# if defined(SELECT)
		return TRUE;
# endif
/*		if (typeahead())
			return TRUE;*/
		}
}
void
mouse_draw_icon(y, x, oldy, oldx)
int	y;
int	x;
int	oldy;
int	oldx;
{	static	vbyte_t old_byte;
# if 0
	int	saved_col = *cur_col;
	int	saved_line = *cur_line;

	if (get_marked_areas(curwp)) {
		curwp->w_flag |= WFHARD; 
		*cur_col = x;
		*cur_line = y;
		update();
		*cur_col = saved_col;
		*cur_line = saved_line;
		}
# endif
	vtmove(oldy, oldx);
	vtputb(old_byte);
	upd_row(oldy);
	vtmove(y, x);
	old_byte = disp_get_ch();
/*	vtputb('*' | 0x5300);*/
	vtputb((old_byte & 0x00ff) | 0xe300);
	upd_row(y);
	set_cursor();
}

# endif
/**********************************************************************/
/*   Primitive  to  translate an (x,y) position on the screen into a  */
/*   window and line/col position to help in writing mouse macros.    */
/**********************************************************************/
void
translate_pos()
{	WINDOW	*wp;
	int	where;
	int	win_id;
	
	wp = mouse_pos((int) argv[1].l_int, (int) argv[2].l_int, 
		&win_id, &where);
	argv_assign(3, (long) win_id);
	if (wp) {
		argv_assign(4, (long) 
			(wp->w_top_line + argv[2].l_int - wp->w_y - 1));
		argv_assign(5, (long) 
			(wp->w_indent + argv[1].l_int - wp->w_x + 1));
		}
	acc_assign_int(where);
}
/**********************************************************************/
/*   Function  to  determine  on  what  type  of object the mouse is  */
/*   sitting  on.  Returns  window pointer to window where mouse is.  */
/*   Set  win_id  to the window id, and where identifies the type of  */
/*   area the mouse is on.					      */
/**********************************************************************/
WINDOW *
mouse_pos(x, y, win_id, where)
int	x;
int	y;
int	*win_id;
int	*where;
{	register WINDOW *wp;
	WINDOW *cur_wp = NULL;
	extern vbyte_t **vscreen;
	
	for (wp = wheadp; wp; wp = wp->w_wndp) {
		if (wp->w_x - 1 <= x && x <= wp->w_x + wp->w_w &&
		    wp->w_y <= y && y <= wp->w_y + wp->w_h)
			cur_wp = wp;
		}
	*where = 0;
	if (cur_wp) {
		*win_id = cur_wp->w_num;
		if (x == cur_wp->w_x - 1)
			*where = LEFT_EDGE;
		else if (x == cur_wp->w_x + cur_wp->w_w)
			*where = RIGHT_EDGE;
		else if (y == cur_wp->w_y) {
			if (vscreen[y][x] & 0x80)
				*where = TOP_EDGE;
			else
				*where = TITLE;
			}
		else if (y == cur_wp->w_y + cur_wp->w_h + 1)
			*where = BOTTOM_EDGE;
		else
			*where = INSIDE_WINDOW;
		}
	else
		*win_id = -1;
	return cur_wp;
}
/*******************************************************************/
/*   Function to handle mouse activity called from user macro.	   */
/*******************************************************************/
void
process_mouse()
{	int	win_id;
	int	x, y, b1, b2, b3;
	int	where;
	char	buf[64];
	
	b1 = (int) argv[1].l_int;
	b2 = (int) argv[2].l_int;
	b3 = (int) argv[3].l_int;
	x = (int) argv[4].l_int;
	y = (int) argv[5].l_int;
	mouse_pos(x, y, &win_id, &where);
		
	sprintf(buf, "mouse %d %d %d %d %d %d %d",
		win_id, where, x, y, b1, b2, b3);
	str_exec(buf);
}
