/*****************************************************************************\
 * $VER: TetrisQ_playerctrl.c 1.4                                            *
 *                               DICE/LATTICE C/SAS C/AZTEC C + AmigaOS 2.04 *
 *                 _                                                         *
 * 6.10.92    _   // (c)1992 by "Quarky" Dieter Temme                        *
 *            \\ //                                                          *
 * :ts=4       \X/ --- Freeware --- ONLY AMIGA MAKES IT POSSIBLE             *
 *                                                                           *
\*****************************************************************************/

#include "amigacompq.h"
#include "definitions.h"

#include <stdlib.h>
#include <string.h>
#include <clib/exec_protos.h>
#include <clib/gadtools_protos.h>
#include <clib/graphics_protos.h>
#include <clib/intuition_protos.h>
#include <clib/wb_protos.h>
#include <dos/dos.h>
#include <intuition/gadgetclass.h>
#include <intuition/intuition.h>
#include <libraries/commodities.h>
#include <libraries/gadtools.h>
#include <workbench/startup.h>
#include <workbench/workbench.h>

#ifdef PRAGMAS_
 #include <pragmas/exec_lib.h>
 #include <pragmas/gadtools_lib.h>
 #include <pragmas/graphics_lib.h>
 #include <pragmas/intuition_lib.h>
 #include <pragmas/wb_lib.h>
#endif


/*>> internal definitions <<*/
#define pc_DEF_	0
#define pc_1PL_	1
#define pc_2PL_	2

/*>> local variables <<*/
APTR vi;						/* visual information */
struct Window *win;				/* pointer to window */
struct RastPort *rport;			/* pointer to window's rastport */
struct AppWindow *appwin;		/* Workbench's application window structure */
struct MsgPort *appport;		/* application window message port */
struct Menu *menu;				/* pointer to menu created by GadTools */
struct TextFont *font;			/* pointer to topaz.8 font description */
struct TextAttr textattr=		/* actually only topaz.8 supported */
{	"topaz.font", TOPAZ_EIGHTY, FS_NORMAL, FPF_ROMFONT
};
UWORD wbleft, wbtop;			/* offsets to skip window border */
UWORD winwidth= win_WDT;		/* absolute actual window width */
UWORD *pimage;					/* mouse pointer zzz image */
UBYTE status[2];				/* status of players */
UWORD winoffs[2]=				/* horiz. offset for left edge of playfields */
{	0, win_WDT
};
struct Gadget *gad[G_ABSMAX_+1]; /* pointer to all gadgets */
UWORD actual;					/* bitfield for actually enabled gadgets */
UBYTE cwstat;					/* activation status of window */
ULONG winsig;					/* signal of window's UserPort */
ULONG appsig;					/* signal of application window message port */
ULONG currentsigs;				/* current signals for Wait() */
BYTE players;					/* number of players -1 */
BYTE pl;						/* player number in the moment (0..players) */
struct TagItem disable[]=		/* enable and disable taglists */
{	GA_Disabled, TRUE,
	TAG_DONE
};
struct TagItem enable[]=
{	GA_Disabled, FALSE,
	TAG_DONE
};


/*==== add/remove/enable/disable gadgets from the frontend ====*/
void PC_CtrlGadgets_(const UBYTE endis, UWORD which)
{	UWORD i;
	UBYTE j, joffs, firstadded, numadded= 0;
	
	if (!win) return;

	/*- find first bit to test/change in bitfield -*/
	if (which&GID_PLAYER2_)
	{	which<<= G_MAX_;
		joffs= G_MAX_+1;
		i= 1<<(G_MAX_+1);
	} else
	{	which>>= 1;
		joffs= 0;
		i= 1;
	}

	/*- change gadget status according to bitfield parameter -*/
	for (j= joffs; j <= G_MAX_+joffs; j++)
	{	if (which&i)
			if (endis == CG_ADD_)
			{	if (!(actual&i))
				{	AddGList(win, gad[j], -1, 2, NULL);
					actual|= i;
					if (!numadded++) firstadded= j;
				}
			} else if (endis == CG_REM_)
			{	if ((actual&i) && gad[j])
				{	RemoveGList(win, gad[j], 2);
					actual&= ~i;
				}
			} else
			{	GT_SetGadgetAttrsA(gad[j]->NextGadget, win, NULL,
					(endis == CG_EN_)? enable : disable);
			}

		i<<= 1;
	}

	/*- refresh gadgets in window if necessary -*/
	if (numadded)
		RefreshGList(gad[firstadded], win, NULL, numadded<<1);
}

static struct NewMenu newmenu[]=
{	NM_TITLE, "Project", NULL, 0, 0, (APTR)MEN_PROJECT_,
		NM_ITEM, "Open Highscores...", "O", 0, 0, (APTR)MEN_LOADTABLE_,
		NM_ITEM, "Save Highscores As...", "A", 0, 0, (APTR)MEN_SAVEAS_,
		NM_ITEM, "Clear Highscores", NULL, 0, 0, (APTR)MEN_CLEARTABLE_,
		NM_ITEM, NM_BARLABEL, NULL, 0, 0, NULL,
		NM_ITEM, "About...", NULL, 0, 0, (APTR)MEN_ABOUT_,
		NM_ITEM, "Keys...", NULL, 0, 0, (APTR)MEN_HELP_,
		NM_ITEM, NM_BARLABEL, NULL, 0, 0, NULL,
		NM_ITEM, "Hide", "H", 0, 0, (APTR)MEN_HIDE_,
		NM_ITEM, "Quit", "Q", 0, 0, (APTR)MEN_QUIT_,
	NM_TITLE, "Settings", NULL, 0, 0, (APTR)MEN_SETTINGS_,
		NM_ITEM, "1 Player", "1", CHECKIT|CHECKED, 0, (APTR)MEN_1PLAYER_,
		NM_ITEM, "2 Players", "2", CHECKIT, 0, (APTR)MEN_2PLAYERS_,
		NM_ITEM, NM_BARLABEL, NULL, 0, 0, NULL,
		NM_ITEM, "Highscores Visible", "V", CHECKIT, 0, (APTR)MEN_HIGHSCORE_,
		NM_ITEM, NM_BARLABEL, NULL, 0, 0, NULL,
		NM_ITEM, "Set Startlevel...", "S", 0, 0, (APTR)MEN_STARTLEVEL_,
		NM_ITEM, NM_BARLABEL, NULL, 0, 0, NULL,
		NM_ITEM, "Auto-Activate Windows", NULL, CHECKIT, 0, (APTR)MEN_AUTOACT_,
		NM_ITEM, NM_BARLABEL, NULL, 0, 0, NULL,
		NM_ITEM, "Reset To Defaults", NULL, 0, 0, (APTR)MEN_DEFAULTS_,
		NM_ITEM, "Last Saved", NULL, 0, 0, (APTR)MEN_LASTSAVED_,
		NM_ITEM, "Save Settings", NULL, 0, 0, (APTR)MEN_SAVESETGS_,
	NM_END
};

/*==== enable/disable/check/uncheck menus and menu items ====*/
void PC_CtrlMenu_(const UBYTE enable, const UBYTE itemid)
{	UWORD no= MENUNULL;
	struct NewMenu *nm= &newmenu[0]-1;
	UBYTE i;

	#define SUB0		0xf800
	#define ITEM0		0x07e0
	#define MENU0		0x001f

	/*- remove menu strip from window -*/
	if (win) ClearMenuStrip(win);

	/*- create standard Intuition menu number -*/
	do
	{	nm++;
		switch (nm->nm_Type)
		{	case NM_TITLE:	no= SHIFTMENU(MENUNUM(no)+1)|ITEM0|SUB0;
							break;
/*			case NM_SUB:	no= (no&(MENU0|ITEM0))|SHIFTSUB(SUBNUM(no)+1);
							break;
			case NM_END:	no= MENUNULL;
							nm= NULL;
							break;
*/			/*case NM_ITEM:*/
			default:		no= (no&MENU0)|SHIFTITEM(ITEMNUM(no)+1)|SUB0;
		}
	} while (/*nm && */(nm->nm_UserData != (APTR)itemid));

	/*- change menu strip -*/
	if ((i= MENUNUM(no)) != NOMENU)
		if (ITEMNUM(no) != NOITEM)
		{	struct MenuItem *mi;
			if (win) mi= ItemAddress(menu, no);
			switch (enable)
			{	case CM_DIS_:	if (win) mi->Flags&= ~ITEMENABLED;
								nm->nm_Flags|= NM_ITEMDISABLED;
								break;
				case CM_EN_:	if (win) mi->Flags|= ITEMENABLED;
								nm->nm_Flags&= ~NM_ITEMDISABLED;
								break;
				case CM_UNCHK_:	if (win) mi->Flags&= ~CHECKED;
								nm->nm_Flags&= ~CHECKED;
								break;
				default:		if (win) mi->Flags|= CHECKED;
								nm->nm_Flags|= CHECKED;

			}
		} else
		{	struct Menu *m;
			if (win)
			{	m= menu;
				while (i--) m= m->NextMenu;
			}
			if (enable == CM_EN_)
			{	if (win) m->Flags|= MENUENABLED;
				nm->nm_Flags&= ~NM_MENUDISABLED;
			} else if (enable == CM_DIS_)
			{	if (win) m->Flags&= ~MENUENABLED;
				nm->nm_Flags|= NM_MENUDISABLED;
			}
		}

	/*- re-build menu strip on window -*/
	if (win) ResetMenuStrip(win, menu);
}

/*==== draw full frontend for one player ====*/
void DrawFront_(UBYTE num)
{	num-= pc_1PL_;

	{	UWORD x;
		static TEXT player[]= "0";

		x= wbleft+winoffs[num]+110;
		SetAPen(rport, 3);
		RectFill(rport, x, wbtop+3, x+11, wbtop+3+15);
		SetAPen(rport, 1);
		SetBPen(rport, 3);
		Move(rport, x+2, wbtop+13);
		player[0]= '1'+num;
		Text(rport, player, 1);
		SetBPen(rport, 0);
	}

	DrawBevelBox(rport,
		wbleft+winoffs[num], wbtop+PGTOP_-BBHEIGHT,
		PGWIDTH_+2*BBWIDTH, PGHEIGHT_+2*BBHEIGHT,
		GT_VisualInfo, vi,
		GTBB_Recessed, TRUE,
		TAG_DONE);

	PC_CtrlGadgets_(CG_ADD_, GID_START_|num);
}

/*>> my NewWindow structure <<*/
struct NewWindow newwin=
{	0, 0, 0, 0, 0, 1,
	BUTTONIDCMP|IDCMP_CLOSEWINDOW|IDCMP_RAWKEY|IDCMP_MENUPICK,
	WFLG_DRAGBAR|WFLG_DEPTHGADGET|WFLG_CLOSEGADGET|WFLG_ACTIVATE
		|WFLG_SMART_REFRESH|WFLG_NOCAREREFRESH,
	NULL, NULL, PRGNAME, NULL, NULL,
	0, 0, 0, 0, PUBLICSCREEN
};

/*==== set window title according to highscore filename ====*/
void PC_SetWindowTitle_(void)
{	extern TEXT *hsdir, *hsname;			/* from "levelscore.c" */
	extern TEXT *hotkey;					/* from "main.c" */

	static TEXT *wintitle;					/* actual window title */
	UWORD l;								/* temporary variable */

	if (!win) return;

	/*- allocate new memory for window title -*/
	if (wintitle) free(wintitle);
	l= PRGNAMELEN+18+strlen(hotkey);
	if (hsdir) l+= strlen(hsdir);
	if (hsname) l+= strlen(hsname);
	wintitle= MAllocQ_(l);

	/*- set new window title -*/
	strcpy(wintitle, PRGNAME);
	strcat(wintitle, " (");
	if (hsdir) strcat(wintitle, hsdir);
	if (hsname) AddPart(wintitle+PRGNAMELEN+2, hsname, ~0);
	strcat(strcat(strcat(wintitle, "): Hot Key = <"), hotkey), ">");
	SetWindowTitles(win, wintitle, (TEXT *)~0);
}

/*==== initialize window (TRUE if successful) ====*/
void PC_InitWindow_(void)
{	/*- NewGadget structure for all gadgets -*/
	static struct NewGadget newgad=
	{	0, 0, 62, 14,
		NULL, &textattr, 0, PLACETEXT_IN, NULL, NULL
	};

	/*- if already open, put window to front -*/
	if (win)
	{	WindowToFront(win);
		return;
	}

	/*- open window -*/
	{	struct Screen *pubscr= LockPubScreen(NULL);
		vi= GetVisualInfo(pubscr, TAG_DONE);
		win= OpenWindowTags(&newwin,
			WA_ScreenTitle, PRGNAME " - (c)1992 by Dieter Temme",
			WA_InnerWidth, winwidth,
			WA_InnerHeight, win_HGT,
			TAG_DONE);
		UnlockPubScreen(NULL, pubscr);
	}
	if (!win || !vi) exit(RETURN_FAIL);

	/*- initialize global variables -*/
	rport= win->RPort;
	winsig= 1<<win->UserPort->mp_SigBit;
	wbleft= win->BorderLeft;
	wbtop= win->BorderTop;
	font= OpenFont(&textattr);
	SetFont(rport, font);

	/*- create gadgets -*/
	newgad.ng_LeftEdge= INTERWIDTH+wbleft;
	newgad.ng_TopEdge= INTERHEIGHT+wbtop;
	newgad.ng_VisualInfo= vi;
	{	BYTE i, j, k;
		for (j= k= 0; k <= 1; j+= G_MAX_+1, k++)
		{	for (i= j; i <= j+G_MAX_; i++)
			{	newgad.ng_GadgetText= (i-j)? "Start" : "Abort";
				newgad.ng_GadgetID= k|((i-j)? GID_START_ : GID_ABORT_);
				while (!CreateGadgetA(BUTTON_KIND,
					CreateContext(&gad[i]), &newgad, NULL))
				{	PrintNoMem_();
					FreeGadgets(gad[i]);
					gad[i]= NULL;
				}
			}
			newgad.ng_LeftEdge+= winoffs[1];
		}
	}

	/*- create menu strip -*/
	if (!(menu= CreateMenusA(newmenu, NULL)) || !LayoutMenusA(menu, vi, NULL))
		exit(RETURN_FAIL);
	SetMenuStrip(win, menu);

	/*- draw playfield -*/
	PC_SetWindowTitle_();
	DrawFront_(pc_1PL_);
	LS_CtrlTable_(CT_SHOW_);
	if (players) DrawFront_(pc_2PL_);

	/*- install application window message port -*/
	if (appport= CreateMsgPort())
		if (appwin= AddAppWindow(0, 0, win, appport, NULL))
			appsig= 1<<appport->mp_SigBit;
}

/*==== close window ====*/
void PC_CloseWindow_(void)
{	PC_CtrlGadgets_(CG_REM_, GID_ABORT_|GID_START_);
	PC_CtrlGadgets_(CG_REM_, GID_ABORT_|GID_START_|GID_PLAYER2_);

	{	BYTE i;
		for (i= 0; i <= G_ABSMAX_; i++)
		{	if (gad[i] && gad[i]->NextGadget)
				gad[i]->NextGadget->NextGadget= NULL;
			FreeGadgets(gad[i]);
		}
	}
	if (appwin) RemoveAppWindow(appwin);
	if (appport)
	{	struct Message *msg;
		while (msg= GetMsg(appport)) ReplyMsg(msg);
		DeleteMsgPort(appport);
	}
	if (win) ClearMenuStrip(win);
	if (font) CloseFont(font);
	if (menu) FreeMenus(menu);
	if (vi) FreeVisualInfo(vi);
	if (win)
	{	CloseWindow(win);
		win= NULL;
		winsig= 0;
	}
}

/*==== activate/deactivate window with all gadgets ====*/
void PC_CtrlWindow_(UBYTE acti)
{	if (!win) return;

	if (acti&CW_SYSTEM_)
	{	acti&= ~CW_SYSTEM_;
		if (acti == CW_ACTIV_)
			switch (cwstat)
			{	case CW_DEACT_:
					CtrlPointer_(MOUSE_CLR_);
				case CW_SLEEP_:
					return;
			}
	} else
		cwstat= acti;

	if (acti == CW_ACTIV_)
	{	CtrlPointer_(MOUSE_CLR_);
		ResetMenuStrip(win, menu);
	} else
	{	CtrlPointer_(MOUSE_SET_);
		ClearMenuStrip(win);
	}
}

/*==== wait until window change has taken place ====*/
void WaitChange_(void)
{	ULONG class;
	struct IntuiMessage *imsg;

	do
	{	while (!(imsg= GT_GetIMsg(win->UserPort))) Wait(winsig);
		class= imsg->Class;
		GT_ReplyIMsg(imsg);
	} while (class != IDCMP_CHANGEWINDOW);
}

/*==== resize window for highscore table ====*/
void PC_ResizeWindow_(const BOOL right)
{	/*- modify variables -*/
	winoffs[1]+= right? hsc_WDT : -hsc_WDT;
	winwidth+= right? hsc_WDT : -hsc_WDT;

	if (!win) return;

	/*- deactivate window -*/
	PC_CtrlWindow_(CW_DEACT_);

	/*- eventually move window and scroll contents -*/
	if (right)
	{	WORD i;
		if ((i= win->WScreen->Width-win->LeftEdge-winwidth) < 0)
		{	MoveWindow(win, i, 0);
			WaitChange_();
		}
	} else
		ScrollRaster(rport, hsc_WDT, 0,
			wbleft+win_WDT, wbtop,
			wbleft+winwidth+hsc_WDT-1, wbtop+win_HGT-1);

	/*- resize window -*/
	SizeWindow(win, right? hsc_WDT : -hsc_WDT, 0);
	WaitChange_();

	/*- remove gadgets, move them and place them again -*/
	if (players) PC_CtrlGadgets_(CG_REM_, GID_PLAYER2_|GID_START_);
	if (right)
		ScrollRaster(rport, -hsc_WDT, 0,
			wbleft+win_WDT, wbtop, wbleft+winwidth-1, wbtop+win_HGT-1);
	{	BYTE i;
		for (i= G_MAX_+1; i <= G_ABSMAX_; i++)
			gad[i]->NextGadget->LeftEdge+= right? hsc_WDT : -hsc_WDT;
	}
	if (players) PC_CtrlGadgets_(CG_ADD_, GID_PLAYER2_|GID_START_);

	/*- activate window again -*/
	PC_CtrlWindow_(CW_ACTIV_);
}

/*==== set number of players and open/close a secondary playfield ====*/
void SetPlayers_(UBYTE num)
{	/*- process parameter if necessary -*/
	if (num == pc_DEF_) num= pc_1PL_;
	if (players == (num-pc_1PL_)) return;
	players= num-pc_1PL_;

	/*- modify menu, deactivate window -*/
	PC_CtrlMenu_(CM_CHECK_-players, MEN_1PLAYER_);
	PC_CtrlMenu_(CM_UNCHK_+players, MEN_2PLAYERS_);
	PC_CtrlWindow_(CW_DEACT_);

	/*- eventually move window -*/
	{	WORD i;

		if (players && win
			&& ((i= win->WScreen->Width-win->LeftEdge-winwidth-win_WDT) < 0))
		{	MoveWindow(win, i, 0);
			WaitChange_();
		}
	}

	/*- resize window -*/
	if (win)
	{	SizeWindow(win, players? win_WDT : -win_WDT, 0);
		WaitChange_();
	}
	winwidth+= players? win_WDT : -win_WDT;

	/*- reactivate window -*/
	PC_CtrlWindow_(CW_ACTIV_);

	/*- draw playfield for second player -*/
	if (players)
	{	if (win) DrawFront_(pc_2PL_);
	} else
		PC_CtrlGadgets_(CG_REM_, GID_PLAYER2_|GID_START_);

	/*- double guess list -*/
	LS_CtrlGuess_(players);
}

/*==== control number of players from icon's tool types ====*/
void PC_CtrlPlayers_(const UBYTE num)
{	if ((num == 1) || (num == 2)) SetPlayers_(num-1+pc_1PL_);
}

/*==== operate on user's menu choice ====*/
BOOL PC_ProcessMenu_(const UBYTE menuno)
{	switch (menuno)
	{	case MEN_ABOUT_:		FC_ShowTitle_(ST_ABOUT_);
								break;
		case MEN_HELP_:			FC_ShowTitle_(ST_HELP_);
								break;
		case MEN_1PLAYER_:		SetPlayers_(pc_1PL_);
								break;
		case MEN_2PLAYERS_:		SetPlayers_(pc_2PL_);
								break;
		case MEN_HIGHSCORE_:	LS_CtrlTable_(CT_TOGGLE_);
								break;
		case MEN_LOADTABLE_:	LS_LoadTable_(LT_CHOOSE_);
								break;
		case MEN_SAVEAS_:		LS_SaveTable_(ST_REQUEST_);
								break;
		case MEN_CLEARTABLE_:	LS_ClearTable_();
								break;
		case MEN_STARTLEVEL_:	LS_NewLevel_();
								break;
		case MEN_AUTOACT_:		LS_CtrlAutoAct_(CA_TOGGLE_);
								break;
		case MEN_LASTSAVED_:	LS_LoadSettings_();
								break;
		case MEN_DEFAULTS_:		LS_ResetLevel_();
								SetPlayers_(pc_DEF_);
								break;
		case MEN_SAVESETGS_:	LS_SaveSettings_();
								break;
		case MEN_HIDE_:			PC_CloseWindow_();
								break;
		case MEN_QUIT_:			return TRUE;
	}
	return FALSE;
}

/*==== operate on user's gadget choice ====*/
void PC_ProcessGadget_(const UBYTE gadid)
{	pl= gadid&GID_PLAYER2_;

	switch (gadid&~GID_PLAYER2_)
	{	case GID_START_: /* start game for the one or both players */
			for (pl= 0; pl <= players; pl++)
			{	LS_StartGame_();
				FC_StartGame_();
				PC_CtrlGadgets_(CG_REM_, pl|GID_START_);
				PC_CtrlGadgets_(CG_ADD_, pl|GID_ABORT_);
				TC_CtrlTimer_(CT_START_);
				status[pl]= RUNNING_;
			}
			PC_CtrlMenu_(CM_DIS_, MEN_PROJECT_);
			PC_CtrlMenu_(CM_DIS_, MEN_SETTINGS_);
			break;
		case GID_ABORT_: /* abort game for one player */
			PC_CtrlGadgets_(CG_REM_, pl|GID_ABORT_);
			PC_CtrlGadgets_(CG_ADD_, pl|GID_START_);
			if (status[pl] != WAITING_) LS_AbortGame_();
			if (status[pl^1] == WAITING_)
			{	PC_CtrlMenu_(CM_EN_, MEN_PROJECT_);
				PC_CtrlMenu_(CM_EN_, MEN_SETTINGS_);
				if (players)
					PC_CtrlGadgets_(CG_EN_, (pl^GID_PLAYER2_)|GID_START_);
			} else
				PC_CtrlGadgets_(CG_DIS_, pl|GID_START_);
			status[pl]= WAITING_;
			break;
	}
}

/*==== message loop (result is event number) ====*/
UWORD PC_WaitForEvents_(void)
{	extern ULONG cxsig;					/* from "main.c" */
	extern struct MsgPort *brokport;	/* from "main.c" */
	extern CxObj *broker;				/* from "main.c" */
	extern ULONG timersig[];			/* from "timerctrl.c" */

	static ULONG signals;
	ULONG waitsigs= winsig|timersig[0]|timersig[1]|appsig|cxsig;
	UWORD eventno= 0;

	signals&= waitsigs;

	while (!eventno)
	{	if (!signals) signals= Wait(waitsigs)&waitsigs;

		while (!eventno && signals)
		{	if (signals&appsig) /* if application window message */
			{	signals&= ~appsig;
				LS_AppLoadTable_();
			}

			if (signals&cxsig) /* if commodities message */
			{	CxMsg *cxmsg;

				while (!eventno && (cxmsg= (CxMsg *)GetMsg(brokport)))
				{	switch (CxMsgType(cxmsg))
					{	case CXM_IEVENT:
							eventno= EV_OPEN_;
    		    	        break;
        		    	case CXM_COMMAND:
							switch (CxMsgID(cxmsg))
							{	case CXCMD_DISABLE:
								case CXCMD_ENABLE:
									ActivateCxObj(broker,
										CxMsgID(cxmsg) == CXCMD_ENABLE);
									break;
								case CXCMD_KILL:
									eventno= EV_EXIT_;
									break;
								case CXCMD_APPEAR:
								case CXCMD_UNIQUE:
									eventno= EV_OPEN_;
									break;
								case CXCMD_DISAPPEAR:
									eventno= EV_CLOSE_;
									break;
		            	    }
			        }
					ReplyMsg((struct Message *)cxmsg);
			    }
				if (!cxmsg) signals&= ~cxsig;
			}

			if (!eventno) /* if timer signal */
			{	if (signals&timersig[0])
				{	signals&= ~timersig[0];
					eventno= EV_TIMER_;
				} else if (signals&timersig[1])
				{	signals&= ~timersig[1];
					eventno= EV_TIMER_|1;
				}
			}

			if (!eventno && (signals&winsig)) /* process window message */
 			{	struct IntuiMessage *imsg= GT_GetIMsg(win->UserPort);

				if (!imsg)
				{	signals&= ~winsig;
					continue;
				}

				switch (imsg->Class)
				{	case IDCMP_GADGETUP:
						eventno= EV_GADGET_|((struct Gadget *)imsg->IAddress)
							->GadgetID;
						break;
					case IDCMP_RAWKEY:
						eventno= EV_RAWKEY_|imsg->Code;
						break;
					case IDCMP_MENUPICK:
					{	UBYTE i;

						eventno= EV_MENU_;
						if (MENUNUM(imsg->Code) != NOMENU)
							if ((i= ITEMNUM(imsg->Code)) != NOITEM)
							{	struct MenuItem *mi=
									ItemAddress(menu, imsg->Code);
								eventno|=
									(UBYTE)(ULONG)GTMENUITEM_USERDATA(mi);
							} else
							{	struct Menu *m= menu;
								while (i--) m= m->NextMenu;
								eventno|= (UBYTE)(ULONG)GTMENU_USERDATA(m);
							}
						if (eventno&0x80) eventno= 0;
						break;
					}
					case IDCMP_CLOSEWINDOW:
						eventno= EV_CLOSE_;
				}
				GT_ReplyIMsg(imsg);
			}
		}
	}

	return eventno;
}
