/*	Copyright (c) 1990 UNIX System Laboratories, Inc.	*/
/*	Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T	*/
/*	  All Rights Reserved  	*/

/*	THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF     	*/
/*	UNIX System Laboratories, Inc.                     	*/
/*	The copyright notice above does not evidence any   	*/
/*	actual or intended publication of such source code.	*/

/*
 * Copyright  (c) 1986 AT&T
 *	All Rights Reserved
 */
#ident	"@(#)fmli:vt/physical.c	1.25"

#include	<curses.h>
#include	<fcntl.h>
#include	"wish.h"
#include	"token.h"
#include	"message.h"
#include	"vt.h"
#include	"var_arrays.h"
#include	"actrec.h"
#include	"moremacros.h"
#include	"vtdefs.h"

#ifdef	TIME_IT

#include	<sys/types.h>
#include	<sys/times.h>

#endif /* TIME_IT */

extern time_t	Cur_time;	/* abs k15, EFT k16*/
extern char Semaphore[];
extern int Coproc_active;
extern int Vflag;
extern time_t	time();	        /* EFT abs k16 */


/* #ifdef i386  abs k18 */

/*
 * redefine curses mouse position macros
 */
#define SCR_ROW		MOUSE_Y_POS
#define SCR_COL		MOUSE_X_POS

/*
 * Given a screen offset (r, c), PTS_to() will determine whether r,c 
 * points to a given frame (excluding the frame border).
 * (br, bc is the beginning offset of the frame on the screen and
 * mr, mc is the maximum rows and columns of the frame)
 */
#define PTS_to(r, c, br, bc, mr, mc) \
		((r > br) && (r < (br + mr - 1)) && \
		 (c > bc) && (c < (bc + mc - 1)))
/*
 * ON_border() will evaluate to true if the mouse points to the
 * frame border
 */
#define ON_border(r, c, br, bc, mr, mc) \
		(((r == br || (r == (br + mr - 1))) && \
		  (c >= bc && (c <= (bc + mc - 1)))) || \
		 ((c == bc || (c == (bc + mc - 1))) && \
		  (r >= br && (r <= (br + mr - 1)))))

/*
 * Determine the mouse offset within the frame (0,0 based)
 * (excluding the frame border). 
 */
#define FRAME_ROW(r1, r2)	(r1 - (r2 + 1))
#define FRAME_COL(c1, c2)	(c1 - (c2 + 1))

static token page_tok();
static token do_mouse(), do_open_mouse();

/* #endif abs k18 */

int Mouse_row;
int Mouse_col;
int Open_mouse_mode = FALSE;

extern long	Mail_check;
extern long	Interupt_pending;

token
physical_stream(t)
register token	t;
{
    token	wgetchar();
    int	fd;

#ifdef PHYSICAL			/* i dont know what this does but since
				 * it was un-compilable until k17
				 * it must never have been used. abs */

    struct tms	tms1, tms2;
    clock_t		real1;	       /* EFT abs k16 */
    int		lcv1 = 10000;

    real1 = times( &tms1 );	/* ; added. abs k17 */
	
    while ( lcv1-- )
    {
#endif /* PHYSICAL */

	Cur_time = time((time_t)0);

	ar_checkworld(FALSE);
	working(FALSE);
	if (Vflag)
	    showmail( FALSE );

	(void) mess_flush(FALSE);

/* new les */
	vt_flush();

	alarm((int) Mail_check);
	if (Coproc_active)
	{
	    /*
	     * The call to open is to protect "vsig" from
	     * sending a signal to FACE when the screen
	     * is being painted ...
	     * Vsig will block on the semaphore until FACE
	     * is able to receive signals ..
	     * This code may be changed if a better solution
	     * is found ...
	     * Interupt_pending is definined in main.c and
	     * set in the interupt handler for a SIGUSR2 
	     * once a signal is encountered ...
	     */ 
	    fd = open(Semaphore, O_RDONLY|O_NDELAY);
	    if (Interupt_pending) 
	    {
		Interupt_pending = 0;
		ar_checkworld(TRUE);
		vt_flush();	/* abs k18.2 */
	    }
	    t = wgetchar();
	    close(fd);
	}	
	else
	    t = wgetchar();
	mess_unlock();		/* allow calls to mess_temp and mess_perm */

	if (t < 0)
	    t = TOK_NOP;
	else if (t >= TOK_F(1) && t <= TOK_F(8))
	    t = t - TOK_F(1) + TOK_SLK1;
/* #ifdef i386  abs k18*/
	else if (t == KEY_MOUSE)
	{ 
	    if (Open_mouse_mode)
		t = do_open_mouse();
	    else
		t = do_mouse();
	}
/* #endif  abs k18 */
	(void) mess_flush(TRUE);

	return t;

#ifdef PHYSICAL			/* abs k17 */
    }				/* abs k17 */
#endif /* PHYSICAL */           /* abs k17 */

}

/* #ifdef i386  abs k18 */

static token
do_mouse()
{
    register int brow, bcol, mrow, mcol;
    struct	 vt *v, *savev, *curvt;
    int	 num, onborder;
    token	 t;
    struct	 actrec *wdw_to_ar();

    if (BUTTON_CHANGED(2) || BUTTON_CHANGED(3))
	return(TOK_NOP);	/* only concerned about button 1 events */	
    if (BUTTON_CHANGED(1) && (BUTTON_STATUS(1) == BUTTON_PRESSED ||
			      BUTTON_STATUS(1) == BUTTON_CLICKED)) {
	/* 
	 * First check to see which frame (if any) the
	 * the mouse points to ...
	 */
	t = TOK_NOP;
	savev = curvt = &VT_array[VT_curid];
	getbegyx(curvt->win, brow, bcol);
	getmaxyx(curvt->win, mrow, mcol);
	if (ON_border(SCR_ROW, SCR_COL, brow, bcol, mrow, mcol)) {
	    /*
	     * Mouse points to the current frame border
	     */
	    onborder = TRUE;
	    t = TOK_BPRESSED;
	}
	else if (PTS_to(SCR_ROW, SCR_COL, brow, bcol, mrow, mcol)) {
	    /*
	     * Mouse points to the current frame
	     */
	    onborder = FALSE;
	    t = TOK_BPRESSED;
	}
	else {
	    /*
	     * Scan the list of VT's to find one that the 
	     * mouse points to ...
	     */
	    v = VT_array;
	    savev = NULL;
	    for (num = array_len(VT_array); num > 0; v++, num--) {
		if (v == curvt || !(v->flags & VT_USED) ||
		    (v->flags & VT_NOBORDER))
		    continue;	/* don't bother */
		getbegyx(v->win, brow, bcol);
		getmaxyx(v->win, mrow, mcol);
		if (ON_border(SCR_ROW, SCR_COL, brow, bcol, mrow, mcol)) {
		    if (on_top(v, savev)) {
			savev = v;
			onborder = TRUE;
		    }
		    t = TOK_BPRESSED;
		}
		else if (PTS_to(SCR_ROW, SCR_COL, brow, bcol, mrow, mcol)) {
		    if (on_top(v, savev)) {
			savev = v;
			onborder = FALSE;
		    }
		    t = TOK_BPRESSED;
		}
	    }
	}
	/*
	 * If the mouse doesn't point to a frame (t != TOK_BPRESSED)
	 * then return TOK_NOP 
	 */
	if (t != TOK_BPRESSED)
	    return(TOK_NOP);

	v = savev; 
	if (v != curvt) {
	    /*
	     * frame is not current so make it current
	     */
	    ar_current(wdw_to_ar(v->number), TRUE); /* abs k15 */
	    vt_flush();
	    curvt = &VT_array[VT_curid];
	    getbegyx(curvt->win, brow, bcol);
	    getmaxyx(curvt->win, mrow, mcol);
	}
	if (onborder == FALSE) {
	    /*
	     * If not on the frame border then
	     * do object specific action for 
	     * BUTTON PRESS 
	     */
	    Mouse_row = FRAME_ROW(SCR_ROW, brow);
	    Mouse_col = FRAME_COL(SCR_COL, bcol);
	    (void) arf_odsh(ar_get_current(), TOK_BPRESSED);
	    wrefresh(curvt->win);
	}
	if (mess_flush(FALSE))	/* update message line */
	    wrefresh(VT_array[MESS_WIN].win);

	if (BUTTON_STATUS(1) == BUTTON_PRESSED) {
	    /*
	     * Perform mouse tracking while the button is
	     * depressed ...  (if the mouse was "clicked" there
	     * is no need to track)
	     *
	     * NOTE: Do not map button release events to SLKS while
	     * tracking.
	     */
	    map_button(0);
	    for (; ;) {
		/* 
		 * No longer track on BUTTON_RELEASE
		 */
		if (BUTTON_STATUS(1) == BUTTON_RELEASED) {
		    Mouse_row = FRAME_ROW(SCR_ROW, brow);
		    Mouse_col = FRAME_COL(SCR_COL, bcol);
		    break;		
		}
		if (request_mouse_pos() == ERR)
		    break;
		if (MOUSE_MOVED && PTS_to(SCR_ROW, SCR_COL, brow, bcol, mrow, mcol)) {
		    Mouse_row = FRAME_ROW(SCR_ROW, brow);
		    Mouse_col = FRAME_COL(SCR_COL, bcol);
		    (void) arf_odsh(ar_get_current(), TOK_BPRESSED);
		    wrefresh(curvt->win);
		    if (mess_flush(FALSE))
			wrefresh(VT_array[MESS_WIN].win);
		}
	    }
	    map_button(BUTTON1_RELEASED);
	}
    }
    if (BUTTON_CHANGED(1) && (BUTTON_STATUS(1) == BUTTON_RELEASED ||
			      BUTTON_STATUS(1) == BUTTON_CLICKED)) {
	/*
	 * If XY points to the current frame return (TOK_BRELEASED)
	 * otherwise ignore the mouse event (TOK_NOP)
	 */
	flushinp();
	curvt = &VT_array[VT_curid];
	getbegyx(curvt->win, brow, bcol);
	getmaxyx(curvt->win, mrow, mcol);
	if ((SCR_COL - bcol + 1) == mcol) {
	    /* 
	     * The mouse points to the right frame border ...
	     * check to see if it is inside the scroll box 
	     */
	    t = page_tok(SCR_ROW, brow, mrow);
	}
	else if (PTS_to(SCR_ROW, SCR_COL, brow, bcol, mrow, mcol)) {
	    /*
	     * The mouse points to the current frame ...
	     * Determine the frame offset
	     */
	    Mouse_row = FRAME_ROW(SCR_ROW, brow);
	    Mouse_col = FRAME_COL(SCR_COL, bcol);
	    t = TOK_BRELEASED;
	}
	else 
	    t = TOK_NOP;
    }
    return(t);
}

/*
 * DO_OPEN_MOUSE is similar to DO_MOUSE except the mouse doesn't have 
 * to point inside a frame (e.g., frame management routines move and 
 * reshape)
 */
static token
do_open_mouse()
{
    token	 t;

    if (BUTTON_CHANGED(2) || BUTTON_CHANGED(3))
	return(TOK_NOP);	/* only concerned about button 1 events */	
    t = TOK_NOP;
    if (BUTTON_CHANGED(1) && BUTTON_STATUS(1) == BUTTON_PRESSED) {
	/*
	 * Perform mouse tracking while button is depressed
	 */
	map_button(0);
	for (; ;) {
	    t = TOK_NOP;
	    /* 
	     * No longer track on BUTTON_RELEASE
	     */
	    if (BUTTON_STATUS(1) == BUTTON_RELEASED) {
		Mouse_row = SCR_ROW;
		Mouse_row = SCR_ROW;
		t = TOK_BRELEASED;
		break;		
	    }
	    if (request_mouse_pos() == ERR)
		break;
	    if (MOUSE_MOVED) {
		Mouse_row = SCR_ROW;
		Mouse_col = SCR_COL;
		(void) arf_odsh(ar_get_current(), TOK_BPRESSED);
		vt_flush();
	    }
	}
	map_button(BUTTON1_RELEASED);
    }
    else if (BUTTON_CHANGED(1) && BUTTON_STATUS(1) == BUTTON_CLICKED) {
	/*
	 * Button was clicked so don't track ... interpret as
	 * Button press immediately followed by button release.
	 */
	Mouse_row = SCR_ROW;
	Mouse_col = SCR_COL;
	(void) arf_odsh(ar_get_current(), TOK_BPRESSED);
	vt_flush();
	t = TOK_BRELEASED;
    }
    return(t);
}

/*
 * Given that the mouse points to the right frame border,
 * PAGE_TOK() returns a page token if the mouse points to
 * the up/down arrow in the scroll box
 */
static token
page_tok(mouserow, brow, mrow)
int mouserow, brow, mrow;
{
    int uparrow, dnarrow, framerow;
    token rettok;

    uparrow = (mrow / 2) - 1;	/* location of up arrow */
    dnarrow = uparrow + 2;	/* location of down arrow */
    framerow = mouserow - brow;	/* location of the mouse */

    if (framerow == uparrow)
	rettok = TOK_PPAGE;
    else if (framerow == dnarrow)
	rettok = TOK_NPAGE; 
    else
	rettok = TOK_NOP;
    return(rettok);
}

/*
 * Given 2 frames ON_TOP will return TRUE if frame 1 (arg1) is
 * "on top of" frame 2 (arg2)
 */
static int
on_top(f1, f2)
struct vt *f1, *f2;
{
    struct	 actrec *wdw_to_ar();
    struct	 actrec *ar1, *ar2;

    if (f2 == (struct vt *)NULL)
	return(TRUE);
    ar1 = wdw_to_ar(f1->number);
    ar2 = wdw_to_ar(f2->number);
		
    if (ar_isfirst(ar1, ar2))
	return(TRUE);
    else
	return(FALSE);
}

/* #endif abs k18 */
