/******************************************************************************/
/*                                                                            */
/* includes                                                                   */
/*                                                                            */
/******************************************************************************/

#include <exec/types.h>
#include <exec/interrupts.h>
#include <hardware/intbits.h>
#include <libraries/commodities.h>
#include <intuition/screens.h>
#include <intuition/intuitionbase.h>
#include <proto/commodities.h>
#include <proto/intuition.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <string.h>

/******************************************************************************/
/*                                                                            */
/* compiler specifics                                                         */
/*                                                                            */
/******************************************************************************/

#ifdef __SASC
   #define main _main
   #define exit _exit
   #define WbMsg _WBenchMsg
   #define SETA4()
   #define RESA4()
#endif

#ifdef __GNUC__
   #define __saveds
   #define main _main
   #define exit _exit
   #define WbMsg _WBenchMsg
   #define SETA4() asm volatile ("\tmovel a4,sp@-\n\tmovel a1,a4\n")
   #define RESA4() asm volatile ("\tmovel sp@+,a4\n")
#endif

/******************************************************************************/
/*                                                                            */
/* prototypes                                                                 */
/*                                                                            */
/******************************************************************************/

int  InstallCx();
void ParseArgs();
int  OpenLibs();
void CheckFrontScr();
int  CheckBroker();
void CloseLibs();
void RemoveCx();
int  ScreenHandler();

/******************************************************************************/
/*                                                                            */
/* useful defines                                                             */
/*                                                                            */
/******************************************************************************/

#define OSVERSION 37L
#define NEEDV37 "This program requires at least v37!\n"
#define TEMPLATE "CX_POPUP/K,CX_POPKEY/K,CX_PRIORITY/N/K"

/******************************************************************************/
/*                                                                            */
/* symbol imports                                                             */
/*                                                                            */
/******************************************************************************/

extern struct WBStartup *WbMsg;
extern struct ExecBase *SysBase;

/******************************************************************************/
/*                                                                            */
/* global variables                                                           */
/*                                                                            */
/******************************************************************************/

struct DosLibrary *DOSBase;
struct Library *CxBase,*IconBase;
struct IntuitionBase *IntuitionBase;

struct Screen *FrontScreen;

const UBYTE verstag[]="$VER: FrontPub 1.1 (25.3.95) © 1995 by G.Nikl";

/*** commodities stuff ***/

struct NewBroker NewBroker =
{ NB_VERSION,
  "FrontPub",
  (UBYTE *)&verstag[6],
  "frontmost pubscreen becomes default",
  NBU_UNIQUE,
  0,0,NULL,0
};

CxObj *Broker;
LONG CxEnable;

/*** interrupt stuff ***/

struct Interrupt ScreenIntr =
{ 0,0,
  NT_INTERRUPT,
  -1,
  "FrontPub",
  0,
  (VOID (*)())&ScreenHandler
};

ULONG IntrSignal,CheckIt=TRUE;

/******************************************************************************/
/*                                                                            */
/* implementation                                                             */
/*                                                                            */
/******************************************************************************/

/******************************************************************************/
/*                                                                            */
/* install program as commodity                                               */
/*                                                                            */
/******************************************************************************/

int InstallCx()
{
  int ret=0;

  if ((NewBroker.nb_Port=CreateMsgPort()) != NULL)
  {
    if ((Broker=CxBroker(&NewBroker,NULL)) != NULL)
    {
      CxEnable=TRUE; (void)ActivateCxObj(Broker,CxEnable); ret=1;
    }
  }
  return ret;
}

/******************************************************************************/
/*                                                                            */
/* open all libraries                                                         */
/*                                                                            */
/******************************************************************************/

int OpenLibs()
{
  int ret=1;

  if (((IntuitionBase=(struct IntuitionBase *)OpenLibrary("intuition.library", OSVERSION)) == NULL) ||
      ((CxBase=OpenLibrary("commodities.library", OSVERSION)) == NULL))
  {
    if (!WbMsg && (DOSBase=(struct DosLibrary *)OpenLibrary("dos.library", 0)) != NULL)
    {
      Write(Output(),NEEDV37,sizeof(NEEDV37)); CloseLibrary((struct Library *)DOSBase);
    }
    ret=0;
  }
  return ret;
}

/******************************************************************************/
/*                                                                            */
/* main loop                                                                  */
/*                                                                            */
/******************************************************************************/

int main()
{
#ifdef __GNUC__
  register void *a4 asm("a4");
#endif

  if (OpenLibs())
  {
    if (!((LONG)(IntrSignal=AllocSignal(-1)) < 0))
    {
      if (InstallCx())
      {
        (void)SetPubScreenModes(SetPubScreenModes(0)|SHANGHAI);
#ifdef __GNUC__
        ScreenIntr.is_Data=a4;
#endif
        AddIntServer(INTB_VERTB,&ScreenIntr);
        for(;;)
         {
           ULONG signals=Wait(1L<<IntrSignal|1L<<NewBroker.nb_Port->mp_SigBit|SIGBREAKF_CTRL_C);

           if (signals & SIGBREAKF_CTRL_C)
             break;

           if (signals & 1L<<IntrSignal)
             CheckFrontScr();

           if (CheckBroker())
             break;
         }
        RemIntServer(INTB_VERTB,&ScreenIntr);
      }
    }
  }
  RemoveCx();
  CloseLibs();
}

int CheckBroker()
{
  CxMsg *cxmsg;
  int quit=0;

  while ((cxmsg=(CxMsg *)GetMsg(NewBroker.nb_Port)) != NULL)
  {
    if (CxMsgType(cxmsg) == CXM_COMMAND)
      switch(CxMsgID(cxmsg))
      {
        case CXCMD_DISABLE:
          CxEnable=FALSE;
          (void)ActivateCxObj(Broker,CxEnable);
          break;
        case CXCMD_ENABLE:
          CxEnable=TRUE;
          (void)ActivateCxObj(Broker,CxEnable);
          break;
        case CXCMD_KILL:
          quit=1;
          break;
      }
    ReplyMsg((struct Message *)cxmsg);
  }
  return quit;
}

void CheckFrontScr()
{
  struct PubScreenNode *pubscrnode,*defpub;
  UBYTE pubscrname[MAXPUBSCREENNAME+3];

  Forbid(); UnlockIBase(LockIBase(0));
  pubscrnode=(struct PubScreenNode *)LockPubScreenList();
  GetDefaultPubScreen(&pubscrname[0]);
  if ((defpub=(struct PubScreenNode *)FindName((struct List *)pubscrnode,&pubscrname[0])) != NULL)
    if (defpub->psn_Screen != (FrontScreen=IntuitionBase->FirstScreen))
      while ((pubscrnode=(struct PubScreenNode *)pubscrnode->psn_Node.ln_Succ)->psn_Node.ln_Succ != NULL)
        if (pubscrnode->psn_Screen == FrontScreen && !(pubscrnode->psn_Flags&PSNF_PRIVATE))
        {
          strcpy(&pubscrname[0],pubscrnode->psn_Node.ln_Name);
          pubscrnode=NULL;
          break;
        }
  UnlockPubScreenList();
  if (!pubscrnode)
    SetDefaultPubScreen(&pubscrname[0]);
  Permit();
  CheckIt=TRUE;
}

/******************************************************************************/
/*                                                                            */
/* close all opened libraries                                                 */
/*                                                                            */
/******************************************************************************/

void CloseLibs()
{
  if (CxBase)
    CloseLibrary(CxBase);
  if (IntuitionBase)
    CloseLibrary((struct Library *)IntuitionBase);
}

/******************************************************************************/
/*                                                                            */
/* closedown commodity broker                                                 */
/*                                                                            */
/******************************************************************************/

void RemoveCx()
{
  if (Broker)
  {
    (void)ActivateCxObj(Broker,FALSE);
    DeleteCxObjAll(Broker);
  }
  if (NewBroker.nb_Port != NULL)
  {
    DeleteMsgPort(NewBroker.nb_Port);
  }
}

/******************************************************************************/
/*                                                                            */
/* vertical blank handler                                                     */
/*                                                                            */
/******************************************************************************/

int __saveds ScreenHandler()
{
  struct Screen *scr;

  SETA4();
  if (CxEnable != FALSE && CheckIt != FALSE)
    if ((scr=IntuitionBase->FirstScreen) != NULL && scr != FrontScreen)
    {
      Signal(NewBroker.nb_Port->mp_SigTask,1L<<IntrSignal); CheckIt=FALSE;
    }
  RESA4();
  return 0;
}
