/* This is a Public Screen program I'm writing.
   Compile with:
    dcc pubby.c -o pubby -l reqtoolss.lib
   Use the -r option to make it residentiable. */

#define PUBBYVERSION    "1.01"

#include <libraries/reqtools.h>
#include <proto/reqtools.h>
#include <libraries/gadtools.h>
#include <clib/gadtools_protos.h>

/* Need this because OpenScreenTags is prototyped here. */
#include <clib/intuition_protos.h>

/* I use this to indicate the version number of Pubby. */
static const char *Ver ="$VER: Pubby 1.0";

struct ReqToolsBase *ReqToolsBase;

/* This is a structure that holds the info for my About... requestor.
   EasyRequest() will be using this to build the requester. */
struct EasyStruct myeasystruct=
{
    sizeof(struct EasyStruct),
    0,
    "About my program",
    "Pubby v%s\nby Todd Courtnage\nE-mail: courtn@cs.uregina.ca",
    "Okey-dokey!",
};


/* This is a structure that tells GadTools what my
   menu will look like.  With ADOS 2.04, it actually seems
   quite easy to do! */
struct NewMenu mynewmenu[]=
{
    { NM_TITLE, "Project",0,0,0,0,},
    {   NM_ITEM, "About...","!",0,0,0,},
    {   NM_ITEM, "Quit","Q",0,0,0,},

    { NM_END,NULL,0,0,0,0,},
};

typedef struct WBStartup    WBS;
short IconSaveOpt;

/* This code was taken from the source for DME.  It is for WB
   startup.  There is no explanation in the docs on how wbmain
   works.  Can someone explain this to me???
   BTW, if you try to start Pubby from the WB after it's already
   running, nothing will happen.  It just won't run. */
int wbmain(wbs)
WBS *wbs;
{
    IconSaveOpt=1;
    return(main(0,(char **)wbs));
}


main(int argc, char *argv[])
{

    struct  Screen *my_screen;
    struct Window *my_window;
    struct rtScreenModeRequester *screenmodereq;
    struct Screen *pubby_screen;

    /* This is a pointer to a structure that holds the visual info
       of the screen I want to put the menu on.  GadTools needs it
       so it knows how to set the menus up so they look pretty. */
    APTR *my_VisualInfo;

    /* This is a structure that holds the structure of the menus. */
    struct Menu *menuStrip;

    /* Don't know what this is for.  I got this from the RKRM: Libraries
       manual. */
    UWORD pens[]={~0};

    /* First things first.  Find out if a copy of Pubby is already running.
       What I do is try to lock a public screen with the LockPubScreen()
       function.  I'll pass it a parameter of Pubby, since that's the name
       of my public screen.  If it returns NULL, then there is not a version
       of Pubby already running. */
    pubby_screen=LockPubScreen("Pubby");
    if(pubby_screen!=NULL)
    {
        printf("A version of Pubby is already running.\n");
        UnlockPubScreen(NULL,pubby_screen);
        exit(0);
    }


    /* Let's parse the command line arguments.  Only a ? will be
       recognized right now.  I don't understand this!  argv is a
       one-dimensional array, yet I've looked at other peoples code,
       and they do this to see if the first argument.  If I try
       if(argv[1]=='?')
       it doesn't work.  And
       if(argv[1]=="?")
       doesn't work either.  Can someone explain this to me?
       PS:  I got this from the source code to Flying Toasters
       screen blanker, but I've seen similar things done in other
       programs as well. */
    if(argv[1][0]=='?')
    {
        printf("Pubby v%s, by Todd Courtnage (e-mail: courtn@cs.uregina.ca)\n",PUBBYVERSION);
        printf("This program opens up a public screen of any size/shape/color/etc.\n");
        printf("upon which any program which has the option of starting up on a public\n");
        printf("screen can use this screen.\nPublic screen name: Pubby (names are case sensitive!)\n");
        exit(0);
    }

    /* Open up the reqtools.library.  Library version must be
       v38 or greater because I want to use the screenmode
       requestor. */
    ReqToolsBase=(struct Library *)OpenLibrary("reqtools.library",38);
    if(ReqToolsBase==NULL)
    {
       printf("Couldn't open reqtools.library\n");
       exit(0);
    }
    else if (ReqToolsBase==0)
    {
        printf("Your reqtools.library isn't of a high enough version.\n");
        printf("Get a new version and try again.\n");
    }

    /* Now, I'm going to try and open up the screen mode requestor.
       First I have to set up the requestor structure using
       rtAllocRequestA(). */
    if(!(screenmodereq=rtAllocRequestA(RT_SCREENMODEREQ,NULL)))
    {
       printf("For some reason, I couldn't allocate the screenmodereq structure.\n");
       CloseLibrary(ReqToolsBase);
       exit(0);
    }

    /* This pops open the screen mode requester in the center of the screen.
       OK, this works!  In order to use rtScreenModeRequest (the one with tags),
       I have to tell DICE to include reqtoolss.lib when I compile it.
       Add "-l reqtoolss.lib" to the compiler command. */
    rtScreenModeRequest(screenmodereq,"Pick a display mode",
                        RT_ReqPos,REQPOS_CENTERSCR,
                        RTSC_Flags,SCREQF_DEPTHGAD|SCREQF_OVERSCANGAD|SCREQF_AUTOSCROLLGAD|SCREQF_SIZEGADS|
                        SCREQF_NONSTDMODES
                        ,TAG_DONE);


    /* I have to free the requester structure now that I'm done with it.
       This is why I was losing some memory every time the program was run.
       (112 bytes was being lost, to be exact.) */
    rtFreeRequest(screenmodereq);

    /* screenmodereq->DisplayID contains which display the user picked from the requester.
       (i.e. PAL:High Res, NTSC:Low Res Laced, etc) */


    /* Now, open up the screen.  Use screenmodereq->DisplayID as the type of display the
       user wants.  Note: Autoscrolling will not work unless there is a windows in the screen! */
    my_screen=OpenScreenTags(NULL,SA_Depth,screenmodereq->DisplayDepth,SA_DisplayID,screenmodereq->DisplayID,
                             SA_Width,screenmodereq->DisplayWidth,SA_Height,screenmodereq->DisplayHeight,
                             SA_Overscan,screenmodereq->OverscanType,SA_AutoScroll,screenmodereq->AutoScroll
                             ,SA_Title,"Pubby",SA_Pens,(ULONG)pens,SA_PubName,"Pubby",
                             TAG_DONE);

    if(my_screen==FALSE)
    {
        printf("You cancelled the requeser!!!  Shame on you!\n");
        CloseLibrary(ReqToolsBase);
        exit(0);
    }
    else if(my_screen==NULL)
    {
        printf("Can't open screen.\n");
        CloseLibrary(ReqToolsBase);
        exit(0);
    }

    PubScreenStatus(my_screen,NULL);
    my_window=OpenWindowTags(NULL,WA_CustomScreen,my_screen,
                            WA_Backdrop,TRUE,
                            WA_Borderless,TRUE,
                            WA_IDCMP,IDCMP_MENUPICK
                            );
    if(my_window==FALSE)
    {
        printf("Couldn't open up the backdrop window.\n");
        CloseScreen(my_screen);
        CloseLibrary(ReqToolsBase);
    }



    /* Get visual info of my screen. */
    my_VisualInfo = GetVisualInfo(my_screen, TAG_END);
    if(my_VisualInfo==NULL)
    {
        printf("GetVisualInfo() failed.  Have no idea why!\n");
        CloseScreen(my_screen);
        CloseLibrary (ReqToolsBase);
        exit(0);
    }

    /* This sets up the menu structure for me automatically. */
    menuStrip = CreateMenus(mynewmenu, TAG_END);
    if(menuStrip==NULL)
    {
        printf("Couldn't create the menu structure (i.e. CreateMenus() failed.\n");
        FreeVisualInfo(my_VisualInfo);
        CloseScreen(my_screen);
        CloseLibrary (ReqToolsBase);
        exit(0);
    }

    /* Now, I have to call LayoutMenus() to layout the menus based on the
       info I got from the GetVisualInfo() call.  LayoutMenus() returns
       either TRUE or FALSE, that's why I'm putting it directly in the
       if() structure. */
    if(!(LayoutMenus(menuStrip,my_VisualInfo,TAG_END)))
    {
        printf("Couldn't layout the menus.\n");
        FreeMenus(menuStrip);    /* Free memory allocated by CreateMenus. */
        FreeVisualInfo(my_VisualInfo);
        CloseScreen(my_screen);
        CloseLibrary (ReqToolsBase);
        exit(0);
    }

    /* Now, I physically open up the menu.  Always returns TRUE.*/
    SetMenuStrip(my_window,menuStrip);

    /*Delay(500L);*/

    /* Now that the screen is opened, just wait for the user to select
       About or Quit from the menu. */
    wait_for_menu(my_window,menuStrip);

    ClearMenuStrip(my_window);
    FreeMenus(menuStrip);
    FreeVisualInfo(my_VisualInfo);
    CloseWindow(my_window);
    CloseScreen(my_screen);
    CloseLibrary (ReqToolsBase);

    exit(0);
}

/* This function waits for the user to select a menu item from the screen, then
   acts accordingly.  I don't fully understand what's going on in here yet, I more
   or less just took it from the RKRM manuals (gadtoolsmenu.c example). */

wait_for_menu(struct Window *my_window, struct Menu *menuStrip)
{
    struct IntuiMessage *msg;
    SHORT done;
    UWORD menuNumber;
    UWORD menuNum;
    UWORD itemNum;
    UWORD subNum;
    struct MenuItem *item;

    done=FALSE;
    while (FALSE==done)
    {
        /* This causes my program to wait until the signal bit of the UserPort structure
           of the window structure get's changed, to indicate a IDCMP event took place.
           i.e. the window (pointed to by win) is a structure, and one of the elements of
           that structure is called UserPort, which is in itself a structure, which has
           an element called mp_SigBit, which is a signal bit to indicate an IDCMP event
           took place. */
        Wait(1L << my_window->UserPort->mp_SigBit);

        while((FALSE==done) && (NULL!=(msg=(struct IntuiMessage *)GetMsg(my_window->UserPort))))
        {
            switch (msg->Class)
            {
                case IDCMP_MENUPICK:
                    menuNumber=msg->Code;
                    while((menuNumber!=MENUNULL)&&(!done))
                    {
                        item=ItemAddress(menuStrip,menuNumber);

                        /* Extracts which item of which menu was selected.
                           Starts counting at 0. */
                        menuNum=MENUNUM(menuNumber);
                        itemNum=ITEMNUM(menuNumber);
                        subNum=SUBNUM(menuNumber);

                        /* If the selection was the first menu (start counting at 0)
                           and the item selected was the 2nd one, then the user
                           selected quit, so quit the program. */
                        if((menuNum==0)&&(itemNum==1))
                            done=TRUE;

                        /* If user selected the About... menu item, then call a function
                           to show my name. :-) */
                        if((menuNum==0)&&(itemNum==0))
                            showabout(my_window);

                        /* Get the next menu item selected, returns MENUNULL if
                           no more selections. */
                        menuNumber=item->NextSelect;
                    }
                break;  /* break out of the switch structure */
            }
            ReplyMsg((struct Message *)msg);
        }
    }
}

/* This procedure get's executed whenever the user select the About... menu
   item.  EasyRequest() simply calls a requester. */
showabout(struct Window *my_window)
{
    LONG answer;

    answer=EasyRequest(my_window,&myeasystruct,NULL,PUBBYVERSION);
}