/**********************************************************************
 
	Copyright (C) 2003 Hirohisa MORI <joshua@nichibun.ac.jp>
 
	This program is free software; you can redistribute it 
	and/or modify it under the terms of the GLOBALBASE 
	Library General Public License (G-LGPL) as published by 

	http://www.globalbase.org/
 
	This program is distributed in the hope that it will be 
	useful, but WITHOUT ANY WARRANTY; without even the 
	implied warranty of MERCHANTABILITY or FITNESS FOR A 
	PARTICULAR PURPOSE.

**********************************************************************/



#include	<stdlib.h>
#include	"machine/u_math.h"
#include	"machine/include.h"
#include	"memory_debug.h"
#include	"gbview.h"
#include	"gbparam.h"
#include	"gbgraph.h"
#include	"lock_level.h"
#include	"routing.h"
#include	"win_flame.h"
#include	"viewindex.h"
#include	"pri_level.h"
#include	"save_global.h"

#define CURRENT_SWITCH_TIMERAG	2
#define ZONBIE_TIMEOUT	120


void ov_default();

void _wakeup_win_manage(void *);
void wakeup_win_manage(void *);
void _wakeup_loading_task(void);
void wakeup_loading_task(void *);
void min_route_task(void *);
void _wakeup_min_route_task(void *);
void wakeup_min_route_task(void *);


int system_wfid;
int system_gfid;
int gf_zonbie_count;

void check_flame_task();

GBVIEW_FLAME * gbview_flame_list;
SEM gbview_flame_lock;
SEM irq_lock,in_lock,iom_lock;
extern void (*draw_gb_indicate_task)();
void indicate_info_task();
#define wf_indicate_lock(gf)	xx_wf_indicate_lock(gf,__FILE__,__LINE__)

void
init_win_flame()
{
	SG_TITLE;
	
	sg("GBVIEW_FLAME*","gbview_flame_list",&gbview_flame_list);

	gbview_flame_lock = new_lock(LL_WF);
/* init GBVIEW_FLAME
	gf->seq = 1;
*/
	irq_lock = new_lock(LL_IRQ);
	in_lock = new_lock(LL_INDICATE);
	iom_lock = new_lock(LL_ONMAP);
	draw_gb_indicate_task = indicate_info_task;
}


int
_get_new_gfid()
{
GBVIEW_FLAME * gf;
retry:
	system_gfid ++;
	if ( system_gfid <= 0 )
		system_gfid = 1;
	for ( gf = gbview_flame_list ; gf ; gf = gf->next ) {
		if ( gf->id == system_gfid )
			goto retry;
	}
	return system_gfid;
}

GBVIEW_FLAME *
_wf_new_gf()
{
GBVIEW_FLAME * ret;
int i;
	ret = d_alloc(sizeof(*ret));
	memset(ret,0,sizeof(*ret));
	ret->seq = 1;
/*
	ret->win_height = 400;
	ret->win_width = 600;
	ret->redraw = d_alloc(ret->win_height*ret->win_width);
	for ( i = 0 ; i < ret->win_height*ret->win_width ; i ++ )
		env.redraw[i] = RP_REDRAW;
	ret->redraw_plane 
		= d_alloc(ret->win_height*ret->win_width*sizeof(long));
*/
	gf_init_indicate(ret);

	ret->id = _get_new_gfid();

	ret->status = GVFS_IDLE;

	ret->next = gbview_flame_list;
	gbview_flame_list = ret;

	return ret;
}

GBVIEW_FLAME *
wf_new_gf()
{
GBVIEW_FLAME * ret;
	lock_task(gbview_flame_lock);
	ret = _wf_new_gf();
	unlock_task(gbview_flame_lock,"wf_new_gf");
	return ret;
}

void
ch_lock_init(LOCK_D * d)
{
	memset(d,0,sizeof(*d));
}

void
_ch_lock(LOCK_D *lock_bit,char * file,int line)
{
	for ( ; lock_bit->file ; ) {
		sleep_task((int)lock_bit,gbview_flame_lock);
		lock_task(gbview_flame_lock);
	}
	if ( file == 0 )
		er_panic("_ch_lock");
	lock_bit->file = file;
	lock_bit->line = line;
	lock_bit->tid = _get_tid();
}

void
ch_lock(LOCK_D *lock_bit,char * file,int line)
{
	lock_task(gbview_flame_lock);
	_ch_lock(lock_bit,file,line);
	unlock_task(gbview_flame_lock,"wf_lock");
}


void
_ch_unlock(LOCK_D * lock_bit)
{
	if ( lock_bit->file == 0 )
		er_panic("wf_unlock");
	lock_bit->file = 0;
	lock_bit->line = 0;
	lock_bit->tid = 0;
	wakeup_task((int)lock_bit);
}

void
ch_unlock(LOCK_D * lock_bit)
{
	lock_task(gbview_flame_lock);
	_ch_unlock(lock_bit);
	unlock_task(gbview_flame_lock,"wf_lock");
}


int
_ch_locked(LOCK_D * d)
{
	if ( d->file )
		return 1;
	return 0;
}

void
ch_sleep_task(int key,LOCK_D * lock_bit)
{
	lock_task(gbview_flame_lock);
	if ( lock_bit->file == 0 )
		er_panic("ch_sleep_task");
	lock_bit->file = 0;
	lock_bit->line = 0;
	lock_bit->tid = 0;
	wakeup_task((int)lock_bit);
	sleep_task(key,gbview_flame_lock);
}

void
xx_wf_lock(GBVIEW_FLAME * gf,char * file,int line)
{
	ch_lock(&gf->_wf_lock,file,line);
}


void
wf_unlock(GBVIEW_FLAME * gf)
{
	ch_unlock(&gf->_wf_lock);
}

void
wf_sleep_task(GBVIEW_FLAME * gf,int key)
{
	ch_sleep_task(key,&gf->_wf_lock);
}


void
wf_apply_all_gf(int (*func)(),void * work,int status,int lock_flag)
{
GBVIEW_FLAME * gf;
	lock_task(gbview_flame_lock);
	for ( gf = gbview_flame_list ; gf ; gf = gf->next ) {
		if ( gf->status & status ) {
			if ( lock_flag == 0 )
				unlock_task(gbview_flame_lock,"wf_apply_all_gf");
			if ( (*func)(gf,work) < 0 ) {
				lock_task(gbview_flame_lock);
				break;
			}
			if ( lock_flag == 0 )
				lock_task(gbview_flame_lock);
		}
	}
	unlock_task(gbview_flame_lock,"wf_apply_all_gf");
}


typedef struct _wf_get_gf_from_id_t {
	int		id;
	GBVIEW_FLAME * 	ret;
} _WF_GET_GF_FROM_ID_T;

int
_wf_get_gf_from_id(GBVIEW_FLAME * gf,_WF_GET_GF_FROM_ID_T * w)
{
	if ( gf->id == w->id ) {
		w->ret = gf;
		return -1;
	}
	return 0;
}

GBVIEW_FLAME *
wf_get_gf_from_id(int id)
{
_WF_GET_GF_FROM_ID_T w;

	w.ret = 0;
	w.id = id;
	wf_apply_all_gf(_wf_get_gf_from_id,&w,GVFM_LIVE,1);
	return w.ret;
}

GBVIEW_FLAME *
wf_next_gf(GBVIEW_FLAME * gf,int status)
{
	lock_task(gbview_flame_lock);
	if ( gf == 0 )
		gf = gbview_flame_list;
	else gf = gf->next;
	for ( ; gf ; gf = gf->next )
		if ( gf->status & status )
			break;
	unlock_task(gbview_flame_lock,"wf_next_gf");
	return gf;
}



void
check_flame_task(GBVIEW_FLAME * gf)
{
WIN_FLAME * wf;
	for ( ; ; ) {
		sleep_sec(1);
		wf_lock(gf);
		ss_printf("CWF\n");
		for ( wf = gf->flame ; wf ; wf = wf->next ) {
			if ( wf->mh == 0 )
				ss_printf(">> * ");
			else	ss_printf(">>   ");
			ss_printf("%ls ",
				get_url_str2(&wf->draw->h.entry));
			ss_printf("%i %x %i\n",wf->lock,wf->flags,wf->pri_adj);
		}
		wf_unlock(gf);
		gv_cpu_direct();
	}
}

int
_get_env_seq(GBVIEW_FLAME * gf)
{
int ret;
	ret = gf->seq ++;
	if ( gf->seq < 1 )
		gf->seq = 1;
	return ret;
}

void
wf_free_si(WIN_FLAME * wf)
{
SYMBOL_INDICATE * si;


	for ( ; wf->sym_i ; ) {
		si = wf->sym_i;
		wf->sym_i = si->next;
		if ( si->data )
			d_f_ree(si->data);
		if ( si->alpha )
			d_f_ree(si->alpha);
		if ( si->ref )
			d_f_ree(si->ref);
		if ( si->rect.tl.x == si->rect.br.x )
			delete_irq(si->rno,si->code);
		d_f_ree(si);
	}
}

int
_win_lock(GBVIEW_FLAME * gf,WIN_FLAME * wf)
{
int id;
WF_LOCK_LIST * wfl;

retry:
	if ( wf->flags & WFF_FREE )
		return -1;
	if ( wf->aboat_count )
		return -1;
	if ( wf->lock >= 0 ) {
		wf->lock ++;

		wfl = d_alloc(sizeof(*wfl));
		wfl->next = wf->lock_list;
		wfl->tid = get_tid();
		wf->lock_list  = wfl;
	}
	else {
		id = wf->id;
		wf_sleep_task(gf,(int)wf);
		wf_lock(gf);
		if ( _get_wf_ptr(gf,id) == 0 )
			return -1;
		goto retry;
	}
	_wakeup_at_redraw_wp(gf);
	return 0;
}

int
_win_wlock(GBVIEW_FLAME * gf,WIN_FLAME * wf)
{
int id;
WF_LOCK_LIST * wfl;
	for ( ; wf->lock ; ) {
		id = wf->id;
		wf_sleep_task(gf,(int)wf);
		wf_lock(gf);
set_t_msg(4);
		if ( _get_wf_ptr(gf,id) == 0 )
			return -1;
	}
	wf->lock = -1;

	wfl = d_alloc(sizeof(*wfl));
	wfl->next = wf->lock_list;
	wfl->tid = get_tid();
	wf->lock_list  = wfl;

	_wakeup_at_redraw_wp(gf);
	return 0;
}

void
_win_unlock(GBVIEW_FLAME * gf,WIN_FLAME * wf)
{
WIN_FLAME * wf2;
WF_LOCK_LIST ** wflp, * wfl;
int tid;

	tid = get_tid();
	for ( wflp = &wf->lock_list ; *wflp ; wflp = &(*wflp)->next ) {
		if ( (*wflp)->tid != tid )
			continue;
		wfl = *wflp;
		*wflp = wfl->next;
		d_f_ree(wfl);
		goto ok;
	}
	return;
ok:
	if ( wf->lock == 0 )
		er_panic("_win_unlock");
	if ( wf->lock > 0 )
		wf->lock --;
	else 	wf->lock = 0;
	if ( wf->lock == 0 ) {
		wakeup_task((int)wf);
		_wakeup_at_redraw_wp(gf);
	}
}

void
wf_free_lock_list(WIN_FLAME * wf)
{
WF_LOCK_LIST * wfl;
	for ( ; wf->lock_list ; ) {
		wfl = wf->lock_list;
		wf->lock_list = wfl->next;
		d_f_ree(wfl);
	}
}


int
win_lock(GBVIEW_FLAME * gf,WIN_FLAME * wf)
{
int ret;
	wf_lock(gf);
	ret = _win_lock(gf,wf);
	wf_unlock(gf);
	return ret;
}

int
win_wlock(GBVIEW_FLAME * gf,WIN_FLAME * wf)
{
int ret;
	wf_lock(gf);
set_t_msg(6);
	ret = _win_wlock(gf,wf);
	wf_unlock(gf);
	return ret;
}

void
win_unlock(GBVIEW_FLAME * gf,WIN_FLAME * wf)
{
	wf_lock(gf);
set_t_msg(7);
	_win_unlock(gf,wf);
	wf_unlock(gf);
}

void
_ex_lock(GBVIEW_FLAME * gf)
{
WIN_FLAME * wf;

	for ( ; gf->ex_lock ; ) {
		wf_sleep_task(gf,(int)&gf->ex_lock);
		wf_lock(gf);
set_t_msg(8);
	}
	gf->ex_lock = 1;
}

void
_ex_unlock(GBVIEW_FLAME * gf)
{
	gf->ex_lock = 0;
	wakeup_task((int)&gf->ex_lock);
}

void
ex_lock(GBVIEW_FLAME * gf)
{
	wf_lock(gf);
set_t_msg(9);
	_ex_lock(gf);
	wf_unlock(gf);
}

void
ex_unlock(GBVIEW_FLAME * gf)
{
	wf_lock(gf);
set_t_msg(10);
	_ex_unlock(gf);
	wf_unlock(gf);
}


int
_check_exit_flame(GBVIEW_FLAME * gf)
{
WIN_FLAME * wf;
int ret;
	ret = 0;
	for ( wf = gf->flame ; wf ; wf = wf->next )
		if ( wf->flags & WFF_FREE )
			ret ++;
	return ret;
}

void
_wakeup_wf(GBVIEW_FLAME * gf,WIN_FLAME * wf)
{
void load_task();

	wf->flags |= WFF_DRAW_REQUEST;
	gf->req_task_nos ++;
	if ( gf->run_req_task_nos < LOAD_TASK_MAX )
		create_task(load_task,(int)gf,PRI_DRAW);
}

void
_reset_task_nos(GBVIEW_FLAME * gf)
{
	gf->req_task_nos --;
	if ( gf->req_task_nos < 0 )
		gf->req_task_nos = 0;
}

/*
void
reset_task_nos()
{
	wf_lock(gf);
	_reset_task_nos();
	wf_unlock(gf);"reset_task_nos");
}
*/

int
_get_new_wfid(GBVIEW_FLAME * gf)
{
WIN_FLAME * wf;
retry:
	system_wfid ++;
	if ( system_wfid <= 0 )
		system_wfid = 1;
	for ( wf = gf->flame ; wf ; wf = wf->next ) {
		if ( wf->id == system_wfid )
			goto retry;
	}
	return  system_wfid;
}

int
_get_next_wfid(GBVIEW_FLAME * gf,int id)
{
WIN_FLAME * wf;
int ret;
	ret = 0;
	for ( wf = gf->flame ; wf ; wf = wf->next ) {
		if ( wf->flags & WFF_FREE )
			continue;
		if ( id >= wf->id )
			continue;
		if ( ret == 0 || ret > wf->id )
			ret = wf->id;
	}
	return ret;
}

int
get_next_wfid(GBVIEW_FLAME * gf,int id)
{
int ret;
	wf_lock(gf);
set_t_msg(12);
	ret = _get_next_wfid(gf,id);
	wf_unlock(gf);
	return ret;
}

WIN_FLAME * 
_get_wf_ptr(GBVIEW_FLAME * gf,WF_ID id)
{
WIN_FLAME * wf;
	for ( wf = gf->flame ; wf ; wf = wf->next )
		if ( wf->id == id )
			return wf;
	return 0;
}


int
wf_check_last(GBVIEW_FLAME * gf,WF_ID id)
{
int ret;
WIN_FLAME * wf, * wf_id;
int cnt;
	wf_lock(gf);
	ZONBIE_CHECK(gf,wf_unlock,1)

	if ( id == 0 ) {
		if ( gf->flame == 0 || gf->flame->next == 0 )
			ret = 1;
		else {
			cnt = 0;
			for ( wf = gf->flame; wf ; wf = wf->next )
				if ( !(wf->flags & WFF_FREE) )
					cnt ++;
			if ( cnt == 0 )
				ret = 1;
			else	ret = 0;
		}
	}
	else {
		if ( gf->flame == 0 )
			ret = 1;
		else  {
			wf_id = 0;
			cnt = 0;
			for ( wf = gf->flame; wf ; wf = wf->next ) {
				if ( !(wf->flags & WFF_FREE) ) {
					cnt ++;
					wf_id = wf;
				}
			}
			if ( wf_id->id == id && cnt == 1 )
				ret = 1;
			else	ret = 0;
		}
	}
	wf_unlock(gf);
	return ret;
}


WF_ID
wf_get(GBVIEW_FLAME * gf,int no)
{
WF_ID ret;
WIN_FLAME * wf;
	wf_lock(gf);
	ZONBIE_CHECK(gf,wf_unlock,0);


	for ( wf = gf->flame ; wf && no > 0 ; wf = wf->next , no -- );
	if ( wf == 0 )
		ret = 0;
	else	ret = wf->id;
	wf_unlock(gf);
	return ret;
}

void
insert_redraw_r(GBVIEW_FLAME * gf,VRECT * r)
{


	if ( gf->redraw_r.tl.x >= gf->redraw_r.br.x ||
			gf->redraw_r.tl.y >= gf->redraw_r.br.y ) {
		gf->redraw_r = *r;
		return;
	}
	if ( gf->redraw_r.tl.x > r->tl.x )
		gf->redraw_r.tl.x = r->tl.x;
	if ( gf->redraw_r.tl.y > r->tl.y )
		gf->redraw_r.tl.y = r->tl.y;
	if ( gf->redraw_r.br.x < r->br.x )
		gf->redraw_r.br.x = r->br.x;
	if ( gf->redraw_r.br.y < r->br.y )
		gf->redraw_r.br.y = r->br.y;
	if ( gf->redraw_r.tl.x < 0 )
		gf->redraw_r.tl.x = 0;
	if ( gf->redraw_r.tl.y < 0 )
		gf->redraw_r.tl.y = 0;
	if ( gf->redraw_r.br.x >= gf->win_width )
		gf->redraw_r.br.x = gf->win_width;
	if ( gf->redraw_r.br.y >= gf->win_height )
		gf->redraw_r.br.y = gf->win_height;
}

void
insert_redraw_gbr(GBVIEW_FLAME * gf,GB_RECT * r)
{
VRECT rr;
	rr.tl.x = r->tl.x;
	rr.tl.y = r->tl.y;
	rr.br.x = r->br.x;
	rr.br.y = r->br.y;
	insert_redraw_r(gf,&rr);
}


void
insert_vrect(VRECT * v,int x,int y)
{
	if ( v->tl.x >= v->br.x ) {
		v->tl.x = x;
		v->br.x = x+1;
		v->tl.y = y;
		v->br.y = y+1;
		return;
	}
	if ( v->tl.x > x )
		v->tl.x = x;
	if ( v->br.x <= x )
		v->br.x = x+1;
	if ( v->tl.y > y )
		v->tl.y = y;
	if ( v->br.y <= y )
		v->br.y = y+1;
}

void
set_redraw_rect(GBVIEW_FLAME * gf,GB_RECT *r)
{
int xx,yy;
int xmax,ymax;
int xmin,ymin;
VRECT rr;

	if ( r->tl.x >= gf->win_width )
		return;
	if ( r->tl.y >= gf->win_height )
		return;
	if ( r->tl.x < 0 )
		xmin = 0;
	else	xmin = r->tl.x;
	if ( r->tl.y < 0 )
		ymin = 0;
	else	ymin = r->tl.y;
	if ( r->br.x >= gf->win_width )
		xmax = gf->win_width;
	else	xmax = r->br.x;
	if ( r->br.y >= gf->win_height )
		ymax = gf->win_height;
	else	ymax = r->br.y;

	rr.tl.x = xmin;
	rr.tl.y = ymin;
	rr.br.x = xmax;
	rr.br.y = ymax;
	insert_redraw_r(gf,&rr);
	for ( xx = xmin ; xx < xmax ; xx ++ )
		for ( yy = ymin ; yy < ymax ; yy ++ )
			gf->redraw[xx + gf->win_width*yy] = RP_REDRAW;
	new_tick(_wf_set_redraw,0,(int)gf);
}


int
wf_insert_si(
	GBVIEW_FLAME * gf,
	int		cmd,
	WF_ID		wfid,
	int 		rno,
	int		code,
	int		sub,
	GB_RECT * 	rect,
	unsigned int *	data,
	unsigned char *	alpha,
	int		flags,
	L_CHAR * 	ref)
{
SYMBOL_INDICATE * si;
int ret;
WIN_FLAME * wf;

	if ( wfid == 0 )
		return 0;
	wf_lock(gf);
set_t_msg(15);


	wf = _get_wf_ptr(gf,wfid);
	if ( wf == 0 ) {
		wf_unlock(gf);
		return 0;
	}

	for ( si = wf->sym_i ; si ; si = si->next ) {
		if ( si->rno != rno || si->code != code ||
			si->sub != sub )
			continue;
		ret = 1;
		if ( cmd == ISI_INFO )
			goto end;
		if ( rect )
			si->rect = *rect;
		set_redraw_rect(gf,&si->rect);
		if ( data ) {
			if ( si->data )
				d_f_ree(si->data);
			si->data = data;
		}
		if ( alpha ) {
			if ( si->alpha )
				d_f_ree(si->alpha);
			si->alpha = alpha;
		}
		si->flags |= SIF_DRAW|SIF_NEW|flags;
		goto end;
	}
	ret = 0;
	if ( cmd == ISI_INFO )
		goto end2;
	si = d_alloc(sizeof(*si));
	si->rno = rno;
	si->code = code;
	si->sub = sub;
	si->flags = SIF_DRAW|SIF_NEW|flags;
	si->rect = *rect;
	si->data = data;
	si->alpha = alpha;
	if ( ref )
		si->ref = ll_copy_str(ref);
	else	si->ref = 0;
	si->next = wf->sym_i;
	wf->sym_i = si;
	set_redraw_rect(gf,&si->rect);

end:
	switch ( cmd ) {
	case ISI_INSERT:
		break;
	case ISI_INFO:
		if ( rect )
			*rect = si->rect;
		break;
	}
end2:

	wf_unlock(gf);
	return ret;
}

int
wf_space_check_si(
	GBVIEW_FLAME * 	gf,
	WF_ID		wfid,
	int 		rno,
	int		code,
	int		sub,
	GB_RECT * 	rect,
	int		percent)
{
SYMBOL_INDICATE * si;
int ret;
REAL1 surf1,surf2;
REAL1 x,y,x_max,y_max,xx,yy;
WIN_FLAME * wf;

	x_max = rect->br.x - rect->tl.x;
	y_max = rect->br.y - rect->tl.y;
	surf1 = x_max*y_max;
	wf_lock(gf);
set_t_msg(16);


	wf = _get_wf_ptr(gf,wfid);
	if ( wf == 0 ) {
		ret = -1;
		goto end;
	}
	ret = -1;
	for ( si = wf->sym_i ; si ; si = si->next ) {
		if ( si->rno == rno && si->code == code &&
			si->sub == sub )
			continue;
		if ( cross_rect_rect(rect,&si->rect) == 0 )
			continue;
		x = x_max;
		xx = rect->br.x - si->rect.tl.x;
		if ( xx < x )
			x = xx;
		xx = si->rect.br.x - rect->tl.x;
		if ( xx < x )
			x = xx;
		y = y_max;
		yy = rect->br.y - si->rect.tl.y;
		if ( yy < y )
			y = yy;
		yy = si->rect.br.y - rect->tl.y;
		if ( yy < y )
			y = yy;
		if ( x*y*100 >= percent*surf1 )
			goto end;
		surf2 = (si->rect.br.x - si->rect.tl.x)*
			(si->rect.br.y - si->rect.tl.y);
		if ( x*y*100 >= percent*surf2 )
			goto end;
	}
	ret = 0;
end:
	wf_unlock(gf);
	return ret;
}

void
regulate_si(WIN_FLAME * wf)
{
SYMBOL_INDICATE * si;
	for ( si = wf->sym_i ; si ; si = si->next ) {
		if ( !(si->flags & SIF_NEW) )
			continue;
		si->flags &= ~SIF_NEW;
		si->rect.tl.x += wf->mov_x;
		si->rect.tl.y += wf->mov_y;
		si->rect.br.x += wf->mov_x;
		si->rect.br.y += wf->mov_y;
	}
}


void
_wf_redraw_si(
	GBVIEW_FLAME * gf,
	WIN_FLAME * wf,int ow,int oh,
	int tl_x,int tl_y,int br_x,int br_y)
{
SYMBOL_INDICATE * si;
int x,y,i;
unsigned int cc,cc1,cc2,cc3,cc4,cc5;
int k,j;
unsigned char alpha;

#define SET_ALPHA(label) \
if ( si->alpha ) {			\
	alpha = si->alpha[i];		\
	switch ( alpha ) {		\
	case 255:			\
		continue;		\
	case 0:				\
		goto label;		\
	}				\
	cc1 = gf->redraw_plane[y*ow+x];			\
	if ( cc1 == C_TRANSPARENT )			\
		cc1 = C_COLOR;				\
	cc5 = 0;						\
	for ( j = 0 ; j < 3 ; j ++ ) {				\
		cc2 = (cc>>(COL_BIT*j))&COL_MASK;		\
		cc3 = (cc1>>(COL_BIT*j))&COL_MASK;		\
		cc4 = (cc2*(256-alpha) + cc3*(alpha))>>8;	\
		cc5 |= cc4<<(COL_BIT*j);			\
	}							\
	cc = cc5;						\
}

	for ( si = wf->sym_i ; si ; si = si->next ) {
		if ( si->data == 0 || si->rect.tl.x == si->rect.br.x ||
					si->rect.tl.y == si->rect.br.y )
				continue;
/*
		if ( (si->flags & SIF_DRAW) ) {
			si->flags &= ~SIF_DRAW;
			i = 0;

			for ( y = si->rect.tl.y ; y < si->rect.br.y ; y ++ )
				for ( x = si->rect.tl.x ; x < si->rect.br.x ; 
						i ++ , x ++ ) {
					if ( x < 0 )
						continue;
					if ( y < 0 )
						continue;
					if ( x >= ow )
						continue;
					if ( y >= oh )
						continue;
					cc = si->data[i];
					if ( cc == C_TRANSPARENT )
						continue;
					if ( (gf->redraw[y*ow+x]&
						(RP_REDRAW|RP_DIRTY))
						== 0  )
						continue;
					SET_ALPHA(next1);
				next1:
					gf->redraw_plane[y*ow+x] = cc;
				}
			continue;
		}
*/
		if ( si->rect.tl.x >= br_x )
			continue;
		if ( si->rect.tl.y >= br_y )
			continue;
		if ( si->rect.br.x < tl_x )
			continue;
		if ( si->rect.br.y < tl_y )
			continue;
		si->flags &= ~SIF_DRAW;
		i = 0;
		for ( y = si->rect.tl.y ; y < si->rect.br.y ; y ++ )
			for ( x = si->rect.tl.x ; x < si->rect.br.x ; 
					i ++ , x ++ ) {
				if ( x < tl_x )
					continue;
				if ( y < tl_y )
					continue;
				if ( x >= br_x )
					continue;
				if ( y >= br_y )
					continue;
				cc = si->data[i];
				if ( cc == C_TRANSPARENT )
					continue;
				if ( (gf->redraw[y*ow+x] &
					(RP_REDRAW|RP_DIRTY)) == 0 )
					continue;
				SET_ALPHA(next2);
			next2:
				gf->redraw_plane[y*ow+x] = cc;
			}
	}
}

void
wf_redraw_si(GBVIEW_FLAME * gf,int x,int y,int w,int h)
{
WIN_FLAME * wf;
int ow,oh;

	ow = gf->win_width;
	oh = gf->win_height;
	for ( wf = gf->flame ; wf ; wf = wf->next )
		_wf_redraw_si(gf,wf,ow,oh,x,y,x+w,y+h);
}

void
wf_wait_stable(GBVIEW_FLAME * gf)
{
WIN_FLAME * wf;
	for ( ; ; ) {
		wf_lock(gf);
		ZONBIE_CHECK_BREAK(gf,wf_unlock);
		for ( wf = gf->flame ; wf ; wf = wf->next ) {
			if ( wf->flags & WFF_FREE )
				break;
		}
		if ( wf == 0 ) {
			wf_unlock(gf);
			break;
		}
		_sleep_at_exit_task_wp(gf,0);
	}
}

void
_free_win_flame(GBVIEW_FLAME * gf,WIN_FLAME * wf)
{
	wf->flags |= WFF_FREE;
ss_printf("FREE %ls\n",get_url_str2(&wf->draw->h.entry));
	_wakeup_at_exit_task_wp(gf);
	_wakeup_at_redraw_wp(gf);
}


void
wf_reset_active(GBVIEW_FLAME * gf)
{
WIN_FLAME * wf;
	wf_lock(gf);
set_t_msg(18);


	for ( wf = gf->flame ; wf ; wf = wf->next )
		wf->flags &= ~WFF_ACTIVE;
	wf_unlock(gf);
}

void
wf_free_nonactive(GBVIEW_FLAME * gf)
{
WIN_FLAME * wf;
	wf_lock(gf);
set_t_msg(19);


	for ( wf = gf->flame ; wf ; wf = wf->next ) {
		if ( !(wf->flags & WFF_ACTIVE) )
			_free_win_flame(gf,wf);
	}
	wf_unlock(gf);
}

void
free_win_flame(GBVIEW_FLAME * gf,WF_ID wfid)
{
WIN_FLAME * wf;

	wf_lock(gf);
set_t_msg(20);

	wf = _get_wf_ptr(gf,wfid);
	if ( wf == 0 ) {
		wf_unlock(gf);
		return;
	}
	_free_win_flame(gf,wf);
	wf_unlock(gf);
}


void
_wf_flame_redraw(GBVIEW_FLAME * gf)
{
int i;
VRECT rr;
	rr.tl.x = rr.tl.y = 0;
	rr.br.x = gf->win_width;
	rr.br.y = gf->win_height;
	insert_redraw_r(gf,&rr);
	for ( i = 0 ; i < gf->win_height*gf->win_width ; i ++ )
		gf->redraw[i] = RP_REDRAW;
	new_tick(_wf_set_redraw,0,(int)gf);
}


void
_wf_set_redraw(GBVIEW_FLAME * gf)
{
	if ( gf->event )
		(*gf->event)(gf,ET_REDRAW);
}

WIN_FLAME *
_wf_get_current(GBVIEW_FLAME * gf)
{
	return gf->flame_base;
}

WF_ID
wf_get_current(GBVIEW_FLAME * gf)
{
WF_ID ret;
WIN_FLAME * wf;
	wf_lock(gf);
	ZONBIE_CHECK(gf,wf_unlock,0)
	wf = _wf_get_current(gf);

	if ( wf )
		ret = wf->id;
	else	ret = 0;
	wf_unlock(gf);
	return ret;
}

int
_wf_set_current(GBVIEW_FLAME * gf,WIN_FLAME * now,WIN_FLAME * target)
{
WIN_FLAME * c, * wf;
MAP_HISTORY * base, * mh;
GB_POINT center,_center[3];
REAL1 reso,_reso[3];
REAL1 rotate;
int i;
REAL1 d,dd;
GB_POINT pp1,pp2;
REAL1 s;
REAL1 _t;
unsigned int now_t;

	if ( gf->flame == 0 )
		return 0;

	if ( now && gf->flame == now && now->next == 0 ) {
		return 0;
	}
	if ( target && target == gf->flame_base )
		return 1;
	c = 0;
	now_t = get_xltime();
	_calc_pitch(gf,0); 
	for ( wf = gf->flame ; wf ; wf = wf->next ) {
		if ( wf == gf->flame_base )
			continue;
		if ( wf == now )
			continue;
		if ( wf->flags & WFF_FREE )
			continue;
		if ( target && wf != target )
			continue;
		if ( target == 0 && now_t - wf->out_base_time <
					CURRENT_SWITCH_TIMERAG )
			continue;
		d = gf->win_width/2;
	retry:
		_center[0].y = _center[1].y = _center[2].y
				= gf->win_height/2;
		_center[0].x = gf->win_width/2;
		_center[1].x = gf->win_width/2 + d;
		_center[2].x = gf->win_width/2 - d;
		_reso[0] = _reso[1] = _reso[2] = 1;
		map_from_flame(&gf->flame_base_display_map,_center,_reso,3);
		map_from_flame(wf->mh,_center,_reso,3);
		if ( _reso[0] < 0 )
			continue;
		if ( _reso[1] >= 0 ) {
			i = 1;
			pp1.x = d;
			pp1.y = 0;
		}
		else if ( _reso[2] >= 0 ) {
			i = 2;
			pp1.x = -d;
			pp1.y = 0;
		}
		else {
			d *= 0.5;
			goto retry;
		}
		dd = distance(_center[i],_center[0]);
		if ( dd == 0 ) {
			d *= 1.2;
			goto retry;
		}
		pp2 = p_sub(_center[i],_center[0]);
		s = asin(pp2.y / dd);
/*
		if ( pp2.x > 0 )
			rotate = s;
		else	rotate = s - M_PI;
*/
		if ( pp2.x > 0 )
			rotate = -s;
		else if ( pp2.y > 0 )
			rotate = - M_PI + s;
		else	rotate = M_PI + s;
		switch ( wf->draw->c.geometory_type & GT_A_MASK ) {
		case GT_A_X_FOR|GT_A_Y_FOR:
		case GT_A_X_REV|GT_A_Y_REV:
			rotate = - rotate;
		}
		c = wf;
		center = _center[0];
		reso = d / dd;
printf("*********SET  %f %f %f %f %f\n",reso,center.x,center.y,gf->flame_base_rotate,rotate);
	}
	if ( c == 0 )
		return 0;
	if ( gf->flame_base == c )
		er_panic("wf_set_current");
	base = rev_mh(c->mh);
	for ( wf = gf->flame ; wf ; wf = wf->next ) {
		if ( wf == c ) {
			free_mh(c->mh);
			c->mh = 0;
			c->flags &= ~WFF_SHORT_MH;
		}
		else {
			mh = add_mh(base,wf->mh);
			mh = optimize_mh(mh);
			free_mh(wf->mh);
			wf->mh = mh;
			c->flags |= WFF_SHORT_MH;
		}
		_win_flame_dirty(gf,wf,0,WFF_DIRTY,0);
	}

	if ( gf->flame_base )
		gf->flame_base->out_base_time = now_t;
	gf->flame_base = c;
	gf->flame_base_center = center;
	gf->flame_base_rotate = rotate;
	gf->flame_base_resolution = reso;
	c->in_base_time = now_t;
	_calc_pitch(gf,1);
	free_mh(base);
	return 1;
}

int
wf_set_current(GBVIEW_FLAME * gf)
{
int ret;

	wf_lock(gf);
set_t_msg(22);


	ret = _wf_set_current(gf,0,0);
	wf_unlock(gf);
	return ret;
}

int
wf_set_current_now(GBVIEW_FLAME * gf,WF_ID n)
{
int ret;
WIN_FLAME * now;
	wf_lock(gf);
	ZONBIE_CHECK(gf,wf_unlock,0);
set_t_msg(23);
	now = _get_wf_ptr(gf,n);
	ret = _wf_set_current(gf,now,0);
	wf_unlock(gf);
	return ret;
}


int
wf_set_current_target(GBVIEW_FLAME * gf,WF_ID id)
{
int ret;
WIN_FLAME * wf;
	wf_lock(gf);
	ZONBIE_CHECK(gf,wf_unlock,0);
	wf = _get_wf_ptr(gf,id);
	if ( wf )
		ret = _wf_set_current(gf,0,wf);
	else	ret = -1;
	wf_unlock(gf);
	return ret;
}


void
wf_move_redraw_x(GBVIEW_FLAME * gf,int dx)
{
int x,y;
char * dest, * src;
unsigned long * rd, * rs;
VRECT rr;
	if ( dx == 0 )
		return;
	gf->redraw_r.tl.x += dx;
	if ( gf->redraw_r.tl.x < 0 )
		gf->redraw_r.tl.x = 0;
	if ( gf->redraw_r.tl.x >= gf->win_width )
		gf->redraw_r.tl.x = gf->win_width;
	gf->redraw_r.br.x += dx;
	if ( gf->redraw_r.br.x < 0 )
		gf->redraw_r.br.x = 0;
	if ( gf->redraw_r.br.x >= gf->win_width )
		gf->redraw_r.br.x = gf->win_width;

	if ( dx > 0 ) {
		rr.tl.x = rr.tl.y = 0;
		rr.br.x = dx;
		rr.br.y = gf->win_height;
		insert_redraw_r(gf,&rr);

		for ( y = 0 ; y < gf->win_height ; y ++ ) {
			dest = &gf->redraw[(y+1)*gf->win_width];
			src = &gf->redraw[(y+1)*gf->win_width - dx];
			for ( x = gf->win_width-dx ; x > 0 ; x -- ) {
				dest --;
				src --;
				*dest = *src;
			}
			dest = &gf->redraw[y*gf->win_width];
			for ( x = dx ; x > 0 ; x -- )
				*dest++ = RP_REDRAW;

			rd = &gf->redraw_plane[(y+1)*gf->win_width];
			rs = &gf->redraw_plane[(y+1)*gf->win_width - dx];
			for ( x = gf->win_width-dx ; x > 0 ; x -- ) {
				rs --;
				rd --;
				*rd = *rs;
			}
			rd = &gf->redraw_plane[y*gf->win_width];
			for ( x = dx ; x > 0 ; x -- )
				*rd ++ = BACKGROUND_COLOR;
		}

	}
	else {
		rr.tl.x = gf->win_width + dx;
		rr.tl.y = 0;
		rr.br.x = gf->win_width;
		rr.br.y = gf->win_height;
		insert_redraw_r(gf,&rr);
		for ( y = 0 ; y < gf->win_height ; y ++ ) {
			dest = &gf->redraw[y*gf->win_width];
			src = &gf->redraw[y*gf->win_width - dx];
			for ( x = gf->win_width+dx ; x > 0 ; x -- )
				*dest ++ = *src ++;
			dest = &gf->redraw[(y+1)*gf->win_width + dx];
			for ( x = - dx ; x > 0 ; x -- )
				*dest++ = RP_REDRAW;

			rd = &gf->redraw_plane[y*gf->win_width];
			rs = &gf->redraw_plane[y*gf->win_width - dx];
			for ( x = gf->win_width+dx ; x > 0 ; x -- )
				*rd ++ = *rs ++;
			rd = &gf->redraw_plane[(y+1)*gf->win_width + dx];
			for ( x = - dx ; x > 0 ; x -- )
				*rd++ = BACKGROUND_COLOR;
		}
	}
}

void
wf_move_redraw_y(GBVIEW_FLAME * gf,int dy)
{
int x,y;
char * dest, * src;
unsigned long * rd, * rs;
VRECT rr;
	if ( dy == 0 )
		return;
	gf->redraw_r.tl.y += dy;
	gf->redraw_r.br.y += dy;
	if ( gf->redraw_r.tl.y < 0 )
		gf->redraw_r.tl.y = 0;
	if ( gf->redraw_r.br.y < 0 )
		gf->redraw_r.br.y = 0;
	if ( gf->redraw_r.br.y >= gf->win_height )
		gf->redraw_r.br.y = gf->win_height;
	if ( gf->redraw_r.tl.y >= gf->win_height )
		gf->redraw_r.tl.y = gf->win_height;
	if ( dy > 0 ) {
		rr.tl.x = rr.tl.y = 0;
		rr.br.x = gf->win_width;
		rr.br.y = dy;
		insert_redraw_r(gf,&rr);

		for ( y = gf->win_height-1 ; y-dy >= 0 ; y -- ) {
			src = &gf->redraw[(y-dy)*gf->win_width];
			dest = &gf->redraw[y*gf->win_width];
			for ( x = 0 ; x < gf->win_width ; x ++ )
				*dest++ = *src++;
		}
		dest = gf->redraw;
		for ( y = 0 ; y < dy ; y ++ )
			for ( x = 0 ; x < gf->win_width ; x ++ )
				*dest++ = RP_REDRAW;

		for ( y = gf->win_height-1 ; y-dy >= 0 ; y -- ) {
			rs = &gf->redraw_plane[(y-dy)*gf->win_width];
			rd = &gf->redraw_plane[y*gf->win_width];
			for ( x = 0 ; x < gf->win_width ; x ++ )
				*rd++ = *rs++;
		}
		rd = gf->redraw_plane;
		for ( y = 0 ; y < dy ; y ++ )
			for ( x = 0 ; x < gf->win_width ; x ++ )
				*rd++ = BACKGROUND_COLOR;
	}
	else {
		rr.tl.x = 0;
		rr.tl.y = gf->win_height + dy;
		rr.br.x = gf->win_width;
		rr.br.y = gf->win_height;
		insert_redraw_r(gf,&rr);

		for ( y = 0 ; y < gf->win_height + dy ; y ++ ) {
			src = &gf->redraw[(y-dy)*gf->win_width];
			dest = &gf->redraw[y*gf->win_width];
			for ( x = 0 ; x < gf->win_width ; x ++ )
				*dest++ = *src++;
		}
		dest = &gf->redraw[(gf->win_height+dy)*gf->win_width];
		for ( y = 0 ; y < - dy ; y ++ )
			for ( x = 0 ; x < gf->win_width ; x ++ )
				*dest ++ = RP_REDRAW;

		for ( y = 0 ; y < gf->win_height + dy ; y ++ ) {
			rs = &gf->redraw_plane[(y-dy)*gf->win_width];
			rd = &gf->redraw_plane[y*gf->win_width];
			for ( x = 0 ; x < gf->win_width ; x ++ )
				*rd++ = *rs++;
		}
		rd = &gf->redraw_plane[(gf->win_height+dy)*gf->win_width];
		for ( y = 0 ; y < - dy ; y ++ )
			for ( x = 0 ; x < gf->win_width ; x ++ )
				*rd ++ = BACKGROUND_COLOR;
	}
}

void
wf_wakeup(GBVIEW_FLAME * gf)
{
WIN_FLAME * wf;
	wf_lock(gf);
set_t_msg(24);
	for ( wf = gf->flame ; wf ; wf = wf->next ) {
		_wakeup_wf(gf,wf);
	}
	wf_unlock(gf);
}

void
set_map_xy(GBVIEW_FLAME * gf,int dx,int dy)
{
MAP_HISTORY * mh;
GB_POINT ptr;
	mh = &gf->flame_base_display_map;
	mh->d.ln.forward.org.x += dx;
	mh->d.ln.forward.org.y += dy;

	ptr.x = -dx;
	ptr.y = -dy;
	mh->d.ln.reverse.org
		= p_add(mh->d.ln.reverse.org,
			mp_mul(mh->d.ln.reverse.matrix,ptr));
}


int
wf_move_xy(GBVIEW_FLAME * gf,VPOINT from,VPOINT to)
{
WIN_FLAME * wf;
GB_POINT d;
int rdm;
GB_RECT r1,r2;
SELECT_INDICATE * si;
int seq;
int dx,dy;

	dx = to.x - from.x;
	dy = to.y - from.y;

set_t_msg(252);
	set_map_xy(gf,dx,dy);
set_t_msg(252);

	for ( wf = gf->flame ; wf ; wf = wf->next ) {
		if ( wf->flags & WFF_FREE )
			continue;
set_t_msg(253);
		win_flame_move(gf,wf,from,to,0);
set_t_msg(254);
	}
	for ( si = gf->si ; si ; si = si->next ) {
		si->x += dx;
		si->y += dy;
	}
set_t_msg(255);
	wf_move_redraw_x(gf,dx);
	wf_move_redraw_y(gf,dy);
set_t_msg(256);
	assert_ls(gf,LSF_MOVE);
set_t_msg(257);
	_wakeup_win_manage(gf->radar_ptr);
set_t_msg(258);

	return _get_env_seq(gf);
}


int
wf_move_globe(GBVIEW_FLAME * gf,VPOINT from,VPOINT to)
{
WIN_FLAME * wf;
GB_POINT d,gb_from,gb_to;
int rdm;
SELECT_INDICATE * si;
int seq;
int dx,dy;
double radius;
RESOURCE * r;
int x,y,ix;
char * rp, * _rp;
unsigned long * rpp,* _rpp;
int w,h;
int er;
GLOBE_MOVE_T gt;
VPOINT * ixp;

	w = gf->win_width;
	h = gf->win_height;

	new_rotate_and_center(gf,v2gb_point(from),v2gb_point(to));

	r = gf->flame_base->draw;
	radius = conv_unit(&er,
			r->h.cu.uenv,
			gf->flame_base_resolution,
			reso_c_unit(&r->h.cu),
			l_string(std_cm,"dot/rad"));

	gt.ix = d_alloc(sizeof(VPOINT)*w*h);
	gt.radius = radius;
	if ( wf_make_gmatrix_index(gt.ix,
			gb_from = v2gb_point(from),
			gb_to = v2gb_point(to),radius,w,h) < 0 ) {
		d_f_ree(gt.ix);
		return 0;
	}
	get_gmatrix(gt.rm,gb_from,gb_to,radius);

	for ( wf = gf->flame ; wf ; wf = wf->next ) {
		if ( wf->flags & WFF_FREE )
			continue;
		win_flame_move(gf,wf,from,to,&gt);
	}

	_wf_purge_select(gf);

	_rp = rp = d_alloc(w*h);
	_rpp = rpp = d_alloc(sizeof(long)*w*h);
	ixp = gt.ix;
	for ( y = 0 ; y < h ; y ++ )
		for ( x = 0 ; x < w ; x ++ , ixp ++ , rp ++ , rpp ++ ) {
			if ( ixp->x < 0 )
				goto no_data;
			ix = ixp->x + ixp->y * w;
			*rp = gf->redraw[ix];
			*rpp = gf->redraw_plane[ix];
			continue;
		no_data:
			*rp = RP_REDRAW;
			*rpp = BACKGROUND_COLOR;
		}
	d_f_ree(gt.ix);
	d_f_ree(gf->redraw);
	gf->redraw = _rp;
	d_f_ree(gf->redraw_plane);
	gf->redraw_plane = _rpp;
	assert_ls(gf,LSF_MOVE);
	_wakeup_win_manage(gf->radar_ptr);

	return _get_env_seq(gf);
}


int
wf_move(GBVIEW_FLAME * gf,VPOINT from,VPOINT to)
{
int ret;
	wf_lock(gf);
	ZONBIE_CHECK(gf,wf_unlock,0)

	switch ( gf->flame_base_display_map.type ) {
	case 0:
		ret = 0;
		break;
	case MHT_LINEAR:
		ret = wf_move_xy(gf,from,to);
		break;
	case MHT_PP:
		ret = wf_move_globe(gf,from,to);
		break;
	default:
		er_panic("wf_move");
	}
	wf_unlock(gf);
	new_tick(_wf_set_redraw,0,(int)gf);
	return ret;
}



void
wf_get_coordinate_info(GBVIEW_FLAME * gf,L_CHAR ** name,int * rid,GB_POINT * ptr,int ptr_len)
{
WIN_FLAME * wf;
REAL1 * reso;
int i;
MAP_HISTORY * mh;
	wf_lock(gf);
	ZONBIE_CHECK_VOID(gf,wf_unlock)

	for ( wf = gf->flame ; wf ; wf = wf->next ) {
		if ( wf->next == 0 )
			break;
	}
	if ( wf == 0 ) {
		*rid = 0;
		wf_unlock(gf);
		return;
	}
	reso = d_alloc(sizeof(REAL1)*ptr_len);
	for ( i = 0 ; i < ptr_len ; i ++ )
		reso[i] = 1;
	mh = add_mh(&gf->flame_base_display_map,wf->mh);

	map_from_flame(mh,ptr,reso,ptr_len);
	*name = get_url_str2(&gf->flame_base->draw->h.entry);
	*rid = gf->flame_base->draw->h.no;

	wf_unlock(gf);
}


void
wf_im_zoom_proc(
	unsigned long *target,
	int w,int h,
	int *index_x,
	int *index_y)
{
unsigned long *buf;
int x,y,xx,yy,i;
	buf = d_alloc(sizeof(long)*w*h);
	i = 0;
	for ( y = 0 ; y < h ; y ++ )
		for ( x = 0 ; x < w ; x ++ ) {
			xx = index_x[x];
			yy = index_y[y];
			if ( xx < 0 || yy < 0 )
				buf[i] = C_TRANSPARENT;
			else	buf[i] = target[xx + yy*w];
			buf[i] |= C_DIRTY;
			i ++;
		}
	for ( i = 0 ; i < h*w ; i ++ )
		target[i] = buf[i];
	d_f_ree(buf);
}

int
wf_zoom(GBVIEW_FLAME * gf,GBVIEW_PLANE * p,REAL1 zoom)
{
WIN_FLAME * wf;
int i;
unsigned long * buf;
int ow,oh;
GB_RECT r;
int * index_x, * index_y;
int len;
int ret;

	wf_lock(gf);
	ZONBIE_CHECK(gf,wf_unlock,0);

	gf->flame_base_resolution *= zoom;

	ow = gf->win_width;
	oh = gf->win_height;
	index_x = d_alloc(sizeof(int)*ow);
	index_y = d_alloc(sizeof(int)*oh);
	wf_make_zoom_index(index_x,index_y,zoom,ow,oh);
	for ( wf = gf->flame ; wf ; wf = wf->next ) {
		if ( wf->flags & WFF_FREE )
			continue;
		win_flame_zoom(gf,wf,ow,oh,index_x,index_y);
		wf->mov_flag = 1;
		_wakeup_wf(gf,wf);
	}

	wf_im_zoom_proc(gf->redraw_plane,ow,oh,index_x,index_y);
	_calc_pitch(gf,0);

	len = gf->win_width*gf->win_height;
	for ( i = 0 ; i < len ; i ++ )
		gf->redraw[i] = RP_DIRTY;

	ret = _get_env_seq(gf);
	wf_unlock(gf);
	assert_ls(gf,LSF_ZOOM);
	_wakeup_win_manage(gf->radar_ptr);

	if ( p ) {
		p->h.type = GPT_ZOOM;
		p->h.seq = ret;
		p->z.index_x = index_x;
		p->z.index_y = index_y;
	} else {
		d_f_ree(index_x);
		d_f_ree(index_y);
	}
	new_tick(_wf_set_redraw,0,(int)gf);
	return ret;
}



void
_change_redraw(GBVIEW_FLAME * gf)
{
char * p;
int w,h;
int i,x,y,dx,dy;
	w = gf->win_width;
	h = gf->win_height;

	gf->redraw = d_re_alloc(gf->redraw,w*h);
	gf->redraw_plane = d_re_alloc(gf->redraw_plane,w*h*sizeof(long));
	for ( i = 0 ; i < w*h ; i ++ )
		gf->redraw[i] = 0;
	gf->win_height = h;
	gf->win_width = w;
}

void
_wf_change_size(GBVIEW_FLAME * gf)
{
WIN_FLAME * wf;
int ret;

	_ex_lock(gf);

	for ( wf = gf->flame ; wf ; wf = wf->next ) {
		win_flame_resize(gf,wf);
		wf->flags |= WFF_RESIZE;
		_wakeup_wf(gf,wf);
	}
	_calc_pitch(gf,1);
	_change_redraw(gf);

	new_tick(_wf_set_redraw,0,(int)gf);

	_ex_unlock(gf);
}


unsigned long
select_color(GBVIEW_FLAME * gf,unsigned long a,int x,int y)
{
SELECT_INDICATE * si;
unsigned long b,c1,c2,c3,c4;
int i;
	for ( si = gf->si ; si ; si = si->next ) {
		if ( x < si->x )
			continue;
		if ( y < si->y )
			continue;
		if ( x >= si->x + si->w )
			continue;
		if ( y >= si->y + si->h )
			continue;
		b = si->pixels[(y-si->y)*si->w + x-si->x];
		if ( b & C_TRANSPARENT )
			continue;
		if ( a & C_TRANSPARENT ) {
			a = b;
			continue;
		}
		if ( si->t == 1 ) {
			a = b;
			continue;
		}
		if ( si->t == 0 )
			continue;
		if ( a == b ) {
			c4 = 0;
			for ( i = 0 ; i < 3 ; i ++ ) {
				c1 = ((a>>(COL_BIT*i))&COL_MASK)/4
					+ 0x400*3/4;
				if ( c1 > 0x400 )
					c1 = 0x3ff;
				c4 |= (c1<<(COL_BIT*i))&
					(COL_MASK<<(COL_BIT*i));
			}
			a = c4;
		}
		else	a = b;
	}
	return a;
}


void
copy_plane(GBVIEW_FLAME * gf,GBVIEW_PLANE * p,unsigned long * plane)
{
unsigned long * sp, * dp;
int w,h;
int y_src,y_dest,y_max,x,x_ofs;

	w = p->r.r.br.x - p->r.r.tl.x;
	h = p->r.r.br.y - p->r.r.tl.y;

	p->r.plane = d_alloc(w*h*sizeof(unsigned long));

	y_max = p->r.r.br.y;
	y_dest = 0;
	x_ofs = p->r.r.tl.x;
	for ( y_src = p->r.r.tl.y ; y_src < y_max ; y_src ++ , y_dest ++ ) {
		sp = &plane[y_src*gf->win_width + x_ofs];
		dp = &p->r.plane[y_dest*w];
		for ( x = 0 ; x < w ; x ++ )
			*dp ++ = *sp ++;
	}
}


int
__wf_redraw(GBVIEW_FLAME * gf,GBVIEW_PLANE * p,int x,int y,int w,int h)
{
unsigned long cc,cc1,cc2,cc3;
WIN_FLAME * wf;
int ow,oh;
int i,j,k;
WIN_FLAME * td;

VRECT tar,rr;
int ix;
unsigned long * sp, * dp;
char * rp;
OV_ARG a;
int ret;

	p->r.plane = 0;
	p->r.r.tl.x = p->r.r.tl.y = 0;
	p->r.r.br.x = p->r.r.br.y = -1;

	ow = gf->win_width;
	oh = gf->win_height;

	if ( x < 0 ) {
		w = w + x;
		x = 0;
		if ( w <= 0 )
			return 0;
	}
	if ( x >= ow )
		return 0;
	if ( x + w >= ow )
		w = ow - x;

	if ( y < 0 ) {
		h = h + y;
		y = 0;
		if ( h <= 0 )
			return 0;
	}
	if ( y >= oh )
		return 0;
	if ( y + h >= oh )
		h = oh - y;

	tar = gf->redraw_r;
	if ( tar.tl.x < x )
		tar.tl.x = x;
	if ( tar.tl.y < y )
		tar.tl.y = y;
	if ( tar.br.x > x+w )
		tar.br.x = x+w;
	if ( tar.br.y > y+h )
		tar.br.y = y+h;
	x = tar.tl.x;
	y = tar.tl.y;
	w = tar.br.x - tar.tl.x;
	h = tar.br.y - tar.tl.y;

	p->h.type = GPT_REDRAW;
	p->h.seq = 0;
	if ( w <= 0 || h <= 0 ) {
		tar.tl.x = tar.br.x = 0;
		tar.tl.y = tar.br.y = 0;
		p->r.r = tar;
		p->r.plane = 0;
		return 0;
	}

	for ( i = 0 ; i < ow*oh ; i ++ ) {
		if ( gf->redraw[i] == 0 )
			continue;
		gf->redraw_plane[i] = C_TRANSPARENT;
	}

	a.redraw = gf->redraw;
	a.dest = gf->redraw_plane;
	a.d_h = oh;
	a.d_w = ow;
	a.d_x = x;
	a.d_y = y;
	a.d_x_w = w;
	a.d_y_h = h;
	for ( wf = gf->flame ; wf ; wf = wf->next ) {
		if ( wf->flags & WFF_FREE )
			continue;
		win_flame_overlay(gf,wf,&a);

	}


	wf_redraw_si(gf,x,y,w,h);

	for ( i = y ; i < y+h ; i ++ ) {
		ix = i*ow+x;
		rp = &gf->redraw[ix];
		for ( j = 0 ; j < w ; j ++ )
			*rp ++ = 0;
	}

	rr = gf->redraw_r;
	if ( tar.tl.x == rr.tl.x &&
			tar.tl.y == rr.tl.y &&
			tar.br.x == rr.br.x &&
			tar.br.y == rr.br.y ) {
		gf->redraw_r.tl.x = 0;
		gf->redraw_r.tl.y = 0;
		gf->redraw_r.br.x = gf->redraw_r.br.y = 0;
		goto last_handle;
	}
	if ( tar.tl.x == rr.tl.x && tar.tl.y == rr.tl.y &&
			tar.br.y == rr.br.y ) {
		gf->redraw_r.tl.x = tar.br.x;
		goto last_handle;
	}
	if ( tar.tl.y == rr.tl.y &&
			tar.br.x == rr.br.x &&
			tar.br.y == rr.br.y ) {
		gf->redraw_r.br.x = tar.tl.x;
		goto last_handle;
	}
	if ( tar.tl.x == rr.tl.x &&
			tar.tl.y == rr.tl.y &&
			tar.br.x == rr.br.x ) {
		gf->redraw_r.tl.y = tar.br.y;
		goto last_handle;
	}
	if ( tar.tl.x == rr.tl.x &&
			tar.br.x == rr.br.x &&
			tar.br.y == rr.br.y ) {
		gf->redraw_r.br.y = tar.tl.y;
		goto last_handle;
	}
last_handle:
	p->r.r = tar;
	if ( tar.tl.x == tar.br.x ||
			tar.tl.y == tar.br.y ) {
		p->r.plane = 0;
	}
	else {
		copy_plane(gf,p,gf->redraw_plane);
	}
	p->h.seq = ret = _get_env_seq(gf);
	return ret;
}

int
wf_redraw(GBVIEW_FLAME * gf,GBVIEW_PLANE * p,int x,int y,int w,int h)
{
int ret;

	wf_lock(gf);
	ZONBIE_CHECK(gf,wf_unlock,0)

	_ex_lock(gf);

	ret = __wf_redraw(gf,p,x,y,w,h);

	_ex_unlock(gf);
	wf_unlock(gf);
	return ret;
}


WIN_FLAME *
touch_wf(GBVIEW_FLAME * gf)
{
WIN_FLAME * wf, * ret_wf;
retry:

	wf_lock(gf);
	ZONBIE_CHECK(gf,wf_unlock,0)

retry2:
	_reset_task_nos(gf);
	ret_wf = 0;
	for ( wf = gf->flame ; wf ; wf = wf->next ) {
		if ( !(wf->flags & WFF_DRAW_REQUEST) )
			continue;
		if ( wf->flags & WFF_FREE )
			continue;
		if ( wf->lock )
			continue;
		ret_wf = wf;

	}
	ZONBIE_CHECK(gf,wf_unlock,0)
	if ( ret_wf ) {
		ret_wf->flags &= ~WFF_DRAW_REQUEST;
		if ( _win_lock(gf,ret_wf) < 0 )
			goto retry2;
		wf_unlock(gf);
		return ret_wf;
	}
	if ( gf->req_task_nos )
		goto retry2;
	wf_unlock(gf);
	return 0;
}

typedef struct wf_search_t {
	RESOURCE * r;
	WF_ID		id;
	GBVIEW_FLAME * gf;
} WF_SEARCH_T;

int
___wf_search(GBVIEW_FLAME * gf,WF_SEARCH_T * w)
{
WIN_FLAME * wf;
WF_ID ret;

	wf_lock(gf);
	for ( wf = gf->flame ; wf ; wf = wf->next )
		if ( wf->draw == w->r ) {
			w->id = wf->id;
			w->gf = gf;
			wf_unlock(gf);
			return -1;
		}
	wf_unlock(gf);
	return 0;
}

GBVIEW_FLAME *
wf_search(WF_ID * ret_id,RESOURCE * r)
{
WF_SEARCH_T w;
	w.r = r;
	w.id = 0;
	w.gf = 0;
	wf_apply_all_gf(___wf_search,&w,GVFS_ACTIVE,0);
	if ( ret_id )
		*ret_id = w.id;
	return w.gf;
}


void
wf_indicate(GBVIEW_FLAME * gf,GBVIEW_STATUS * sts,int x,int y,int button)
{
WIN_FLAME * wf;
MAP_HISTORY * mh;
GB_POINT p,org;
REAL1 reso;
INDICATE * in;
GET_POINT_WORK w;
int i,cnt;
SYMBOL_INDICATE * si;
RESOURCE * r;
OBJ * o;
int * no_list;
int no_cnt;
int sub,code;
int id;
void wf_init_status();

	if ( sts )
		wf_init_status(sts);

	wf_lock(gf);
	ZONBIE_CHECK_VOID(gf,wf_unlock)

	for ( in = gf->indicate ; in ; in = in->next ) {
		in->status = 0;
	}
	wf_unlock(gf);
	clear_info(gf);
	for ( cnt = 0 ; ; cnt ++ ) {
		wf_lock(gf);
set_t_msg(32);


		i = 0;
		for ( wf = gf->flame ; wf && i < cnt ; wf = wf->next , i ++ );
		if ( wf == 0 ) {
			wf_unlock(gf);
			break;
		}
		id = wf->id;
		no_cnt = 0;
		if ( button == GPB_PRESS ) {
			for ( si = wf->sym_i ; si ; si = si->next ) {
				if ( !(si->flags & SIF_ANCOR) )
					continue;
				p.x = x;
				p.y = y;
				if ( inside_rect(&si->rect,p) == 0 )
					continue;
				if ( sts && si->ref ) {
printf("REFERENCE\n");
					sts->reference 
						= ll_copy_str(si->ref);
					sts->flags |= SF_REFERENCE;

					wf_unlock(gf);
					clear_info(gf);
					return;
				}
				no_cnt ++;
			}
			if ( no_cnt ) {
				no_list = d_alloc(no_cnt*2*sizeof(int));
				i = 0;
				for ( si = wf->sym_i ; si ; si = si->next ) {
					if ( !(si->flags & SIF_ANCOR) )
						continue;
					p.x = x;
					p.y = y;
					if ( inside_rect(&si->rect,p) == 0 )
						continue;
					no_list[2*i] = si->rno;
					no_list[2*i+1] = si->code;
					i ++;
				}
			}
			else	no_list = 0;
		}
		else	no_list = 0;
		mh = add_mh(&gf->flame_base_display_map,
			wf->mh);
		p.x = x;
		p.y = y;
		org = p;
		reso = 1;

		map_from_flame(mh,&p,&reso,1);

		free_mh(mh);


		if ( reso < 0 ) {
			wf_unlock(gf);
			continue;
		}
		w.pt = p;
		w.org = org;
		w.button = button;
		wf_unlock(gf);

		for ( i = 0 ; i < no_cnt ; i ++ ) {
			r = search_resource_by_no(no_list[2*i]);
			if ( r == 0 )
				continue;
			code = no_list[2*i+1]&MAIN_CODE;
			for ( sub = 0 ; sub < USER_SUBCODE ; sub ++ ) {
				o = search_obj(r,code|sub);
				if ( o )
					break;
			}
			if ( o == 0 )
				continue;
			indicate_info_card(gf,r,o);
		}
		if ( no_list )
			d_f_ree(no_list);
		wf_lock(gf);
set_t_msg(33);
		if ( _get_wf_ptr(gf,id) )
			r = wf->draw;
		else r = 0;
		wf_unlock(gf);
		lock_task(in_lock);
		if ( r ) {
			get_point_resource(gf,r,&w);
		}
		unlock_task(in_lock,"ill");
	}
}


void
wf_lock_test(GBVIEW_FLAME * gf,char * str)
{
	printf("%s...\n",str);
	wf_lock(gf);
set_t_msg(34);
	wf_unlock(gf);
	printf("%s...OK\n",str);
}


void
_all_dirty_out(GBVIEW_FLAME * gf)
{
WIN_FLAME * wf;
	for ( wf = gf->flame ; wf ; wf = wf->next ) {
		if ( wf->flags & WFF_FREE )
			continue;
		wf->aboat_count ++;
		_wakeup_at_redraw_wp(gf);
		_win_wlock(gf,wf);
		wf_free_si(wf);
		_win_flame_dirty(gf,wf,0,WFF_DIRTY,0);
		_win_unlock(gf,wf);
		wf->aboat_count --;
		_wakeup_at_redraw_wp(gf);
	}
}

void
all_dirty_out(GBVIEW_FLAME * gf)
{
	wf_lock(gf);
set_t_msg(35);
	_all_dirty_out(gf);
	wf_unlock(gf);
}


REAL1
get_rad(GB_POINT p)
{
double d;
	d = sqrt(p.x*p.x + p.y*p.y);
	if ( d == 0 )
		return 0;
	if ( p.x > 0 )
		return acos(-p.y/d);
	else	return -acos(-p.y/d);
}

int
wf_goto_point(
	GBVIEW_FLAME * gf,
	L_CHAR * url,
	GB_POINT ptr,
	REAL1 rotate,
	REAL1 reso)
{
URL u;
WIN_FLAME * wf;
RESOURCE * c;
WF_ID ret_wf;
unsigned long * pp;
int size;
int ses;
int er;

	get_url2(&u,url);
	if ( u.proto == 0 || u.db == 0 || u.server == 0 || u.resource == 0 )
		return 0;
	wf_lock(gf);
	ZONBIE_CHECK(gf,wf_unlock,0);

	for ( wf = gf->flame ; wf ; wf = wf->next )
		if ( url_cmp_str(&wf->draw->h.entry,&u) == 0 )
			break;
	if ( wf == 0 ) {
	wf_0:
		wf_unlock(gf);
		ses = open_session();
		c = load_resource(ses,&u,Q_PRI_RADAR);
		close_session(ses);
		if ( c == 0 ) {
			fprintf(stderr,"cannot load resource \"%s\"\n",
				n_string(std_cm,url));
			goto end;
		}
		wf_lock(gf);
set_t_msg(37);
		for ( wf = gf->flame ; wf ; wf = wf->next )
			_free_win_flame(gf,wf);
		wf_unlock(gf);
/*
		switch ( c->c.geometory_type & GT_T_MASK ) {
		case GT_T_2D:
			break;
		case GT_T_GLOBE_SUR:
			reso = conv_unit(&er,
					c->h.cu.uenv,
					reso,
					reso_c_unit(&c->h.cu),
					l_string(std_cm,"dot/rad"));
			break;
		default:
			er_panic("wf_goto_point");
		}
*/
		new_win_flame(&ret_wf,
			gf,
			c->h.visible_resolution,
			c,0,ptr,rotate,reso);
		assert_ls(gf,LSF_ZOOM);

		goto end;
	}
/*
	switch ( wf->draw->c.geometory_type & GT_T_MASK ) {
	case GT_T_2D:
		break;
	case GT_T_GLOBE_SUR:
		reso = conv_unit(&er,
				wf->draw->h.cu.uenv,
				reso,
				reso_c_unit(&wf->draw->h.cu),
				l_string(std_cm,"dot/rad"));
		break;
	default:
		er_panic("wf_goto_point");
	}
*/
	if ( wf->flags & WFF_FREE ) {
		wf_unlock(gf);
		return 0;
	}
	if ( wf == gf->flame_base ) {
		gf->flame_base_resolution = reso;
		gf->flame_base_rotate = rotate;
		gf->flame_base_center = ptr;
	}
	else {
	GB_POINT ptr_list[2];
	REAL1 reso_list[2];
	GB_POINT a;
		if ( wf->flags & WFF_FREE ) {
			wf_unlock(gf);
			return 0;
		}
		a.x = sin(rotate);
		a.y = - cos(rotate);
		ptr_list[0] = ptr;
		ptr_list[1] = p_add(ptr,a);
		reso_list[0] = reso;
		reso_list[1] = reso;
		map_from_resource(wf->mh,ptr_list,reso_list,2);
		if ( reso_list[0] < 0 )
			goto wf_0;
		if ( reso_list[1] < 0 ) {
			gf->flame_base_resolution = reso_list[0];
			gf->flame_base_center = ptr_list[0];
			gf->flame_base_rotate = rotate;
		}
		else {
			gf->flame_base_resolution = reso_list[0];
			gf->flame_base_center = ptr_list[0];
			gf->flame_base_rotate = get_rad(
				p_sub(ptr_list[1],ptr_list[0]));
		}
	}
	_calc_pitch(gf,1);
	_all_dirty_out(gf);
	assert_ls(gf,LSF_ZOOM);
	wf_unlock(gf);
end:
	return 0;
}


void
_wf_select(GBVIEW_FLAME * gf,GBVIEW_PLANE * p,OBJ * obj)
{
SELECT_WORK sw;
WIN_FLAME * wf;
SELECT_INDICATE * si;
int xx,yy,x1,y1,i;
MAP_HISTORY * mh;
int ow,oh;
unsigned long * buf;
unsigned int cc1,cc2;
VRECT tar;
int ret;


	tar.tl.x = 0;
	tar.tl.y = 0;
	tar.br.x = -1;
	tar.br.y = -1;
	ow = gf->win_width;
	oh = gf->win_height;
	buf = p->r.plane;

	for ( wf = gf->flame ; wf ; wf = wf->next ) {
		sw.mh = add_mh(&gf->flame_base_display_map,wf->mh);
		sw.select_obj = obj;
		sw.map = 0;
		sw.color.c = 0x3ff;
		sw.color.t = 1;
		sw.color.rev_t = 0;
		sw.width = gf->win_width;
		sw.height = gf->win_height;
		si = d_alloc(sizeof(*si));
		sw.si = si;
		si->pixels = 0;
		select_resource(wf->draw,&sw);
		if ( si->pixels ) {
			si->t = 0.4;
			si->rev_t = 1-si->t;
			si->next = gf->si;
			gf->si = si;

			y1 = 0;
			for ( yy = si->y ; ; yy ++ ) {
				if ( yy < 0 )
					continue;
				if ( yy >= si->y + si->h )
					break;
				if ( yy >= gf->win_height )
					break;
				x1 = 0;
				for ( xx = si->x ; ; xx ++ ) {
					if ( xx < 0 )
						continue;
					if ( xx >= si->x + si->w )
						break;
					if ( xx >= gf->win_width )
						break;
					if ( (xx&1) == (yy&1) ) {
						cc1 = select_color(
							gf,
							C_TRANSPARENT,
							xx,yy);
						buf[yy*ow + xx] = cc1;
						insert_vrect(&tar,
							xx,yy);
					}
					x1 ++;
				}
				y1 ++;
			}
			break;
		}
		else {
			d_f_ree(si);
		}
	}
	marge_vrect(&p->r.r,&tar);
	return;
}



int
_wf_purge_select(GBVIEW_FLAME * gf)
{
SELECT_INDICATE * si;
int xx,yy;
VRECT rr;

	if ( gf->si == 0 )
		return -1;
	for ( ; gf->si ; ) {
		si = gf->si;
		gf->si = si->next;
		if ( si->x < 0 )
			xx = 0;
		else	xx = si->x;
		rr.tl.x = si->x;
		rr.tl.y = si->y;
		rr.br.x = si->x + si->w;
		rr.br.y = si->y + si->h;
		insert_redraw_r(gf,&rr);
		for ( ; ; xx ++ ) {
			if ( xx >= si->x + si->w )
				break;
			if ( xx >= gf->win_width )
				break;
			if ( si->y < 0 )
				yy = 0;
			else	yy = si->y;
			for ( ; ; yy ++ ) {
				if ( yy >= si->y + si->h )
					break;
				if ( yy >= gf->win_height )
					break;
				gf->redraw[yy*gf->win_width + xx]
					= RP_REDRAW;
			}
		}

		d_f_ree(si->pixels);
		d_f_ree(si);
	}
	return 0;
}

int
wf_purge_select(GBVIEW_FLAME * gf)
{
int ret;
	wf_lock(gf);
	ZONBIE_CHECK(gf,wf_unlock,0);

	if ( _wf_purge_select(gf) < 0 )
		ret = 0;
	else	ret = _get_env_seq(gf);
	wf_unlock(gf);
	return ret;
}


void
wf_check_resource(GBVIEW_FLAME * gf)
{
WIN_FLAME * wf;
CHECK_WORK c;
int i;

	wf_lock(gf);
set_t_msg(39);
	for ( wf = gf->flame ; wf ; wf = wf->next ) {
		for ( i = 0 ; i < RT_MAX ; i ++ ) {
			c.type[i] = 0;
			c.opt[i] = 0;
		}
		c.max_coord_level = 1;
		c.coord_level = 0;
		c.resource = 0;
		c.flags = 0;
		check_resource(wf->draw,&c);
		if ( c.type[RT_PIXEL_MAP_R64] )
			wf->flags |= WFF_LUSTER;
		else	wf->flags &= ~WFF_LUSTER;
		if ( c.opt[RT_DRAW_GB] & DGF_POLY )
			wf->flags |= WFF_POLY;
		if ( c.opt[RT_DRAW_GB] & (DGF_INFO|DGF_MARK) )
			wf->flags |= WFF_PLOT;

	}
	wf_unlock(gf);
}

typedef struct wfs_wfid_ir {
	RESOURCE * r;
	WFID_INCLUDE_RESOURCE * ret;
} WFS_WFID_IR;

int
_wf_search_wfid_include_resource(GBVIEW_FLAME * gf,WFS_WFID_IR * w)
{
WIN_FLAME * wf;
CHECK_WORK c;
int i;
WF_ID ret;
RESOURCE * r;
WFID_INCLUDE_RESOURCE * ir;
	r = w->r;

	wf_lock(gf);


	for ( wf = gf->flame ; wf ; wf = wf->next ) {
		for ( i = 0 ; i < RT_MAX ; i ++ ) {
			c.type[i] = 0;
			c.opt[i] = 0;
		}
		c.max_coord_level = 1;
		c.coord_level = 0;
		c.resource = r;
		c.flags = 0;
		check_resource(wf->draw,&c);
		if ( c.flags & CWF_RESOURCE )
			break;
	}
	if ( wf ) {
		ir = d_alloc(sizeof(*ir));
		ir->id = wf->id;
		ir->gf = gf;
		ir->next = w->ret;
		w->ret = ir;
	}
	wf_unlock(gf);
	return 0;
}

WFID_INCLUDE_RESOURCE *
wf_search_wfid_include_resource(RESOURCE *r)
{
WFS_WFID_IR w;
	w.ret = 0;
	w.r = r;
	wf_apply_all_gf(_wf_search_wfid_include_resource,&w,GVFS_ACTIVE,0);
	return w.ret;
}

void
free_wfid_include_resource(WFID_INCLUDE_RESOURCE * wir)
{
WFID_INCLUDE_RESOURCE * wir2;
	for ( ; wir ; ) {
		wir2 = wir->next;
		d_f_ree(wir);
		wir = wir2;
	}
}



int
min_route_wf(GBVIEW_FLAME * gf,int ses)
{
int cnt,i;
WIN_FLAME * wf;
L_CHAR * target, * org, * t;
MAP_HISTORY * mh;
MP_ROUTE * mpr;
URL u;
int ret;

	ret = 0;
	cnt = 0;
retry:
	wf_lock(gf);
set_t_msg(41);

	wf = _wf_get_current(gf);
	if ( wf == 0 ) {
		wf_unlock(gf);
		return ret;
	}
	org = ll_copy_str(get_url_str2(&wf->draw->h.entry));

	i = cnt;
	for ( wf = gf->flame ; wf && i ; wf = wf->next , i -- ) {
		if ( wf->mh == 0 )
			continue;
	}
	if ( wf == 0 ) {
		wf_unlock(gf);
		return ret;
	}
	target = ll_copy_str(get_url_str2(&wf->draw->h.entry));
	wf_unlock(gf);

	mpr = resolve_route(org,target,RR_WM_DIRECT_NO_WAIT);
	if ( mpr == 0 ) {
		goto flush_mpr2;
	}
	if ( mpr == MP_NO_ROUTE ) {
		ret = -1;
		goto flush_mpr2;
	}
	get_url2(&u,org);
	mh = get_mh_from_route(ses,&u,mpr);
	free_url(&u);
	if ( mh == MP_MH_NO_ROUTE ) {
		ret = -1;
		goto flush_mpr;
	}

	wf_lock(gf);
set_t_msg(42);


	wf = _wf_get_current(gf);
	if ( wf == 0 ) {
		free_mh(mh);
		wf_unlock(gf);
		goto flush_mpr;
	}
	for ( wf = gf->flame ; wf ; wf = wf->next ) {
		if ( wf->mh == 0 )
			continue;
		if ( l_strcmp(target,get_url_str2(&wf->draw->h.entry)) == 0 )
			break;
	}
	if ( wf == 0 ) {
		wf_unlock(gf);
		goto flush_mpr;
	}
	free_mh(wf->mh);
	wf->mh = optimize_mh(mh);
	wf_unlock(gf);

flush_mpr:
	flush_route(mpr);
flush_mpr2:
	d_f_ree(target);
	d_f_ree(org);

	cnt ++;
	goto retry;

}

RESOURCE *
wf_get_resource(GBVIEW_FLAME * gf,WF_ID id)
{
RESOURCE * ret;
WIN_FLAME * wf;
	wf_lock(gf);
	ZONBIE_CHECK(gf,wf_unlock,0);


	wf = _get_wf_ptr(gf,id);
	if ( wf == 0 ) {
		wf_unlock(gf);
		return 0;
	}
	ret = wf->draw;
	wf_unlock(gf);
	return ret;
}


void
wakeup_wf(GBVIEW_FLAME * gf,WF_ID wfid)
{
WIN_FLAME * wf;
	wf_lock(gf);
set_t_msg(44);


	wf = _get_wf_ptr(gf,wfid);
	if ( wf == 0 )
		goto end;
	_wakeup_wf(gf,wf);
end:
	wf_unlock(gf);
}


REAL1
get_radian(
	GBVIEW_FLAME * gf,
	GB_POINT from,
	GB_POINT to)
{
REAL1 A,B;
double d,s,c;
GB_POINT center;
	center.x = gf->win_width/2;
	center.y = gf->win_height/2;
	from = p_sub(from,center);
	to = p_sub(to,center);
	d = sqrt(inner(from,from) * inner(to,to));
	A = inner(from,to)/d;
	B = (to.x * from.y - from.x * to.y)/d;
	if ( A > 1 )
		A = 1;
	else if ( A < -1 )
		A = -1;
	if ( B > 1 )
		B = 1;
	else if ( B < -1 )
		B = -1;
	c = acos(A);
	s = asin(B);
	if ( c < M_PI/2 )
		return s;
	if ( s < 0 )
		return -c;
	else	return c;
}



unsigned long *
_rotate_plane(
	GBVIEW_FLAME * gf,
	unsigned long * plane,
	VPOINT * index)
{
unsigned long * ret, * rp;
int x,y;
	ret = d_alloc(sizeof(long)*gf->win_width*gf->win_height);
	rp = ret;
	for ( y = 0 ; y < gf->win_height ; y ++ )
		for ( x = 0 ; x < gf->win_width ; x++ ) {
			if ( index->x < 0 )
				*rp++ = BACKGROUND_COLOR_MID;
			else	*rp++ = 
				plane[index->x + index->y * gf->win_width];
			index ++;
		}
	return ret;
}

int
wf_rotate(GBVIEW_FLAME * gf,GB_POINT from,GB_POINT to)
{
int ret;
VPOINT * index;
unsigned long * plane, * pp;
int i;
WIN_FLAME * wf;

	if ( from.x == to.x && from.y == to.y )
		return 0;
	wf_lock(gf);
	ZONBIE_CHECK(gf,wf_unlock,0)
	
	index = d_alloc(sizeof(VPOINT)*gf->win_width*gf->win_height);
	wf_make_rotate_index(index,from,to,gf->win_width,gf->win_height);
	plane = _rotate_plane(gf,gf->redraw_plane,index);
	d_f_ree(gf->redraw_plane);
	gf->redraw_plane = plane;
	for ( i = 0 ; i < gf->win_width * gf->win_height ; i ++ )
		gf->redraw[i] = 0;
	for ( wf = gf->flame ; wf ; wf = wf->next ) {
		if ( wf->flags & WFF_FREE )
			continue;
		win_flame_rotate(gf,wf,index);
		_wakeup_wf(gf,wf);
	}
	d_f_ree(index);
	_calc_pitch(gf,0);
	gf->flame_base_rotate -= get_radian(gf,from,to);
	_calc_pitch(gf,1);

	ret = _get_env_seq(gf);
	wf_unlock(gf);
	new_tick(_wf_set_redraw,0,(int)gf);
	return ret;
}



RESOURCE * 
_wf_get_mh(GBVIEW_FLAME * gf,WIN_FLAME * wf,MAP_HISTORY ** mhp)
{
	*mhp = add_mh(&gf->flame_base_display_map,wf->mh);
	return wf->draw;
}

RESOURCE *
wf_get_mh(GBVIEW_FLAME * gf,WF_ID id,MAP_HISTORY ** mhp)
{
RESOURCE * ret;
WIN_FLAME * wf;
	wf_lock(gf);
set_t_msg(47);
	wf = _get_wf_ptr(gf,id);
	if ( wf == 0 ) {
		wf_unlock(gf);
		return 0;
	}
	ret = _wf_get_mh(gf,wf,mhp);
	wf_unlock(gf);
	return ret;
}


void
wf_insert_dirty_rect(RESOURCE * r,GB_RECT * d_rect,
	int flags,
	int ofs_w,int ofs_h)
{
SURP_SET ss;
MAP_HISTORY * mh;
RESOURCE * draw;
GB_RECT rct,* _rct;
int nos;
RESOURCE * map;
WFID_INCLUDE_RESOURCE * wir,* p;
	wir = wf_search_wfid_include_resource(r);
if ( r->h.target.port == 9000 )
ss_printf("********DIRTY 1 %x\n",wir);
	for ( p = wir ; p ; p = p->next ) {
		if ( p->id == 0 )
			continue;
		set_surp(&ss,d_rect,1);
		draw = wf_get_mh(p->gf,p->id,&mh);
		if ( draw == 0 )
			continue;
		map = get_map_between2(r,draw);
		if ( map == 0 )
			continue;
		map_conv_forward(map,ss.ptr,ss.reso,SURP_NOS);
		map_from_resource(mh,ss.ptr,ss.reso,SURP_NOS);
		memset(ss.group,0,sizeof(ss.group));
		_rct = get_surp_rect(&nos,&ss,0);
		if ( nos > 1 )
			er_panic("wf_insert_dirty_rect");
		if ( nos == 0 )
			continue;
		rct = *_rct;

		rct.tl.x -= ofs_w;
		rct.tl.y -= ofs_h;
		rct.br.x += ofs_w;
		rct.br.y += ofs_h;
if ( r->h.target.port == 9000 )
ss_printf("********DIRTY %f %f - %f %f\n",
rct.tl.x,
rct.tl.y,
rct.br.x,
rct.br.y);
		win_flame_dirty(p->gf,p->id,&rct,flags,0);

		free_mh(mh);
	}
	free_wfid_include_resource(wir);
}


int
_get_wf_pri(GBVIEW_FLAME * gf,WIN_FLAME * wf)
{
WIN_FLAME * w;
int ret;
	if ( wf->flags & WFF_LUSTER ) {
		ret = 0;
		for ( w = gf->flame ; 
			!(w->flags & WFF_FREE) &&
			w && w != wf ;
			w = w->next , ret -- );
		return ret + wf->pri_adj;
	}
	if ( wf->flags & WFF_POLY )
		return 1 + wf->pri_adj;
	return 2 + wf->pri_adj;
}

int
get_wf_priadj(GBVIEW_FLAME * gf,WF_ID id)
{
WIN_FLAME * wf;
int ret;
	wf_lock(gf);
	wf = _get_wf_ptr(gf,id);
	if ( wf == 0 ) {
		ret = -1;
		goto end;
	}
	ret = wf->pri_adj;
end:
	wf_unlock(gf);
	return ret;
}

void
_ind_pri(GBVIEW_FLAME * gf)
{
WIN_FLAME * wf;
int p;
	for ( wf = gf->flame ; wf ; wf = wf->next ) {
		p = _get_wf_pri(gf,wf);
		printf("(%x:%i:%i:%i)",wf->flags,p,wf->pri_adj,wf->lock);
	}
	printf("\n");
}


void
_set_pri_adj(GBVIEW_FLAME * gf,WIN_FLAME * wf,int adj)
{
	wf->pri_adj = adj;
	_wakeup_at_redraw_wp(gf);
}

void
set_pri_adj(GBVIEW_FLAME * gf,int wfid,int adj)
{
WIN_FLAME * wf;
	wf_lock(gf);
	wf = _get_wf_ptr(gf,wfid);
	if ( wf )
		_set_pri_adj(gf,wf,adj);
	wf_unlock(gf);
}


int
wf_button_action(GBVIEW_FLAME * gf,OBJ * o,char * type)
{
WIN_FLAME * wf;
RESOURCE ** rlist;
int rlist_len,i;
int ret;

	if ( o == 0 || o->h.name == 0 )
		return 0;
	wf_lock(gf);
set_t_msg(49);
	ZONBIE_CHECK(gf,wf_unlock,0)
	rlist_len = 0;
	for ( wf = gf->flame ; wf ; wf = wf->next ) {
		if ( wf->draw->c.button_action )
			rlist_len ++;
	}
	rlist = d_alloc(sizeof(RESOURCE*)*rlist_len);
	i = 0;
	for ( wf = gf->flame ; wf ; wf = wf->next ) {
		if ( wf->draw->c.button_action )
			rlist[i++] = wf->draw;
	}
	wf_unlock(gf);

	ret = 0;
	for ( i = 0 ; i < rlist_len ; i ++ ) {
		if ( do_button_action(rlist[i],
				type,
				o->h.name) ) {
			ret = 1;
			goto end1;
		}
	}
end1:
	d_f_ree(rlist);
	return ret;
}

void
wf_status(GBVIEW_FLAME * gf,GBVIEW_STATUS * e)
{
WIN_FLAME * wf;
int n;
int ret;
RESOURCE * r;
int er;
GBVIEW_LAYER_STATUS * ls, ** lsp;


	wf_lock(gf);

	wf_init_status(e);
	ZONBIE_CHECK_VOID(gf,wf_unlock)

	e->width = gf->win_width;
	e->height = gf->win_height;
	n = 0;
	for ( wf = gf->flame ; wf ; wf = wf->next , n ++ );
	e->layer_nos = n;
	e->event = gf->event;

	if ( gf->flame_base )
		e->current = gf->flame_base->id;
	else	e->current = 0;

	e->flags = SF_BASE;

	if ( gf->flame_base ) {
		r = gf->flame_base->draw;
		e->flame_base_resolution = gf->flame_base_resolution;
		e->flame_base_display_map_type
			= gf->flame_base_display_map.type;
		e->flame_base_unit = ll_copy_str(r->h.cu.unit);

		e->flags |= SF_RESOLUTION|SF_MAP_TYPE|SF_UNIT;

		if ( e->flame_base_display_map_type == MHT_PP ) {
			e->pp_radius = conv_unit(&er,
				r->h.cu.uenv,
				gf->flame_base_resolution,
				reso_c_unit(&r->h.cu),
				l_string(std_cm,"dot/rad"));

			e->flags |= SF_PP_RADIUS;
		}
	}
	if ( gf->flame ) {
		lsp = &e->layers;
		for ( wf = gf->flame ; wf ; wf = wf->next ) {
			if ( wf->flags & WFF_FREE )
				continue;
			ls = d_alloc(sizeof(*ls));
			ls->id = wf->id;
			ls->entry_url = ll_copy_str(
				get_url_str2(&wf->draw->h.entry));
			ls->target_url = ll_copy_str(
				get_url_str2(&wf->draw->h.target));
			ls->next = 0;
			*lsp = ls;
			lsp = &ls->next;
		}
	}
	if ( gf->radar_ptr )
		e->flags |= SF_RADAR;


	wf_unlock(gf);
	e->infolist = copy_infolist(gf);

	lock_task(in_lock);
	e->indicate = _copy_indicate(gf);
	unlock_task(in_lock,"wf_status");
}

int
change_status_rule(int * old_st,int new_st)
{
int ret;
	if ( *old_st != new_st )
		ret = 1;
	else	ret = 0;
	switch ( *old_st ) {
	case GVFS_IDLE:
	case GVFS_ACTIVE:
		switch ( new_st ) {
		case GVFS_ZONBIE_2:
			*old_st = GVFS_ZONBIE;
			break;
		default:
			*old_st = new_st;
			break;
		}
		return ret;
	case GVFS_ZONBIE:
	case GVFS_ZONBIE_2:
		return -1;
	default:
		er_panic("change_status_rule");
	}
	return 0;
}

void
gf_zonbie_tick()
{
GBVIEW_FLAME ** gfp,* gf;
WIN_FLAME * wf;
	lock_task(gbview_flame_lock);
	if ( gf_zonbie_count == 0 ) {
		del_tick(gf_zonbie_tick);
		goto end;
	}
	for ( gfp = &gbview_flame_list ; *gfp ; ) {
		gf = *gfp;
		switch ( gf->status ) {
		case GVFS_ZONBIE:
			if ( _ch_locked(&gf->_wf_lock) )
				break;
			_ch_lock(&gf->_wf_lock,__FILE__,__LINE__);
			for ( wf = gf->flame ; wf ; wf = wf->next )
				_free_win_flame(gf,gf->flame);
			_wf_purge_select(gf);
			_ch_unlock(&gf->_wf_lock);
			gf->status = GVFS_ZONBIE_2;
			gf->zonbie_timeout = get_xltime() + ZONBIE_TIMEOUT;
			break;
		case GVFS_ZONBIE_2:
			if ( gf->zonbie_timeout < get_xltime() )
				gf->status = GVFS_ZONBIE_3;
		case GVFS_ZONBIE_3:
			if ( _ch_locked(&gf->_wf_lock) )
				break;
			if ( _ch_locked(&gf->_ls_lock) )
				break;
			if ( _ch_locked(&gf->indicate_lock) )
				break;
			if ( gf->ex_lock )
				break;
			if ( gf->run_req_task_nos )
				break;
			if ( gf->ls_task_cnt )
				break;
			if ( gf->exit_task_wp )
				break;
			if ( gf->redraw_wp )
				break;
			d_f_ree(gf->redraw);
			d_f_ree(gf->redraw_plane);
			free_indicate(gf->indicate);
			free_infolist(gf->infolist);
			free_infolist(gf->click_op_list);
			*gfp = gf->next;
			d_f_ree(gf);
			gf_zonbie_count --;
			continue;
		default:
			break;
		}
		gfp = &(*gfp)->next;
	}
end:
	unlock_task(gbview_flame_lock,"gf_zonbie_tick");
}

void
_wf_st_change(GBVIEW_FLAME * gf,int old_status)
{
	switch ( gf->status ) {
	case GVFS_IDLE:
		break;
	case GVFS_ACTIVE:
		radar_status(gf);
		break;
	case GVFS_ZONBIE:
		detach_radar(gf);
		lock_task(gbview_flame_lock);
		gf_zonbie_count ++;
		unlock_task(gbview_flame_lock,"_wf_st_change");
		new_tick(gf_zonbie_tick,0,0);
		break;
	default:
		er_panic("_wf_st_change");
	}
}

int
wf_set_status(GBVIEW_FLAME * gf,GBVIEW_STATUS * e)
{
int ret;
int change,st_change;
int shift;
	wf_lock(gf);
	ZONBIE_CHECK(gf,wf_unlock,0)
set_t_msg(51);
	change = 0;
	st_change = 0;
	if ( e->flags & SF_STATUS ) {
		shift = 1;
		for ( ; (e->status & shift) == 0 ; shift <<= 1 );
		if ( change_status_rule(&gf->status,shift) == 1 )
			st_change = gf->status;
		else	st_change = 0;
	}
	if ( e->flags & SF_WIDTH ) {
		if ( gf->win_width != e->width )
			change = 1;
		gf->win_width = e->width;
	}
	if ( e->flags & SF_HEIGHT ) {
		if ( gf->win_height != e->height )
			change = 1;
		gf->win_height = e->height;
	}
	if ( e->flags & SF_EVENT )
		gf->event = e->event;

	if ( change )
		_wf_change_size(gf);
	if ( gf->radar_ptr == 0 && (e->flags & SF_RADAR) )
		attach_radar(gf);
	if ( st_change )
		_wf_st_change(gf,st_change);
	ret = _get_env_seq(gf);
	wf_unlock(gf);
	return ret;
}


int
_wf_click(GBVIEW_FLAME * gf,GBVIEW_PLANE * gbp,INFO_LIST * lst);

void
_wf_click_func(GBVIEW_FLAME * gf)
{
GBVIEW_PLANE gbp;
INFO_LIST * info;
int seq;

	wf_lock(gf);
	ZONBIE_CHECK_VOID(gf,wf_unlock)
set_t_msg(52);
	info = gf->click_op_list;
	gf->click_op_list = 0;
	wf_unlock(gf);
	_wf_click(gf,&gbp,info);
	if ( gf->event )
		(*gf->event)(gf,ET_CLICK,&gbp);
	free_infolist(info);
}

void
wf_click_func(GBVIEW_FLAME * gf)
{
	new_tick(_wf_click_func,0,(int)gf);
}

int
_wf_click(GBVIEW_FLAME * gf,GBVIEW_PLANE * gbp,INFO_LIST * lst)
{
INFO_LIST * il, * il2;
GBVIEW_STATUS sts;
int seq;
int ow,oh;
unsigned long * buf;
int i;

	if ( gf->status & GVFM_ZONBIE )
		return 0;

	wf_status(gf,&sts);

	if ( lst )
		il2 = il = lst;
	else {
		il2 = il = sts.infolist;
		sts.infolist = 0;
	}

	for ( il = il2 ; il ; il = il->next ) {
		if ( wf_button_action(gf,il->obj,"click") )
			goto next;
	}

	if ( invoke_indicate(gf,wf_click_func,gf) ) {
		wf_lock(gf);
set_t_msg(53);
		if ( gf->click_op_list )
			free_infolist(gf->click_op_list);
		sts.infolist = 0;
		gf->click_op_list = il2;
		wf_unlock(gf);

		wf_free_status(&sts);
		return 0;
	}

next:

	wf_lock(gf);
set_t_msg(54);
	ow = gf->win_width;
	oh = gf->win_height;
	gbp->r.r.tl.x = gbp->r.r.br.x = 0;
	gbp->r.r.tl.y = gbp->r.r.br.y = -1;
	gbp->r.plane = buf = d_alloc(sizeof(unsigned long)*ow*oh);
	gbp->h.type = GPT_REDRAW;
	for ( i = 0 ; i < ow*oh ; i ++ , buf ++ )
		*buf = C_TRANSPARENT;
	for ( il = il2 ; il ; il = il->next )
		_wf_select(gf,gbp,il->obj);
	buf = gbp->r.plane;
	gbp->r.plane = 0;
/*
printf("CLICK TAR %i %i - %i %i\n",
gbp->r.r.tl.x,
gbp->r.r.tl.y,
gbp->r.r.br.x,
gbp->r.r.br.y);
*/
	if ( gbp->r.r.tl.x >= gbp->r.r.br.x ) {
		gbp->h.seq = seq = 0;
		gbp->h.type = 0;
		gbp->r.plane = 0;
		d_f_ree(buf);
	}
	else {
		copy_plane(gf,gbp,buf);
		d_f_ree(buf);
		gbp->h.seq = seq = _get_env_seq(gf);
	}

	wf_unlock(gf);

	return seq;
}


int
wf_click(GBVIEW_FLAME * gf,GBVIEW_STATUS * sts,GBVIEW_PLANE * p,int x,int y)
{

printf("CLICK 1\n");
	wf_indicate(gf,sts,x,y,GPB_PRESS);
	return _wf_click(gf,p,0);
}

unsigned int
_wf_insert_time(WIN_FLAME * wf)
{
	return wf->insert_time;
}

unsigned int
wf_insert_time(GBVIEW_FLAME * gf,int wfid)
{
WIN_FLAME * wf;
unsigned int ret;
	wf_lock(gf);
	ZONBIE_CHECK(gf,wf_unlock,0)
	wf = _get_wf_ptr(gf,wfid);
	if ( wf == 0 )
		ret = 0;
	else	ret = _wf_insert_time(wf);
	wf_unlock(gf);
	return ret;
}
