/*
 *	(c) Copyright 1991 Sun Microsystems, Inc.  All rights reserved.
 *	See LEGAL_NOTICE file for terms and restrictions.
 */

#ifndef lint
#ifdef sccs
static char	sccsid[] = "@(#)canshell_eve.c 1.19 91/05/10";
#endif
#endif

#include <X11/Xlib.h>
#include <xview/canvas.h>
#include <xview/rect.h>
#include <xview/xv_xrect.h>
#include <assert.h>
#include "canshell_impl.h"

void	canvas_shell_split_proc();
void	canvas_shell_repaint_proc();
void	canvas_shell_paint_rect();
void	canvas_shell_event_proc();

extern	Attr_attribute	canvas_shell_context_key;

/*----------------------------------------------------------------------*/

/*ARGSUSED*/
void
canvas_shell_split_proc(origview, newview, pos)
	Xv_window origview, newview;
	int pos;
{
	xv_set(xv_get(newview, CANVAS_VIEW_PAINT_WINDOW),
		WIN_CONSUME_EVENTS,
			WIN_UP_EVENTS, 
			WIN_MOUSE_BUTTONS,
			LOC_DRAG,
			MS_LEFT,
			0,
		WIN_EVENT_PROC, canvas_shell_event_proc,
		XV_KEY_DATA, canvas_shell_context_key, 
			xv_get(xv_get(origview, CANVAS_VIEW_PAINT_WINDOW), 
				XV_KEY_DATA, canvas_shell_context_key),
			0);
}


/*ARGSUSED*/
void
canvas_shell_repaint_proc(canvas_shell_public, paint_window, dpy, win, xrects)
	Canvas_shell	canvas_shell_public;
	Xv_Window	paint_window;	/* unused */
	Display		*dpy;
	Window		win;
	Xv_xrectlist	*xrects;
{
	Rectobj_info *rinfo = RECTOBJ_PRIVATE(canvas_shell_public);

	if(rinfo->paint_proc)
		(rinfo->paint_proc)(canvas_shell_public, dpy, win, xrects);
}


void
canvas_shell_event_proc(paint_window, start_event, arg)
	Xv_window	paint_window;
	Event		*start_event;
	Notify_arg	arg;
{
	Canvas_shell		canvas_shell_public;
	Canvas_shell_info	*csinfo;
	Rectobj			event_rectobj;
	Rectobj_info		*event_rinfo;
	Event			event;
	
	csinfo = (Canvas_shell_info*) xv_get(paint_window, 
			XV_KEY_DATA, canvas_shell_context_key);
	if(!csinfo)
		return;

	canvas_shell_public = CANVAS_SHELL_PUBLIC(csinfo);
	event = *start_event;

	if(event_shift_is_down(&event) && event_ctrl_is_down(&event))
	  rectobj_paint_outlines(canvas_shell_public, &csinfo->shared_info);

	while(1) {
		event_rectobj = event_to_rectobj(canvas_shell_public, &event);

		if(!event_rectobj) 
			break;

		event_rinfo = RECTOBJ_PRIVATE(event_rectobj);

		if(!event_rinfo->event_proc)
			break;

		if((event_rinfo->event_proc)(paint_window, &event, 
				canvas_shell_public, event_rectobj) == TRUE)
			break;
	}
}


Rectobj
event_to_rectobj(canvas_shell, event)
	Rectobj	canvas_shell;
	Event	*event;
{
	Rectobj_info *rinfo = RECTOBJ_PRIVATE(canvas_shell);

	if(rinfo->map_event_proc)
		return( (rinfo->map_event_proc)(canvas_shell, event) );
	return (Rectobj) 0;
}


int
count_buttons_down(event)
	Event *event;
{
	int down = 0;
	if( event_right_is_down(event) )	down++;
	if( event_left_is_down(event) )		down++;
	if( event_middle_is_down(event) )	down++;
	return down;
}


/*
 * For right now, this is really dumb.  It maintains one rect that contains
 * the union of all areas that need repainting.  If it proves that something
 * more sophisticated is needed, this will be replaced.
 */
void
rectobj_repaint_rect(rectobj, rect, clear)
	Rectobj		rectobj;
	Rect		*rect;
	int		clear;
{
	Rectobj_info		*rinfo = RECTOBJ_PRIVATE(rectobj);
	Canvas_shell_info	*csinfo;
 
	if(!rinfo->shared_info)
		return;

	csinfo = CANVAS_SHELL_PRIVATE(rinfo->shared_info->canvas_shell);

	if(!rect)
		rect = &rinfo->rect;

	if(!rinfo->painted)
		return;

	if((rect->r_width == 0) || (rect->r_height == 0))
		return;

	if(clear)
		csinfo->repaint_clear = TRUE;

	csinfo->repaint_rect = rect_bounding( &csinfo->repaint_rect, rect );

#ifdef REPAINT_DEBUG
	{
	GC gc;

	gc = XCreateGC(rinfo->shared_info->dpy, 
		xv_get(rinfo->shared_info->canvas_shell, XV_XID),
		0, 0);

	/* batching must be turned off */
	xv_set(rinfo->shared_info->canvas_shell,CANVAS_SHELL_BATCH_REPAINT,0,0);

	XSetForeground(rinfo->shared_info->dpy, gc, 1);
	XFillRectangle(rinfo->shared_info->dpy,
		xv_get(xv_get(rinfo->shared_info->canvas_shell, 
			CANVAS_NTH_PAINT_WINDOW, 0), XV_XID),
		gc,
		rect->r_left, rect->r_top,
		rect->r_width-1, rect->r_height-1);
	XFreeGC(rinfo->shared_info->dpy, gc);
	XFlush(rinfo->shared_info->dpy);
	}
#endif
	
	return;
}
 

void
rectobj_flush_repaint()
{
	Xv_window		xv_win;
	Xv_xrectlist		xrects;
	Canvas_shell_info	*csinfo;
	extern 	Listnode	*canvas_shells;
	Listnode		*node;

	node = canvas_shells;

#ifdef REPAINT_DEBUG
	usleep(3000);
#endif 

	list_for(node) {

	  csinfo = (Canvas_shell_info*) list_handle(node);

	  if((csinfo->repaint_rect.r_width == 0) ||
	    (csinfo->repaint_rect.r_height == 0) ||
	    (csinfo->delay_repaint))
		continue;

	  xrects.count = 1;
	  /* different structs, but equivalent */
	  xrects.rect_array[0] = *(XRectangle*) &csinfo->repaint_rect;

	/* isn't repaint_clear almost always set? -- it may be worthless */

	  if(csinfo->batch_pixmap) {
	    GC gc;

	    gc = XCreateGC(csinfo->shared_info.dpy, csinfo->batch_pixmap, 0, 0);
	    XSetForeground(csinfo->shared_info.dpy, gc, 
	      csinfo->shared_info.pixels[ xv_get(
		csinfo->shared_info.canvas_shell, WIN_BACKGROUND_COLOR)]);
	    if(csinfo->repaint_clear) 
		XFillRectangle(csinfo->shared_info.dpy, 
			csinfo->batch_pixmap,
			gc,
			csinfo->repaint_rect.r_left,
			csinfo->repaint_rect.r_top,
			csinfo->repaint_rect.r_width,
			csinfo->repaint_rect.r_height);

	    canvas_shell_repaint_proc(csinfo->shared_info.canvas_shell, 
			0/*unused*/,
			csinfo->shared_info.dpy, 
			csinfo->batch_pixmap,
			&xrects);

	    CANVAS_EACH_PAINT_WINDOW(csinfo->shared_info.canvas_shell, xv_win)
		XCopyArea(csinfo->shared_info.dpy,
			csinfo->batch_pixmap,
			xv_get(xv_win, XV_XID), 
			gc,
			csinfo->repaint_rect.r_left,
			csinfo->repaint_rect.r_top,
			csinfo->repaint_rect.r_width,
			csinfo->repaint_rect.r_height,
			csinfo->repaint_rect.r_left,
			csinfo->repaint_rect.r_top);
	    CANVAS_END_EACH
	    XFreeGC(csinfo->shared_info.dpy, gc);

	  } else {
	    CANVAS_EACH_PAINT_WINDOW(csinfo->shared_info.canvas_shell, xv_win)

		if(csinfo->repaint_clear) 
			XClearArea(csinfo->shared_info.dpy, 
				xv_get(xv_win, XV_XID),
				csinfo->repaint_rect.r_left,
				csinfo->repaint_rect.r_top,
				csinfo->repaint_rect.r_width,
				csinfo->repaint_rect.r_height,
				FALSE);

		canvas_shell_repaint_proc(csinfo->shared_info.canvas_shell, 
			0/*unused*/,
			csinfo->shared_info.dpy, 
			xv_get(xv_win, XV_XID), 
			&xrects);

	    CANVAS_END_EACH
	  }

	  csinfo->repaint_clear = FALSE;
	  csinfo->repaint_rect.r_width = 0;
	  csinfo->repaint_rect.r_height = 0;
	}
}


void
rectobj_set_delay_repaint(rectobj, flag)
	Rectobj	rectobj;
	int	flag;
{
	Rectobj_info		*rinfo = RECTOBJ_PRIVATE(rectobj);
	Canvas_shell_info	*csinfo;
	extern 	int		rectobj_global_invocation_level;

	if(!rinfo->shared_info)
		return;

	csinfo = CANVAS_SHELL_PRIVATE(rinfo->shared_info->canvas_shell);

	if(flag)
		csinfo->delay_repaint++;
	else
		csinfo->delay_repaint--;

	if((!csinfo->delay_repaint) && (!rectobj_global_invocation_level))
		rectobj_flush_repaint();
}
 

rectobj_paint_outlines(rectobj, sh_info)
	Rectobj		rectobj;
	Shared_info	*sh_info;
{
	Rectobj_list	*list;
	Rectobj		child;
	Rectobj_info	*rinfo;
	GC		gc;
	Xv_window	xv_win;

	if(!sh_info)
		return;
	gc = XCreateGC(sh_info->dpy,
	xv_get(sh_info->canvas_shell, XV_XID), 0, 0);
	XSetForeground(sh_info->dpy, gc,
		sh_info->pixels[xv_get(sh_info->canvas_shell, WIN_FOREGROUND_COLOR)]);
	list = (Rectobj_list*)xv_get(rectobj, RECTOBJ_CHILDREN);
	list_for(list) {
	  CANVAS_EACH_PAINT_WINDOW(sh_info->canvas_shell, xv_win)
		child = RECTOBJ_LIST_HANDLE(list);
		rinfo = RECTOBJ_PRIVATE(child);
		XDrawRectangle(sh_info->dpy,
		xv_get(xv_win, XV_XID),
			gc,
			rinfo->rect.r_left,
			rinfo->rect.r_top,
			rinfo->rect.r_width,
			rinfo->rect.r_height);
			rectobj_paint_outlines(child, sh_info);
	  CANVAS_END_EACH
	}
	XFreeGC(sh_info->dpy, gc);
}        
 

