/* ---------------------------------------------------------------------- */
/* PowerGem Library, Version 1.1                                          */
/*																		  */
/* by Boris Sander			                                              */
/* Gerh.-Hauptmann-Str. 23	    										  */
/* 4350 Recklinghausen													  */
/*																		  */
/* Copyright (c) 1992 by ICP - Innovativ Computer-Presse GmbH & Co. KG    */
/* erweitert und, soweit sichtbar ,fehlerbereinigt von Mario Bahr			  */
/* ---------------------------------------------------------------------- */
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>
#include <aes.h>
#include <vdi.h>
#include <tos.h>
#include "powergem.h"

/* geh”rt eigentlich in aes.h */
#ifndef WF_BOTTOM
#define WF_BOTTOM 25
#endif
/* ---------------------------------------------------------------------- */
/* Funktionsprototypen                                                    */
/* ---------------------------------------------------------------------- */
struct WINDOW      *alloc_window(void);
struct BUTTON_LIST *alloc_button(struct WINDOW *win);
struct KEY_LIST    *alloc_key(void);
struct MENU_LIST   *alloc_menu(void);
struct MSG_LIST    *alloc_msg(void);

boolean compare_grect(GRECT *r1, GRECT *r2);
void    copy_grect(GRECT *r1, GRECT *r2);
void    clipping(int vdi_handle, GRECT *r, int mode);
void    blank(struct WINDOW *, int x, int y, int w, int h);

void sort_win_by_top(struct WINDOW *win);
void kill_window(int wh);
void win_manager(int msg, struct WINDOW *win, int x, int y, int w, int h);
void change_slider_size(struct WINDOW *win);
void new_slider_pos(struct WINDOW *win);
void hndl_slider_pos(struct WINDOW *win, int what, int position);

int  find_obj(OBJECT *tree);
int  fm_inifld(OBJECT *tree, int start_fld);
void draw_dial(struct WINDOW *win, GRECT *rc);
void draw_object(struct WINDOW *win,int obj_index);
void align_dial(struct WINDOW *win);
void align_panel(struct WINDOW *win);
boolean check_rect(int x,int y,GRECT *rect);

void button_manager(int m_x, int m_y, int m_button, int k_state);
void kill_button(struct WINDOW *win);

void key_manager(int code);
void kill_key(void);

void menu_manager(int title, int item, int scan_code);
void menu_all_change(int menu_flag);		  
void kill_menu(void);

void msg_manager(int *event);
void kill_msg(void);
void all_free(void);

#define DESK_TOP (void *)-1UL
/* ---------------------------------------------------------------------- */
/* Globale Variablen                                                      */
/* ---------------------------------------------------------------------- */
struct MSG_LIST  *msg_start;
struct KEY_LIST  *key_start;
struct MENU_LIST *menu_start; 
struct WINDOW *start, *help; 
MFDB screen;				 /* Struktur fr Bildschirmparameter   */

struct A_CNTRL app_cntrl;

/* ---------------------------------------------------------------------- */
/* Programmdeskriptor initialisieren, Resourcedatei laden, Men darst.    */
/* ---------------------------------------------------------------------- */
boolean init_powergem(char *rsc_name, int menu_index)
{
	register int i;
	int phys_handle;
	int work_in[11], work_out[57],work_ext[57];
	char alert_text[80];
	/* Alle globalen Variablen Null setzen */
	msg_start  = NULL;
	key_start  = NULL;
	menu_start =  NULL;
	start= help = NULL;
	memset( &app_cntrl, 0, sizeof(struct A_CNTRL));

	if ((app_cntrl.ap_id = appl_init()) != -1)
	{
		phys_handle = graf_handle(&app_cntrl.gl_wchar, &app_cntrl.gl_hchar,
								  &app_cntrl.gl_wbox, &app_cntrl.gl_hbox);
		work_in[0] = Getrez() + 2;
		for (i =1 ; i < 10; work_in[i++] = 1);
		work_in[10] = 2;
		app_cntrl.vdi_handle = phys_handle;

		v_opnvwk(work_in, &app_cntrl.vdi_handle, work_out);
		vq_extnd(app_cntrl.vdi_handle,1,work_ext);

	   /* fllt die vollst„ndige BITBLK-Struktur des Bildschirms */	 
       screen.fd_addr=NULL;	          /* Bildspeicherbasisadresse */
       screen.fd_w=work_out[0]+1;     /* Blockbreite in Pixeln    */
       screen.fd_h=work_out[1]+1;     /* H”he des Blocks in Pixeln*/
       screen.fd_wdwidth=((screen.fd_w+15)>>4);
       					             /* Blockbreite in Integern  */
       screen.fd_stand=0;            /* ger„teabh„ngiges Format  */
	   screen.fd_nplanes=work_ext[4];/* Anzahl der Farbebenen    */
       screen.fd_r1=screen.fd_r2=screen.fd_r3=0;
       							     /* reserviert               */
	}
	else
	{
		sprintf(alert_text, "[3][Applikation konnte nicht|angemeldet werden!|"
				"][Abbruch]");
		form_alert(1, alert_text);
		return(FALSE);
	} 

	/* Warnung, wenn Resource-Datei nicht geladen werden konnte -> Abbruch */
	if (!rsrc_load(rsc_name))
	{ 
		sprintf(alert_text, "[3][Die Resource-Datei|  %s|konnte nicht geladen|"
				"werden!][Abbruch]", rsc_name);
		form_alert(1, alert_text);
		return(FALSE);
	}	
	
	if (rsrc_gaddr(0, menu_index, &app_cntrl.menu))
		menu_bar(app_cntrl.menu, 1);
	else 
		return(FALSE);
	
	wind_get(0, WF_WORKXYWH, &app_cntrl.workarea.g_x,
			 &app_cntrl.workarea.g_y, &app_cntrl.workarea.g_w, 
			 &app_cntrl.workarea.g_h);
	return(TRUE);
}
/***********************************************************
 * Stellt den DESKTOP-Hintergrund dar 					   *	
 ***********************************************************/
boolean init_desktop(int desk)
{
OBJECT *desktop;
extern GEMPARBLK _GemParBlk;
if(rsrc_gaddr(R_TREE,desk,&desktop) && 	_GemParBlk.global[0]<0x0400
										 && _GemParBlk.global[1] == 1  )
	{
	desktop[ROOT].ob_x =app_cntrl.workarea.g_x;
	desktop[ROOT].ob_y =app_cntrl.workarea.g_y;
	desktop[ROOT].ob_width =app_cntrl.workarea.g_w;
	desktop[ROOT].ob_height=app_cntrl.workarea.g_h;
	wind_set(0,WF_NEWDESK,desktop,ROOT,MAX_DEPTH);
		objc_draw(desktop, 0,ROOT, desktop[ROOT].ob_x
   	  , desktop[ROOT].ob_y, desktop[ROOT].ob_width,desktop[ROOT].ob_height);
	}
else
	return FALSE;
return TRUE;
}
/***************************
 * Screenadresse ermitteln *
 ***************************/
MFDB *get_screen(void)
{
	return(&screen);
}
/***************************************** 
 * Oberstes Fenster je nach Typ 		 *
 * Input:  Typ des Fensters				 *
 * Output: wh_handle				     *
 *****************************************/
struct WINDOW *get_lastwin(int typ) 
{
struct WINDOW *win_b;

win_b=start;
if(win_b == NULL)
	return NULL;
if( (win_b->type&3) == typ)
   return start;        /* Etwa oberstes Fenster ? */

while(win_b->next != NULL)
	{
	win_b=win_b->next;
	if((win_b->type&3) == typ)
		return win_b; 	  
	}
return NULL;
}	
/**************************************************
 * Ermittlungn des Powergemeigenen VDI-Handles    *
 **************************************************/
int get_handle(void)
{
	return(app_cntrl.vdi_handle);
}	

/**************************************
 * PowerGEM anmelden zum verlassen 	  *
 **************************************/
void exit_powergem(void)
{
app_cntrl.quit = TRUE;	/* Quit-Flag auf TRUE setzen (fr multi) */
}
/******************************************
 * Gibt die Resourcen von PowerGEM frei   *
 ******************************************/
void all_free(void)
{
int x,y,w,h,wh;
extern GEMPARBLK _GemParBlk;
	
/* Prfen, ob noch Fenster offen sind */
help = start;
while(start)
	{
	/* Fenster schliežen, Speicher freigeben */
	start = help->next;
	wind_get(help->w_handle, WF_CURRXYWH, &x, &y, &w, &h);
	graf_shrinkbox(0,0,0,0, x,y,w,h);
	wind_close(help->w_handle); 
	wind_delete(help->w_handle);
	if ((help->type & DIAL_WINDOW) || (help->type & PANEL_WINDOW))
		kill_button(help);
	if(help->close_code)
		help->close_code(help);/* Resourcen des Anwenders ebenfalls freigeben */
	kill_window(help->w_handle); 
	help = start;
	}
			
/* evtl. Key-Liste freigeben */
if (key_start)
	kill_key();

/* evtl. Message-Liste freigeben */ 
if (msg_start)
	kill_msg();
	
/* evtl. Menu-Liste freigeben */
if (menu_start)
	kill_menu();
		
/* Men l”schen */
	menu_bar(app_cntrl.menu, 0);

/* Resource-Speicher freigeben */
	rsrc_free();

/* Erst ab TOS 1.4 ! -Fenster der Accssories auch schliežen !*/
wind_get(0, WF_TOP, &wh, 0,0,0);/* Oberstes Fenster ermitteln  */  
if(_GemParBlk.global[0] >= 0x140 && wh > 0)
	wind_new();  	
}
/* ---------------------------------------------------------------------- */
/* Adresse des Programmdeskriptors ermitteln                              */
/* ---------------------------------------------------------------------- */
struct A_CNTRL *get_app_cntrl()
{
	return(&app_cntrl);
}
/**************************************************************************
 * Sortiert WINDOW-next-Pointer neu (fr Fensterreihenfolge bei Tastatur- * 
 * topping)                                                               *
 * Zugriff auf globalen start-Zeiger                                      *
 * Input: win getopptes Fenster  									      *	
 **************************************************************************/
void sort_win_by_top(struct WINDOW *win)
{
struct WINDOW *win_b;

win_b=start;
	
if( win != start)         /* sonst win schon oberstes Fenster */
	{
	while(win_b->next != win) /* Vorg„nger suchen */
		win_b = win_b->next;
	win_b->next = win->next; /* Bekommt nun Zeiger auf dem ich zeige    */
	win->next = start;       /* Zeige nun auf das ehemals erste Element */
	start = win;             /* Werde erstes Element                    */
	}
}	

/**************************************************************************
 * Speicher fr WINDOW-Struktur alloziieren                               *
 **************************************************************************/
struct WINDOW *alloc_window(void)
{
	help = start;           
	start = (struct WINDOW *)calloc(1,sizeof(struct WINDOW)); 
	if (!start)
		return(NULL);
	start->next = help;     
	return(start);          
}

/************************************************************************
 * WINDOW-struct-Speicher freigeben                                     *
 * Input: wh Fensterhandle                                              *
 ************************************************************************/
void kill_window(int wh)
{
struct WINDOW *ptr;

ptr = get_winfh(wh);            
if (ptr) 
	{
	help = start; 
	if (help == ptr)    /* Wenn erstes Element */             
		{
		if (ptr->next)   /* wenn es einen Nachfolger gibt */
			{
			start = help->next; /* Element freigeben, Zeiger verbiegen */
			if (ptr->slider)
				free(ptr->slider);    
			if (ptr->dialog)         
				free(ptr->dialog);    
			free(ptr); 
			}
		else		
			{
			start = help = NULL; /* Es gibt keinen Nachfolger -> alles */
			if (ptr->slider)		/* auf NULL setzen, freigeben */
				free(ptr->slider);
			if (ptr->dialog)
				free(ptr->dialog);
			free(ptr);
			}
		}
	else 
		{									
		while (help->next != ptr) /* Vorg„nger suchen */
			help = help->next;
				
		if (!ptr->next)   /* Wenn es keinen Nachfolger gibt */ 
			{
			help->next = 0; /* dann l”schen */
			if (ptr->slider)
				free(ptr->slider);
			if (ptr->dialog)
				free(ptr->dialog);
			free(ptr);
			}
		else              /* Ansonsten Zeiger verbiegen und l”schen */
			{
			help->next = ptr->next;
			if (ptr->slider)
				free(ptr->slider);
			if (ptr->dialog)
				free(ptr->dialog);
			free(ptr);
			}
		}
	}
}

/* ---------------------------------------------------------------------- */
/* Suche anhand des gegebenen Window Handles die passende WINDOW Struktur */
/* Ergebnis: Adresse der WINDOW Struktur, ansonsten NULL          		  */
/* ---------------------------------------------------------------------- */
struct WINDOW *get_winfh(int wh)
{
	help = start;
	while(help)
	{
		if (help->w_handle == wh)
			return(help);
		help = help->next;
	}
	return(NULL);
}

/* ---------------------------------------------------------------------- */
/* Suche anhand des gegebenen Fensternamens die passende WINDOW Struktur  */
/* Ergebnis: Adresse der WINDOW Struktur, ansonsten NULL          		  */
/* ---------------------------------------------------------------------- */
struct WINDOW *get_winfn(char *name)
{
	help = start;
	while(help)
	{
		if (!(strcmp(help->name, name)))
			return(help);
		help = help->next;
	}
	return(NULL);
}
/**************************************************************************
 * Stellt das aktive Fenster fest                                         *
 * Output: Zeiger auf WINDOW-Struktur oder NULL                           *
 **************************************************************************/
 struct WINDOW *get_activwin(void)
 {
 int wh;
 
wind_get(0, WF_TOP, &wh, 0,0,0);     /* Oberstes Fenster ermitteln  */  
if(wh > 0)
	return(get_winfh(wh));
return NULL;
 }
  
/**************************************************************************
 * Macht das jetzige Fenster zum letzten                                  *
 * Zugriff auf globalen start-Zeiger                                      *
 **************************************************************************/
void untop_win(void)
{
struct WINDOW *win_b1,*win_b2;

if(start == NULL)
	return;
	
if( start->next != NULL)
	{
	win_b1=start;
	win_b2=start;
	wind_set(start->w_handle, WF_BOTTOM, 0,0,0,0); 

	start=start->next;    /* darunterliegende Fenster nach oben */
	while( win_b2->next != NULL)  /* letzte Fenster suchen */
		win_b2=win_b2->next;

	win_b2->next=win_b1; /* erh„lt Zeiger auf ehemals erstes Fenster     */
	win_b1->next=NULL;   /* ehemals erstes Fenster hat keinen Nachfolger */	
	wind_set(start->w_handle, WF_TOP, 0,0,0,0); 
	app_cntrl.w_handle = start->w_handle;
	if (start->type & DIAL_WINDOW)         /* blichen Reaktionen */
		start->dialog->cont = TRUE;
	if (start->type & DIAL_WINDOW)
		start->dialog->cont = TRUE;
	if(start->wtop_code) 		/* Erste Reaktion des Fensters */ 
		start->wtop_code(start);
	}
}
/* ---------------------------------------------------------------------- */
/* Kopieren einer Rechteckstruktur                                        */
/* ---------------------------------------------------------------------- */
void copy_grect(GRECT *src, GRECT *dest)
{
	dest->g_x = src->g_x;
	dest->g_y = src->g_y;
	dest->g_w = src->g_w;
	dest->g_h = src->g_h;
}

/* ---------------------------------------------------------------------- */
/* Vergleich zweier Rechteckstrukturen, Ergebnis: TRUE oder FALSE         */
/* ---------------------------------------------------------------------- */
boolean compare_grect(GRECT *r1, GRECT *r2)
{
	return((r1->g_x & r2->g_x) &
		   (r1->g_y & r2->g_y) &
		   (r1->g_w & r2->g_w) &
		   (r1->g_h & r2->g_h));
}
	
/* ---------------------------------------------------------------------- */
/* Schnittmenge zweier Rechtecke berechnen                                */
/* ---------------------------------------------------------------------- */
boolean rc_intersect(GRECT *r1, GRECT *r2)
{
	int x, y, w, h;
	
	x = max(r2->g_x, r1->g_x);
	y = max(r2->g_y, r1->g_y);
	w = min(r2->g_x + r2->g_w, r1->g_x + r1->g_w);
	h = min(r2->g_y + r2->g_h, r1->g_y + r1->g_h);
	r2->g_x = x;
	r2->g_y = y;
	r2->g_w = w - x;
	r2->g_h = h - y;
	return((boolean)((w > x) && (h > y)));
}

/* ---------------------------------------------------------------------- */
/* Bildschirmausgabe "clippen"                                            */
/* ---------------------------------------------------------------------- */
void clipping(int vdi_handle, GRECT *r, int mode)
{
	int pxy[4];
	
	pxy[0] = r->g_x;
	pxy[1] = r->g_y;
	pxy[2] = r->g_x + r->g_w - 1;
	pxy[3] = r->g_y + r->g_h - 1;
	vs_clip(vdi_handle, mode, pxy);
}

/* ---------------------------------------------------------------------- */
/* Bereich l”schen                                                        */
/* ---------------------------------------------------------------------- */
/* Alle Fllattributeinstellungen der Workstation werden gesichert und    */
/* zurckgesetzt                                                  		  */
/* ---------------------------------------------------------------------- */
void blank(struct WINDOW *win, int x, int y, int w, int h)
{
	GRECT r1, r2;
	int pxy[4];
	int attr[5];

	if(start == NULL)
		return;
		
	vqf_attributes(app_cntrl.vdi_handle, attr);
	if(win==NULL) /* Alles updaten */
		{
		win=start;
		x=app_cntrl.workarea.g_x;
		y=app_cntrl.workarea.g_y;
		w=app_cntrl.workarea.g_w;
		h=app_cntrl.workarea.g_h;
		}
	else
		{
		if(win->type&8)		
			return;	/* Dieses Fenster wird geschložen -> REDRAW sinnlos */
		}
	r2.g_x = pxy[0] = x;
	r2.g_y = pxy[1] = y;
	r2.g_w = w;
	r2.g_h = h;
	pxy[2] = x + w - 1;
	pxy[3] = y + h - 1;
	
	graf_mouse(M_OFF, 0);
	wind_get(win->w_handle, WF_FIRSTXYWH, &r1.g_x, &r1.g_y, &r1.g_w,
				&r1.g_h);
	
	while (r1.g_w && r1.g_h)
		{
		if (rc_intersect(&r2, &r1) == TRUE)
			{
			clipping(app_cntrl.vdi_handle, &r1, TRUE);
			vsf_color(app_cntrl.vdi_handle, 1);
			vsf_interior(app_cntrl.vdi_handle, 0);
			vsf_style(app_cntrl.vdi_handle, 0);
			vswr_mode(app_cntrl.vdi_handle, 0);
			vsf_perimeter(app_cntrl.vdi_handle, 0);
			wind_update(BEG_UPDATE);
			if ((win->type&3) != DIAL_WINDOW)
				{	
				if (win->type & PANEL_WINDOW)
					{
					v_bar(app_cntrl.vdi_handle, pxy);
					draw_dial(win, &r1);
					}
				if(win->draw_code)
					win->draw_code(win);
				}
			else
				draw_dial(win, &r1);
			wind_update(END_UPDATE);
			clipping(app_cntrl.vdi_handle, &r1, FALSE);
			vsf_interior(app_cntrl.vdi_handle,  attr[0]);
			vsf_color(app_cntrl.vdi_handle,     attr[1]);
			vsf_style(app_cntrl.vdi_handle,     attr[2]);
			vswr_mode(app_cntrl.vdi_handle,     attr[3]);
			vsf_perimeter(app_cntrl.vdi_handle, attr[4]);
		}
		wind_get(win->w_handle, WF_NEXTXYWH, &r1.g_x, &r1.g_y, &r1.g_w,
			      &r1.g_h);
	}
	clipping(app_cntrl.vdi_handle, &r1, FALSE);
	graf_mouse(M_ON, 0);
}


/* ---------------------------------------------------------------------- */
/* Rechteck #1 beobachten                                                 */
/* ---------------------------------------------------------------------- */
void watch_r1(int flag, GRECT *rc, void (*code)(void))
{
	if (rc)
		app_cntrl.multi_flags |= MU_M1;
	else
		app_cntrl.multi_flags &= ~MU_M1;

	app_cntrl.m1_flag = flag;
	copy_grect(rc, &app_cntrl.m1);
	app_cntrl.m1_code = code;
}

/* ---------------------------------------------------------------------- */
/* Rechteck #2 beobachten                                                 */
/* ---------------------------------------------------------------------- */
void watch_r2(int flag, GRECT *rc, void (*code)(void))
{
	if (rc)
		app_cntrl.multi_flags |= MU_M2;
	else
		app_cntrl.multi_flags &= ~MU_M2;

	app_cntrl.m2_flag = flag;
	copy_grect(rc, &app_cntrl.m2);
	app_cntrl.m2_code = code;
}

/* ---------------------------------------------------------------------- */
/* Zeitabschnitt abwarten                                                 */
/* ---------------------------------------------------------------------- */
void watch_timer(int low, int high, void (*code)(void))
{
	if (low == 0 && high == 0)
		app_cntrl.multi_flags &= ~MU_TIMER;

	else
		app_cntrl.multi_flags |= MU_TIMER;

	app_cntrl.mt_locount = low;
	app_cntrl.mt_hicount = high;
	app_cntrl.time_code  = code;
}

/* ---------------------------------------------------------------------- */
/* Ereignisse einstellen, auf die multi() reagiert                        */
/* ---------------------------------------------------------------------- */
void watch_events(int flags, int clicks, int mask, int state)
{
	app_cntrl.multi_flags = flags;
	app_cntrl.mb_clicks   = clicks;
	app_cntrl.mb_mask     = mask;
	app_cntrl.mb_state    = state;
}


/* ---------------------------------------------------------------------- */
/* Ereignisverwaltung                                                     */
/* ---------------------------------------------------------------------- */
void multi()
{
int event = 0, mmo_x, mmo_y, mm_button, mmok_state, mk_return, mb_return;
int msgbuff[8] = {0,0,0,0,0,0,0,0},
	 buffer[8]  = {0,0,0,0,0,0,0,0};
int sel_obj, obj_state;
GRECT h1,h2;
struct WINDOW *win;
struct BUTTON_LIST *button_help;
int wh;

do
{
	copy_grect(&app_cntrl.m1, &h1);
	copy_grect(&app_cntrl.m2, &h2); 
	if(app_cntrl.modal != NULL)			/* wenn modales Fenster */
		win=app_cntrl.modal;
	else
		{
		wind_get(0, WF_TOP, &wh, 0,0,0);     /* Oberstes Fenster ermitteln  */  
		win = get_winfh(app_cntrl.w_handle); 
		if(win)
			{
			/* Modale Dialogbox -> andere Aktionen sperren */
			if((win->type&MODAL)==MODAL && app_cntrl.modal == NULL )
				{
				app_cntrl.modal = win;
				menu_all_change(0);	/* alle Meneintr„ge disablen   */	  
								/* (ACC noch bedienbar !!       */
				}
			}
		}				
	/* Wenn externes Fenster 'getopped' ist und wenn es sich um einen */
	/* Dialog handelt, passiert nichts */
	if ((win) && (win->type & DIAL_WINDOW) && (win->w_handle != wh))
		win->dialog->cont = FALSE;  

	/* Wenn es ein Dialog ist und es editierbare Texte gibt, dann */
	/* wird der Cursor an der akt. Position im Text eingeschaltet */
	if ((win) && (win->type & DIAL_WINDOW) && 
		 (win->dialog->next_obj != 0) &&
		 (win->dialog->edit_obj != win->dialog->next_obj))
		{
		if (win->dialog->cont) 
			{	
			if(ObjTree(win)[win->dialog->next_obj].ob_type ==G_FTEXT 
			|| ObjTree(win)[win->dialog->next_obj].ob_type ==G_FBOXTEXT)
				win->dialog->edit_obj = win->dialog->next_obj;
			win->dialog->next_obj = 0;
			objc_edit(win->dialog->tree, win->dialog->edit_obj, 0,
		   	          &(win->dialog->idx), ED_INIT);
			}
		}

	/* Ereignisse abwarten, die im Programmdeskriptor festgelegt */
	/* wurden */
	event = evnt_multi(app_cntrl.multi_flags, app_cntrl.mb_clicks,
					   app_cntrl.mb_mask, app_cntrl.mb_state,
	                   app_cntrl.m1_flag, h1.g_x, h1.g_y, h1.g_w, h1.g_h,
	                   app_cntrl.m2_flag, h2.g_x, h2.g_y, h2.g_w, h2.g_h, 
					   msgbuff, app_cntrl.mt_locount,
					   app_cntrl.mt_hicount, &mmo_x, &mmo_y, &mm_button,
					   &mmok_state, &mk_return, &mb_return);
	
	if (event & MU_MESAG)
		{
		/* Hat das Ereignis was mit Fenstern zu tun ? */
		if (msgbuff[0] >= WM_REDRAW && WM_NEWTOP >= msgbuff[0])
			{
			if(app_cntrl.modal != NULL && (msgbuff[0] == WM_TOPPED) ) 
				{
				if(win == app_cntrl.modal)
					printf("\a");
				}
			else
				win = get_winfh(msgbuff[3]);
			if(win)
				{
				wind_update(BEG_UPDATE);
				win_manager(msgbuff[0], win, msgbuff[4],
					msgbuff[5], msgbuff[6], msgbuff[7]);
				wind_update(END_UPDATE);
				}
			}
		else 
			{
			if ((msgbuff[0] & MN_SELECTED) && app_cntrl.modal==NULL)
				menu_manager(msgbuff[3], msgbuff[4], 0);
		/* Hier kann der Programmierer im Message Manager auf andere */
		/* Nachrichten reagieren, z.B. Schnittstelle via appl_write  */
			else
				{
				if(app_cntrl.modal==NULL)
					msg_manager(msgbuff);	       
				}
			}
		}
	
	/* Wurde eine Taste bet„tigt ? */
	if (event & MU_KEYBD)
	    {
		if(app_cntrl.modal != NULL)			/* wenn modales Fenster */
			win=app_cntrl.modal;
		else
			win = get_winfh(app_cntrl.w_handle); 
		
		/* Wenn es ein Dialog ist */
		if ((win) && (win->type & DIAL_WINDOW))
		{
			/* dann bearbeite Taste und editiere den aktuellen Text */
			win->dialog->cont = form_keybd(win->dialog->tree,
										   win->dialog->edit_obj,
									       win->dialog->next_obj, mk_return, 
										   &(win->dialog->next_obj), 
										   &mk_return);
			if (!win->dialog->cont)
			{
				button_help = win->dialog->button_start;
				while(button_help->obj_index != win->dialog->next_obj)
					button_help = button_help->next;
				if (button_help->obj_index == win->dialog->next_obj)
				{
					if(button_help->action)
						button_help->action();
					obj_state = win->dialog->tree[win->dialog->next_obj].
								ob_state;
					obj_state ^= SELECTED;
					objc_change(win->dialog->tree, win->dialog->next_obj, 0, 
				   	            win->workarea.g_x, win->workarea.g_y, 
				      	        win->workarea.g_w, win->workarea.g_h, 
				         	    obj_state, 1);

					if (button_help->redraw)
						{
						buffer[0] = WM_REDRAW;
						buffer[1] = app_cntrl.ap_id;
						buffer[3] = win->w_handle;
						buffer[4] = win->workarea.g_x;
						buffer[5] = win->workarea.g_y;
						buffer[6] = win->workarea.g_w;
						buffer[7] = win->workarea.g_h;
						appl_write(app_cntrl.ap_id, 16, buffer);
						}
					}
				}						 
			if ((mk_return) && (win->dialog->cont)) 
				objc_edit(win->dialog->tree, win->dialog->edit_obj,
						  mk_return, &(win->dialog->idx), ED_CHAR);

			if ((!win->dialog->cont) || ((win->dialog->next_obj != 0) &&
				 (win->dialog->next_obj != win->dialog->edit_obj)))
				objc_edit(win->dialog->tree, win->dialog->edit_obj, 0,
				      &(win->dialog->idx), ED_END); 	
			}
/*		if (((mk_return & 0xff) < 0x20 || (mk_return & 0xff) > 0x7e)*/

		if(app_cntrl.modal == NULL)
			{
			menu_manager(0,0, mk_return);
			key_manager(mk_return);
			}
		else 
			{
			if ((win) && (win->key_code))
				win->key_code(win, (char)mk_return & 0xff);
			}
		}
		
	/* Wurde Maustaste bet„tigt ? */
	if (event & MU_BUTTON)
		{
		if(app_cntrl.modal != NULL) 
			win = app_cntrl.modal;
		else
			win = get_winfh(app_cntrl.w_handle);
        /* wenn normales Fenster */ 	
		if ((win) && (win->type&3) == DATA_WINDOW)
			{  /* innerhalb des Fensters  */
            if (check_rect(mmo_x,mmo_y,&win->workarea))
				{
				if (win->button_code)
					win->button_code(win, mmo_x, mmo_y, mm_button, mmok_state);
				}	
			else  /* aužerhalb des Fensters */
				{	
				if (app_cntrl.button_code && app_cntrl.modal == NULL)
					app_cntrl.button_code(mmo_x, mmo_y, mm_button, mmok_state);
				}
			}	
		else 
			{    /* aužerhalb der Fenster und kein eigenes Fenster aktiv */
			if ((!win) && (app_cntrl.button_code) && app_cntrl.modal == NULL )
				app_cntrl.button_code(mmo_x, mmo_y, mm_button, mmok_state);
			}
		/* Dialog und Panelfenster */		
		if ((win) && ((win->type & DIAL_WINDOW) || (win->type & PANEL_WINDOW)))
			{
			/* Bei Dialogen wird berprft, ob ein OBJECT angeklickt wurde */
			win->dialog->next_obj = objc_find(win->dialog->tree,0,8,mmo_x, mmo_y);
			/* Wenn ja, wird der Objektstatus angepažt und ggfl. ein */
			/* neuer editierbarer Text initialisiert */
			if (win->dialog->next_obj >= 0)
				{ 
				int ob_flags=ObjTree(win)[win->dialog->next_obj].ob_flags;
				sel_obj = win->dialog->next_obj;

				/* Fixing bei form_button da Fehler bei Touchexit und Exit */
				if((ob_flags&EXIT) || (ob_flags&TOUCHEXIT))
					{
					ObjTree(win)[win->dialog->next_obj].ob_state^=SELECTED;
					win->dialog->cont= FALSE;
					}
				else
					win->dialog->cont = form_button(win->dialog->tree, 
									    win->dialog->next_obj, mb_return,
									    &(win->dialog->next_obj));
				if ( ((!win->dialog->cont) || win->dialog->next_obj != 0) &&
					(win->dialog->next_obj != win->dialog->edit_obj) &&
					(win->type & DIAL_WINDOW))
						{
						objc_edit(win->dialog->tree, win->dialog->edit_obj, 0,
								  &(win->dialog->idx), ED_END); 	
						win->dialog->cont=TRUE;
						}
				/* Aktion ausfhren, die den ausgew„hlten Button betrifft */ 
				if (win->dialog->tree[sel_obj].ob_state & SELECTED)
					button_manager(mmo_x, mmo_y, mm_button, mmok_state);
				else if (win->dialog->tree[sel_obj].ob_flags & TOUCHEXIT)
					button_manager(mmo_x, mmo_y, mm_button, mmok_state);
				if (win->dialog->release)
					win->dialog->release(sel_obj, win->dialog->tree[sel_obj].ob_state);
				}
			else /* wenn kein OBJECT angeklickt worden ist */ 
				{
				if ((win->type & PANEL_WINDOW) && check_rect(mmo_x,mmo_y,&win->workarea))
					{  /* innerhalb des Panelfensters aber aužerhalb des Dialoges */
					if (win->button_code)
						win->button_code(win, mmo_x, mmo_y, mm_button, mmok_state);
					}	
				else 
					{
					if (app_cntrl.button_code && app_cntrl.modal == NULL )
					/*	{*/
						app_cntrl.button_code(mmo_x, mmo_y, mm_button, mmok_state);	
	/* ge„ndert */
						if ((win->type & DIAL_WINDOW) || ((win->dialog->next_obj != 0) &&
							 (win->dialog->next_obj != win->dialog->edit_obj)))
							{
							objc_edit(win->dialog->tree, win->dialog->edit_obj, 0,
									  &(win->dialog->idx), ED_END); 	
							win->dialog->next_obj = win->dialog->edit_obj;
							win->dialog->edit_obj = 0;
							}
				/*		} */
					}
				}
			}
		}		
	/* Wurde der Mauspfeil in ein Rechteck hinein oder aus einem Recht- */
	/* eck heraus bewegt, dann die zugeh”rige Aktion bearbeiten */
	if (event & MU_M1 && app_cntrl.modal == NULL)
		if (app_cntrl.m1_code)
			app_cntrl.m1_code();
		
	if (event & MU_M2 && app_cntrl.modal == NULL)
		if (app_cntrl.m2_code)
			app_cntrl.m2_code();
		
	/* Aktion zu einem Zeitereignis aufrufen */
	if (event & MU_TIMER && app_cntrl.modal == NULL)
		{
		if (app_cntrl.time_code)
			app_cntrl.time_code();
		}
		
	} while (!app_cntrl.quit); /* Solange bis der Anwender das Programm */
										/* verlassen m”chte */
	all_free();
	v_clsvwk(app_cntrl.vdi_handle);
	appl_exit();
}

/* ---------------------------------------------------------------------- */
/* Sliderstruktur initialisieren                                          */
/* ---------------------------------------------------------------------- */
boolean init_slider(struct WINDOW *win, int x_elements, int y_elements,
						  int x_size, int y_size)
{
	struct slide_def *ptr;
	 
	/* Ist noch genug Speicher da ? */
	if ((ptr = (struct slide_def *)calloc(1, sizeof(struct slide_def)))
		 != NULL)
	{
		win->slider = ptr;
		win->slider->x_elements = x_elements;
		win->slider->y_elements = y_elements;
		win->slider->x_size     = x_size;
		win->slider->y_size     = y_size;
		
		win->slider->x_offset   = 0;
		win->slider->y_offset   = 0;
		win->slider->x_cursor   = 0;
		win->slider->y_cursor   = 0;
			
		change_slider_size(win); /* Slidergr”žen anpassen  */
		new_slider_pos(win);
		return(TRUE);
	}
	else
	{
		form_alert(1,"[3][Slider konnte nicht|initialisiert werden!][Sorry]");
		return(FALSE);
	}
}

/* ---------------------------------------------------------------------- */
/* Hor. und vert. Slidergr”žen anpassen                                   */
/* ---------------------------------------------------------------------- */
void change_slider_size(struct WINDOW *win)
{
	float x,y;
	
	if (win->slider)
	{
	    x = 1000.0 / (float)win->slider->x_elements;
		x *= (float)win->workarea.g_w / (float)win->slider->x_size;
	    y = 1000.0 / (float)win->slider->y_elements;
		y *= (float)win->workarea.g_h / (float)win->slider->y_size;
			        
		wind_set(win->w_handle, WF_HSLSIZE, (unsigned int)x, 0, 0, 0);
		wind_set(win->w_handle, WF_VSLSIZE, (unsigned int)y, 0, 0, 0);

		if (win->workarea.g_w/win->slider->x_size+win->slider->x_offset >
			 win->slider->x_elements )
			set_x_slider(win,(int)((float)win->slider->x_elements - 
								(float)win->workarea.g_w/win->slider->x_size));

		if (win->workarea.g_h/win->slider->y_size+win->slider->y_offset >
			 win->slider->y_elements )
			set_y_slider(win,(int)((float)win->slider->y_elements - 
								(float)win->workarea.g_h/win->slider->y_size));
	}
}


/* ---------------------------------------------------------------------- */
/* Sliderposition verwalten                                               */
/* ---------------------------------------------------------------------- */
void hndl_slider_pos(struct WINDOW *win, int what, int position)
{
	long x,y;
	int  w,h;
	int sx_b,sy_b;
	static int change;
	
	sy_b=win->slider->y_offset;
	sx_b=win->slider->x_offset; /* Zwischenspeichern */
	if ((w = win->workarea.g_w / win->slider->x_size) * win->slider->x_size 
		  > win->workarea.g_w)
		w--;
   if ((h = win->workarea.g_h / win->slider->y_size) * win->slider->y_size
   	  > win->workarea.g_h)
   	h--;

	switch (what)
	{
		case PAGE_UP:
			if (win->slider->y_offset >= h)
			{
				win->slider->y_offset -= h;
				change = 2;
			}
			else if (win->slider->y_offset > 0)
			{
				win->slider->y_offset = 0;
				change = 1;
			}
			if (win->slider->y_cursor > win->slider->y_offset + h - 1)
				win->slider->y_cursor = win->slider->y_offset + h - 1;	
			break;
		
		case PAGE_DN:
			if (win->slider->y_offset + 2*h < win->slider->y_elements)
			{
				win->slider->y_offset += h;
				change = 2;
			}
			else if (win->slider->y_offset < win->slider->y_elements - h)
			{
				win->slider->y_offset = win->slider->y_elements - h;
				change = 1;
			}
			if (win->slider->y_cursor < win->slider->y_offset)
				win->slider->y_cursor = win->slider->y_offset;
			break;
			
		case PAGE_LF:
			if (win->slider->x_offset >= w)
			{
				win->slider->x_offset -= w;
				change = 2;
			}
			else if (win->slider->x_offset > 0)
			{
				win->slider->x_offset = 0;
				change = 1;
			}
			if (win->slider->x_cursor > win->slider->x_offset + w - 1)
				win->slider->x_cursor = win->slider->x_offset + w - 1;
			break;
		
		case PAGE_RT:
			if (win->slider->x_offset + 2*w < win->slider->x_elements)
			{
				win->slider->x_offset += w;
				change = 2;
			}
			else if (win->slider->x_offset < win->slider->x_elements - w)
			{
				win->slider->x_offset = win->slider->x_elements - w;
				change = 1;
			}
			if (win->slider->x_cursor < win->slider->x_elements)
				win->slider->x_cursor = win->slider->x_elements;
			break;
			
		case CLMN_LF:
			if (win->slider->x_offset > 0)
			{
				win->slider->x_offset--;
				change = 2;
				if (win->slider->x_cursor > win->slider->x_offset + w - 1)
					win->slider->x_cursor--;
			}
			else 
				change = 0;
			break;
			
		case CLMN_RT:
			if (win->slider->x_offset + w - 1 < win->slider->x_elements - 1)
			{
				win->slider->x_offset++;
				change = 2;
				if (win->slider->x_cursor < win->slider->x_offset)
					win->slider->x_cursor++;
			}
			else
				change = 0;
			break;
			
		case ROW_UP:
			if (win->slider->y_offset > 0)
			{
				win->slider->y_offset--;
				change = 2;
				if (win->slider->y_cursor > win->slider->y_offset + h - 1)
					win->slider->y_cursor--;
			}
			else
				change = 0;
			break;
			
		case ROW_DN:
			if (win->slider->y_offset + h - 1 < win->slider->y_elements - 1)
			{
				win->slider->y_offset++;
				change = 2;
				if (win->slider->y_cursor < win->slider->y_offset)
					win->slider->y_cursor++;
			}
			else
				change = 0;
			break;
			
		case H_SLIDE:
			x = win->slider->x_elements - win->workarea.g_w / 
				 win->slider->x_size;
			x *= position;
			x /= 1000;
			win->slider->x_offset = (unsigned int)x;
			change = 1;
			break;

		case V_SLIDE:
			y = win->slider->y_elements - win->workarea.g_h /
				 win->slider->y_size;
			y *= position;
			y /= 1000;
			win->slider->y_offset = (unsigned int)y; 
			change = 1;
	}

	if (change > 0 && ( win->slider->y_offset != sy_b || win->slider->x_offset!= sx_b) )
	{
		new_slider_pos(win);
	}
	if (change == 1)
		change = 0;
}


/**************************************************************************
 * Sliderposition innerhalb des Fensters setzen                           *
 * Dazu werden die einfach die Sliderkoordinaten abgefragt 				  *	
 * Input: win: Fensterverwaltungsstruktur u.a . mit den Daten fr die     *
 * 			   Slider des aktuellen Fensters							  *	
 **************************************************************************/
void new_slider_pos(struct WINDOW *win)
{
	float x,y;
			
	if (win->slider)
	{
		if(win->slider->x_offset==win->slider->x_elements)
			x=1000.0; /* wegen Quantisierung */
		else
			{
			if(win->slider->x_elements - win->workarea.g_w / 
			    win->slider->x_size!=0)
				{
				x =( 1000.0 / ((float)win->slider->x_elements 
				-(float)win->workarea.g_w /(float)win->slider->x_size));
				x *= win->slider->x_offset;
				}
			else x=0.0;
			}
		if(win->slider->y_offset==win->slider->y_elements)
			y=1000.0;
		else
			{	
			if(win->slider->y_elements - win->workarea.g_h / 
			    win->slider->y_size!=0)
				{			
				y =(1000.0 / ((float)win->slider->y_elements
				- (float)win->workarea.g_h/(float)win->slider->y_size));
				y *= win->slider->y_offset;
				}
			else y=0.0; 
			}
		wind_set(win->w_handle, WF_VSLIDE, (unsigned int)y, 0, 0, 0);
		wind_set(win->w_handle, WF_HSLIDE, (unsigned int)x, 0, 0, 0);
		/* Window Redraw erzwingen */
		blank(win, win->workarea.g_x, win->workarea.g_y,
				win->workarea.g_w, win->workarea.g_h); 
	}
}


/* ---------------------------------------------------------------------- */
/* Zeile einfgen (z.B. in Textfenster)                                   */
/* ---------------------------------------------------------------------- */
void add_rows(struct WINDOW *win, int count)
{
	win->slider->y_elements += count;
	if(win->slider->y_elements<=0) 
		win->slider->y_elements = 1;
	 			
}

/* ---------------------------------------------------------------------- */
/* Spalte einfgen                                                        */
/* ---------------------------------------------------------------------- */
void add_columne(struct WINDOW *win, int count)
{
	win->slider->x_elements += count;
	if(win->slider->x_elements<=0)
		win->slider->x_elements = 1;
}
	 
/* ---------------------------------------------------------------------- */
/* Fensterstruktur generieren                                             */
/* ---------------------------------------------------------------------- */
struct WINDOW *create_window(GRECT *max, GRECT *real, int min_w, int min_h,
									  int flags, int type, 
									  void (*draw_code)(struct WINDOW *win),
									  void (*slide_code)(struct WINDOW *win,
									                     int message),
									  void (*button_code)(struct WINDOW *win, int mx,
									  					  int my, int mb, int ks),
									  void (*key_code)(struct WINDOW *win,
									  						 char ascii),
									  void (*wtop_code)(struct WINDOW *win),
									  int  (*close_code)(struct WINDOW *win))

{
	int wh;
	struct WINDOW *ptr;
	
	if(start) /* eventuell im letzen Fensters Cursor ausschalten */
		{
		if( start->type & DIAL_WINDOW)
			{
			if(ObjTree(start)[start->dialog->edit_obj].ob_type ==G_FTEXT 
			|| ObjTree(start)[start->dialog->edit_obj].ob_type ==G_FBOXTEXT)
			objc_edit(start->dialog->tree, start->dialog->edit_obj, 0,
    	    &(start->dialog->idx), ED_END); 	
			}
		}
	ptr = alloc_window();
	if (!ptr)
	{
		form_alert(1,"[3][Kein Speicher frei!|Kann Fenster nicht ”ffnen.]"
					  "[Abbruch]");	
		return(FALSE);
	} 
	
	if ((wh =  wind_create(flags, max->g_x, max->g_y, max->g_w, 
		  max->g_h)) < 0)
	{	
		form_alert(1,"[3][Zuviele Fenster offen!|Bitte schliežen Sie ein|"
					  "nicht mehr ben”tigtes Fenster.][Okay]");
		return(FALSE);
	}
	
	/* Struktur initialisieren */
	ptr->w_handle    = wh;
	ptr->type        = (type&7); 	
	if (type & DATA_WINDOW)
		ptr->dialog   = NULL;
	ptr->fulled      = compare_grect(max, real);
	ptr->flags       = flags;
	ptr->min_w       = min_w;
	ptr->min_h       = min_h;
	ptr->draw_code   = draw_code;
	ptr->slide_code  = slide_code;
	ptr->key_code    = key_code;
	ptr->button_code = button_code;
	ptr->wtop_code   = wtop_code;
	ptr->close_code   = close_code;
	ptr->slider      = NULL;
	copy_grect(real, &ptr->actual_position);

	return(ptr);
}


/* ---------------------------------------------------------------------- */
/* Panel-Window generieren                                                */
/* ---------------------------------------------------------------------- */
struct WINDOW *create_pwindow(int obj_name, GRECT *max, GRECT *real,
							  int min_w, int min_h, int flags,int modal,
							  int align,
							  void (*draw_code)(struct WINDOW *win),
							  void (*slide_code)(struct WINDOW *win, 
    											 int message),
						      void (*button_code)(struct WINDOW *win, int mx,
				  		  					      int my, int mb, int ks),
						      void (*key_code)(struct WINDOW *win,
					    					   char ascii),
						      void (*wtop_code)(struct WINDOW *win),

						      void (*release)(int obj_index, int obj_state))
{
	struct WINDOW *ptr;
	OBJECT *tree;
	int msgbuff[8] = {0,0,0,0,0,0,0,0};
	int type_flag= PANEL_WINDOW;

	if (rsrc_gaddr(0, obj_name, &tree))
	{
		help = start;
		while (help)
		{
			if ((help->dialog) && (help->dialog->tree) && 
				 (help->dialog->tree == tree))
			{
				msgbuff[0] = WM_TOPPED;
				msgbuff[1] = app_cntrl.ap_id;
				msgbuff[3] = help->w_handle;
				appl_write(app_cntrl.ap_id, 16, msgbuff);
				return(NULL);
			}
			help = help->next;
		}
		if(modal)
			type_flag|=MODAL;
		ptr = create_window(max, real, min_w, min_h, flags, type_flag,
								  draw_code, slide_code, button_code
								  	, key_code,wtop_code,0);
		if (!ptr)
			return(NULL);
		
		ptr->dialog = (struct dial *)calloc(1, sizeof(struct dial));
		if (!ptr->dialog)
			return(NULL);
		
		ptr->dialog->tree    = tree;
		ptr->dialog->release = release;
		ptr->dialog->align   = align;
		return(ptr);
	}
	else
		return(NULL);
}
																										 

/* ---------------------------------------------------------------------- */
/* Fenster ”ffnen                                                         */
/* ---------------------------------------------------------------------- */
void open_window(struct WINDOW *win, char *name, char *info) 
{
	strcpy(win->name, name);
	wind_set(win->w_handle, WF_NAME, win->name, 0, 0);
	if (win->flags & INFO)
	{
		strcpy(win->info, info);
		wind_set(win->w_handle, WF_INFO, win->info, 0, 0);
	}
	else
		strcpy(win->info, "\0");

	graf_growbox(0,0,0,0, win->actual_position.g_x, win->actual_position.g_y,
				 win->actual_position.g_w, win->actual_position.g_h);
	wind_open(win->w_handle, win->actual_position.g_x, win->actual_position.g_y,
			  win->actual_position.g_w, win->actual_position.g_h);
	wind_get(win->w_handle, WF_WORKXYWH, &win->workarea.g_x, &win->workarea.g_y,
		     &win->workarea.g_w, &win->workarea.g_h);

	if (win->slider)
		change_slider_size(win);
	
	if (win->type & DIAL_WINDOW)
		align_dial(win);
		
	if (win->type & PANEL_WINDOW)
		align_panel(win);
		
	/* Window Handle in Programmdeskriptor eintragen */
	app_cntrl.w_handle = win->w_handle;
	blank(win, win->workarea.g_x, win->workarea.g_y,
			win->workarea.g_w, win->workarea.g_h);  /* REDRAW erzwingen */
	if(win->wtop_code!=NULL) /* Erste Reaktion des Fensters */ 
		win->wtop_code(win);

}	


/* ---------------------------------------------------------------------- */
/* PANEL an Fensterkoordinaten anpassen                                   */
/* ---------------------------------------------------------------------- */
void align_panel(struct WINDOW *win)
{
	win->dialog->tree->ob_x = win->workarea.g_x;
	win->dialog->tree->ob_y = win->workarea.g_y;
		
	switch(win->dialog->align)
	{
		case ALIGN_X:
			win->dialog->tree->ob_width = win->workarea.g_w;
			win->workarea.g_y += win->dialog->tree->ob_height;
			win->workarea.g_h -= win->dialog->tree->ob_height;
			break;
		case ALIGN_Y:
			win->dialog->tree->ob_height = win->workarea.g_h;
			win->workarea.g_x += win->dialog->tree->ob_width;
			win->workarea.g_w -= win->dialog->tree->ob_width;
	}
}


/* ---------------------------------------------------------------------- */
/* DIALOG an Fensterkoordinaten anpassen                                  */
/* ---------------------------------------------------------------------- */
void align_dial(struct WINDOW *win)
{
	win->dialog->tree->ob_x = win->workarea.g_x;
	win->dialog->tree->ob_y = win->workarea.g_y;
	win->dialog->tree->ob_width = win->workarea.g_w;
	win->dialog->tree->ob_height = win->workarea.g_h;
}

/* ---------------------------------------------------------------------- */
/* Window Manager                                                         */
/* ---------------------------------------------------------------------- */
void win_manager(int msg, struct WINDOW *ptr, int x, int y, int w, int h)
{
	int act_wh;
	struct WINDOW *win;
	if(ptr==NULL)
		{
		printf("\n The worst case in the win_manager!");
		return; /* Das schlimmste verhindern (kommt manchmal vor !)*/
		}
		
	switch(msg)
	{
		case WM_REDRAW:            /* Window wird neu gezeichnet */
			blank(ptr, x,y,w,h);
			if (ptr->type & DIAL_WINDOW) /* Wenn Dialog, dann prfe, ob */
			{                            /* Fenster ganz oben liegt */
				wind_get(0, WF_TOP, &act_wh, 0,0,0);
				if (act_wh == ptr->w_handle) /* Wenn ja, erzwinge */
				{                            /* Cursor Redraw     */
					ptr->dialog->cont     = TRUE;
					ptr->dialog->next_obj = ptr->dialog->edit_obj;
					ptr->dialog->edit_obj = 0;
				}
			}
			break;
		case WM_CLOSED:      /* Fenster soll geschlossen werden */
			if(ptr->close_code!=NULL)   /* POWERGEM-Nutzer gibt frei */
				if(ptr->close_code(ptr) !=0 )
					break;    /* Will es der POWERGEM-Nutzer auch ? */
			if(app_cntrl.modal != NULL)
				{
				app_cntrl.modal=NULL; /* Fenster nach schliežen der modalen
								  Dialogbox freigeben */
				menu_all_change(1); /* Men wie vorher an */
				}
			wind_get(ptr->w_handle, WF_CURRXYWH, &x, &y, &w, &h);
			graf_shrinkbox(0,0,0,0, x,y,w,h);
			wind_close(ptr->w_handle); 
			wind_delete(ptr->w_handle); /* Alles, was mit dem Fenster zusam- */
			if (ptr->type & DIAL_WINDOW || (ptr->type & PANEL_WINDOW))
				kill_button(ptr);
			kill_window(ptr->w_handle); /* menh„ngt, wird aus dem Speicher   */
			wind_get(0, WF_TOP, &(app_cntrl.w_handle), 0,0,0); /* entfernt   */
			ptr=get_winfh(app_cntrl.w_handle);
			if(ptr)
				{
				if(ptr->wtop_code) /* das Fenster darunter wurde somit   */
					ptr->wtop_code(ptr);/* unfreiwillig getoppt          */  
				}	
			break;
		case WM_MOVED:  /* Fenster wurde verschoben/vergr”žert/verkleinert */
		case WM_SIZED:  /* Neue Fensterausmaže erfragen */
			wind_set(ptr->w_handle, WF_CURRXYWH, x,y,max(ptr->min_w,
	    		  min(w,ptr->actual_position.g_w)), max(ptr->min_h,
	    		  		min(h,ptr->actual_position.g_h)));

			wind_get(ptr->w_handle, WF_WORKXYWH, &ptr->workarea.g_x, &ptr->workarea.g_y,
						&ptr->workarea.g_w, &ptr->workarea.g_h);
			  
			if (ptr->type & DIAL_WINDOW) /* Bei Dialogen wird die OBJECT- */
				align_dial(ptr);

			if (ptr->type & PANEL_WINDOW)
				align_panel(ptr);

			change_slider_size(ptr);
			break;
		case WM_TOPPED: /* Neues Fenster soll nach oben gebracht werden */
		case WM_NEWTOP:
			win=start; /* evtl. Cursor im alten Fenster aus !*/
			if(win)
				{
				if( win->type & DIAL_WINDOW)
					{
					if(ObjTree(win)[win->dialog->edit_obj].ob_type ==G_FTEXT 
					|| ObjTree(win)[win->dialog->edit_obj].ob_type ==G_FBOXTEXT)
					objc_edit(win->dialog->tree, win->dialog->edit_obj, 0,
						  &(win->dialog->idx), ED_END); 	
					}
				}
			wind_set(ptr->w_handle, WF_TOP, 0,0,0,0);
			win = get_winfh(app_cntrl.w_handle);
			if(!win)
				break;
			if (win->type & DIAL_WINDOW)
				win->dialog->cont = FALSE;
			app_cntrl.w_handle = ptr->w_handle;
			win = get_winfh(ptr->w_handle);
			if(!win)
				printf("\n Great mistake 2 in win_manager !");
			if (win->type & DIAL_WINDOW)
				win->dialog->cont = TRUE;
			if(win->wtop_code) 		/* Erste Reaktion des Fensters */ 
				win->wtop_code(win);
			sort_win_by_top(win);  /* Pointer neu sortieren */
			break;
		case WM_FULLED: /* Fenster auf volle Gr”že/letzte Position bringen */
			if ((ptr->fulled ^= TRUE))
				wind_get(ptr->w_handle, WF_FULLXYWH, &x, &y, &w, &h);
			else
				wind_get(ptr->w_handle, WF_PREVXYWH, &x, &y, &w, &h);
			wind_set(ptr->w_handle, WF_CURRXYWH, x,y,w,h);
			wind_get(ptr->w_handle, WF_WORKXYWH, &ptr->workarea.g_x, &ptr->workarea.g_y,
						&ptr->workarea.g_w, &ptr->workarea.g_h); 	 	

			if (ptr->type & PANEL_WINDOW)
				align_panel(ptr);

  			change_slider_size(ptr);			
			break;
		case WM_ARROWED: /* Sliderverwaltung */
			hndl_slider_pos(ptr, x, 0);
			break;
		case WM_VSLID:
			hndl_slider_pos(ptr, V_SLIDE, x);
			break;
		case WM_HSLID:
			hndl_slider_pos(ptr, H_SLIDE, x);
	}
}



/* ---------------------------------------------------------------------- */
/* Auskunftsfunktionen                                                    */
/* ---------------------------------------------------------------------- */
/************************************************
 * Arbeitsbereich eines  Fensters bzw. des      * 
 * Desktops ermitteln			    		    *
 * Input: win Zeiger auf Window-Struktur        *
 *            (bei Null -> Desktop-Koordinaten) *
 * 		  rc  Zeiger auf Rechteckstruktur fr   *
 *            Ergebnisdaten						*
 ************************************************/
void get_workarea(struct WINDOW *win, GRECT *rc)
{
if(win)	
	copy_grect(&win->workarea, rc);
else
	copy_grect(&app_cntrl.workarea, rc);
}	

/* ---------------------------------------------------------------------- */
/* Fensterposition ermitteln                                              */
/* ---------------------------------------------------------------------- */
void get_winpos(struct WINDOW *win, GRECT *rc)
{
	copy_grect(&win->actual_position, rc);
}

/**************************************************************************
 * Horizontale Sliderposition abfragen									  *
 * Input: win Zeiger auf aktuelle Fensterverwaltungsstruktur			  *
 **************************************************************************/
int get_y_slider(struct WINDOW *win)
{
if(win)
	{
	if(win->slider)
		return(win->slider->y_offset);
	}
return 0;	
}

/**************************************************************************
 * Vertikale Sliderposition abfragen									  *
 * Input: win Zeiger auf aktuelle Fensterverwaltungsstruktur			  *
 **************************************************************************/
int get_x_slider(struct WINDOW *win)
{
if(win)
	{
	if(win->slider)
		return(win->slider->x_offset);
	}
return 0;	
}

/* ---------------------------------------------------------------------- */
/* Žnderungsfunktionen                                                    */
/* ---------------------------------------------------------------------- */
/***************************
 * Setzt die Mausposition  *
 ***************************/
void set_mousepos(int x,int y)
{
int buf[4];
buf[0]=0;		/* muž null sein  		 */
buf[1]=2;		/* Code fr Mausbewegung */
buf[2]=x;		/* x-Koordinate			 */
buf[3]=y;		/* y-Koordinate			 */
appl_tplay(&buf[0],1,100); /* abspielen  */
}
/**************************************************************************
 * Horizontale Sliderposition setzen evtl. Unter/berschreitungen		  *
 * werden erkannt und korrigiert 										  *
 * Slider wird upgedatet												  *	
 * Input: win Zeiger auf aktuelle Fensterverwaltungsstruktur			  *
 *        new neuer Wert												  *	
 **************************************************************************/
void set_y_slider(struct WINDOW *win,int new_y_offset)
{
int h;

if(win)
	{
	if(win->slider)
		{	
		if((h = win->workarea.g_h / win->slider->y_size) 
		* win->slider->y_size > win->workarea.g_h)
			h--;

		if(new_y_offset < 0)
			new_y_offset=0;
		else
			if((long)new_y_offset + (long)h > (long)win->slider->y_elements)
				new_y_offset=  win->slider->y_elements-h;			
			
		if(new_y_offset == win->slider->y_offset)
			return;
		else
			{
			win->slider->y_offset=new_y_offset;
			new_slider_pos(win); /* Slider updaten */
			}
		}
	}
}
/**************************************************************************
 * Vertikale Sliderposition setzen evtl. Unter/berschreitungen		  	  *
 * werden erkannt und korrigiert 										  *
 * Input: win Zeiger auf aktuelle Fensterverwaltungsstruktur			  *
 *        new neuer Wert												  *	
 **************************************************************************/
void set_x_slider(struct WINDOW *win,int new_x_offset)
{
int w;

if(win)
	{
	if(win->slider)
		{
		if((w = win->workarea.g_w / win->slider->x_size) 
		* win->slider->x_size > win->workarea.g_w)
			w--;
		if(new_x_offset < 0)
			new_x_offset=0;
		else
			if((long)new_x_offset + (long)w > (long)win->slider->x_elements)
				new_x_offset=  win->slider->x_elements-w;			

		if(new_x_offset < 0)
			new_x_offset=0;

		if(win->slider->x_offset == new_x_offset)
			return;
		else
			{
			win->slider->x_offset=new_x_offset;
			new_slider_pos(win); /* Slider updaten */
			}
		}
	}
}
	
 
/* ---------------------------------------------------------------------- */
/* Fensterposition setzen                                                 */
/* ---------------------------------------------------------------------- */
void set_winpos(struct WINDOW *win, GRECT *rc)
{
	copy_grect(rc, &win->actual_position);
}
/* ---------------------------------------------------------------------- */
/* Dialog Manager                                                         */
/* ---------------------------------------------------------------------- */
/* Dialog erzeugen                        										  */
/* ---------------------------------------------------------------------- */
struct WINDOW *create_dial(int obj_name, int start_obj, int wi_flags,int modal, 
						   void (*slide_code)(struct WINDOW *win,
						 				      int message), 
						   void (*button_code)(struct WINDOW *win, int mx,
												   int my, int mb, int ks),
						   void (*key_code)(struct WINDOW *win,
										    char ascii),
					   	  void (*wtop_code)(struct WINDOW *win),

						   void (*release)(int obj_index, int obj_state))		 					  
{
	struct WINDOW *win;
	OBJECT *tree;
	GRECT r1 = {0,0,0,0}, r2 = {0,0,0,0};
	int msgbuff[8] = {0,0,0,0,0,0,0,0};
	int type_flag=DIAL_WINDOW;
	int mx,my,dummy;

	if(modal)
		type_flag|=MODAL;				

	if (rsrc_gaddr(0, obj_name, &tree))
	{
		help = start;
		while (help)
		{
			if ((help->dialog) && (help->dialog->tree) && 
				 (help->dialog->tree == tree))
			{
				msgbuff[0] = WM_TOPPED;
				msgbuff[1] = app_cntrl.ap_id;
				msgbuff[3] = help->w_handle;
				appl_write(app_cntrl.ap_id, 16, msgbuff);

				if(!(help->type & DIAL_WINDOW))
					return(NULL);
				help->dialog->next_obj = fm_inifld(help->dialog->tree, start_obj);
				help->type        = type_flag&7; 	
			    help->slide_code  = slide_code;
				help->button_code = button_code;
				help->key_code    = key_code;						    
				help->wtop_code   = wtop_code;
				help->dialog->release = release;
				return(help); /* es l„žt sich darber streiten ob
				NULL oder help (Es wurde dementsprechend vorher 
				diese Dialogbox mit z. B. evtl. anderen ! TEXTEN geschložen).  
				Vorsicht ist trotzdem geboten ! */	
			}
			help = help->next;
		}

		wind_get(0, WF_WORKXYWH, &r1.g_x, &r1.g_y, &r1.g_w, &r1.g_h);
	
		r2.g_x = tree->ob_x;
		r2.g_y = tree->ob_y;
		r2.g_w = tree->ob_width;
		r2.g_h = tree->ob_height;
		wind_calc(0, wi_flags, r2.g_x, r2.g_y, r2.g_w, r2.g_h,
				    &r2.g_x, &r2.g_y, &r2.g_w, &r2.g_h);
		
		/* unter der Maus positionieren */
		graf_mkstate( &mx,&my,&dummy,&dummy);
		r2.g_x= mx + r2.g_w/2; 
		r2.g_y= my + r2.g_h/2;
		r2.g_x=  min(r2.g_x - r2.g_w,app_cntrl.workarea.g_x +
		app_cntrl.workarea.g_w -r2.g_w);
		
		r2.g_y=  min(r2.g_y - r2.g_h,app_cntrl.workarea.g_y +
		app_cntrl.workarea.g_h -r2.g_h);
		r2.g_x = max(r2.g_x,app_cntrl.workarea.g_x);
		r2.g_y = max(r2.g_y,app_cntrl.workarea.g_y);
		
		win = create_window(&r1, &r2, tree->ob_width, tree->ob_height,
								  wi_flags, type_flag, 0, slide_code, button_code,
								  key_code,wtop_code,0);
		if (!win)
			return(NULL);		
	
		wind_calc(1, wi_flags, r2.g_x, r2.g_y, r2.g_w, r2.g_h,
					 &r2.g_x, &r2.g_y, &r2.g_w, &r2.g_h);
		tree->ob_x = r2.g_x;
		tree->ob_y = r2.g_y; 
	
		win->dialog = (struct dial *)calloc(1, sizeof(struct dial));
		if (!win->dialog)
			return(NULL);
		
		win->dialog->release = release;
		win->dialog->tree = tree;
		win->dialog->cont = TRUE;
		win->dialog->next_obj = fm_inifld(win->dialog->tree, start_obj);
		win->dialog->edit_obj = 0;
		return(win);
	}
	else
		return(NULL);
}   


void draw_dial(struct WINDOW *win, GRECT *rc)
{
	objc_draw(win->dialog->tree, 0,MAX_DEPTH, 
	                              rc->g_x, rc->g_y, rc->g_w, rc->g_h);
}

void draw_object(struct WINDOW *win,int obj_index)
	{
	int x,y,w,h;

	x=win->dialog->tree[obj_index].ob_x + win->dialog->tree[0].ob_x;
	y=win->dialog->tree[obj_index].ob_y + win->dialog->tree[0].ob_y;;
	w=win->dialog->tree[obj_index].ob_width + win->dialog->tree[0].ob_width;
	h=win->dialog->tree[obj_index].ob_height + win->dialog->tree[0].ob_height;
	objc_draw( win->dialog->tree,obj_index,0,x,y,w,h);
	}

int fm_inifld(OBJECT *tree, int start_obj)
{
	if (start_obj == 0)
		start_obj = find_obj(tree);
	return(start_obj);
}
 

int find_obj(OBJECT *tree)
{
	int obj = 0;
	
	while (!(tree[obj].ob_flags & LASTOB))
	{
		if (tree[obj].ob_flags & EDITABLE)
			return(obj);
		obj++;
	}
	return(0);
}

/* ---------------------------------------------------------------------- */
/* Button Manager																			  */
/* ---------------------------------------------------------------------- */
/* DESKTOP Button-Funktion anmelden                                       */
/* ---------------------------------------------------------------------- */
void set_button_fnc(void (*button_code)(int m_x, int m_y, int mb_state,
				        int k_state))
{
	app_cntrl.button_code = button_code;
}


/* ---------------------------------------------------------------------- */
/* Speicher fr Button-Ereignis alloziieren                               */
/* ---------------------------------------------------------------------- */
struct BUTTON_LIST *alloc_button(struct WINDOW *win)
{
	struct BUTTON_LIST *help;

	help = win->dialog->button_start;
	win->dialog->button_start = (struct BUTTON_LIST *)calloc(1,
								 sizeof(struct BUTTON_LIST));
	win->dialog->button_start->next = help;
	return(win->dialog->button_start);
}


/* ---------------------------------------------------------------------- */
/* Button-Ereignis anmelden                                               */
/* ---------------------------------------------------------------------- */
void button_action(struct WINDOW *win, int obj_index, void (*action)(void),
						 boolean redraw)
{
	struct BUTTON_LIST *ptr;
	ptr = alloc_button(win);
	if (ptr)
	{
	 	ptr->tree      = win->dialog->tree;
		ptr->obj_index = obj_index;
		ptr->action    = action;
		ptr->redraw    = redraw;
	}
}


/* ---------------------------------------------------------------------- */
/* Button-Ereignisse bearbeiten     												  */
/* ---------------------------------------------------------------------- */
void button_manager(int m_x, int m_y, int m_button, int k_state)
{
	struct BUTTON_LIST *help;

	int obj_index, obj_state;
	struct WINDOW *win;
	int buffer[8] = {0,0,0,0,0,0,0,0};
	
	win = get_winfh(app_cntrl.w_handle);
	if(!win)
		{printf("\n Great Error in button_manager");return;}
	
	if ((win->type & DIAL_WINDOW) || (win->type & PANEL_WINDOW))
	{
		if ((obj_index = objc_find(win->dialog->tree, 0, 8, m_x, m_y)) >= 0)
			{
			help = win->dialog->button_start;
			while (help) 
				{
				if (obj_index == help->obj_index)
					{
					if ((win->dialog->tree[obj_index].ob_flags & TOUCHEXIT))
						{
						obj_state = win->dialog->tree[obj_index].ob_state;
						obj_state ^= SELECTED;
						objc_change(win->dialog->tree, obj_index, 0, 
					   	         win->workarea.g_x, win->workarea.g_y, 
					      	      win->workarea.g_w, win->workarea.g_h, 
					         	   obj_state, 1);
						}
					
					if(help->action);
						help->action();
	
					if (help->redraw)
						{
						buffer[0] = WM_REDRAW;
						buffer[1] = app_cntrl.ap_id;
						buffer[3] = win->w_handle;
						buffer[4] = win->workarea.g_x;
						buffer[5] = win->workarea.g_y;
						buffer[6] = win->workarea.g_w;
						buffer[7] = win->workarea.g_h;
						appl_write(app_cntrl.ap_id, 16, buffer);
						}

					break;
					}
				help = help->next;
				}
			}
		else
			if(win->button_code)
				win->button_code(win, m_x, m_y, m_button, k_state); 
	}
}


/* ---------------------------------------------------------------------- */
/* Button-Liste freigeben  															  */
/* ---------------------------------------------------------------------- */
void kill_button(struct WINDOW *win)
{
	struct BUTTON_LIST *help;

	help = win->dialog->button_start;
	while(win->dialog->button_start)
	{
		win->dialog->button_start = help->next;
		free(help);
		help = win->dialog->button_start;
	}
}
	
	

/* ---------------------------------------------------------------------- */
/* Dialog abbrechen (bsp. "Abbruch" - Button im Dialog gedrckt)          */
/* ---------------------------------------------------------------------- */
void break_dial(void)
{
break_win(get_winfh(app_cntrl.w_handle));
}
/*********************************************************
 * Fenster schliežen, so ist es auch m”glich, Fenster 	 *
 * per Tastatur zu schliežen.							 *	
 * Input: win	zu schliežendes Fenster					 *
 *********************************************************/
void break_win(struct WINDOW *win)
{
int buffer[8] = {0,0,0,0,0,0,0,0};

if (win)
	{
	win->type|=CLOSED;/* Kennung, so daž keine sinnlosen REDRAWS */
	buffer[0] = WM_CLOSED;
	buffer[1] = app_cntrl.ap_id;
	buffer[3] = win->w_handle;
	appl_write(app_cntrl.ap_id, 16, buffer);
	}
}
/******************************************************************
 * Adresse eines Zeichenbuffers in TEDINFO-Struktur eintragen     *        
 * und updaten 													  *			
 * Input: win Fensterstruktur 									  *
 *        obj_index upzudatendes Objekt							  *
 *        buf Zeiger auf neuen Text								  *
 *		  lenght L„nge des Textes								  *			
 *        redraw Sofortiges Redraw bei TRUE 					  *
 ******************************************************************/
void set_text(struct WINDOW *win, int obj_index, char *buf, int length,
														boolean redraw)
{
if(!win)
	return;
win->dialog->tree[obj_index].ob_spec.tedinfo->te_ptext  = buf;
win->dialog->tree[obj_index].ob_spec.tedinfo->te_txtlen = length+1;

if(redraw ==TRUE) /* REDRAW */
	{
	int x,y,w,h;
	x=win->dialog->tree[obj_index].ob_x + win->dialog->tree[0].ob_x;
	y=win->dialog->tree[obj_index].ob_y + win->dialog->tree[0].ob_y;;
	w=win->dialog->tree[obj_index].ob_width;
	h=win->dialog->tree[obj_index].ob_height;
    blank(win, x, y, w, h);
	}
}
/********************************************************
 * Testet ob bergebene Koordinatenpaar innerhalb       *
 * eines Rechteckes sind.                               *
 * Input: x    x-Koordinate                             *  
 *        y    y-Koordinate                             *
 *        rect Zeiger auf Rechteckkoordinaten           *                   
 * Output: TRUE innerhalb des Rechteckes                *
 *         FALSE aužerhalb                              *              
 ********************************************************/
boolean check_rect(int x,int y,GRECT *rect)
{
if(x >= rect->g_x && y >= rect->g_y &&
   x <= (rect->g_x + rect->g_w) && y <= (rect->g_y + rect->g_h))
	return TRUE;

return FALSE;
}
/* ---------------------------------------------------------------------- */
/* Button selektieren 																	  */
/* ---------------------------------------------------------------------- */
void select_btn(struct WINDOW *win, int obj_index, boolean redraw)
{
	if ((win) && (obj_index != 0) && (!(win->dialog->tree[obj_index].ob_state
		 & SELECTED)))
		objc_change(win->dialog->tree, obj_index, 0, win->workarea.g_x,
						win->workarea.g_y, win->workarea.g_w, win->workarea.g_h,
						win->dialog->tree[obj_index].ob_state | SELECTED, redraw);
}


/* ---------------------------------------------------------------------- */
/* Button deselektieren                                                   */
/* ---------------------------------------------------------------------- */
void unselect_btn(struct WINDOW *win, int obj_index, boolean redraw)
{
	if ((win) && (obj_index != 0) && (win->dialog->tree[obj_index].ob_state 
		 & SELECTED))
		objc_change(win->dialog->tree, obj_index, 0, win->workarea.g_x,
					   win->workarea.g_y, win->workarea.g_w, win->workarea.g_h,
					   win->dialog->tree[obj_index].ob_state ^ SELECTED, redraw);
}



/* ---------------------------------------------------------------------- */
/* Button selektiert ?  --> TRUE oder FALSE                               */
/* ---------------------------------------------------------------------- */
boolean get_objstate(struct WINDOW *win, int obj_index)				   
{
	return(win->dialog->tree[obj_index].ob_state & SELECTED);
}
	
/* ---------------------------------------------------------------------- */
/* Key Manager                                                            */
/* ---------------------------------------------------------------------- */
/* Speicher fr Tastatur-Ereignis alloziieren									  */
/* ---------------------------------------------------------------------- */
struct KEY_LIST *alloc_key()
{
	struct KEY_LIST *help;
	
	help = key_start;
	key_start = (struct KEY_LIST *)calloc(1, sizeof(struct KEY_LIST));
	key_start->next = help;
	return(key_start);
}


/* ---------------------------------------------------------------------- */
/* Tastatur-Ereignis anmelden   														  */
/* ---------------------------------------------------------------------- */
void key_action(int code, void (*action)(void))
{
	struct KEY_LIST *ptr;
	ptr = alloc_key();
	if (ptr)
	{
	 	ptr->code   = code;
		ptr->action = action;
	}
}


/* ---------------------------------------------------------------------- */
/* Tastatur-Ereignisse bearbeiten                                         */
/* ---------------------------------------------------------------------- */
void key_manager(int code)
{
	struct KEY_LIST *help;
	
	help = key_start;

	while (help)
	{
		if (code == help->code)
			if(help->action)
				help->action();
		help = help->next;
	} 
}	



/* ---------------------------------------------------------------------- */
/* Key-Liste freigeben																	  */
/* ---------------------------------------------------------------------- */
void kill_key(void)
{
	struct KEY_LIST *help;

	help = key_start;
	while(key_start)
	{
		key_start = help->next;
		free(help);
		help = key_start;
	}
}

/* ---------------------------------------------------------------------- */
/* Menu Manager 																			  */
/* ---------------------------------------------------------------------- */
/* Speicher fr Men-Ereignis reservieren                                 */
/* ---------------------------------------------------------------------- */                 
struct MENU_LIST *alloc_menu(void)
{
	struct MENU_LIST *help;

	help = menu_start;
	menu_start = (struct MENU_LIST *)calloc(1, sizeof(struct MENU_LIST));
	menu_start->next = help;
	return(menu_start);
}


/* ---------------------------------------------------------------------- */
/* Men-Ereignis anmelden                                                 */
/* ---------------------------------------------------------------------- */
void menu_action(int title, int item, int scan_code, void (*action)(void))
{
	struct MENU_LIST *ptr;
	ptr = alloc_menu();
	if (ptr)
	{
	 	ptr->title     = title;
		ptr->item      = item;
		ptr->scan_code = scan_code;
		ptr->action    = action;
	}
} 
/*******************************************
 * Meneintr„ge ein/auschalten             *
 * Input: menu_flag 0 ALLE auschalten 	   *
 *                  1 Zustand rcksetzen   *
 *******************************************/
void menu_all_change(int menu_flag)		  
{
struct MENU_LIST *help;
	
help = menu_start;
while(help)
	{
	menu_ienable( app_cntrl.menu,help->item,menu_flag );

	if(((app_cntrl.menu+help->item)->ob_state&DISABLED) == 0 &&
		menu_flag==0)
		menu_ienable( app_cntrl.menu,help->item,0);

	if(((app_cntrl.menu+help->item)->ob_state&DISABLED) == 1 &&
		menu_flag==1)
		menu_ienable( app_cntrl.menu,help->item,1);
	
	help = help->next;
	}
}

/* ---------------------------------------------------------------------- */
/* Men-Ereignisse bearbeiten                                             */
/* ---------------------------------------------------------------------- */
void menu_manager(int title, int item, int scan_code)
{
	struct MENU_LIST *help;
	OBJECT *menue;
	menue=get_app_cntrl()->menu;
	help = menu_start;

	while (help)
	{
		if (((title == help->title && item == help->item) ||
			 (scan_code == help->scan_code)) && 	
			 (((menue+help->item)->ob_state&DISABLED) == 0)) 
			 
		{
			if(help->action)
				help->action();
			menu_tnormal(app_cntrl.menu, title, 1);
			return;
		}
		help = help->next;
	} 		
}	


/* ---------------------------------------------------------------------- */
/* Menu-Liste freigeben                                                   */
/* ---------------------------------------------------------------------- */
void kill_menu()
{
	struct MENU_LIST *help;

	help = menu_start;
	while(menu_start)
	{
		menu_start = help->next;
		free(help);
		help = menu_start;
	}
}

/*------------------------------------------------------------------------*/
/* Message Manager               													  */
/*------------------------------------------------------------------------*/
/* Speicher fr Message-Ereignis alloziieren                              */
/* ---------------------------------------------------------------------- */
struct MSG_LIST *alloc_msg(void)
{
	struct MSG_LIST *help;
	
	help = msg_start;
	msg_start = (struct MSG_LIST *)calloc(1, sizeof(struct MSG_LIST));
	msg_start->next = help;
	return(msg_start);
}



/*------------------------------------------------------------------------*/
/* Message-Ereignis anmelden                                              */
/* ---------------------------------------------------------------------- */
void msg_action(int event, void (*action)(int *))
{
	struct MSG_LIST *ptr;
	ptr = alloc_msg();
	if (ptr)
	{
	 	ptr->event  = event;
		ptr->action = action;
	}
}



/*------------------------------------------------------------------------*/
/* Message-Ereignisse bearbeiten                                          */
/* ---------------------------------------------------------------------- */
void msg_manager(int *event)
{
	struct MSG_LIST *help;
	
	help = msg_start;
	while (help) 
	{
		if (event[0] == help->event)
			help->action(event);
		help = help->next;
	} 
}	



/*------------------------------------------------------------------------*/
/* Message-Liste freigeben                                                */
/* ---------------------------------------------------------------------- */
void kill_msg()
{
	struct MSG_LIST *help;

	help = msg_start;
	while(msg_start)
	{
		msg_start = help->next;
		free(help);
		help = msg_start;
	}
}
/* EOF */