ShadingWinds.c

/*
    File:       ShadingWinds.c
 
    Contains:   This little application includes code to allow you to detect whether or not the Shell
                Window is "rolled up" by WindowShade.  How do you do this?  You check the window's 
                contRgn.  If the contRgn is empty, then the window is shaded.  You'll note that the
                grafPort is unchanged by WindowShade, so if you need to save window dimensions, you
                can grab that information from the portRect.
 
    Written by:  Virginia (Ginny) McCulloh  
 
    Copyright:  Copyright © 1995-1999 by Apple Computer, Inc., All Rights Reserved.
 
                You may incorporate this Apple sample source code into your program(s) without
                restriction. This Apple sample source code has been provided "AS IS" and the
                responsibility for its operation is yours. You are not permitted to redistribute
                this Apple sample source code as "Apple sample source code" after having made
                changes. If you're going to re-distribute the source, we require that you make
                it clear in the source that the code was descended from Apple sample source
                code, but that you've made changes.
 
    Change History (most recent first):
                8/9/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
                
 
*/
 
#include "ShadingWinds.h"
#include <TextUtils.h>
 
typedef struct {
    Rect    windPort;
    Point   windPosition;
}WindDimAndPos;
 
 
/*****     Prototypes      *****/
void        main(void);
void        initApp(void);
Boolean     checkGestaltFeatures(void);
Boolean     installAEHandlers();
void        setUpMenus(void);
void        setUpWindow(void);
void        setUpMenus(void);
void        doHighLevel(EventRecord *eventRec);
void        doMousedown(EventRecord *eventRec);
void        doKey(EventRecord *eventRec);
void        doUpdate(EventRecord *eventRec);
void        dispatch(long menuResult);
void        doAppleCmds (short theItem);
void        doFileCmds (short theItem);
void        doTestCmds (short theItem);
void        TestForWindowShade(void);
void        HideShellWindow(void);
void        RevealShellWindow(void);
 
 
pascal OSErr    DoOpenAppAE(AppleEvent theAppleEvent, AppleEvent reply, long refCon);
pascal OSErr    DoOpenDocAE(AppleEvent theAppleEvent, AppleEvent reply, long refCon);
pascal OSErr    DoPrintDocAE(AppleEvent theAppleEvent, AppleEvent reply, long refCon);
pascal OSErr    DoQuitAppAE(AppleEvent theAppleEvent, AppleEvent reply, long refCon);
 
 
/*****  globals *****/
Boolean         gQuitTheApp = false;        /* true = quit program */
WindowPtr       gStatusWindow, gHiddenWindow;
Boolean         gIsShellWindVisible = false;
WindDimAndPos   myWindDimAndPos;
 
/*****  main() *****/
 
void main()
{
    short           sleepTime  =  60;
    EventRecord     myEvent;
 
    
    initApp();                              /* call initialization routine */
    setUpMenus();
    do
    {
        if (WaitNextEvent(everyEvent, &myEvent, sleepTime, NIL))
            switch (myEvent.what)
            {
                case mouseDown:
                    doMousedown(&myEvent);
                    break;
                    
                case keyDown:
                case autoKey:
                    doKey(&myEvent);
                    break;
 
                case kHighLevelEvent:
                    doHighLevel(&myEvent);
                    break;
 
                case activateEvt:
                    break;
                
                case updateEvt:
                    doUpdate(&myEvent);
                    break; 
                
                case diskEvt:
                    break;
            
                case osEvt:             /*  I don't really care yet. */
                    break;
            }
    }  while (!gQuitTheApp);        
    
}               /* end of main */
 
 
/*****  initApp() *****/
 
void initApp()
{
    
    /* Memory specific initializations. */
    
    MaxApplZone();              /* grow the heap to its maximum size */
    MoreMasters();              /* create more master pointers       */
    MoreMasters();
    MoreMasters();
    MoreMasters();
    MoreMasters();
 
    /* Initializing the ROM Managers */
    
    InitGraf((Ptr) &qd.thePort);
    InitFonts();
    InitWindows();
    InitMenus();
    FlushEvents(everyEvent,0);
    TEInit();
    InitDialogs(NIL);
    InitCursor();
    
    if (!checkGestaltFeatures())
        ExitToShell();
    
    /* Install the required Apple Event Handlers */
    if (!installAEHandlers())
        ExitToShell();
}               /* end of initApp() */
 
 
 
/*****  checkGestaltFeatures() *****/
Boolean checkGestaltFeatures()
{
    long        gestaltFeature;
    OSErr       myErr;
 
    myErr = Gestalt(gestaltSystemVersion, &gestaltFeature);     /* which SysVersion present? */
    if (myErr == noErr)
    {
        gestaltFeature = (gestaltFeature >> 8) & 0xf; 
                                        /* shift result over & mask out major version number */
        if (gestaltFeature < 7)         /* This is a System 7+ shell.  We quit otherwise. */
        {
            StopAlert(BADSYSTEMID, nil);
            return(false);
        }
    }
    
    if (myErr == noErr)
    {
        myErr = Gestalt(gestaltQuickdrawVersion, &gestaltFeature);
                                                    /* we want color QD cuz we're spoiled */
        if (myErr == noErr)
        {
            if(gestaltFeature < gestalt32BitQD)
            {
                StopAlert(BADQUICKDRAWID, nil);
                return(false);
            }
        }
    }
    
    
    
    if (myErr == noErr)
    {
        myErr = Gestalt(gestaltAppleEventsAttr, &gestaltFeature);
        if (myErr == noErr)
        {
            if (!(gestaltFeature & 0xf))
            {
                StopAlert(NOAPPLEEVENTS, nil);
                return(false);
            }
        }
    }
    if (!myErr)     
        return(true);           /* if there was an error we cannot continue */
    else
        return(false);          /* we made it through without a hitch */
}
 
/*****  installAEHandlers *****/
Boolean installAEHandlers()
{
    OSErr       myErr;
    
    myErr = AEInstallEventHandler ( kCoreEventClass, 
                    kAEOpenApplication, NewAEEventHandlerProc(DoOpenAppAE), 0L, false );
    if (myErr == noErr)
        myErr = AEInstallEventHandler ( kCoreEventClass,
                    kAEOpenDocuments, NewAEEventHandlerProc(DoOpenDocAE), 0L, false );
    if (myErr == noErr)
        myErr = AEInstallEventHandler ( kCoreEventClass,
                    kAEPrintDocuments, NewAEEventHandlerProc(DoPrintDocAE), 0L, false );
    if (myErr == noErr)
        myErr = AEInstallEventHandler ( kCoreEventClass,
                    kAEQuitApplication, NewAEEventHandlerProc(DoQuitAppAE), 0L, false );
    if (myErr)
        return(false);
    else
        return(true);
}
 
/*****  setUpMenus() 
            This will put up our menus.  Be sure to read the comments by the
            AppendMenu() and SetItem() calls to see how different options
            behave.     
*****/
void setUpMenus()
{
    short           n;
    MenuHandle      theMenu;
    
    for (n = 0; n < MAXMENUS; n++)
    {
        theMenu = GetMenu(FIRSTMENUID + n);
        if (theMenu)                
            InsertMenu(theMenu, 0);
    }
 
    theMenu = GetMenuHandle(APPLEMENU);
    if (theMenu)
        AppendResMenu(theMenu, 'DRVR');
    
    DrawMenuBar();
    return;
}                   /* end of setUpMenus()  */
 
/*****  setUpWindow() *****/
 
void setUpWindow( void )
{
#define     GLOBALWINDID    2001
 
    WindowPtr   myWind;
 
    myWind = GetNewCWindow(WINDOWID, nil, PUTINFRONT);
    if (myWind != nil)
    {
        ShowWindow(myWind);
        gIsShellWindVisible = true;
    }
    gStatusWindow = GetNewWindow(GLOBALWINDID, nil, PUTINFRONT);
    if (gStatusWindow == nil)
        DebugStr("\pWe can't put up StatusWindow.");
    
    SelectWindow(myWind);       // activate the "Shell Window"
}
 
 
/*****  doMousedown()
            We figure out where the user has clicked the mouse.  If the user
            clicks anywhere but the menu bar, we beep.  Otherwise, we figure
            out which menu they have clicked and dispatch.
*****/
void doMousedown(EventRecord *eventRec)
{
    short       windPart;
    WindowPtr   myWind;
    long        menuResult;
    
    windPart = FindWindow(eventRec->where, &myWind);
    
    switch(windPart)
    {
        case inContent:
            SelectWindow(myWind);
            break;
 
        case inDrag:
            DragWindow( myWind, eventRec->where, &qd.screenBits.bounds );
            break;
 
        case inMenuBar:
            menuResult = MenuSelect(eventRec->where);
            dispatch(menuResult);
            break;
 
        case inSysWindow:
            SystemClick( eventRec, myWind );
            break;
            
        case inGoAway:
            gQuitTheApp = true;
            break;
            
        default:
            break;
    }
    return;
}               /* end of doMousedown */
 
 
/*****  doKey()
            We ignore keys pressed unless they are accompanied by a 
            command key.  Then we dispatch.
*****/
void doKey(EventRecord *eventRec)
{
    char    keyPressed;
    long    menuResult;
    
    keyPressed = (char) (eventRec->message & charCodeMask);
    
    if((eventRec->modifiers & cmdKey) != 0)
    {
        menuResult = MenuKey(keyPressed);
        dispatch(menuResult);   
    }
    return;
}               /* end of do_key */
 
 
/*****  doHighLevel() *****/
void doHighLevel(EventRecord *eventRec)
{
    OSErr myErr;
    myErr = AEProcessAppleEvent(eventRec);
}
 
 
pascal OSErr    DoOpenAppAE(AppleEvent theAppleEvent, AppleEvent reply, long refCon)
{
    #pragma unused(theAppleEvent,reply,refCon)
    setUpWindow();
    return(noErr);
}
pascal OSErr    DoOpenDocAE(AppleEvent theAppleEvent, AppleEvent reply, long refCon)
{
    #pragma unused(theAppleEvent,reply,refCon)
    return(noErr);
}
pascal OSErr    DoPrintDocAE(AppleEvent theAppleEvent, AppleEvent reply, long refCon)
{
    #pragma unused(theAppleEvent,reply,refCon)
    return(noErr);
}
pascal OSErr    DoQuitAppAE(AppleEvent theAppleEvent, AppleEvent reply, long refCon)
{
    #pragma unused(theAppleEvent,reply,refCon)
    gQuitTheApp = true;
    return(noErr);
}
 
 
/***** doUpdate() *****/
void    doUpdate(EventRecord *eventRec)
{
    GrafPtr     savedPort;
    WindowPtr   theWindow;
    theWindow = (WindowPtr) eventRec->message;
    
    GetPort(&savedPort);
    SetPort((GrafPtr) theWindow);
    BeginUpdate(theWindow);
    EndUpdate(theWindow);
    SetPort(savedPort);
}
 
 
/*****  dispatch()
            We determine which menu the user has chosen (either with mouse
            or with command keys) and jump to the routine that handles
            that menu's commands.
*****/
void dispatch(long menuResult)
{
    short       theMenu;            /* menu selected */
    short       theItem;            /* item selected */
    
    theMenu = HiWord (menuResult);      /* menuID selected */
    theItem = LoWord (menuResult);      /* item# selected */
    
    switch (theMenu)
    {
        case APPLEMENU:
            doAppleCmds(theItem);
            break;
 
        case FILEMENU:
            doFileCmds(theItem);
            break;
            
        case EDITMENU:
            break;
 
        case TESTMENU:
            doTestCmds(theItem);
            break;
    }
    HiliteMenu(0);
}               /* end of dispatch */
 
 
 
/*****  doAppleCmds() 
            When the user chooses the "About MyMenuText" item, we display the
            About box.  If the user chooses a DA, we open the DA.
*****/
void doAppleCmds(short theItem)
{   
    MenuHandle      myMenu;
    Str255          name;
    short           dummy;
    
    if(theItem == appleABOUT)
    {
        Alert(ABOUTID, (ModalFilterUPP) NIL);
    }
    else
    {
        myMenu = GetMenuHandle (APPLEMENU);
        if (myMenu)
        {
            GetMenuItemText(myMenu, theItem, name);
            dummy = OpenDeskAcc(name);
        }
    }
    return;
}               /* end of doAppleCmds */
 
 
 
/*****  doFileCmds() 
            When the user chooses Quit on the File menu, we quit.
*****/
void doFileCmds (short theItem)
{
    switch (theItem)
    {           
        case fileQUIT:
            gQuitTheApp = true;
            break;
    }
    return;
} /* end of doFileCmds */
 
 
 
/*****  doTestCmds()
            When the user chooses any of the items in the Test menu.  
            They will see the TESTALERT. 
*****/
void doTestCmds (short theItem)
{   
 
    switch (theItem)
    {
        case testWINDSHADE:
            TestForWindowShade();
            break;
        case testHIDEWIND:
            HideShellWindow();
            break;
        case testREVEALWIND:
            RevealShellWindow();
            break;
    }   
    return;
}               /* end of doTestCmds */
 
 
 
void TestForWindowShade()
{
    WindowPtr   myShellWindow;
    GrafPtr     oldPort;
    Str255      theString;
    short       windDimensions;
    Point       globalWindPosition;
    
    myShellWindow = FrontWindow();      /* 
                                            Unless you click in the StatusWindow, your
                                            front window should be the Shell Window.
                                        */
    if (myShellWindow)      // if myShellWindow is not nil
    {
        if (myShellWindow != gStatusWindow) // Make sure we're looking at Shell Window
        {
            GetPort(&oldPort);
            SetPort(gStatusWindow);
                EraseRect(&gStatusWindow->portRect);
                MoveTo(10, 20);
                DrawString("\pShell Window's dimensions:");
                MoveTo(70, 40);
                DrawString("\pWidth = ");
                MoveTo(150, 40);
                windDimensions = (*myShellWindow).portRect.right - 
                            (*myShellWindow).portRect.left;
                NumToString((long) windDimensions, theString);
                DrawString(theString);
                MoveTo(70, 60);
                DrawString("\pHeight = ");
                MoveTo(150, 60);
                windDimensions = (*myShellWindow).portRect.bottom - 
                            (*myShellWindow).portRect.top;
                NumToString((long) windDimensions, theString);
                DrawString(theString);
                
                MoveTo(10, 80);
                DrawString ("\pThe global top and left of content region are:");
                
                MoveTo(70, 100);
                DrawString("\pGlobal Top = ");
                
                MoveTo(150, 100);
                globalWindPosition.v = (**((WindowPeek)myShellWindow)->contRgn).rgnBBox.top;
                NumToString((long) globalWindPosition.v, theString);
                DrawString(theString);
                
                MoveTo(70, 120);
                DrawString("\pGlobal Left = ");
                
                MoveTo(150, 120);
                globalWindPosition.h = (**((WindowPeek)myShellWindow)->contRgn).rgnBBox.left;
                NumToString((long) globalWindPosition.h, theString);
                DrawString(theString);
                
                MoveTo(10, 140);
                
                /*
                    The next section of code tests to see if myShellWindow's
                    contRgn is EMPTY. If it is, that means that WindowShade 
                    has rolled up the content region.
                    Note:  the window's portRect dimensions do not change.
                */
                
                if (EmptyRgn(((WindowPeek) myShellWindow)->contRgn))
                    DrawString("\pShell Window has been rolled up.  Unshade it and retest.");
                else
                    DrawString("\pShell Window unrolled. Shade the Shell Window & retest.");
            SetPort(oldPort);
        }
        else        /*
                        The status window is the front window.
                        We don't test for shading there.  Tell user
                        to activate the Shell window.
                    */
        {
            GetPort(&oldPort);
            SetPort(gStatusWindow);
                EraseRect(&gStatusWindow->portRect);
                MoveTo(10, 20);
                DrawString("\pWrong window is active. Click in Shell Window & retest.");
            SetPort(oldPort);
        }
    }
    
 
}
 
void HideShellWindow()
{
    WindowPtr   theShellWind;
    GrafPtr     oldPort;
    
    
    if (gIsShellWindVisible)
    {
        theShellWind = FrontWindow();
        if (theShellWind != gStatusWindow)
        {
            gHiddenWindow = theShellWind;
            myWindDimAndPos.windPort.left = (*theShellWind).portRect.left;
            myWindDimAndPos.windPort.top = (*theShellWind).portRect.top;
            myWindDimAndPos.windPort.right = (*theShellWind).portRect.right;
            myWindDimAndPos.windPort.bottom = (*theShellWind).portRect.bottom;
            
            
            // get the content rgn's global top and left coordinates
            myWindDimAndPos.windPosition.h = (**(*(WindowPeek)theShellWind).contRgn).rgnBBox.left;
            myWindDimAndPos.windPosition.v = (**(*(WindowPeek)theShellWind).contRgn).rgnBBox.top;
                            
            HideWindow(theShellWind);
            gIsShellWindVisible = false;
        }
        else
        {
            GetPort(&oldPort);
            SetPort(gStatusWindow);
                EraseRect(&gStatusWindow->portRect);
                MoveTo(10, 20);
                DrawString("\pWhy would you want to hide Status window?");
            SetPort(oldPort);
        }
    }
    else
    {
        GetPort(&oldPort);
        SetPort(gStatusWindow);
            EraseRect(&gStatusWindow->portRect);
            MoveTo(10, 20);
            DrawString("\pShell Window is hidden. Try revealing it instead.");
        SetPort(oldPort);
    }
}
 
void RevealShellWindow()
{
    GrafPtr     oldPort;
    
    if (!gIsShellWindVisible)
    {
        if (gHiddenWindow != nil)
        {
            ShowWindow(gHiddenWindow);
            SelectWindow(gHiddenWindow);
            
            gIsShellWindVisible = true;
        }
        else
        {
            GetPort(&oldPort);
            SetPort(gStatusWindow);
                EraseRect(&gStatusWindow->portRect);
                MoveTo(10, 20);
                DrawString("\pProblems have emerged.  Quit while you're behind.");
            SetPort(oldPort);
        }
    }
    else
    {
        GetPort(&oldPort);
        SetPort(gStatusWindow);
            EraseRect(&gStatusWindow->portRect);
            MoveTo(10, 20);
            DrawString("\pShell window is visible.  Try hiding it first.");
        SetPort(oldPort);
    }
 
}