wdefpatch.c

/*******************************************
 
    WDEF Patcher
    Steve Falkenburg MacDTS
    ©1991 Apple Computer
    
    This snippet shows how you can add a simple extra part to a WDEF without
    writing an entire WDEF.  It also shows how to access the new part via
    FindWindow().
 
    6/1/92  SJF     fixed a5 problem in WDEF patch (StripAddress is glue, and a5 wasn't set up)
    6/1/92  SJF     fixed varCode bug that made zoom boxes not work (masked out high 8 bits)
    
*******************************************/
 
#include <Windows.h>
 
/* add 2 to this when checking with FindWindow() ! */
 
#define kOurHit 32
 
Boolean gInBackground;
Boolean gDone;
 
void InitStuff(void);
void EventLoop(WindowPtr window);
void DoDrag(WindowPtr window,Point globMouse);
void HandleMouseDowns(EventRecord *ev);
void HandleContent(WindowPtr theWindow,EventRecord *ev);
void HandleUpdates(WindowPtr wind);
void DoDeActivate(WindowPtr window,Boolean chFlag);
void DoActivate(WindowPtr window,Boolean chFlag);
void HandleActivates(EventRecord *ev);
void HandleSREvt(long message);
void DoGrow(WindowPtr window,Point globMouse);
void PatchWindowWDEF(WindowPtr window);
pascal long MyWDEFPatch(short varCode,WindowPtr window,short message,long param);
void HandleOurPart(WindowPtr window);
 
 
/* this struct allows us to insert a WDEF patch safely.  It contains a jump instruction
    and stores the old handle to the WDEF
*/
 
typedef struct {
    short jmpInst;
    ProcPtr patchAddr;
    Handle oldAddr;
    long ourA5;
} WDEFPatch, *WDEFPatchPtr, **WDEFPatchHndl;
 
 
void main(void)
{
    WindowPtr mainWindow;
    Rect bounds = {100,100,150,300};
    
    gInBackground = false;
    gDone = false;
    
    InitStuff();
    mainWindow = NewWindow(nil,&bounds,"\pWDEF Patcher",false,8,(WindowPtr)-1,true,0);
    PatchWindowWDEF(mainWindow);
    ShowWindow(mainWindow);
    EventLoop(mainWindow);
}
 
 
void InitStuff(void)
{
    InitGraf(&qd.thePort);
    InitFonts();
    InitWindows();
    InitMenus();
    TEInit();
    InitDialogs(nil);
    InitCursor();
    FlushEvents(everyEvent,0);
}
 
 
void EventLoop(WindowPtr window)
{
    EventRecord ev;
    
    do {
        if (WaitNextEvent(everyEvent,&ev,10,nil)) {
            switch (ev.what) {
                case mouseDown:
                    HandleMouseDowns(&ev);
                    break;
                case updateEvt:
                    HandleUpdates((WindowPtr)ev.message);
                    break;
                case activateEvt:
                    HandleActivates(&ev);
                    break;
                case app4Evt:
                    HandleSREvt(ev.message);
                    break;
            }
        }
    } while (!gDone);
}
 
 
void HandleMouseDowns(EventRecord *ev)
{
    WindowPtr theWindow;
    short part;
    
    part = FindWindow(ev->where,&theWindow);
 
    switch (FindWindow(ev->where,&theWindow)) {
        case inMenuBar:
            break;
        case inSysWindow:
            SystemClick(ev,theWindow);
            break;
        case inDrag:
            DoDrag(theWindow,ev->where);
            break;
        case inGoAway:
            if (TrackGoAway(theWindow,ev->where)) {
                gDone = true;
            }
            break;
        case inContent:
            HandleContent(theWindow,ev);
            break;
        case inGrow:
            DoGrow(theWindow,ev->where);
            break;
        case kOurHit+2:                     // remember, we're adding 2 so the FindWindow/WDEF
            HandleOurPart(theWindow);       // codes match
            break;
    }
}
 
 
 
/* handles a mouse down in our added window part */
 
void HandleOurPart(WindowPtr window)
{
    long final;
    
    SetPort(window);
    InvertRect(&window->portRect);
    while (StillDown());
    InvertRect(&window->portRect);
}
 
 
/* DoDrag: Handles drag window events */
 
void DoDrag(WindowPtr window,Point globMouse)
{
    Rect dragRect;
    
    SetRect(&dragRect,-32000,-32000,32000,32000);
    
    DragWindow(window,globMouse,&dragRect);
    SetPort(window);
}
 
 
/* DoGrow: Handles grow window events */
 
void DoGrow(WindowPtr window,Point globMouse)
{
    long newSize;
    Rect windLimits;
    GrafPtr tempPort;
    
    SetRect(&windLimits,64,64,32000,32000);
    
    if ((newSize = GrowWindow(window,globMouse,&windLimits)) != 0) {
        GetPort(&tempPort);
        SetPort(window);
        SizeWindow(window,LoWord(newSize),HiWord(newSize),true);
        InvalRect(&window->portRect);
        SetPort(tempPort);
    }
}
 
 
void HandleContent(WindowPtr theWindow,EventRecord *ev)
{
    GrafPtr savePort;
    Point where;
    
    where = ev->where;
    SetPort(theWindow);
    
    if (theWindow != FrontWindow()) {
        SelectWindow(theWindow);
        return;
    }
}
 
 
void HandleUpdates(WindowPtr wind)
{
    GrafPtr savePort;
    
    GetPort(&savePort);
    SetPort(wind);
    BeginUpdate(wind);
    EraseRect(&wind->portRect);
    DrawGrowIcon(wind);
    EndUpdate(wind);
    SetPort(savePort);
}
 
 
void HandleActivates(EventRecord *ev)
{
    if ((ev->modifiers & activeFlag) != 0) {
        DoActivate((WindowPtr)ev->message,((ev->modifiers & 0x0002) != 0));
    }
    else {
        DoDeActivate((WindowPtr)ev->message,((ev->modifiers & 0x0002) != 0));
    }
}
 
 
/* DoActivate: Performs activate tasks */
 
void DoActivate(WindowPtr window,Boolean chFlag)
{
    DrawGrowIcon(window);
}
 
 
/* DoDeActivate: Performs deactivate tasks */
 
void DoDeActivate(WindowPtr window,Boolean chFlag)
{
    DrawGrowIcon(window);
}
 
 
void HandleSREvt(long message)
{
    if ((message >> 24) == 1)
        if ((message & 1) != 0) {
            gInBackground = false;
            SetCursor(&arrow);
            if (FrontWindow()) {  
                HiliteWindow(FrontWindow(),true);
                DoActivate(FrontWindow(),true);
            }
        }
        else if (FrontWindow()) {
            gInBackground = true;
            HiliteWindow(FrontWindow(),false);
            DoDeActivate(FrontWindow(),true);
        }
}
 
 
 
 
/* this installs the WDEF patch into a window */
 
void PatchWindowWDEF(WindowPtr window)
{
    WDEFPatchHndl wdefHndl;
    WDEFPatchPtr wdefPatch;
    Handle oldAddr;
    unsigned long wdefEntry;
    
    wdefHndl = (WDEFPatchHndl)NewHandle(sizeof(WDEFPatch));
    if (MemError()!=noErr)
        ExitToShell();
        
    oldAddr = ((WindowPeek)window)->windowDefProc;
    if (GetMMUMode()) // 32-bit
        wdefEntry = (unsigned long)wdefHndl;
    else
        wdefEntry = (unsigned long)StripAddress(wdefHndl) | ((unsigned long)oldAddr&0xff000000);
    
    HLock(wdefHndl);
    wdefPatch = *wdefHndl;
    wdefPatch->oldAddr = oldAddr;
    wdefPatch->jmpInst = 0x4ef9; /*JMP*/
    wdefPatch->patchAddr = MyWDEFPatch;
#ifdef __SYSEQU__
    wdefPatch->ourA5 = *(long *)CurrentA5;
#else
    wdefPatch->ourA5 = (long)CurrentA5;
#endif
    HUnlock(wdefHndl);
    ((WindowPeek)window)->windowDefProc = (Handle)wdefEntry;
}
 
 
pascal long MyWDEFPatch(short varCode,WindowPtr window,short message,long param)
{
    WDEFPatchHndl wdPatch;
    pascal long (*wdefProc)(short varCode,WindowPtr window,short message,long param);
    Handle oldWDEF;
    long result;
    Rect ourRect,ourElementRect;
    Point *hitPt;
    Point mouse;
    long appA5,saveA5;
    
    wdPatch = (WDEFPatchHndl) ((WindowPeek)window)->windowDefProc;
    appA5 = (**wdPatch).ourA5;
    saveA5 = SetA5(appA5);
    
    ourRect = (**((WindowPeek)window)->strucRgn).rgnBBox;
    SetRect(&ourElementRect,ourRect.right-32,ourRect.top+4,ourRect.right-20,ourRect.top+15);
    
    oldWDEF = (**wdPatch).oldAddr;
    HLock(oldWDEF);
    wdefProc = (void *)*oldWDEF;
    wdefProc = (void *)StripAddress(wdefProc);
    result = (wdefProc)(varCode,window,message,param);
    
    switch (message) {
        case wDraw:
            if (((WindowPeek)window)->visible) {
                PenNormal();                            // draw our part
                InsetRect(&ourElementRect,-1,0);
                EraseRect(&ourElementRect);
                InsetRect(&ourElementRect,1,0);
                FrameRect(&ourElementRect);
                InsetRect(&ourElementRect,2,2);
                FrameRect(&ourElementRect);
            }
            break;
        case wHit:
            hitPt = (Point *)&param;                    // hit test our part
            if (PtInRect(*hitPt,&ourElementRect))
                result =  kOurHit;
            break;
    }
 
    HUnlock(oldWDEF);
    
    SetA5(saveA5);
    
    return result;
}