/*
 *	(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.c 1.24 91/05/06";
#endif
#endif

#include <X11/Xlib.h>
#include <xview/cms.h>
#include <memory.h>
#include "canshell_impl.h"

Pkg_private int 	canvas_shell_init();
Pkg_private Xv_opaque	canvas_shell_set_avlist();
Pkg_private Xv_opaque	canvas_shell_get_attr();
Pkg_private int 	canvas_shell_destroy();

extern void rectobj_internal_init();
void	canvas_shell_split_proc();
void	canvas_shell_repaint_proc();
void	canvas_shell_event_proc();
Rectobj	canvas_shell_map_event_proc();
void	canvas_shell_geometry_manage_proc();


Attr_attribute  canvas_shell_context_key;
Listnode	*canvas_shells = NULL;

/*ARGSUSED*/
Pkg_private int
canvas_shell_init(parent, canvas_shell, avlist)
	Xv_opaque	parent;
	Canvas_shell	canvas_shell;
	Attr_avlist	avlist;
{
	Canvas_shell_info	*csinfo;
	Canvas_shell_struct	*canvas_shell_object;
	Shared_info		*sinfo;
	int			background_event_proc();

	if (canvas_shell_context_key == (Attr_attribute) 0) {
		canvas_shell_context_key = xv_unique_key();
	}

	csinfo = xv_alloc(Canvas_shell_info);
	canvas_shell_object = (Canvas_shell_struct*)canvas_shell;
	canvas_shell_object->private_data = (Xv_opaque) csinfo;
	rectobj_internal_init(canvas_shell, &csinfo->rectobj_info);

	xv_set(canvas_shell, 
		OPENWIN_SPLIT,
			OPENWIN_SPLIT_INIT_PROC, canvas_shell_split_proc, 
			XV_NULL,
		CANVAS_REPAINT_PROC, canvas_shell_repaint_proc,
		CANVAS_X_PAINT_WINDOW, TRUE,
		CANVAS_AUTO_EXPAND, TRUE,
		CANVAS_AUTO_SHRINK, TRUE,
		CANVAS_FIXED_IMAGE, FALSE, /* set forget gravity */
		CANVAS_RETAINED, FALSE,
		CANVAS_PAINTWINDOW_ATTRS,
			WIN_CONSUME_EVENTS,
				WIN_UP_EVENTS, 
				WIN_MOUSE_BUTTONS,
				LOC_DRAG,
				MS_LEFT,
				XV_NULL,
			WIN_EVENT_PROC, canvas_shell_event_proc,
			XV_KEY_DATA, canvas_shell_context_key, csinfo,
			XV_NULL,
		RECTOBJ_EVENT_PROC, background_event_proc,
		/* RECTOBJ_PAINT_PROC, */
		RECTOBJ_MANAGE_CHILD_PROC, canvas_shell_geometry_manage_proc,
		XV_NULL);

	/* initialize shared_info */
	sinfo = &csinfo->shared_info;
	sinfo->canvas_shell = canvas_shell;
	sinfo->dpy = (Display*) xv_get(canvas_shell, XV_DISPLAY);
	sinfo->screen_number = (int) xv_get( 
			xv_get(canvas_shell, XV_SCREEN), SCREEN_NUMBER);
	sinfo->num_colors = xv_get(
			xv_get(canvas_shell, WIN_CMS), CMS_SIZE);
	sinfo->pixels = (unsigned long*) xv_get(
			xv_get(canvas_shell, WIN_CMS), CMS_INDEX_TABLE);

	csinfo->rectobj_info.shared_info = sinfo;

	canvas_shells = list_concat(canvas_shells, &csinfo->listnode);
	csinfo->listnode.handle = (void*)csinfo;

	return(XV_OK);
}


Pkg_private Xv_opaque
canvas_shell_set_avlist(canvas_shell, avlist_arg)
	Canvas_shell	canvas_shell;
	Attr_avlist	avlist_arg;
{
	Canvas_shell_info *csinfo = CANVAS_SHELL_PRIVATE(canvas_shell);
	register Canvas_shell_attr attr;
	Attr_attribute	avlist_array[ATTR_STANDARD_SIZE];
	Attr_avlist	avlist;
	extern	int	rectobj_global_invocation_level;

	/*
	 * 1) Copy the attribute list.
	 * 2) Consume attributes that the rectobj should see.
	 * 3) Call the rectobj set function.
	 */
	
	/* find the end of the list */
	avlist = avlist_arg;
	while (attr = (Canvas_shell_attr) * avlist) {
		avlist = attr_next(avlist);
	}

	memcpy( (char*)avlist_array, (char*)avlist_arg, 
		(int)avlist - (int)avlist_arg + sizeof attr);
	
	avlist = avlist_array;
	while (attr = (Canvas_shell_attr) * avlist) {
	  switch(attr) {

	  case WIN_CMS:
		ATTR_CONSUME(*avlist);
		csinfo->shared_info.num_colors = xv_get( *(avlist+1), CMS_SIZE);
		csinfo->shared_info.pixels = 
			(unsigned long*) xv_get( *(avlist+1), CMS_INDEX_TABLE);
		avlist = attr_next(avlist);
		break;

	  case RECTOBJ_PARENT:
	  case XV_OWNER:
		ATTR_CONSUME(*avlist);
		avlist = attr_next(avlist);
		break;

	  case CANVAS_SHELL_DELAY_REPAINT:
		ATTR_CONSUME(*avlist);
		rectobj_set_delay_repaint(canvas_shell, 
			*(avlist+1));
		avlist = attr_next(avlist);
		break;

	  case CANVAS_SHELL_BATCH_REPAINT:
		ATTR_CONSUME(*avlist);
		if(csinfo->batch_pixmap)
			XFreePixmap(csinfo->shared_info.dpy, csinfo->batch_pixmap);
		if((int)*(avlist+1))
			csinfo->batch_pixmap = 
				XCreatePixmap(csinfo->shared_info.dpy, 
				xv_get(canvas_shell, XV_XID), 
				xv_get(canvas_shell, XV_WIDTH), 
				xv_get(canvas_shell, XV_HEIGHT), 
				xv_get(canvas_shell, WIN_DEPTH)); 
		avlist = attr_next(avlist);
		break;

	  default:
		if(ATTR_PKG(attr) != ATTR_RECTOBJ)
			ATTR_CONSUME(*avlist);
		avlist = attr_next(avlist);
		break;
	  }
	}

	rectobj_set_avlist(canvas_shell, (Attr_avlist) avlist_array);
	/*
	 * should rectobj_finish_set be called here?
	 * as a minimum, we need to reset global invocation level
	 */

	rectobj_global_invocation_level--;
	return XV_OK;
}


/*ARGSUSED*/
Pkg_private Xv_opaque
canvas_shell_get_attr(canvas_shell, status, which_attr, avlist)
	Canvas_shell	canvas_shell;
	int		*status;
	register Attr_attribute which_attr;
	Attr_avlist	avlist;
{
	Canvas_shell_info *csinfo = CANVAS_SHELL_PRIVATE(canvas_shell);

	switch(which_attr) {
	  case RECTOBJ_PARENT:
		return (Xv_opaque) 0;

	  case CANVAS_SHELL_DELAY_REPAINT:
		return (Xv_opaque) csinfo->delay_repaint;

	  case CANVAS_SHELL_BATCH_REPAINT:
		return (Xv_opaque) (csinfo->batch_pixmap != (Pixmap) 0);

	  default:
		break;
	}
	if(ATTR_PKG(which_attr) == ATTR_RECTOBJ)
		  return( rectobj_get_attr(canvas_shell, 
				status, which_attr, avlist) );

	*status = XV_ERROR;
	return (Xv_opaque) 0;
}


/*ARGSUSED*/
Pkg_private int
canvas_shell_destroy(canvas_shell, status)
	Canvas_shell	canvas_shell;
	Destroy_status	status;
{
	Canvas_shell_info *csinfo = CANVAS_SHELL_PRIVATE(canvas_shell);

	if ((status == DESTROY_CHECKING) || (status == DESTROY_SAVE_YOURSELF))
		return XV_OK;

	canvas_shells = list_unlink_node(&csinfo->listnode);

	rectobj_destroy(canvas_shell, status);
	/* no need to free csinfo, it is freed by the rectobj */

	return XV_OK;
}


void
canvas_shell_geometry_manage_proc(parent, child, child_new_rect, child_old_rect)
	Rectobj	parent;
	Rectobj	child;
	Rect	*child_new_rect;
	Rect	*child_old_rect;
{
#define BORDER 10
	register Rectobj_info *rinfo = RECTOBJ_PRIVATE(parent);
	int w, h;

#ifdef RESIZE
/* To be used later when scrollbars are manipulated...*/
	if(rect_includesrect(&rinfo->rect, child_new_rect)) {
		/* check for shrink to fit? */
		;
	} else {
		/* expand to fit child */
		w = rect_right(child_new_rect) - rect_right(&rinfo->rect);
		if(w > 0)
			rinfo->rect.r_width += (w + BORDER);

		h = rect_bottom(child_new_rect) - rect_bottom(&rinfo->rect);
		if(h > 0)
			rinfo->rect.r_height += (h + BORDER);
		
		if(w > 0 || h > 0)
			xv_set(parent, XV_RECT, &rinfo->rect, XV_NULL);
	}
#endif
	rectobj_set_geometry(child, child_new_rect);
}


