MoreAppearance/MoreAppearance.cp

/*
    File:       MoreAppearance.cp
 
    Contains:   
 
    Written by: Pete Gontier
 
    Copyright:  Copyright (c) 1998 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):
 
         <4>     20/3/00    Quinn   The various "have this feature" routines now auto-initialise. 
                                    Made this change so that other MIB modules can call them without
                                    worrying about initialising this module.
         <3>     1/22/99    PCG     TARGET_CARBON
         <2>    11/11/98    PCG     fix header
         <1>    11/10/98    PCG     first big re-org at behest of Quinn
 
    Old Change History (most recent first):
 
         <6>    10/11/98    Quinn   Convert "MorePrefix.h" to "MoreSetup.h".
         <5>     9/11/98    PCG     conditionalize calls to Appearance Manager 1.1 so they occur on
                                    PowerPC only and add sanity checks for Appearance Manager
                                    availability
         <4>      9/4/98    PCG     theme drawing state functions call real APIs if present
         <3>      9/1/98    PCG     clean up Gestalt cache logic; MoreGetThemeDrawingState inits
                                    stateResult to NIL
         <2>      9/1/98    PCG     add theme drawing state functions
         <1>     6/16/98    PCG     initial checkin
*/
 
#include "MoreSetup.h"
 
#include "MoreAppearance.h"
#include "MoreQuickDraw.h"
 
#include <Appearance.h>
#include <Gestalt.h>
#include <MacMemory.h>
 
static Boolean gHaveInited;
static UInt32  gAppearanceAttributes;
static UInt32  gAppearanceVersion;
 
pascal long GetAppearanceVersion (void)
{
    OSStatus junk;
    
    //
    //  Simply returns our cached variable. See InitMoreAppearance
    //  for how this variable is initialized.
    //
 
    if (!gHaveInited) {
        junk = InitMoreAppearance();
        MoreAssertQ(junk == noErr);
    }
    return gAppearanceVersion;
}
 
pascal Boolean HaveAppearance (void)
{
    OSStatus junk;
 
    //
    //  Tests a bit in our cached variable and promotes it to a byte
    //  indicating whether the Appearance APIs are present.
    //
 
    if (!gHaveInited) {
        junk = InitMoreAppearance();
        MoreAssertQ(junk == noErr);
    }
    return (gAppearanceAttributes & (1 << gestaltAppearanceExists)) != 0;
}
 
pascal Boolean AppearanceInCompatibilityMode (void)
{
    OSStatus junk;
 
    //
    //  Tests a bit in our cached variable and promotes it to a byte
    //  indicating whether Appearance is running in compatibility mode.
    //
 
    if (!gHaveInited) {
        junk = InitMoreAppearance();
        MoreAssertQ(junk == noErr);
    }
    return (gAppearanceAttributes & (1 << gestaltAppearanceCompatMode)) != 0;
}
 
pascal OSStatus InitMoreAppearance (void)
{
    //
    //  Caches some Gestalt values so we don't have to keep calling Gestalt.
    //  If Appearance is present, registers us as an Appearance-savvy app.
    //  Second-guesses the version advertised by Gestalt.
    //
 
    gHaveInited = true;
    
    OSStatus err = Gestalt (gestaltAppearanceAttr, (SInt32 *) &gAppearanceAttributes);
 
    if (err == gestaltUndefSelectorErr)
    {
        gAppearanceAttributes = 0;
        err = noErr;
    }
    else if (!err)
    {
        err = Gestalt (gestaltAppearanceVersion, (SInt32 *) &gAppearanceVersion);
 
        if (err == gestaltUndefSelectorErr)
        {
            gAppearanceVersion = 0x0100;
            err = noErr;
        }
    }
 
    if (!err && HaveAppearance ( ))
    {
        //
        //  Perform sanity checking for potential weak links.
        //  Even though Gestalt claims a certain version of
        //  Appearance is available, we still may not have
        //  successfully resolved all weak links to it. So
        //  we second-guess Gestalt's claim and fall back to
        //  progressively less useful versions of Appearance.
        //  This is not an extensible approach; Appearance
        //  Manager 2.0 weak links might be unresolved and
        //  this code would never know to check. Still, this
        //  code is only for ADDITIONAL paranoia/safety, and
        //  a new Appearance Manager will not render it
        //  invalid, just a little less canonical.
        //
 
#if TARGET_RT_MAC_CFM
 
#if TARGET_CPU_PPC
 
        if (gAppearanceVersion >= 0x0110 && !GetTheme)
            gAppearanceVersion = 0x0101;
 
#endif // TARGET_CPU_PPC
 
        if (gAppearanceVersion >= 0x0101 && !DrawThemeModelessDialogFrame)
            gAppearanceVersion = 0x0100;
 
        if (gAppearanceVersion >= 0x0100 && !RegisterAppearanceClient)
        {
            gAppearanceVersion      = 0;
            gAppearanceAttributes   = 0;
        }
 
#endif // TARGET_RT_MAC_CFM
 
        if (HaveAppearance ( ))
            err = RegisterAppearanceClient ( );
    }
 
    return err;
}
 
#pragma mark -
 
#if !TARGET_CARBON
 
struct MoreThemeDrawingStateTag
{
    //
    //  stolen from
    //      {CommonSystem}:Toolbox:ToolboxUtils:CommonUtilities:ColorPenState.c
    //
 
    Boolean         colorPort;
    Boolean         bkPatternIsValid;
    RGBColor        foreColor;
    RGBColor        backColor;
    PenState        pen;
    SInt16          textMode;
    PixPatHandle    pnPixPat;
    PixPatHandle    bkPixPat;
    Pattern         bkPat;
    UInt32          fgColor;
    UInt32          bkColor;
};
 
#endif
 
pascal OSStatus MoreGetThemeDrawingState (MoreThemeDrawingState *stateResult)
{
    //
    //  mostly stolen from
    //      {CommonSystem}:Toolbox:ToolboxUtils:CommonUtilities:ColorPenState.c
    //
 
    *stateResult = nil;
 
    OSStatus err = noErr;
 
#if TARGET_CPU_PPC
 
    if (::GetAppearanceVersion ( ) >= 0x0110 && ::GetThemeDrawingState)
        err = ::GetThemeDrawingState ((ThemeDrawingState *) stateResult);
    else
 
#endif
 
#if TARGET_CARBON
        err = unimpErr;
#else
 
    {
        MoreThemeDrawingState state = MoreThemeDrawingState (::NewPtrClear (sizeof (*state)));
 
        if (!state)
            err = ::MemError ( );
        else
        {
            GrafPtr curPort;
            
            ::GetPort( &curPort );
            
            state->pnPixPat = nil;
            state->bkPixPat = nil;
 
            state->colorPort = ::IsColorGrafPort( curPort );
            
            // Save the black and white information always
            
            state->bkPatternIsValid = true;
            state->bkPat = curPort->bkPat;
            state->bkColor = curPort->bkColor;
            state->fgColor = curPort->fgColor;
 
            if ( state->colorPort )
            {
                ::GetForeColor( &state->foreColor );
                ::GetBackColor( &state->backColor );
                
                //
                // If the pen pattern is not an old style pattern,
                // copy the handle. If it is an old style pattern,
                // GetPenState below will save the right thing.
                //
 
                PixPatHandle    penPixPat = ((CGrafPtr)curPort)->pnPixPat;
                PixPatHandle    backPixPat = ((CGrafPtr)curPort)->bkPixPat;
                
                if ( penPixPat != NULL )
                    if( (**penPixPat).patType != 0 )
                        state->pnPixPat = penPixPat;
 
                //
                // If the back pattern is not an old style pattern,
                // copy the handle, else get the old pattern into
                // bkPat for restoring that way.
                //
                
                if( backPixPat != NULL )
                {
                    if ( (**backPixPat).patType != 0 )
                        state->bkPixPat = backPixPat;
                    else
                        state->bkPat = *(PatPtr)(*(**backPixPat).patData);
                    
                    state->bkPatternIsValid = true;
                }
                else
                {
                    state->bkPatternIsValid = false;
                }
                
            }
            
            ::GetPenState( &state->pen );
            state->textMode = curPort->txMode;
 
            *stateResult = state;
        }
    }
 
#endif
 
    return err;
}
 
pascal OSStatus MoreNormalizeThemeDrawingState (void)
{
    //
    //  mostly stolen from
    //      {CommonSystem}:Toolbox:ToolboxUtils:CommonUtilities:ColorPenState.c
    //
 
    OSStatus err = noErr;
 
#if TARGET_CPU_PPC
 
    if (::GetAppearanceVersion ( ) >= 0x0110 && ::NormalizeThemeDrawingState)
        err = NormalizeThemeDrawingState ( );
    else
 
#endif
 
#if TARGET_CARBON
        err = unimpErr;
#else
 
    {
        static Pattern  whitePat = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
        GrafPtr         curPort;
        
        ::GetPort( &curPort );
        ::ForeColor( blackColor );
        ::BackColor( whiteColor );
        ::PenNormal ( );
        ::BackPat( &whitePat );
        ::TextMode( srcOr );
    }
 
#endif
 
    return err;
}
 
pascal OSStatus MoreSetThemeDrawingState (MoreThemeDrawingState state, Boolean disposeNow)
{
    //
    //  mostly stolen from
    //      {CommonSystem}:Toolbox:ToolboxUtils:CommonUtilities:ColorPenState.c
    //  and
    //      {CommonSystem}:Toolbox:Appearance:AppearanceCore:ThemeDrawingState.cp
    //
 
    OSStatus err = noErr;
 
    if (!state)
        err = paramErr;
    else
 
#if TARGET_CPU_PPC
 
    if (::GetAppearanceVersion ( ) >= 0x0110 && ::SetThemeDrawingState)
        err = ::SetThemeDrawingState (ThemeDrawingState (state), disposeNow);
    else
 
#endif
 
#if TARGET_CARBON
        err = unimpErr;
#else
 
    {
        GrafPtr curPort;
        
        ::GetPort( &curPort );
 
        ::SetPenState (&(state->pen));
 
        //
        // If we saved color information, and this port is a
        // color port, use the color stuff, else just use the
        // black and white information.
        //
    
        if ( ::IsColorGrafPort( curPort ) && state->colorPort )
        {
            ::RGBForeColor( &state->foreColor );
            ::RGBBackColor( &state->backColor );
 
            if ( state->pnPixPat != NULL )
                ::PenPixPat( state->pnPixPat );
            
            if( state->bkPatternIsValid )
            {
                if ( state->bkPixPat != NULL )
                    ::BackPixPat( state->bkPixPat );
                else
                    ::BackPat( &state->bkPat );
            }
        }
        else
        {
            //
            // back pattern is always valid for monochrome ports
            //
        
            ::BackPat( &state->bkPat );
            ::ForeColor( state->fgColor );
            ::BackColor( state->bkColor );
        }
 
        ::TextMode( state->textMode );
 
        if (disposeNow)
        {
            ::DisposePtr (Ptr (state));
            err = ::MemError ( );
        }
    }
 
#endif
 
    return err;
}
 
pascal OSStatus MoreDisposeThemeDrawingState (MoreThemeDrawingState state)
{
    //
    //  mostly stolen from
    //      {CommonSystem}:Toolbox:Appearance:AppearanceCore:ThemeDrawingState.cp
    //
 
    OSStatus err = noErr;
 
    if (!state)
        err = paramErr;
    else
 
#if TARGET_CPU_PPC
 
    if (::GetAppearanceVersion ( ) >= 0x0110 && ::DisposeThemeDrawingState)
        err = ::DisposeThemeDrawingState (ThemeDrawingState (state));
    else
 
#endif
 
#if TARGET_CARBON
        err = unimpErr;
#else
 
    {
        ::DisposePtr (Ptr (state));
        err = ::MemError ( );
    }
 
#endif
 
    return err;
}