/*

 This piece of code is Copyright © 1995 by Stefano Reksten of 3AM
 - The Three Amigos!!!

*/

#define PRGNAME		"Public Screen Manager"
#define PRGNAMESH	"PSM"
#define PRGVER		"1.2"

char *ver = "$VER: PSM 1.2 "__AMIGADATE__" by Stefano Reksten";

#include <exec/memory.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <intuition/screens.h>
#include <libraries/commodities.h>
#include <libraries/gadtools.h>
#include <dos/dostags.h>
#include <string.h>

#include <stdio.h>

#include <proto/exec.h>
#include <proto/intuition.h>
#include <proto/graphics.h>
#include <proto/gadtools.h>
#include <proto/icon.h>
#include <proto/commodities.h>
#include <proto/asl.h>
#include <proto/dos.h>
#include <clib/alib_protos.h>

/*
 *  Prototypes
 */

/* in locale.c */
extern void initLocale( void ), flushLocale( void );
extern char *s_opennew, *s_closescr, *s_moveto, *s_refresh, *s_makedef,
  *s_keepop, *s_closeaft, *s_shanoff, *s_shanon, *s_popoff, *s_popon,
  *s_hide, *s_quit, *s_about, *s_cool, *s_cantquit, *s_quitcanc,
  *s_noasl, *s_cantclose, *s_continue;

/* in screenstuff.c */
extern void FreeFontAttr( void );
extern BOOL AllocTextAttr( STRPTR, UWORD );
extern void FontRequest( void );
extern void PattRequest( void );
extern void OpenPubScreen( void );
extern void ClosePubScreen( struct PubScrNode * );
extern void PublicScrDone( ULONG );
extern char backdropname[256];


void ProcessMsg( void );
BOOL OpenPSMWindow( void );
void ClosePSMWindow( void );
void ClearMsgPort( struct MsgPort * );
BOOL ProcessCommodityMsg( void );
BOOL ProcessWindowMsg( void );
void ProcessPubScrMenu( struct PubScrNode * );
BOOL Quit( void );

void ConsScreenList( void );
void FreeScreenList( void );
void RefreshList( void );
STRPTR FindPubScreenName( void );
struct PubScrNode *FindNthNode( WORD );

void UpdateModes( void );
void GetScreenPrefix( void );

/*
 * Variables - General stuff (commodity, libraries)
 */

struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct Library *CxBase, *IconBase, *GadToolsBase, *AslBase,
               *DiskfontBase, *DataTypesBase, *UtilityBase;
struct Gadget *glist = NULL, *gstring, *gdisplay;
struct MsgPort *broker_mp;
CxObj *broker, *filter;
ULONG cxsigflag;

struct NewBroker newbroker = {
	NB_VERSION,
	PRGNAMESH,
	PRGNAMESH" "PRGVER" © 1995 Stefano Reksten of 3AM",
	PRGNAME,
	NBU_UNIQUE | NBU_NOTIFY,
	COF_SHOW_HIDE, 0, 0, 0 };

/*
 * Variables - Window data
 */

#define EVT_POPKEY 1

#define OPENSCR_ID	1
#define CLOSESCR_ID	2
#define MOVETO_ID	3
#define REFRESH_ID	4
#define MAKEDEF_ID	5
#define SHANGHAI_ID	7
#define POPPUB_ID	8
#define HIDE_ID	9
#define QUIT_ID	10
#define LISTVIEW_ID	11
#define STRING_ID	12

STRPTR shanghailabels[3] = { NULL, NULL, 0L };
STRPTR poppublabels[3] = { NULL, NULL, 0L };
struct IntuiText it = { 0, 0, 0, 0, 0, NULL, NULL, NULL };
struct NewGadget ng = { 0, 0, 50, 0, NULL, NULL, 0, 0, NULL, NULL };
struct VisualInfo *vi;
struct Gadget *gad;
UWORD textw, wleft, wtop;
struct Window *psmwindow;

/*
 * Variables - Public screens internal list
 */

struct PubScrNode {
	struct Node psns_Node;
	struct Screen *psns_Screen;
	struct TextAttr *psns_TextAttr;
	struct TextFont *psns_Font;
	struct Window *psns_BackdropWindow;
	struct Menu *psns_MenuStrip;
	struct VisualInfo *psns_VisualInfo;
	};

struct List *scrlist;

UWORD scrcounter = 1;		/* Index to choose an unique screen name */
char scrprefix[MAXPUBSCREENNAME-3] = { 'P','S','M',0 };
char pubscrname[MAXPUBSCREENNAME+1] = { 'P','S','M','_','0','0','1',0 };

/*
 * Variables - Public screens stuff
 */

UWORD listv_scr_nmb = 0;			/* No. of selected scr in listview */
UWORD host_screen = (UWORD)(-1);	/* on which screen shall we open */
ULONG shanghai = 0, poppubscr = 0;	/* No explanation needed */
UWORD screens_opened;

struct EasyStruct  easyr = {
	sizeof(struct EasyStruct), 0, PRGNAMESH" Notify", NULL, NULL };

STRPTR thisscrname;					/* Name of public screen we're open in */

/*
 * Menues - Sorry to put these here but needed them for Locale :-)
 */

#define MENUID_ABOUT		1
#define MENUID_HIDE			2
#define MENUID_QUIT			3
#define MENUID_FONTRQ		4
#define MENUID_PATTRQ		5
#define MENUID_PUBLIC       6
#define MENUID_CLOSE        7

struct NewMenu psmnewmenus[] = {
	{ NM_TITLE,	NULL,         0, 0, 0, 0 },
	{ NM_ITEM,  NULL,         0, 0, 0, (APTR)MENUID_ABOUT },
	{ NM_ITEM,  NULL,         0, 0, 0, (APTR)MENUID_HIDE },
	{ NM_ITEM,  NULL,	      0, 0, 0, (APTR)MENUID_QUIT },
	{ NM_TITLE, NULL,         0, 0, 0, 0 },
	{ NM_ITEM,  NULL,         0, 0, 0, (APTR)MENUID_FONTRQ },
	{ NM_ITEM,  NULL,         0, 0, 0, (APTR)MENUID_PATTRQ },
	{ NM_END,   NULL,         0, 0, 0, 0 } };

struct Menu *psmmenus;

struct NewMenu pubscrnewmenus[] = {
	{ NM_TITLE, NULL,         0, 0, 0, 0 },
	{ NM_ITEM,  NULL,         0, 0, 0, (APTR)MENUID_PUBLIC },
	{ NM_ITEM,  NULL,         0, 0, 0, (APTR)MENUID_CLOSE },
	{ NM_END,   NULL,         0, 0, 0, 0 } };

/*
 * Main program stuff
 */


void ClearMsgPort( struct MsgPort *mp )
{
struct Message *msg;

while( msg = GetMsg( mp ) )
	ReplyMsg( msg );
}


void main( int argc, char **argv )
{
UBYTE popkey[30];
BOOL popup = TRUE;

if ( IntuitionBase = (struct IntuitionBase *)OpenLibrary( "intuition.library", 37L ) )
	{
	if ( GfxBase = (struct GfxBase *)OpenLibrary( "graphics.library", 37L ) )
		{
		if ( GadToolsBase = OpenLibrary( "gadtools.library", 37L ) )
			{
			if ( CxBase = OpenLibrary( "commodities.library", 37L ) )
				{
				if ( DiskfontBase = OpenLibrary( "diskfont.library", 37L ) )
					{
					initLocale();

					if ( DataTypesBase = OpenLibrary( "datatypes.library", 39L ) )
						{
						if ( !(UtilityBase = OpenLibrary( "utility.library", 39L )) )
							{
							CloseLibrary( DataTypesBase );
							DataTypesBase = NULL;
							}
						}

					if ( broker_mp = CreateMsgPort() )
						{
						newbroker.nb_Port = broker_mp;
						cxsigflag = 1L << broker_mp->mp_SigBit;

						popkey[0] = NULL;

						if ( IconBase = OpenLibrary( "icon.library",37L ) )
							{
							char **ttypes;
							struct DiskObject *ob;

							if ( ob = GetDiskObject( "PSM" ) )
								{
								ttypes = ob->do_ToolTypes;

								newbroker.nb_Pri = (BYTE)ArgInt(ttypes, "CX_PRIORITY", 0);
								popup = MatchToolValue(FindToolType(ttypes, "CX_POPUP"), "YES");
								strcpy( popkey, FindToolType(ttypes, "CX_POPKEY") );
								wleft = (UWORD)ArgInt(ttypes, "WLEFT", ~0);
								wtop = (UWORD)ArgInt(ttypes, "WTOP", ~0);
								if ( MatchToolValue(FindToolType(ttypes, "SHANGHAI"), "YES") )
									shanghai = SHANGHAI;
								if ( MatchToolValue(FindToolType(ttypes, "POPPUBSCREEN"), "YES") )
									poppubscr = POPPUBSCREEN;
								if ( FindToolType(ttypes, "FONTNAME") && FindToolType(ttypes, "FONTHEIGHT") )
								AllocTextAttr( FindToolType(ttypes, "FONTNAME"), ArgInt(ttypes, "FONTHEIGHT", 8) );
								strcpy( backdropname, FindToolType(ttypes, "PATTERN" ) );
								FreeDiskObject( ob );
								}
							CloseLibrary(IconBase);
							}

						if ( !(popkey[0]) )
							strcpy( popkey, "ctrl lalt s" );

						if ( broker = CxBroker( &newbroker, NULL ) )
							{
							if ( filter = HotKey( popkey, broker_mp, EVT_POPKEY ) )
								{
								AttachCxObj( broker, filter );

								if ( scrlist = AllocVec( sizeof(struct List), MEMF_ANY|MEMF_CLEAR ) )
									{
									NewList( scrlist );
									ConsScreenList();
									ActivateCxObj(broker, 1L);
									if ( popup )
										OpenPSMWindow();
									ProcessMsg();
									ClosePSMWindow();
									FreeScreenList();
									FreeFontAttr();
									}
								}
							DeleteCxObjAll(broker);
							}
						ClearMsgPort( broker_mp );
						DeletePort( broker_mp );
						}

					if ( DataTypesBase )
						{
						CloseLibrary( UtilityBase );
						CloseLibrary( DataTypesBase );
						}

					flushLocale();

					CloseLibrary( DiskfontBase );
					}
				CloseLibrary( CxBase );
				}
			CloseLibrary( GadToolsBase );
			}
		CloseLibrary( (struct Library *)GfxBase );
		}
	CloseLibrary( (struct Library *)IntuitionBase );
	}
}


void ProcessMsg(void)
{
BOOL stay = TRUE;
ULONG sigrcvd, waitmask;
struct PubScrNode *node;

while( stay )
	{
	waitmask = cxsigflag | SIGBREAKF_CTRL_C;
	if ( psmwindow )
		waitmask |= 1L<<psmwindow->UserPort->mp_SigBit;
	for ( node = (struct PubScrNode *)scrlist->lh_Head; node->psns_Node.ln_Succ; node = (struct PubScrNode *)node->psns_Node.ln_Succ )
		{
		if ( node->psns_BackdropWindow )
			waitmask |= 1L<<node->psns_BackdropWindow->UserPort->mp_SigBit;
		}

	sigrcvd = Wait( waitmask );

	if ( sigrcvd & SIGBREAKF_CTRL_C )
		stay = Quit();
	else
	if ( sigrcvd & cxsigflag )
		stay = ProcessCommodityMsg();
	else
	if ( psmwindow && sigrcvd & 1L<<psmwindow->UserPort->mp_SigBit )
		stay = ProcessWindowMsg();
	else
	for ( node = (struct PubScrNode *)scrlist->lh_Head; node->psns_Node.ln_Succ; node = (struct PubScrNode *)node->psns_Node.ln_Succ )
		{
		if ( node->psns_BackdropWindow )
			{
			if ( sigrcvd & 1L<<node->psns_BackdropWindow->UserPort->mp_SigBit )
				{
				ProcessPubScrMenu( node );
				break;
				}
			}
		}
	}
}


/*
 * GUI stuff
 */

/* Some routines to make it shorter */

UWORD MaxBetween( STRPTR text, UWORD prev )
{
register UWORD ilength, max;

it.IText = text;
ilength = IntuiTextLength( &it );
max = ( ilength > prev ? ilength : prev );
return max;
}

void AddButtonGadget( STRPTR name, ULONG ID )
{
ng.ng_TopEdge += ng.ng_Height + 1;
ng.ng_GadgetText = name;
ng.ng_GadgetID = ID;
gad = CreateGadget(BUTTON_KIND,gad,&ng,TAG_END);
}

void AddCycleGadget( STRPTR *labels, ULONG ID, UBYTE actnum )
{
ng.ng_TopEdge += ng.ng_Height + 1;
ng.ng_GadgetText = NULL;
ng.ng_GadgetID = ID;
gad = CreateGadget(CYCLE_KIND,gad,&ng,GTCY_Labels,labels,GTCY_Active,actnum,TAG_END);
}


BOOL OpenPSMWindow(void)
{
struct Screen *wbs = NULL;
register UWORD fonth, wheight, wwidth;

if ( !psmwindow )
	{
	if ( host_screen != (UWORD)(-1) )
		{
		thisscrname = FindNthNode( host_screen )->psns_Node.ln_Name;
		wbs = LockPubScreen( thisscrname );
		}
	if ( !wbs )
		{
		thisscrname = "Workbench";
		wbs = LockPubScreen( thisscrname );
		}

	if ( wbs )
		{
		fonth = wbs->Font->ta_YSize;
		if ( fonth < 12 )
			fonth = 12;
		it.ITextFont = wbs->Font;
		ng.ng_TextAttr = wbs->Font;
		ng.ng_Height = fonth + 2;

		if ( vi = GetVisualInfo( wbs, NULL ) )
			{
			ng.ng_VisualInfo = vi;
			ng.ng_LeftEdge = wbs->WBorLeft + 4;
			ng.ng_TopEdge = wbs->BarHeight;

			gad = CreateContext(&glist);
			if ( gad )
				{
				ng.ng_TopEdge -= fonth;
				ng.ng_Flags = PLACETEXT_IN;

				textw = 0;
				textw = MaxBetween( s_opennew, textw );
				textw = MaxBetween( s_closescr, textw );
				textw = MaxBetween( s_moveto, textw );
				textw = MaxBetween( s_refresh, textw );
				textw = MaxBetween( s_makedef, textw );
				textw = MaxBetween( s_keepop, textw );
				textw = MaxBetween( s_shanoff, textw );
				textw = MaxBetween( s_popoff, textw );

				ng.ng_Width = textw + 40;

				AddButtonGadget( s_opennew, OPENSCR_ID );
				AddButtonGadget( s_closescr, CLOSESCR_ID );
				AddButtonGadget( s_moveto, MOVETO_ID );
				AddButtonGadget( s_refresh, REFRESH_ID );
				AddButtonGadget( s_makedef, MAKEDEF_ID );
				AddCycleGadget( shanghailabels, SHANGHAI_ID, (shanghai?1:0) );
				AddCycleGadget( poppublabels, POPPUB_ID, (poppubscr?1:0) );

				ng.ng_TopEdge += fonth + 3;
				ng.ng_Width = (textw>>1) + 19;
				ng.ng_Flags = PLACETEXT_IN;
				ng.ng_GadgetText = s_hide;
				ng.ng_GadgetID = HIDE_ID;
				gad = CreateGadget(BUTTON_KIND,gad,&ng,TAG_END);

				wheight = gad->TopEdge + gad->Height + 2 + wbs->WBorBottom;

				ng.ng_LeftEdge += ng.ng_Width + 2;
				ng.ng_GadgetText = s_quit;
				ng.ng_GadgetID = QUIT_ID;
				gad = CreateGadget(BUTTON_KIND,gad,&ng,TAG_END);

				ng.ng_LeftEdge += ng.ng_Width + 2;
				ng.ng_Width = textw + 40;
				ng.ng_GadgetText = NULL;
				ng.ng_GadgetID = (UWORD)~0;
				gdisplay = gad = CreateGadget(TEXT_KIND,gad,&ng,GTTX_Border,TRUE,TAG_END);

				ng.ng_TopEdge = wbs->BarHeight + 3;
				ng.ng_GadgetText = NULL;
				ng.ng_Height = fonth + 4;
				ng.ng_GadgetID = STRING_ID;
				gstring = gad = CreateGadget(STRING_KIND,gad,&ng,GTST_String,scrprefix,TAG_END);

				ng.ng_TopEdge += fonth + 6;
				ng.ng_Height = 5 * (ng.ng_Height + 1);
				ng.ng_GadgetID = LISTVIEW_ID;
				ng.ng_Flags = PLACETEXT_ABOVE;
				gad = CreateGadget(LISTVIEW_KIND,gad,&ng,GTLV_Labels,scrlist,GTLV_ShowSelected,NULL,TAG_END);

				wwidth = ng.ng_Width * 2 + wbs->WBorLeft + wbs->WBorRight + 10;

				if ( gad && ( psmwindow = OpenWindowTags( NULL,
					WA_Left, wleft == ~0 ? (wbs->Width - wwidth)>>1 : wleft,
					WA_Top, wtop == ~0 ? (wbs->Height - wheight)>>1 : wtop,
					WA_Width, wwidth,
					WA_Height, wheight,
					WA_Title, PRGNAMESH" "PRGVER,
					WA_ScreenTitle, PRGNAME" "PRGVER" © 1995 Stefano Reksten of 3AM",
					WA_Flags, WFLG_CLOSEGADGET|WFLG_DEPTHGADGET|WFLG_DRAGBAR|WFLG_ACTIVATE,
					WA_Gadgets, glist,
					WA_IDCMP, IDCMP_CLOSEWINDOW|IDCMP_GADGETDOWN|IDCMP_GADGETUP|IDCMP_REFRESHWINDOW|IDCMP_MENUPICK|BUTTONIDCMP|LISTVIEWIDCMP,
					WA_PubScreenName, thisscrname,
					TAG_END ) ) )
					{
					if ( psmmenus = CreateMenus( psmnewmenus, TAG_END ) )
						{
						if ( LayoutMenus( psmmenus, vi, TAG_END ) )
							{
							if ( SetMenuStrip( psmwindow, psmmenus ) )
								{
								RefreshList();
								ScreenToFront( wbs );
								UnlockPubScreen( thisscrname, NULL );
								GT_SetGadgetAttrs( gdisplay, psmwindow, NULL, GTTX_Text, FindPubScreenName(), TAG_END );

								if ( !DataTypesBase )
									OffMenu( psmwindow, FULLMENUNUM(1,1,0) );

								return TRUE;
								}
							}
						FreeMenus( psmmenus );
						}
					}
				}
			FreeVisualInfo(vi);
			}
		UnlockPubScreen( thisscrname, NULL );
		}
	else DisplayBeep( NULL );
	}

if ( psmwindow )
	ScreenToFront( psmwindow->WScreen );

if ( host_screen != -1 )
	{
	host_screen = (UWORD)(-1);
	return OpenPSMWindow();
	}
else
	return FALSE;
}


/*
 * Process events stuff
 */

BOOL ProcessCommodityMsg(void)
{
BOOL returnvalue = TRUE;
CxMsg *msg;
ULONG msgid, msgtype;

while(msg = (CxMsg *)GetMsg(broker_mp))
	{
	msgid = CxMsgID(msg);
	msgtype = CxMsgType(msg);
	ReplyMsg((struct Message *)msg);

	switch(msgtype)
		{
		case CXM_IEVENT:
			OpenPSMWindow();
			break;

		case CXM_COMMAND:
			switch(msgid)
				{
				case CXCMD_DISABLE:
					ActivateCxObj(broker, 0L);
					break;

				case CXCMD_ENABLE:
					ActivateCxObj(broker, 1L);
					break;

				case CXCMD_KILL:
					returnvalue = Quit();
					break;

				case CXCMD_UNIQUE:
					OpenPSMWindow();
					break;

				case CXCMD_APPEAR:
					OpenPSMWindow();
					break;

				case CXCMD_DISAPPEAR:
					ClosePSMWindow();

				default:
					break;
				}
			break;

			default:
			break;
		}
	}
return returnvalue;
}


BOOL ProcessWindowMsg(void)
{
register struct IntuiMessage *msg;
register BOOL returnvalue = TRUE;
register ULONG class;
register UWORD msgID;
register UWORD code;
register ULONG menuid;

while(psmwindow && (msg = GT_GetIMsg(psmwindow->UserPort)))
	{
	class = msg->Class;
	code = msg->Code;
	if ( class & (BUTTONIDCMP|IDCMP_GADGETDOWN) )
	    msgID = ((struct Gadget *)msg->IAddress)->GadgetID;
	GT_ReplyIMsg(msg);

	switch(class)
		{
		case IDCMP_REFRESHWINDOW:
		    GT_BeginRefresh(psmwindow);
    		GT_EndRefresh(psmwindow,TRUE);
		    break;

		case IDCMP_MENUPICK:
			if ( code != MENUNULL )
				{
				menuid = (ULONG)GTMENUITEM_USERDATA( ItemAddress( psmmenus, code ) );
				switch ( menuid )
					{
					case MENUID_ABOUT:
						easyr.es_TextFormat = s_about;
						easyr.es_GadgetFormat = s_cool;
						if ( IntuitionBase->LibNode.lib_Version >= 39 )
							SetWindowPointer( psmwindow, WA_BusyPointer, TRUE, TAG_END );
						EasyRequest( psmwindow, &easyr, NULL );
						if ( IntuitionBase->LibNode.lib_Version >= 39 )
							SetWindowPointer( psmwindow, TAG_END );
						break;

					case MENUID_HIDE:
						host_screen = (UWORD)-1;
						ClosePSMWindow();
						break;

					case MENUID_QUIT:
						returnvalue = Quit();
						break;

					case MENUID_FONTRQ:
						FontRequest();
						break;

					case MENUID_PATTRQ:
						PattRequest();
						break;
					}
				}
			break;

		case IDCMP_CLOSEWINDOW:
			host_screen = (UWORD)(-1);
		    ClosePSMWindow();
		    break;

		case BUTTONIDCMP:
		case IDCMP_GADGETDOWN:
		    if ( msgID == OPENSCR_ID )
				OpenPubScreen();
			else if ( msgID == CLOSESCR_ID )
				ClosePubScreen( FindNthNode( listv_scr_nmb ) );
			else if ( msgID == MOVETO_ID )
				{
				host_screen = listv_scr_nmb;
				ClosePSMWindow();
				OpenPSMWindow();
				}
			else if ( msgID == MAKEDEF_ID )
				{
				struct PubScrNode *node = FindNthNode( listv_scr_nmb );
				SetDefaultPubScreen( node->psns_Node.ln_Name );
				GT_SetGadgetAttrs( gdisplay, psmwindow, NULL, GTTX_Text, node->psns_Node.ln_Name, TAG_END );
				UpdateModes();
				}
			else if ( msgID == REFRESH_ID )
				RefreshList();
			else if ( msgID == SHANGHAI_ID )
				{
				shanghai ^= SHANGHAI;
				UpdateModes();
				}
			else if ( msgID == POPPUB_ID)
				{
				poppubscr ^= POPPUBSCREEN;
				UpdateModes();
				}
			else if ( msgID == HIDE_ID )
				{
				host_screen = (UWORD)-1;
				ClosePSMWindow();
				}
			else if ( msgID == QUIT_ID )
				returnvalue = Quit();
			else if ( msgID == LISTVIEW_ID )
				{
				static ULONG oldsecs, oldmics, actualsecs = 0, actualmics = 0;
				listv_scr_nmb = code;
				oldsecs = actualsecs;
				oldmics = actualmics;
				CurrentTime( &actualsecs, &actualmics );
				if ( DoubleClick( oldsecs, oldmics, actualsecs, actualmics ) )
					{
					struct PubScrNode *node = FindNthNode( listv_scr_nmb );
					if ( LockPubScreen( node->psns_Node.ln_Name ) )
						{
						if ( host_screen != listv_scr_nmb )
							ClosePSMWindow();
						host_screen = listv_scr_nmb;
						SetDefaultPubScreen( node->psns_Node.ln_Name );
						GT_SetGadgetAttrs( gdisplay, psmwindow, NULL, GTTX_Text, node->psns_Node.ln_Name, TAG_END );
						UpdateModes();
						OpenPSMWindow();
						UnlockPubScreen( node->psns_Node.ln_Name, NULL );
						}
					}
				}
			else if ( msgID == STRING_ID )
				{
				strcpy( pubscrname, ((struct StringInfo *)gstring->SpecialInfo)->Buffer );
				strcpy( scrprefix, pubscrname );
				strcat( pubscrname, "_000" );
				}
		}
	}
return returnvalue;
}


void ProcessPubScrMenu( struct PubScrNode *node )
{
register struct IntuiMessage *msg;
register ULONG class;
register UWORD code;
register ULONG menuid;

while(msg = GT_GetIMsg(node->psns_BackdropWindow->UserPort))
	{
	class = msg->Class;
	code = msg->Code;
	GT_ReplyIMsg(msg);

	switch(class)
		{
		case IDCMP_REFRESHWINDOW:
		    GT_BeginRefresh( node->psns_BackdropWindow );
    		GT_EndRefresh( node->psns_BackdropWindow, TRUE );
		    break;

		case IDCMP_MENUPICK:
			if ( code != MENUNULL )
				{
				menuid = (ULONG)GTMENUITEM_USERDATA( ItemAddress( node->psns_BackdropWindow->MenuStrip, code ) );
				switch ( menuid )
					{
					case MENUID_PUBLIC:
						SetDefaultPubScreen( node->psns_Node.ln_Name );
						GT_SetGadgetAttrs( gdisplay, psmwindow, NULL, GTTX_Text, node->psns_Node.ln_Name, TAG_END );
						UpdateModes();
						break;

					case MENUID_CLOSE:
						while ( msg = GT_GetIMsg(node->psns_BackdropWindow->UserPort) )
							GT_ReplyIMsg(msg);
						ClosePubScreen( node );
						return;
					}
				}
			break;
		}
	}
}


void ClosePSMWindow(void)
{
if ( psmwindow )
	{
	wleft = psmwindow->LeftEdge;
	wtop = psmwindow->TopEdge;
	ClearMsgPort( psmwindow->UserPort );
	ClearMenuStrip( psmwindow );
	CloseWindow( psmwindow );
	FreeMenus( psmmenus ); 
	FreeGadgets( glist );
	FreeVisualInfo( vi );
	CloseLibrary( GadToolsBase );
	psmwindow = NULL;
	}
}


/*
 * Screen list stuff
 */


void ConsScreenList( void )
{
struct List *publiclist;
struct PubScreenNode *pubnode;
struct PubScrNode *node, *prevnode;
STRPTR scrname;

if ( publiclist = LockPubScreenList() )
	{
	for ( pubnode = (struct PubScreenNode *)publiclist->lh_Head; pubnode->psn_Node.ln_Succ; pubnode = (struct PubScreenNode *)pubnode->psn_Node.ln_Succ )
		{
		if ( !FindName( scrlist, pubnode->psn_Node.ln_Name ) )
			{
			if ( node = AllocVec( sizeof(struct PubScrNode), MEMF_ANY|MEMF_CLEAR ) )
				{
				node->psns_Screen = pubnode->psn_Screen;
				if ( scrname = AllocVec( MAXPUBSCREENNAME+1, MEMF_ANY|MEMF_CLEAR ) )
					{
					node->psns_Node.ln_Name = scrname;
					strcpy( scrname, pubnode->psn_Node.ln_Name );
					AddTail( scrlist, (struct Node *)node );
					}
				}
			}
		}

	for ( node = (struct PubScrNode *)scrlist->lh_Head; node->psns_Node.ln_Succ; node = (struct PubScrNode *)node->psns_Node.ln_Succ )
		if ( !FindName( publiclist, node->psns_Node.ln_Name ) )
			{
			prevnode = (struct PubScrNode *)node->psns_Node.ln_Pred;
			Remove( (struct Node *)node );
			node = prevnode;
			}

	UnlockPubScreenList();
	}
}


void FreeScreenList()
{
struct PubScrNode *node;

while ( node = (struct PubScrNode *)RemHead( scrlist ) )
	{
	FreeVec( node->psns_Node.ln_Name );
	FreeVec( node );
	}
}


void RefreshList( void )
{
GT_SetGadgetAttrs( gad, psmwindow, NULL, GTLV_Labels, ~0, TAG_END );
ConsScreenList();
GT_SetGadgetAttrs( gad, psmwindow, NULL, GTLV_Labels, scrlist, GTLV_Selected, listv_scr_nmb, TAG_END );
}


STRPTR FindPubScreenName( void )
{
struct Screen *scr;
struct PubScreenNode *node;
struct List *list;
STRPTR result = NULL;

if ( scr = LockPubScreen( NULL ) )
	{
	if ( list = LockPubScreenList() )
		{
		for ( node = (struct PubScreenNode *)list->lh_Head; node->psn_Node.ln_Succ; node = (struct PubScreenNode *)node->psn_Node.ln_Succ )
			{
			if ( scr == node->psn_Screen )
				{
				result = node->psn_Node.ln_Name;
				break;
				}
			}
		UnlockPubScreenList();
		}
	UnlockPubScreen( NULL, scr );
	}
return result;
}


struct PubScrNode *FindNthNode( WORD n )
{
struct Node *node;

node = scrlist->lh_Head;
while ( node && n-- > 0 )
	node = node->ln_Succ;

if ( node )
	return( (struct PubScrNode *)node );
else
	return( 0L );
}


void UpdateModes( void )
{
struct Screen *scr = LockPubScreen( NULL );
SetPubScreenModes( shanghai | poppubscr );
UnlockPubScreen( NULL, scr );
}


BOOL Quit( void )
{
if ( screens_opened )
	{
	easyr.es_TextFormat = s_cantquit;
	easyr.es_GadgetFormat = s_quitcanc;
	return (BOOL)( EasyRequest( psmwindow, &easyr, NULL ) == 0 );
	}
else
	return FALSE;
}
