OffScreenControlUpdate.c

/*
    File:       OffScreenControlUpdate.c
 
    Contains:   A simple code sample which demonstrates how to draw controls into an off-screen
                GWorld so you can draw them back to the screen without flicker. 
 
    Written by:     
 
    Copyright:  Copyright © 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):
                7/12/1999   Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
                
 
*/
 
#define OLDROUTINELOCATIONS     0
#define OLDROUTINENAMES         0
#define SystemSevenOrLater      1
#include <Sound.h>
#ifndef __FONTS__
#   include <Fonts.h>
#endif
 
#ifndef __DIALOGS__
#   include <Dialogs.h>
#endif
 
#ifndef __QDOFFSCREEN__
#   include <QDOffscreen.h>
#endif
 
enum
{
    kDialogItemIndex_DrawButton = 3,
    kDialogItemIndex_CheckBox
};
 
static pascal OSErr InitMac (void)
{
    MaxApplZone ( );
    InitGraf (&(qd.thePort));
    InitFonts ( );
    InitWindows ( );
    InitMenus ( );
    TEInit ( );
    InitDialogs (nil);
 
    return noErr;
}
 
static pascal GDHandle GetMaxControlDevice (ControlRef controlRef)
{
    GrafPtr     savePort            = qd.thePort;
    Rect        globalControlRect   = (**controlRef).contrlRect;
 
    SetPort ((**controlRef).contrlOwner);
    {
        LocalToGlobal ((Point *) &(globalControlRect.top));
        LocalToGlobal ((Point *) &(globalControlRect.bottom));
    }
    SetPort (savePort);
 
    return GetMaxDevice (&globalControlRect);
}
 
static pascal OSErr BuggyDraw1ControlWithOffScreen (ControlRef controlRef, short transferMode)
{
    //
    //  This doesn't work. Check boxes draw as push buttons. I suspect this
    //  is because controls assume they live in a window, and for the
    //  duration of the Draw1Control call in this function, the control
    //  lives in a GWorld, not a window. Probably the CDEF dereferences
    //  some offset beyond the end of the GWorld, since a window record
    //  is bigger.
    //
 
    OSErr err = noErr;
 
    GDHandle maxDevice = GetMaxControlDevice (controlRef);
 
    if (maxDevice)
    {
        GWorldPtr       grafWorld       = nil;
        Rect            contrlRect      = (**controlRef).contrlRect;
        PixMapHandle    contrlPixMapH   = (**maxDevice).gdPMap;
        short           pixelDepth      = (**contrlPixMapH).pixelSize;
        CTabHandle      cTable          = (**contrlPixMapH).pmTable;
 
        if (!(err = NewGWorld (&grafWorld,pixelDepth,&contrlRect,cTable,maxDevice,noNewDevice)))
        {
            GWorldPtr       saveGrafWorld   = nil;
            GDHandle        saveGDH         = nil;
            PixMapHandle    pixMapH         = GetGWorldPixMap (grafWorld);
 
            GetGWorld (&saveGrafWorld,&saveGDH);
            SetGWorld (grafWorld,nil);
 
            if (LockPixels (pixMapH)) // this should always work, but be paranoid
            {
                GrafPtr     contrlOwner     = (**controlRef).contrlOwner;
                BitMapPtr   srcBitMap       = &(((GrafPtr) grafWorld)->portBits),
                            destBitMap      = &(contrlOwner->portBits);
 
                EraseRect (&contrlRect);
                (**controlRef).contrlOwner = (GrafPtr) grafWorld;
                Draw1Control (controlRef);
                (**controlRef).contrlOwner = contrlOwner;
 
                CopyBits (srcBitMap,destBitMap,&contrlRect,&contrlRect,transferMode,nil);
 
                UnlockPixels (pixMapH);
            }
 
            SetGWorld (saveGrafWorld,saveGDH);
            DisposeGWorld (grafWorld);
        }
    }
 
    return err;
}
 
static pascal Boolean GrafPortIsColor (GrafPtr gp)
{
    if (!gp) gp = qd.thePort;
    return (0xC000 & (((CGrafPtr) gp)->portVersion)) ? true : false;
}
 
static pascal OSErr Draw1ControlWithOffScreen (ControlRef controlRef)
{
    //
    //  [1]     create a GWorld with the same coords as the control
    //          and as deep as the deepest intersecting monitor
    //  [2]     make sure nothing gets colorized by CopyBits
    //  [3]     grab the screen pixels that will be under the control
    //  [4]     make the control's GrafPort have the GWorld's pixels
    //  [5]     draw the control into the off-screen bits
    //  [6]     blast the control image onto the screen
    //
 
    OSErr err = noErr;
 
    GrafPtr contrlOwner = (**controlRef).contrlOwner;
 
    if (!GrafPortIsColor (contrlOwner))
        err = paramErr;
        //  contrlOwner must be color because the GWorld must be color
        //  and both ports must be the same
    else
    {
        // begin 1
 
        GDHandle maxDevice = GetMaxControlDevice (controlRef);
 
        if (!maxDevice)
            err = nilHandleErr;
        else
        {
            Rect            contrlRect  = (**controlRef).contrlRect;
            GWorldPtr       grafWorld   = nil;
            PixMapHandle    gdPMap      = (**maxDevice).gdPMap;
            short           pixelSize   = (**gdPMap).pixelSize;
            CTabHandle      pmTable     = (**gdPMap).pmTable;
 
            if (!(err = NewGWorld (&grafWorld,pixelSize,&contrlRect,pmTable,maxDevice,0)))
            {
                PixMapHandle grafWorldPixMapH = GetGWorldPixMap (grafWorld);
 
                if (!grafWorldPixMapH)
                    err = nilHandleErr;
                else if (!LockPixels (grafWorldPixMapH))
                    err = updPixMemErr;
                else
                {
                    // end 1
 
                    BitMapPtr   grafWorldBitMap     = &(((GrafPtr) grafWorld)->portBits),           // 3,4,6
                                controlBitMap       = &(contrlOwner->portBits);                     // 3,4,6
                    BitMap      saveControlBitMap   = *controlBitMap;                               // 4
                    RGBColor    rgbFgColor          = grafWorld->rgbFgColor,                        // 2
                                rgbBkColor          = grafWorld->rgbBkColor;                        // 2
                    GWorldPtr   saveGrafWorld       = nil;                                          // 2
                    GDHandle    saveGDH             = nil;                                          // 2
 
                    GetGWorld (&saveGrafWorld,&saveGDH);                                            // 2
 
                    SetGWorld (grafWorld,nil);                                                      // 2
                    ForeColor (blackColor);                                                         // 2
                    BackColor (whiteColor);                                                         // 2
                    CopyBits (controlBitMap,grafWorldBitMap,&contrlRect,&contrlRect,srcCopy,nil);   // 3
                    RGBForeColor (&rgbFgColor);                                                     // 2
                    RGBBackColor (&rgbBkColor);                                                     // 2
 
                    *controlBitMap = *grafWorldBitMap;                                              // 4
                    PortChanged (contrlOwner);                                                      // 4
                    Draw1Control (controlRef);                                                      // 5
                    *controlBitMap = saveControlBitMap;                                             // 4
                    PortChanged (contrlOwner);                                                      // 4
 
                    SetGWorld ((CGrafPtr)contrlOwner,nil);                                          // 2
                    rgbFgColor = ((CGrafPtr)contrlOwner)->rgbFgColor,                               // 2
                    rgbBkColor = ((CGrafPtr)contrlOwner)->rgbBkColor;                               // 2
                    ForeColor (blackColor);                                                         // 2
                    BackColor (whiteColor);                                                         // 2
                    CopyBits (grafWorldBitMap,controlBitMap,&contrlRect,&contrlRect,srcCopy,nil);   // 6
                    RGBForeColor (&rgbFgColor);                                                     // 2
                    RGBBackColor (&rgbBkColor);                                                     // 2
 
                    SetGWorld (saveGrafWorld,saveGDH);                                              // 2
                    UnlockPixels (grafWorldPixMapH);                                                // 1
                }
                DisposeGWorld (grafWorld);                                                          // 1
            }
        }
    }
 
    return err;
}
 
void main (void)
{
    if (InitMac ( ))
        SysBeep (10);
    else
    {
        DialogRef dlgRef = GetNewDialog (129,nil,(WindowRef)-1);
        if (dlgRef)
        {
            short itemHit;
 
            SetDialogDefaultItem (dlgRef,kStdOkItemIndex);
 
            do
            {
                ModalDialog (nil,&itemHit);
 
                if (itemHit == kDialogItemIndex_DrawButton)
                {
                    short iType; Handle iHandle; Rect iRect;
                    GetDialogItem (dlgRef,kDialogItemIndex_CheckBox,&iType,&iHandle,&iRect);
                    if (Draw1ControlWithOffScreen ((ControlRef)iHandle))
                        SysBeep (10);
                }
            }
            while (itemHit != kStdOkItemIndex);
 
            DisposeDialog (dlgRef);
        }
    }
}