TweetFollow Us on Twitter

MACINTOSH C CARBON

Demonstration Program MoreResources

Goto Contents

// *******************************************************************************************
// MoreResources.c                                                          CARBON EVENT MODEL
// *******************************************************************************************
// 
// This program uses custom resources to:
//
// o  Store application preferences in the resource fork of a Preferences file.
//
// o  Store, in the resource fork of a document file:
//
//    o  The size and position of the window associated with the document.
//
//    o  A flattened PMPageFormat object containing information about how the pages of the
//       document should be printed, for example, on what paper size, in what printable
//       area, and in what orientation (landscape or portrait). 
//
// The program also demonstrates setting, storing, and retrieving application preferences 
// using Core Foundation Preferences Services.
//
// The program utilises the following standard resources:
//
// o  A 'plst' resource.
//
// o  An 'MBAR' resource, and 'MENU' resources for OS9Apple/Applcation, File, Edit and 
//    Demonstration menus (preload, non-purgeable).  
//
// o  A 'DLOG' resource (purgeable) and associated 'dlgx', 'DITL' and 'CNTL' resources 
//    (purgeable) associated with the display of, and user modification of, current 
//    application preferences. 
//
// o  A 'STR#' resource (purgeable) containing the required name of the preferences file
//    created by the program.
//
// o  A 'STR ' resource (purgeable) containing the application-missing string, which is copied
//    to the resource fork of the preferences file.
//
// o  A 'SIZE' resource with the acceptSuspendResumeEvents, canBackground, 
//    doesActivateOnFGSwitch, and isHighLevelEventAware flags set.
//
// The program creates and utilises the following custom resources:
//
// o  A 'PrFn' (preferences) resource comprising three boolean values, which is located in the
//    program's resource file, which contains default preference values, and which is copied 
//    to the resource fork of a preferences file created when the program is run for the first
//    time.  Thereafter, the 'PrFn' resource in the preferences file is used for the storage
//    and retrieval of application preferences set by the user.
//
// o  A 'WiSp' (window size and position) resource, which is created in the resource fork of
//    the document file used by the program, and which is used to store the associated 
//    window's port rectangle converted to global coordinates.
//
// o  A 'PgFt' (page format) resource, which is created in the resource fork of the document
//    file used by the program, and which is used to store a flattened PMPageFormat object.
//
// *******************************************************************************************

// .................................................................................. includes

#include <Carbon.h>

// ................................................................................... defines

#define rMenubar          128
#define mAppleApplication 128
#define  iAbout           1
#define mFile             129
#define  iOpen            2
#define  iClose           4
#define  iPageSetup       9
#define  iQuit            12
#define mEdit             130
#define  iPreferences     10
#define rPrefsDialog      128
#define  iSound           4
#define  iFullScreen      5
#define  iAutoScroll      6
#define rStringList       128
#define  iPrefsFileName   1
#define rTypePrefs        'PrFn'
#define  kPrefsID         128
#define rTypeWinSizePos   'WiSp'
#define  kWinSizePosID    128
#define rPageFormat       'PgFt'
#define  kPageFormatID    128
#define rTypeAppMiss      'STR '
#define  kAppMissID       -16397
#define topLeft(r)        (((Point *) &(r))[0])
#define botRight(r)       (((Point *) &(r))[1])

// .................................................................................. typedefs

typedef struct
{
  Boolean sound;
  Boolean fullScreen;
  Boolean autoScroll;
  SInt16  programRunCount;
} appPrefs, **appPrefsHandle;

typedef struct
{
  Rect windowRect;
} windowSizePos, **windowSizePosHandle;

typedef struct
{
  Handle pageFormatHdl;
  FSSpec fileFSSpec;
} docStructure, **docStructureHandle;

// .......................................................................... global variables

Boolean        gRunningOnX = false;
PMPrintSession gPrintSession;
WindowRef      gWindowRef;
SInt16         gAppResFileRefNum;
Boolean        gSoundPref;
Boolean        gFullScreenPref;
Boolean        gAutoScrollPref;  
SInt16         gProgramRunCountPref;
Boolean        gSoundCFPref;
Boolean        gFullScreenCFPref;
Boolean        gAutoScrollCFPref;
SInt16         gProgramRunCountCFPref;
Boolean        gWindowOpen        = false;
Boolean        gPageFormatChanged = false;
SInt16         gPrefsFileRefNum   = 0;

// ....................................................................... function prototypes

void      main                              (void);
void      doPreliminaries                   (void);
OSStatus  appEventHandler                   (EventHandlerCallRef,EventRef,void *);
OSStatus  windowEventHandler                (EventHandlerCallRef,EventRef,void *);
void      doDrawContent                     (WindowRef);
void      doAdjustMenus                     (void);
void      doMenuChoice                      (MenuID,MenuItemIndex);
void      doErrorAlert                      (SInt16);
void      doOpenCommand                     (void);
void      navEventFunction                  (NavEventCallbackMessage,NavCBRecPtr,
                                            NavCallBackUserData);
void      doOpenWindow                      (FSSpec);
void      doCloseWindow                     (void);
void      doPreferencesDialog               (void);
OSStatus  doPageSetupDialog                 (void);
void      doGetPreferencesResource          (void);
void      doGetPreferencesCFPrefs           (void);
OSErr     doCopyResource                    (ResType,SInt16,SInt16,SInt16);
void      doSavePreferencesResource         (void);
void      doSavePreferencesCFPrefs          (void);
void      doLoadAndSetWindowSizeAndPosition (WindowRef);
void      doGetFrameWidthAndTitleBarHeight  (WindowRef,SInt16 *,SInt16 *);
void      doSaveWindowSizeAndPosition       (WindowRef);
void      doGetPageFormat                   (WindowRef);
void      doSavePageFormat                  (WindowRef);

// ************************************************************************************** main

void  main(void)
{
  MenuBarHandle menubarHdl;
  SInt32        response;
  MenuRef       menuRef;
  OSStatus      osStatus;
  EventTypeSpec applicationEvents[] = { { kEventClassCommand, kEventProcessCommand  },
                                        { kEventClassMenu,    kEventMenuEnableItems } };

  // ........................................................................ do preliminaries

  doPreliminaries();

  // .................................. set current resource file to application resource fork

  gAppResFileRefNum = CurResFile();

  // ............................................................... set up menu bar and menus

  menubarHdl = GetNewMBar(rMenubar);
  if(menubarHdl == NULL)
    doErrorAlert(MemError());
  SetMenuBar(menubarHdl);
  DrawMenuBar();

  Gestalt(gestaltMenuMgrAttr,&response);
  if(response & gestaltMenuMgrAquaLayoutMask)
  {
    menuRef = GetMenuRef(mFile);
    if(menuRef != NULL)
    {
      DeleteMenuItem(menuRef,iQuit);
      DeleteMenuItem(menuRef,iQuit - 1);
    }
    menuRef = GetMenuRef(mEdit);
    if(menuRef != NULL)
    {
      DeleteMenuItem(menuRef,iPreferences);
      DeleteMenuItem(menuRef,iPreferences - 1);
      DisableMenuItem(menuRef,0);
    }
  
    EnableMenuCommand(NULL,kHICommandPreferences);

    gRunningOnX = true;
  }
  else
  {
    menuRef = GetMenuRef(mFile);
    if(menuRef != NULL)
      SetMenuItemCommandID(menuRef,iQuit,kHICommandQuit);

    menuRef = GetMenuRef(mEdit);
    if(menuRef != NULL)
      SetMenuItemCommandID(menuRef,iPreferences,kHICommandPreferences);
  }

  // ................................................................. create printing session

  osStatus = PMCreateSession(&gPrintSession);
  if(osStatus != kPMNoError)
    doErrorAlert(osStatus);

  // ......................... read in application preferences and increment program run count

  doGetPreferencesResource();
  doGetPreferencesCFPrefs();

  gProgramRunCountPref++;
  gProgramRunCountCFPref++;

  // ....................................................... install application event handler
  
  InstallApplicationEventHandler(NewEventHandlerUPP((EventHandlerProcPtr) appEventHandler),
                                 GetEventTypeCount(applicationEvents),applicationEvents,
                                 0,NULL);

  // .............................................................. run application event loop

  RunApplicationEventLoop();
}

// *************************************************************************** doPreliminaries

void  doPreliminaries(void)
{
  MoreMasterPointers(320);
  InitCursor();
}

// *************************************************************************** appEventHandler

OSStatus  appEventHandler(EventHandlerCallRef eventHandlerCallRef,EventRef eventRef,
                          void * userData)
{
  OSStatus      result = eventNotHandledErr;
  UInt32        eventClass;
  UInt32        eventKind;
  HICommand     hiCommand;
  MenuID        menuID;
  MenuItemIndex menuItem;

  eventClass = GetEventClass(eventRef);
  eventKind  = GetEventKind(eventRef);

  switch(eventClass)
  {
    case kEventClassCommand:
      if(eventKind == kEventProcessCommand)
      {
        GetEventParameter(eventRef,kEventParamDirectObject,typeHICommand,NULL,
                          sizeof(HICommand),NULL,&hiCommand);
        menuID = GetMenuID(hiCommand.menu.menuRef);
        menuItem = hiCommand.menu.menuItemIndex;
        if(hiCommand.commandID == kHICommandPreferences)
        {
          doPreferencesDialog();
          result = noErr;
        }
        else if(hiCommand.commandID == kHICommandQuit)
        {
          while(FrontWindow())
            doCloseWindow();
          PMRelease(&gPrintSession);
          doSavePreferencesResource();
          doSavePreferencesCFPrefs();
        }
        else if((menuID >= mAppleApplication && menuID <= mEdit))
        {
          doMenuChoice(menuID,menuItem);
          result = noErr;
        }
      }
      break;

    case kEventClassMenu:
      if(eventKind == kEventMenuEnableItems)
      {
        doAdjustMenus();
        result = noErr;
      }
      break;
  }

  return result;
}

// ************************************************************************ windowEventHandler

OSStatus  windowEventHandler(EventHandlerCallRef eventHandlerCallRef,EventRef eventRef,
                             void* userData)
{
  OSStatus  result = eventNotHandledErr;
  UInt32    eventClass;
  UInt32    eventKind;
  WindowRef windowRef;
  Rect      mainScreenRect;
  BitMap    screenBits;
  Point     idealHeightAndWidth, minimumHeightAndWidth;
  
  eventClass = GetEventClass(eventRef);
  eventKind  = GetEventKind(eventRef);

  switch(eventClass)
  {
    case kEventClassWindow:
      GetEventParameter(eventRef,kEventParamDirectObject,typeWindowRef,NULL,sizeof(windowRef),
                    NULL,&windowRef);
      switch(eventKind)
      {
        case kEventWindowDrawContent:
          doDrawContent(windowRef);
          result = noErr;
          break;

        case kEventWindowGetIdealSize:
          mainScreenRect = GetQDGlobalsScreenBits(&screenBits)->bounds;
          idealHeightAndWidth.v = mainScreenRect.bottom - 75;
          idealHeightAndWidth.h = 600;
          SetEventParameter(eventRef,kEventParamDimensions,typeQDPoint,
                            sizeof(idealHeightAndWidth),&idealHeightAndWidth);
           result = noErr;
          break;

        case kEventWindowGetMinimumSize:
          minimumHeightAndWidth.v = 190; 
          minimumHeightAndWidth.h = 400;
          SetEventParameter(eventRef,kEventParamDimensions,typeQDPoint,
                            sizeof(minimumHeightAndWidth),&minimumHeightAndWidth);
          result = noErr;
          break;

        case kEventWindowClose:
          doCloseWindow();
          result = noErr;
          break;
      }
      break;
  }

  return result;
}

// ***************************************************************************** doDrawContent

void  doDrawContent(WindowRef windowRef)
{
  RGBColor           whiteColour  = { 0xFFFF, 0xFFFF, 0xFFFF };
  RGBColor           blueColour  = { 0x1818, 0x4B4B, 0x8181 };
  Rect               portRect;
  docStructureHandle docStrucHdl;
  PMPageFormat       pageFormat  = kPMNoPageFormat;
  Str255             string;
  PMResolution       resolution;
  PMRect             paperRect;
  PMRect             pageRect;
  UInt16             orientation;

  RGBForeColor(&whiteColour);
  RGBBackColor(&blueColour);
  GetWindowPortBounds(windowRef,&portRect);
  EraseRect(&portRect);  

  SetPortWindowPort(windowRef);

  MoveTo(10,20);
  TextFace(bold);
  DrawString("\pApplication Preferences:");
  MoveTo(10,35);
  DrawString("\pResource Fork Prefs File");
  MoveTo(170,35);
  DrawString("\pCF Preferences Services");
  TextFace(normal);
  MoveTo(10,50);
  DrawString("\pSound On:  ");
  if(gSoundPref)  DrawString("\pYES");
  else  DrawString("\pNO");
  MoveTo(10,65);
  DrawString("\pFull Screen On:  ");
  if(gFullScreenPref)  DrawString("\pYES");
  else  DrawString("\pNO");
  MoveTo(10,80);
  DrawString("\pAutoScroll On:  ");
  if(gAutoScrollPref)  DrawString("\pYES");
  else  DrawString("\pNO");
  MoveTo(10,95);
  DrawString("\pProgram run count: ");
  NumToString((SInt32) gProgramRunCountPref,string);
  DrawString(string);

  MoveTo(170,50);
  DrawString("\pSound On:  ");
  if(gSoundCFPref)  DrawString("\pYES");
  else  DrawString("\pNO");
  MoveTo(170,65);
  DrawString("\pFull Screen On:  ");
  if(gFullScreenCFPref)  DrawString("\pYES");
  else  DrawString("\pNO");
  MoveTo(170,80);
  DrawString("\pAutoScroll On:  ");
  if(gAutoScrollCFPref)  DrawString("\pYES");
  else  DrawString("\pNO");
  MoveTo(170,95);
  DrawString("\pProgram run count: ");
  NumToString((SInt32) gProgramRunCountCFPref,string);
  DrawString(string);

  docStrucHdl = (docStructureHandle) GetWRefCon(windowRef);
  PMUnflattenPageFormat((*docStrucHdl)->pageFormatHdl,&pageFormat);
  PMGetResolution(pageFormat,&resolution);
  PMGetAdjustedPaperRect(pageFormat,&paperRect);
  PMGetAdjustedPageRect(pageFormat,&pageRect);
  PMGetOrientation(pageFormat,&orientation);
  if(pageFormat != kPMNoPageFormat)
    PMRelease(&pageFormat);

  MoveTo(10,115);
  TextFace(bold);
  DrawString("\pInformation From Document's 'PgFt' (Page Format) Resource:"); 
  TextFace(normal);

  if((*docStrucHdl)->pageFormatHdl != NULL)
  {
    MoveTo(10,130);
    DrawString("\pApplication's Drawing Resolution:  ");
    NumToString((long) resolution.hRes,string);
    DrawString(string);
    DrawString("\p dpi horizontal, ");
    NumToString((long) resolution.vRes,string);
    DrawString(string);
    DrawString("\p dpi vertical");
    
    MoveTo(10,145);
    DrawString("\pPaper Rectangle Size in Drawing Resolution:  ");
    NumToString((long) (paperRect.bottom - paperRect.top),string);
    DrawString(string);
    DrawString("\p by ");
    NumToString((long) (paperRect.right - paperRect.left),string);
    DrawString(string);

    MoveTo(10,160);
    DrawString("\pPage Rectangle Size in Drawing Resolution:  ");
    NumToString((long) (pageRect.bottom - pageRect.top),string);
    DrawString(string);
    DrawString("\p by ");
    NumToString((long) (pageRect.right - pageRect.left),string);
    DrawString(string);

    MoveTo(10,175);
    DrawString("\pOrientation:  ");
    if(orientation == 1)
      DrawString("\pPortrait");
    else if(orientation == 2)
      DrawString("\pLandscape");
  }
  else
  {
    MoveTo(10,130);
    DrawString("\pA page format ('PgFt') resource has not been saved yet."); 
    MoveTo(10,145);
    DrawString("\pOpen the Page Setup... dialog before closing the window or quitting."); 
  }

  QDFlushPortBuffer(GetWindowPort(gWindowRef),NULL);
}

// ***************************************************************************** doAdjustMenus

void  doAdjustMenus(void)
{
  MenuRef menuRef;

  if(gWindowOpen)
  {
    menuRef = GetMenuRef(mFile);
    DisableMenuItem(menuRef,iOpen);
    EnableMenuItem(menuRef,iClose);
    EnableMenuItem(menuRef,iPageSetup);
  }
  else
  {
    menuRef = GetMenuRef(mFile);
    EnableMenuItem(menuRef,iOpen);
    DisableMenuItem(menuRef,iClose);
    DisableMenuItem(menuRef,iPageSetup);
  }

  DrawMenuBar();
}

// ****************************************************************************** doMenuChoice

void  doMenuChoice(MenuID menuID,MenuItemIndex menuItem)
{
  OSStatus osStatus;
  Rect     portRect;

  if(menuID == 0)
    return;

  switch(menuID)
  {
    case mAppleApplication:
      if(menuItem == iAbout)
        SysBeep(10);
      break;

    case mFile:
      switch(menuItem)
      {
        case iClose:
          doCloseWindow();
          break;

        case iOpen:
          doOpenCommand();
          break;

        case iPageSetup:
          osStatus = doPageSetupDialog();
          if(osStatus != kPMNoError && osStatus != kPMCancel)
            doErrorAlert(osStatus);
          if(FrontWindow())
          {
            GetWindowPortBounds(FrontWindow(),&portRect);
            InvalWindowRect(FrontWindow(),&portRect);
          }
          break;
      }
      break;
  }
}

// ****************************************************************************** doErrorAlert

void  doErrorAlert(SInt16 errorCode)
{
  Str255 errorString;
  SInt16 itemHit;

  NumToString((SInt32) errorCode,errorString);

  if(errorCode != memFullErr)
    StandardAlert(kAlertCautionAlert,errorString,NULL,NULL,&itemHit);
  else
  {
    StandardAlert(kAlertStopAlert,errorString,NULL,NULL,&itemHit);
    ExitToShell();
  }
}

// ***************************************************************************** doOpenCommand

void  doOpenCommand(void)
{
  OSErr            osError = noErr;
  NavDialogOptions dialogOptions;
  NavEventUPP      navEventFunctionUPP;  
  NavReplyRecord   navReplyStruc;
  SInt32           index, count;
  AEKeyword        theKeyword;
  DescType         actualType;
  FSSpec           fileSpec;  
  Size             actualSize;

  osError = NavGetDefaultDialogOptions(&dialogOptions);

  if(osError == noErr)
  {
    navEventFunctionUPP = NewNavEventUPP((NavEventProcPtr) navEventFunction);
    osError = NavGetFile(NULL,&navReplyStruc,&dialogOptions,navEventFunctionUPP,NULL,NULL,
                         NULL,NULL);
    DisposeNavEventUPP(navEventFunctionUPP);

    if(osError == noErr && navReplyStruc.validRecord)
    {
      osError = AECountItems(&(navReplyStruc.selection),&count);
      if(osError == noErr)
      {
        for(index=1;index<=count;index++)
        {
          osError = AEGetNthPtr(&(navReplyStruc.selection),index,typeFSS,&theKeyword,
                                &actualType,&fileSpec,sizeof(fileSpec),&actualSize);

          doOpenWindow(fileSpec);
        }
      }

      NavDisposeReply(&navReplyStruc);  
    }
  }
}

// ************************************************************************** navEventFunction

void  navEventFunction(NavEventCallbackMessage callBackSelector,NavCBRecPtr callBackParms,
                       NavCallBackUserData callBackUD)
{
}

// ****************************************************************************** doOpenWindow

void  doOpenWindow(FSSpec fileSpec)
{
  OSStatus           osError;
  docStructureHandle docStrucHdl;
  Rect               contentRect = { 100,100,290,500 };
  WindowAttributes   attributes  = { kWindowStandardHandlerAttribute |
                                      kWindowStandardDocumentAttributes };
  EventTypeSpec      windowEvents[] = { { kEventClassWindow, kEventWindowDrawContent    },
                                        { kEventClassWindow, kEventWindowGetIdealSize   },
                                        { kEventClassWindow, kEventWindowGetMinimumSize },
                                        { kEventClassWindow, kEventWindowClose          } };

  osError = CreateNewWindow(kDocumentWindowClass,attributes,&contentRect,&gWindowRef);
  if(osError != noErr)
    QuitApplicationEventLoop();

  if(!(docStrucHdl = (docStructureHandle) NewHandle(sizeof(docStructure))))
  {
    DisposeWindow(gWindowRef);
    QuitApplicationEventLoop();
  }

  SetWRefCon(gWindowRef,(SInt32) docStrucHdl);
  (*docStrucHdl)->fileFSSpec = fileSpec;
  SetWTitle(gWindowRef,(*docStrucHdl)->fileFSSpec.name);  
  (*docStrucHdl)->pageFormatHdl = NULL;

  SetPortWindowPort(gWindowRef);
  UseThemeFont(kThemeSmallSystemFont,smSystemScript);

  InstallWindowEventHandler(gWindowRef,
                            NewEventHandlerUPP((EventHandlerProcPtr) windowEventHandler),
                            GetEventTypeCount(windowEvents),windowEvents,0,NULL);
          
  doLoadAndSetWindowSizeAndPosition(gWindowRef);
  doGetPageFormat(gWindowRef);
  ShowWindow(gWindowRef);
  gWindowOpen = true; 
}

// ***************************************************************************** doCloseWindow

void  doCloseWindow(void)
{
  WindowRef          windowRef;
  docStructureHandle docStrucHdl;
  OSErr              osError = 0;

  windowRef = FrontWindow();
  docStrucHdl = (docStructureHandle) GetWRefCon(windowRef);

  doSaveWindowSizeAndPosition(windowRef);

  if(gPageFormatChanged)
    doSavePageFormat(windowRef);

  DisposeHandle((Handle) docStrucHdl);
  DisposeWindow(windowRef);
  gWindowOpen = false;
}

// *********************************************************************** doPreferencesDialog

void  doPreferencesDialog(void)
{
  DialogRef  modalDlgRef;
  ControlRef controlHdl;
  SInt16     itemHit;
  Rect       portRect;

  if(!(modalDlgRef = GetNewDialog(rPrefsDialog,NULL,(WindowRef) -1)))
    return;

  SetDialogDefaultItem(modalDlgRef,kStdOkItemIndex);
  SetDialogCancelItem(modalDlgRef,kStdCancelItemIndex);

  GetDialogItemAsControl(modalDlgRef,iSound,&controlHdl);
  SetControlValue(controlHdl,gSoundPref);
  GetDialogItemAsControl(modalDlgRef,iFullScreen,&controlHdl);
  SetControlValue(controlHdl,gFullScreenPref);
  GetDialogItemAsControl(modalDlgRef,iAutoScroll,&controlHdl);
  SetControlValue(controlHdl,gAutoScrollPref);

  ShowWindow(GetDialogWindow(modalDlgRef));

  do
  {
    ModalDialog(NULL,&itemHit);
    GetDialogItemAsControl(modalDlgRef,itemHit,&controlHdl);
    SetControlValue(controlHdl,!GetControlValue(controlHdl));
  } while((itemHit != kStdOkItemIndex) && (itemHit != kStdCancelItemIndex));
  
  if(itemHit == kStdOkItemIndex)
  {
    GetDialogItemAsControl(modalDlgRef,iSound,&controlHdl);
    gSoundPref = gSoundCFPref = GetControlValue(controlHdl);
    GetDialogItemAsControl(modalDlgRef,iFullScreen,&controlHdl);
    gFullScreenPref = gFullScreenCFPref = GetControlValue(controlHdl);
    GetDialogItemAsControl(modalDlgRef,iAutoScroll,&controlHdl);
    gAutoScrollPref = gAutoScrollCFPref = GetControlValue(controlHdl);        
  }

  DisposeDialog(modalDlgRef);

  if(gWindowRef)
  {
    GetWindowPortBounds(gWindowRef,&portRect);
    InvalWindowRect(gWindowRef,&portRect);
  }

  doSavePreferencesResource();
  doSavePreferencesCFPrefs();
}

// ************************************************************************* doPageSetupDialog

OSStatus  doPageSetupDialog(void)
{
  docStructureHandle docStrucHdl;
  OSStatus           osStatus    = kPMNoError;
  PMPageFormat       pageFormat  = kPMNoPageFormat;
  Boolean            userClickedOKButton;

  docStrucHdl = (docStructureHandle) GetWRefCon(gWindowRef);  
  HLock((Handle) docStrucHdl);

  if((*docStrucHdl)->pageFormatHdl == NULL)
  {
    osStatus = PMCreatePageFormat(&pageFormat);
    if((osStatus == kPMNoError) && (pageFormat != kPMNoPageFormat))
      osStatus = PMSessionDefaultPageFormat(gPrintSession,pageFormat);
    if(osStatus == kPMNoError)
      osStatus = PMFlattenPageFormat(pageFormat,&(*docStrucHdl)->pageFormatHdl);
  }
  else
  {
    osStatus = PMUnflattenPageFormat((*docStrucHdl)->pageFormatHdl,&pageFormat);
    if(osStatus == kPMNoError)
      osStatus = PMSessionValidatePageFormat(gPrintSession,pageFormat,kPMDontWantBoolean);
  }

  if((osStatus == kPMNoError) && (pageFormat != kPMNoPageFormat))
  {
    SetThemeCursor(kThemeArrowCursor);

    osStatus = PMSessionPageSetupDialog(gPrintSession,pageFormat,&userClickedOKButton);
    if(!userClickedOKButton)
      osStatus = kPMCancel;
  }

  if(osStatus == kPMNoError && userClickedOKButton)
  {
    DisposeHandle((*docStrucHdl)->pageFormatHdl);
    (*docStrucHdl)->pageFormatHdl = NULL;
    osStatus = PMFlattenPageFormat(pageFormat,&(*docStrucHdl)->pageFormatHdl);

    gPageFormatChanged = true;
  }

  if(pageFormat != kPMNoPageFormat)
    PMRelease(&pageFormat);

  HUnlock((Handle) docStrucHdl);

  return osStatus;
}

// ****************************************************************** doGetPreferencesResource

void  doGetPreferencesResource(void)
{
  Str255         prefsFileName;
  OSErr          osError;
  SInt16         volRefNum;
  long           directoryID;
  FSSpec         fileSSpec;
  SInt16         fileRefNum;
  appPrefsHandle appPrefsHdl;

  GetIndString(prefsFileName,rStringList,iPrefsFileName);

  osError = FindFolder(kUserDomain,kPreferencesFolderType,kDontCreateFolder,&volRefNum,
                       &directoryID);
  if(osError == noErr)
    osError = FSMakeFSSpec(volRefNum,directoryID,prefsFileName,&fileSSpec);
  if(osError == noErr || osError == fnfErr)
    fileRefNum = FSpOpenResFile(&fileSSpec,fsCurPerm);

  if(fileRefNum == -1)
  {
    FSpCreateResFile(&fileSSpec,'PpPp','pref',smSystemScript);
    osError = ResError();

    if(osError == noErr)
    {
      fileRefNum = FSpOpenResFile(&fileSSpec,fsCurPerm);
      if(fileRefNum != -1 )
      {
        UseResFile(gAppResFileRefNum);
          
        osError = doCopyResource(rTypePrefs,kPrefsID,gAppResFileRefNum,fileRefNum);
        if(osError == noErr)
          osError = doCopyResource(rTypeAppMiss,kAppMissID,gAppResFileRefNum,fileRefNum);
        if(osError != noErr)
        {
          CloseResFile(fileRefNum);
          osError = FSpDelete(&fileSSpec);
          fileRefNum = -1;
        }
      }
    }
  }

  if(fileRefNum != -1)
  {
    UseResFile(fileRefNum); 

    appPrefsHdl = (appPrefsHandle) Get1Resource(rTypePrefs,kPrefsID);
    if(appPrefsHdl == NULL)
      return;

    gSoundPref = (*appPrefsHdl)->sound;
    gFullScreenPref = (*appPrefsHdl)->fullScreen;
    gAutoScrollPref = (*appPrefsHdl)->autoScroll;
    gProgramRunCountPref = (*appPrefsHdl)->programRunCount;    

    gPrefsFileRefNum = fileRefNum;

    UseResFile(gAppResFileRefNum);
  }
}

// ******************************************************************* doGetPreferencesCFPrefs

void  doGetPreferencesCFPrefs(void)
{
  CFStringRef applicationID9 = CFSTR("MoreResources CFPrefs");
  CFStringRef applicationIDX = CFSTR("com.Windmill.MoreResources");
  CFStringRef applicationID;
  CFStringRef soundOnKey     = CFSTR("sound");
  CFStringRef fullScreenKey  = CFSTR("fullScreen");
  CFStringRef autoScrollKey  = CFSTR("autoScroll");
  CFStringRef runCountKey    = CFSTR("runCount");
  Boolean     booleanValue, success;

  if(gRunningOnX)
    applicationID = applicationIDX;
  else
    applicationID = applicationID9;

  booleanValue = CFPreferencesGetAppBooleanValue(soundOnKey,applicationID,&success);
  if(success)
    gSoundCFPref = booleanValue;
  else
  {
    gSoundCFPref      = true;
    gFullScreenCFPref = true;
    gAutoScrollCFPref = true;
    doSavePreferencesCFPrefs();
    return;
  }

  booleanValue = CFPreferencesGetAppBooleanValue(fullScreenKey,applicationID,&success);
  if(success)
    gFullScreenCFPref = booleanValue;

  booleanValue = CFPreferencesGetAppBooleanValue(autoScrollKey,applicationID,&success);
  if(success)
    gAutoScrollCFPref = booleanValue;

  gProgramRunCountCFPref = CFPreferencesGetAppIntegerValue(runCountKey,applicationID,
                                                           &success);
}

// **************************************************************************** doCopyResource

OSErr  doCopyResource(ResType resType,SInt16 resID,SInt16 sourceFileRefNum,
                      SInt16 destFileRefNum)
{
  SInt16  oldResFileRefNum;
  Handle  sourceResourceHdl;
  ResType ignoredType;
  SInt16  ignoredID;
  Str255  resourceName;
  SInt16  resAttributes;
  OSErr   osError;

  oldResFileRefNum = CurResFile();
  UseResFile(sourceFileRefNum);

  sourceResourceHdl = Get1Resource(resType,resID);

  if(sourceResourceHdl != NULL)
  {
    GetResInfo(sourceResourceHdl,&ignoredID,&ignoredType,resourceName);
    resAttributes = GetResAttrs(sourceResourceHdl);
    DetachResource(sourceResourceHdl);
    UseResFile(destFileRefNum);
    if(ResError() == noErr)
      AddResource(sourceResourceHdl,resType,resID,resourceName);
    if(ResError() == noErr)
      SetResAttrs(sourceResourceHdl,resAttributes);
    if(ResError() == noErr)
      ChangedResource(sourceResourceHdl);
    if(ResError() == noErr)
      WriteResource(sourceResourceHdl);
  }

  osError = ResError();

  ReleaseResource(sourceResourceHdl);
  UseResFile(oldResFileRefNum);

  return osError;
}

// ***************************************************************** doSavePreferencesResource

void  doSavePreferencesResource(void)
{
  SInt16         currentResFile;
  appPrefsHandle appPrefsHdl;
  Handle         existingResHdl;
  Str255         resourceName = "\pPreferences";

  if(gPrefsFileRefNum == -1)
    return;

  currentResFile = CurResFile();

  appPrefsHdl = (appPrefsHandle) NewHandleClear(sizeof(appPrefs));

  HLock((Handle) appPrefsHdl);

  (*appPrefsHdl)->sound = gSoundPref;
  (*appPrefsHdl)->fullScreen = gFullScreenPref;
  (*appPrefsHdl)->autoScroll = gAutoScrollPref;
  (*appPrefsHdl)->programRunCount = gProgramRunCountPref;     

  UseResFile(gPrefsFileRefNum);

  existingResHdl = Get1Resource(rTypePrefs,kPrefsID);
  
  if(existingResHdl != NULL)
  {
    RemoveResource(existingResHdl);
    DisposeHandle(existingResHdl);
    if(ResError() == noErr)
      AddResource((Handle) appPrefsHdl,rTypePrefs,kPrefsID,resourceName);
    if(ResError() == noErr)
      WriteResource((Handle) appPrefsHdl);
  }

  HUnlock((Handle) appPrefsHdl);

  ReleaseResource((Handle) appPrefsHdl);
  UseResFile(currentResFile);
}

// ****************************************************************** doSavePreferencesCFPrefs

void  doSavePreferencesCFPrefs(void)
{
  CFStringRef applicationID9 = CFSTR("MoreResources CFPrefs");
  CFStringRef applicationIDX = CFSTR("com.Windmill.MoreResources");
  CFStringRef applicationID;
  CFStringRef soundOnKey    = CFSTR("sound");
  CFStringRef fullScreenKey = CFSTR("fullScreen");
  CFStringRef autoScrollKey = CFSTR("autoScroll");
  CFStringRef yes           = CFSTR("yes");
  CFStringRef no            = CFSTR("no");
  CFStringRef runCountKey   = CFSTR("runCount");
  Str255      runCountPascalString;
  CFStringRef runCountCFString;

  if(gRunningOnX)
    applicationID = applicationIDX;
  else
    applicationID = applicationID9;

  if(gSoundCFPref)
    CFPreferencesSetAppValue(soundOnKey,yes,applicationID);
  else
    CFPreferencesSetAppValue(soundOnKey,no,applicationID);
    
  if(gFullScreenCFPref)
    CFPreferencesSetAppValue(fullScreenKey,yes,applicationID);
  else
    CFPreferencesSetAppValue(fullScreenKey,no,applicationID);

  if(gAutoScrollCFPref)
    CFPreferencesSetAppValue(autoScrollKey,yes,applicationID);
  else
    CFPreferencesSetAppValue(autoScrollKey,no,applicationID);

  NumToString((SInt32) gProgramRunCountCFPref,runCountPascalString);
  runCountCFString = CFStringCreateWithPascalString(NULL,runCountPascalString,
                                                        CFStringGetSystemEncoding());
  CFPreferencesSetAppValue(runCountKey,runCountCFString,applicationID);

  CFPreferencesAppSynchronize(applicationID);

  if(runCountCFString != NULL)
    CFRelease(runCountCFString);
}

// ********************************************************* doLoadAndSetWindowSizeAndPosition

void  doLoadAndSetWindowSizeAndPosition(WindowRef windowRef)
{
  docStructureHandle  docStrucHdl;
  SInt16              fileRefNum;
  OSErr               osError;
  windowSizePosHandle windowSizePosHdl;
  Rect                windowRect;
  SInt16              frameWidth, titleBarHeight, menuBarHeight;

  docStrucHdl = (docStructureHandle) GetWRefCon(windowRef);
  fileRefNum = FSpOpenResFile(&(*docStrucHdl)->fileFSSpec,fsRdWrPerm);
  if(fileRefNum < 0)
  {
    osError = ResError();
    doErrorAlert(osError);
    return;
  }

  windowSizePosHdl = (windowSizePosHandle) Get1Resource(rTypeWinSizePos,kWinSizePosID);

  if(windowSizePosHdl != NULL )
  {
    windowRect = (*windowSizePosHdl)->windowRect;
  }
  else
  {
    doGetFrameWidthAndTitleBarHeight(windowRef,&frameWidth,&titleBarHeight);
    GetThemeMenuBarHeight(&menuBarHeight);
    SetRect(&windowRect,frameWidth + 1,titleBarHeight + menuBarHeight + 1,
            frameWidth + 400,titleBarHeight + menuBarHeight + 190);
  }

  MoveWindow(windowRef,windowRect.left,windowRect.top,false);
  SizeWindow(windowRef,windowRect.right - windowRect.left,windowRect.bottom - windowRect.top,
             true);

  ReleaseResource((Handle) windowSizePosHdl);
  CloseResFile(fileRefNum);
}

// ********************************************************** doGetFrameWidthAndTitleBarHeight

void  doGetFrameWidthAndTitleBarHeight(WindowRef windowRef,SInt16 *frameWidth,
                                       SInt16 *titleBarHeight)
{
  RgnHandle structureRegionHdl = NewRgn();
  RgnHandle contentRegionHdl   = NewRgn();
  Rect      structureRect, contentRect;

  GetWindowRegion(windowRef,kWindowStructureRgn,structureRegionHdl);
  GetRegionBounds(structureRegionHdl,&structureRect);
  GetWindowRegion(windowRef,kWindowContentRgn,contentRegionHdl);
  GetRegionBounds(contentRegionHdl,&contentRect);

  *frameWidth = contentRect.left - structureRect.left - 1;
  *titleBarHeight = contentRect.top - structureRect.top - 1;

  DisposeRgn(structureRegionHdl);
  DisposeRgn(contentRegionHdl);
}

// *************************************************************** doSaveWindowSizeAndPosition

void  doSaveWindowSizeAndPosition(WindowRef windowRef)
{
  docStructureHandle docStrucHdl;
  Rect               portRect;
  SInt16             fileRefNum;
  OSErr               osError;
  windowSizePos       windowSizePosStruct;
  windowSizePosHandle windowSizePosHdl;

  docStrucHdl = (docStructureHandle) GetWRefCon(windowRef);
  fileRefNum = FSpOpenResFile(&(*docStrucHdl)->fileFSSpec,fsRdWrPerm);
  if(fileRefNum < 0)
  {
    osError = ResError();
    doErrorAlert(osError);
    return;
  }

  GetWindowPortBounds(windowRef,&portRect);
  SetPortWindowPort(windowRef);
  LocalToGlobal(&topLeft(portRect));
  LocalToGlobal(&botRight(portRect));
  windowSizePosStruct.windowRect = portRect;

  windowSizePosHdl = (windowSizePosHandle) Get1Resource(rTypeWinSizePos,kWinSizePosID);
  if(windowSizePosHdl != NULL)
  {  
    **windowSizePosHdl = windowSizePosStruct;
    ChangedResource((Handle) windowSizePosHdl);
    osError = ResError();
    if(osError != noErr)
      doErrorAlert(osError);
  }
  else
  {
    windowSizePosHdl = (windowSizePosHandle) NewHandle(sizeof(windowSizePos));
    if(windowSizePosHdl != NULL)
    {
      **windowSizePosHdl = windowSizePosStruct;
      AddResource((Handle) windowSizePosHdl,rTypeWinSizePos,kWinSizePosID,
                  "\pLast window size and position");
    }
  }

  if(windowSizePosHdl != NULL)
  {
    UpdateResFile(fileRefNum);
    osError = ResError();
    if(osError != noErr)
      doErrorAlert(osError);

    ReleaseResource((Handle) windowSizePosHdl);
  }

  CloseResFile(fileRefNum);
}

// *************************************************************************** doGetPageFormat

void  doGetPageFormat(WindowRef windowRef)
{
  docStructureHandle docStrucHdl;
  SInt16             fileRefNum;
  OSErr              osError;
  Handle             pageFormatResourceHdl = NULL;
  PMPageFormat       pageFormat  = kPMNoPageFormat;
  Boolean            settingsChanged;

  docStrucHdl = (docStructureHandle) GetWRefCon(windowRef);
  HLock((Handle) docStrucHdl);

  fileRefNum = FSpOpenResFile(&(*docStrucHdl)->fileFSSpec,fsRdWrPerm);
  if(fileRefNum < 0)
  {
    osError = ResError();
    doErrorAlert(osError);
    return;
  }

  pageFormatResourceHdl = Get1Resource(rPageFormat,kPageFormatID);

  if(pageFormatResourceHdl != NULL)
  {
    PMUnflattenPageFormat(pageFormatResourceHdl,&pageFormat);
    PMSessionValidatePageFormat(gPrintSession,pageFormat,&settingsChanged);

    DisposeHandle((*docStrucHdl)->pageFormatHdl);
    PMFlattenPageFormat(pageFormat,&((*docStrucHdl)->pageFormatHdl));

    if(pageFormat != kPMNoPageFormat)
      PMRelease(&pageFormat);
    ReleaseResource(pageFormatResourceHdl);
  }

  CloseResFile(fileRefNum);

  HUnlock((Handle) docStrucHdl);
}

// ************************************************************************** doSavePageFormat

void  doSavePageFormat(WindowRef windowRef)
{
  docStructureHandle docStrucHdl;
  Handle             pageFormatHdl;
  SInt16             fileRefNum;
  OSErr              osError;
  Size               handleSize;

  docStrucHdl = (docStructureHandle) GetWRefCon(windowRef);
  handleSize = GetHandleSize((*docStrucHdl)->pageFormatHdl);

  fileRefNum = FSpOpenResFile(&(*docStrucHdl)->fileFSSpec,fsRdWrPerm);
  if(fileRefNum < 0)
  {
    osError = ResError();
    doErrorAlert(osError);
    return;
  }

  pageFormatHdl = Get1Resource(rPageFormat,kPageFormatID);

  if(pageFormatHdl != NULL)
  {
    RemoveResource(pageFormatHdl);
    DisposeHandle(pageFormatHdl);
    pageFormatHdl = NewHandle(handleSize);
    BlockMove(*((*docStrucHdl)->pageFormatHdl),*pageFormatHdl,handleSize);
    AddResource(pageFormatHdl,rPageFormat,kPageFormatID,"\pPage Format");
    osError = ResError();
    if(osError != noErr)
      doErrorAlert(osError);
  }
  else
  {
    pageFormatHdl = NewHandle(handleSize);
    if(pageFormatHdl != NULL)
    {
      BlockMove(*((*docStrucHdl)->pageFormatHdl),*pageFormatHdl,handleSize);
      AddResource(pageFormatHdl,rPageFormat,kPageFormatID,"\pPage Format");
      osError = ResError();
      if(osError != noErr)
        doErrorAlert(osError);
    }
  }

  if(pageFormatHdl != NULL)
  {
    UpdateResFile(fileRefNum);
    osError = ResError();
    if(osError != noErr)
      doErrorAlert(osError);

    ReleaseResource(pageFormatHdl);
  }

  gPageFormatChanged = false;

  CloseResFile(fileRefNum);
}

// *******************************************************************************************

Demonstration Program MoreResources Comments

This program uses two methods for saving and retrieving application preferences.  The first
method involves a custom preferences ('PrFn') resource, which is saved to the resource fork of
a preferences file named MoreResources Preferences.  The second method involves the use of Core
Foundation Preferences Services, which creates, and saves preferences to, a file named
com.Windmill.MoreResources.plist on Mac OS X and MoreResources CFPrefs.plist on Mac OS 8/9. 
These files are created when the program is first run.  Thereafter, the preferences will be
read in from the preferences files every time the program is run and replaced whenever the user
invokes the Preferences dialog to change the preferences settings.

When the application is first run, an "application missing" 'STR ' resource is also copied to
the resource fork of the preferences file created by the first method.  On Mac OS 8/9, if the
user double clicks on the icon for this preferences file, an alert is invoked displaying the
text contained in the "application missing" resource.

After the program is launched, the user should choose Open from the File menu to open the
included demonstration document file (titled "MoreResources Document").  The resource fork of
this file contains two custom resources, namely, a 'WiSp' resource containing the last saved
window user state and zoom state, and a 'PgFt' resource containing a flattened PMPageFormat
object.  These two resources are read in whenever the document file is opened.  The 'WiSp'
resource is written to whenever the file is closed.  The 'PgFt' resource is written to when the
file is closed only if the user invoked the Page Setup dialog while the document was open.

No data is read in from the document's data fork.  Instead, the window is used to display the
current preferences settings and information extracted from the document's 'PgFt' resource.
This is simply to keep the code not directly related to resources to a minimum.

The user should choose different paper size, scaling, and orientation settings in the Page
Setup dialog, re-size or zoom the window, close the file, re-open the file, and note that,
firstly, the saved page format values are correctly retrieved and, secondly, the window is
re-opened in the size and position in which is was closed.  The user should also change the
application preferences settings via the Preferences dialog (which is invoked when the
Preference item in the Mac OS 8/9 Edit menu or Mac OS X Application menu is chosen), quit the
program, re-launch the program, and note that the last saved preferences settings are retrieved
at program launch.

The user may also care to remove the 'WiSp' and 'PgFt' resources from the document file's
resource fork, run the program, force a 'PgFt' resource to be created and written to by
invoking the Page Setup dialog while the document file is open, quit the program, and re-run
the program, noting that 'WiSp' and 'PgFt' resources are created in the document file's
resource fork if they do not already exist.

When done, the user may want to remove the preferences files from the Preferences folder.

defines

rPrefsDialog represents the 'DLOG' resource ID for the Preferences dialog and the following
three constants represent the item numbers of the dialog's checkboxes.  rStringList and
iPrefsFileName represent the 'STR#' resource ID and index for the string containing the name of
the application's preferences file created by the first method.  The next eight constants
represent resource types and IDs for the custom preferences resource, the custom window state
resource, the custom page format resource, and the application missing string resource.

typedefs

The appPrefs data type is for the application preferences settings.  The three Boolean fields
are set by checkboxes in the Preferences dialog.  The SInt16 field is incremented each time the
program is run.

The windowSizePos data type is for the window size and position.  The docStructure data type is
for the window's document structure.

Global Variables

gAppResFileRefNum will be assigned the file reference number for the application file's
resource fork.

gSoundPref, gFullScreenPref, and gAutoScrollPref will hold the application preferences
settings, as will gSoundCFPref gFullScreenCFPref and gAutoScrollCFPref.  gProgramRunCountPref
will hold the number of times the application has been run, as will gProgramRunCountCFPref.

gPageFormatChanged is set to true when the Page Setup dialog is invoked, and determines whether
a new page format resource will be written to the document file when the file is closed. 

gPrefsFileRefNum will be assigned the file reference number for the preferences file's resource
fork.

main

The call to CurResFile sets the application's resource fork as the current resource file.

If the application is running on Mac OS X, DeleteMenuItem is called to delete the Preferences
item and its preceding divider from the Edit menu.  (On Mac OS X, the Preferences command is in
the Application menu.)  Since, on Mac OS X, the Preferences item is disabled by default,
EnableMenuCommand is called to enable that item.

The call to PMCreateSession creates a printing session.

The calls to doGetPreferencesResource and doGetPreferencesCFPrefs read in the application
preferences settings from the preferences files.  As will be seen:

o If the preferences file to which the doGetPreferencesResource call pertains does not exist, a
  preferences file will be created, default preferences settings will be copied to it from the
  application file, and these default settings will then be read in from the newly-created
  file.

o If the preferences file to which the doGetPreferencesCFPrefs call pertains does not exist, a
  a preferences file will be created by Core Foundation Preferences Services and default
  preferences settings will be copied to it.

appEventHandler

When the kEventProcessCommand event type is received, if the commandID field of the HICommand
structure contains 'pref', the function doPreferencesDialog is called to display the
Preferences dialog.

windowEventHandler

When the kWindowEventClose event type is received, the function doCloseWindow is called. 
Amongst other things, doCloseWindow calls the function doSaveWindowSizeAndPosition, which saves
the windows position and size to the resource fork of the document file. 

doDrawContent

doDrawContent simply prints the current preferences and page format information in the window
for the information of the user.

doOpenCommand

doOpenCommand is a much simplified version of the actions normally taken when a user chooses
the Open command from a File menu.  Note that, in this program, NavGetFile, rather than the
Navigation Services 3.0 functions NavCreateGetFileDialog and NavDialogRun, is used to create
and display the Open dialog.

NavGetFile presents the Open dialog.  If the user clicks the Open button, doOpenWindow is
called.

doOpenWindow

doOpenWindow creates a new window, creates a block for a document structure, associates the
document structure with the window object, assigns the file system specification for the chosen
file to the document structure's file system specification field, sets the window's title,
assigns NULL to the pageFormatHdl field of the document structure, and installs the window's
event handler.

At that point, doLoadAndSetWindowSizeAndPosition is called to read in the window size and
position ('Wisp') resource from the document's resource fork, and to position and size the
window accordingly.  In addition, doGetPageFormat is called to read in the page format ('PgFt')
resource, and assign a handle to it to the pageFormatHdl field of the document structure.

With the window sized and positioned, ShowWindow is called to make the window visible (the
window's 'WIND' resource specifies that the window is to be initially invisible) and a flag is
set to indicate that the window is open.

navEventFunction

A universal procedure pointer to a navigation event (callback) function must be passed in the
eventProc parameter of the NavGetFile call if the Open dialog is to be movable and resizable. 
However, in a Carbon event model application this function may be empty if it's only purpose
would be to call the window's updating function, and if the window receives, and responds to,
the kEventWindowDrawContent event type.

doCloseWindow

doCloseWindow is called when the user chooses the Quit item, chooses Close from the File menu,
or clicks the window's close box/button.

At the first two lines, a reference to the front window, and a handle to the associated
document structure, are retrieved.

The call to doSaveWindowSizeAndPosition saves the window's port rectangle coordinates,
converted to global coordinates, to the window size and position ('WiSp') resource in the
document's resource fork.  If the Page Setup dialog was invoked while the window was open, and
if the user dismissed the dialog by clicking the OK button, a call is made to doSavePageFormat
to save the PMPageFormat object to the page format ('PgFt') resource in the document file's
resource fork.

DisposeHandle disposes of the document structure, DisposeWindow disposes of the window
structure, and the last line sets the "window is open" flag to indicate that the window is not
open.

doPreferencesDialog

doPreferencesDialog is called when the user chooses the Preferences item.  The function
presents the Preferences dialog and sets the values in the global variables which hold the
current application preferences according to the settings of the dialog's checkboxes.

Note that, at the last two lines, calls are made to doSavePreferencesResource and
doSavePreferencesCFPrefs.

doPageSetupDialog

doPageSetupDialog is called when the user chooses the Page Setup item in the File menu.  It
presents the Page Setup dialog.

If the user dismisses the dialog with a click on the OK button, the flag which indicates that a
page format change has been made is set to true.

doGetPreferencesResource

doGetPreferencesResource, which is called from the main function immediately after program
launch, is the first of those functions central to the demonstration aspects of the program. 
Its purpose is to create the preferences file if it does not already exist, copying the default
preferences resource and the missing application string resource to that file as part of the
creation process, and to read in the preferences resource from the previously existing or
newly-created preferences file.

GetIndString retrieves from the application's resource fork the resource containing the
required name of the preferences file ("MoreResources Preferences").

FindFolder finds the location of the Preferences folder, returning the volume reference number
and directory ID in the last two parameters. (Note that kUserDomain is passed in the vRefNum
parameter.  On Mac OS 8/9, this is mapped to kOnSystemDisk.)  FSMakeFSSpec makes a file system
specification from the preferences file name, volume reference number and directory ID.  This
file system specification is used in the FSpOpenResFile call to open the resource fork of the
preferences file with exclusive read/write permission.

If the specified file does not exist, FSpOpenResFile returns -1.  In that event
FSpCreateResFile creates the preferences file.  The call to FSpCreateResFile creates the file
of the specified type on the specified volume in the specified directory and with the specified
name and creator.  (Note that the creator is set to an arbitrary signature which no other
application known to the Finder is likely to have.  This is so that a double click on the
preferences file icon will cause the Finder to immediately display the missing application
alert (Mac OS 8/9).  Note also that, if 'pref' is used as the fileType parameter, the icon used
for the file will be the system-supplied preferences document icon.
If the file is created successfully, the resource fork of the file is opened by FSpOpenResFile
and the master preferences ('PrFn') and application missing 'STR ' resources are copied to the
resource fork from the application's resource file.  If the resources are not successfully
copied, CloseResFile closes the resource fork of the new file, FspDelete deletes the file, and
the fileRefNum variable is set to indicate that the file does not exist.

If the preferences file exists (either previously or newly-created), UseResFile sets the
resource fork of that file as the current resource file, the preferences resource is read in
from the resource fork by Get1Resource and, if the read was successful, the three Boolean
values and one SInt16 value that constitute the application's preference settings are assigned
to the global variables which store those values.  (Note that, in this program, the function
Get1Resource is used to read in resources so as to restrict the Resource Manager's search for
the specified resource to the current resource file.)

The penultimate line assigns the file reference number for the open preferences file resource
fork to a global variable.  (The fork is left open).  The last line resets the application's
resource fork as the current resource file.

doGetPreferencesCFPrefs

doGetPreferencesCFPrefs is called from main to retrieve the application's preferences using
Core Foundation Preferences Services routines.

Since the application ID in Java package name format (with ".plst" appended) exceeds the
31-character limit for Mac OS 8/9 filenames, an abbreviated ID is used if the program is
running on Mac OS 8/9.

If the first call to CFPreferencesGetAppBooleanValue is successful, the preferences file exists
and the Boolean value retrieved using the "sound" key is assigned to the relevant global
variable.  If this call is not successful, default values are assigned to the three global
variables which hold the Boolean preferences values, and the function returns.

Two more calls to CFPreferencesGetAppBooleanValue with the appropriate keys retrieve the
remaining two Boolean values and assign them to the relevant global variables.  The call to
CFPreferencesGetAppIntegerValue with the "run count" key retrieves the integer value
representing the number of times the program has been run and assigns it to the relevant global
variable.

doCopyResource

doCopyResource is called by doGetPreferences to copy the default preferences and application
missing string to the newly-created preferences file from the application file.

The first two lines save the current resource file's file reference number and set the
application's resource fork as the current resource file.  This will be the "source" file.

The Get1Resource call reads the specified resource into memory.  GetResInfo gets the resource's
name and GetResAttrs gets the resource's attributes.  DetachResource replaces the resource's
handle in the resource map with NULL without releasing the associated memory.  The resource
data is now simply arbitrary data in memory.

UseResFile sets the preferences file's resource fork as the current resource file.  AddResource
makes the arbitrary data in memory into a resource, assigning it the specified type, ID and
name.  SetResAttrs sets the resource attributes in the resource map.  ChangedResource tags the
resource for update and pre-allocates the required disk space.  WriteResource then writes the
resource to disk.

With the resource written to disk, ReleaseResource discards the resource in memory and
UseResFile resets the resource file saved at the first line as the current resource file.

doSavePreferencesResource

doSavePreferencesResource is called when the user dismisses the Preferences dialog to save the
new preference settings to the preferences file created by doGetPreferencesResource.  It
assumes that that preferences file is already open.

At the first two lines, if doGetPreferences was not successful in opening the preferences file
at program launch, the function simply returns.  The call to CurResFile saves the file
reference number of the current resource file for later restoration.

The next six lines create a new preferences structure and assign to its fields the values in
the global variables which store the current preference settings.  UseResFile makes the
preferences file's resource fork the current resource file.  Get1Resource gets a handle to the
existing preferences resource.  Assuming the call is successful (that is, the preferences
resource exists), RemoveResource is called to remove the resource from the resource map,
AddResource is called to make the preferences structure in memory into a resource, and
WriteResource is called to write the resource data to disk.

ReleaseResource disposes of the preferences structure in memory and UseResFile makes the
previously saved resource file the current resource file.

doSavePreferencesCFPrefs

doSavePreferencesCFPrefs is called when the user dismisses the Preferences dialog to set and
store the new preference settings using Core Foundation Preferences Services functions.

Since the application ID in Java package name format (with ".plst" appended) exceeds the
31-character limit for Mac OS 8/9 filenames, an abbreviated ID is used if the program is
running on Mac OS 8/9.

For the three Boolean preferences values, CFPreferencesSetAppValue is called with the
appropriate key to set the values in the application's preferences cache.  For the program run
count (integer) value, NumToString and CFStringCreateWithPascalString are called to convert the
integer value to a CFString before CFPreferencesSetAppValue is called.

The call to CFPreferencesAppSynchronize flushes the cache to permanent storage, creating the
preferences file if it does not already exist. 

doLoadAndSetWindowSizeAndPosition

doLoadAndSetWindowSizeAndPosition gets the window size and position ('WiSp') resource from the
resource fork of the document file and moves and sizes the window according to retrieved size
and position data.

GetWRefCon gets a handle to the window's document structure so that the file system
specification can be retrieved and used in the FSpOpenResFile call to open the document file's
resource fork.

Get1Resource attempts to read in the 'WiSp' resource.  If the Get1Resource call is successful,
the retrieved data is assigned to a local variable of type Rect.  (Recall that this is the
window's port rectangle in global coordinates.)  If Get1Resource call is not successful (as it
will be if no 'WiSp' resource currently exists in the document file's resource fork), a default
size and position for the window is established.

The calls to MoveWindow and SizeWindow set the position and size of the window to either the
retrieved or default position and size.

doSaveWindowSizeAndPosition

doSaveWindowSizeAndPosition saves the current window size and position (the window's port
rectangle in global coordinates) to the document file's resource fork, and is called when the
associated window is closed by the user or the Quit item is chosen.

The first line gets a handle to the window's document structure so that the document file's
file system specification can be retrieved and used in the FSpOpenResFile call.  If the
resource fork cannot be opened, an error alert is presented and the function simply returns.

The next block gets the window's port rectangle, converts it to global coordinates, and assigns
it to the windowRect field of a windowSizePosStruct structure.

Get1Resource attempts to read the 'WiSp' resource from the document's resource fork into
memory.  If the Get1Resource call is successful, the resource in memory is made equal to the
previously "filled-in" windowSizePosStruct structure and the resource is tagged as changed.  If
the Get1Resource call is not successful (that is, the document file's resource fork does not
yet contain a 'WiSp' resource), the else block creates a new windowSizePosStruct structure,
makes this structure equal to the previously "filled-in" windowSizePosStruct structure, and
makes this data in memory into a 'WiSp' resource.

If an existing 'WiSp' resource was successfully read in, or if a new 'WiSp' resource was
successfully created in memory, UpdateResFile writes the resource data and map to disk, and
ReleaseResource discards the resource in memory.  The document file's resource fork is then
closed by CloseResFile.

doGetPageFormat

doGetPageFormat reads in the 'PgFt' resource, which contains a flattened PMPageFormat object,
from the document file's resource fork.  The function is called when the document is opened.

The first line gets a handle to the window's document structure so that the document file's
file system specification can be retrieved and used in the call to FSpOpenResFile.  If the call
is not successful, an error alert is presented and the function simply returns.

If the resource fork is successfully opened, the call to Get1Resource attempts to read in the
resource.  If the call is successful, the resource is unflattened into a PMPageFormat object,
PMValidatePageFormat is called to ensure that the page format information is compatible with
the driver for the current printer, and PMFlattenPageFormat is called to flatten the
PMPageFormat object.  When PMFlattenPageFormat returns, the second parameter (the relevant
field of the window's document structure) contains a handle to the flattened data.  The
resource is then released and the document file's resource fork is closed.

doSavePageFormat

doSavePageFormat saves the flattened PMPageFormat object, whose handle is stored in the
window's document structure, to a 'PgFt' resource in the document file's resource fork.  The
function is called when the file is closed if the user invoked the PageSetup dialog while the
document was open and dismissed the dialog by clicking the OK button.

The first line gets a handle to the window's document structure so that the document file's
file system specification can be retrieved and used in the call to FSpOpenResFile.  If the call
is not successful, an error alert is presented and the function simply returns.

Get1Resource attempts to read the 'PgFt' resource from the document's resource fork into
memory.  If the Get1Resource call is successful, the contents of the handle in the document
structure's pageFormatHdl field are copied to the resource in memory, and the resource is
tagged as changed.  If the Get1Resource call is not successful (that is, the document file's
resource fork does not yet contain a 'PgFt' resource), a block of memory the size of a 'PgFt'
resource is allocated, the contents of the handle in the document structure's pageFormatHdl
field are copied to that block, and AddResource makes that block into a 'PgFt' resource.

If an existing 'PgFt' resource was successfully read in, or if a new 'PgFt' resource was
successfully created in memory, UpdateResFile writes the resource map and data to disk. 
ReleaseResource then discards the resource in memory.  At the last line, the document file's
resource fork is then closed.
[include: /mt_footer.html]
 
AAPL
$117.60
Apple Inc.
-1.03
MSFT
$47.47
Microsoft Corpora
-0.12
GOOG
$541.08
Google Inc.
+1.81

MacTech Search:
Community Search:

Software Updates via MacUpdate

MacUpdate Desktop 6.0.3 - Discover and i...
MacUpdate Desktop 6 brings seamless 1-click installs and version updates to your Mac. With a free MacUpdate account and MacUpdate Desktop 6, Mac users can now install almost any Mac app on macupdate.... Read more
SteerMouse 4.2.2 - Powerful third-party...
SteerMouse is an advanced driver for USB and Bluetooth mice. It also supports Apple Mighty Mouse very well. SteerMouse can assign various functions to buttons that Apple's software does not allow,... Read more
iMazing 1.1 - Complete iOS device manage...
iMazing (was DiskAid) is the ultimate iOS device manager with capabilities far beyond what iTunes offers. With iMazing and your iOS device (iPhone, iPad, or iPod), you can: Copy music to and from... Read more
PopChar X 7.0 - Floating window shows av...
PopChar X helps you get the most out of your font collection. With its crystal-clear interface, PopChar X provides a frustration-free way to access any font's special characters. Expanded... Read more
Carbon Copy Cloner 4.0.3 - Easy-to-use b...
Carbon Copy Cloner backups are better than ordinary backups. Suppose the unthinkable happens while you're under deadline to finish a project: your Mac is unresponsive and all you hear is an ominous,... Read more
ForeverSave 2.1.3 - Universal auto-save...
ForeverSave auto-saves all documents you're working on while simultaneously doing backup versioning in the background. Lost data can be quickly restored at any time. Losing data, caused by... Read more
Voila 3.8.1 - Capture, annotate, organiz...
Voila is a screen-capture, recording, and annotation tool that is a full-featured replacement for Mac's screen-capture and screen-recording capabilities. It has a large and robust set of editing,... Read more
SyncTwoFolders 2.0.6 - Syncs two user-sp...
SyncTwoFolders simply synchronizes two folders. It supports synchronization across mounted network drives and it is a possibility to run a simulation showing in a log what will be done. Please visit... Read more
Duplicate Annihilator 5.1.1 - Find and d...
Duplicate Annihilator takes on the time-consuming task of comparing the images in your iPhoto library using effective algorithms to make sure that no duplicate escapes. Duplicate Annihilator detects... Read more
HandBrake 0.10.0 - Versatile video encod...
HandBrake is a tool for converting video from nearly any format to a selection of modern, widely supported codecs. Supported Sources: VIDEO_TS folder, DVD image or real DVD (unencrypted -- CSS is... Read more

Latest Forum Discussions

See All

Tilt to Live Bundle Set to Arrive This T...
Tilt to Live Bundle Set to Arrive This Thanksgiving Posted by Ellis Spice on November 25th, 2014 [ permalink ] One Man Left has unveiled an upcoming Tilt to Live bundle, allowing players to get the series for a di | Read more »
BattleLore: Command (Entertainment)
BattleLore: Command 1.0 Device: iOS Universal Category: Entertainment Price: $9.99, Version: 1.0 (iTunes) Description: ***NOTE: Compatible with iPad 2/iPad mini, iPod touch 5 and up and iPhone 4S and up – WILL NOT RUN ON EARLIER... | Read more »
Weather Or Not Review
Weather Or Not Review By Jennifer Allen on November 25th, 2014 Our Rating: :: STYLISH WEATHER REPORTINGiPhone App - Designed for the iPhone, compatible with the iPad Check the weather quickly and conveniently with Weather or Not... | Read more »
The All-New Football Manager Handheld 20...
The All-New Football Manager Handheld 2015 is Available Now Posted by Jessica Fisher on November 25th, 2014 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
Six iOS Games to Get You Ready for Thank...
Image Source: Friends Wiki At this point in the month, you or at least a few people you know are probably getting ready to scramble around (or are already scrambling around) for Thanksgiving Dinner. It’s a hectic day of precise oven utilization, but... | Read more »
Call of Duty: Heroes: Tips, Tricks, and...
Hello Heroes: What’d we think of Call of Duty‘s take on Clash of Clans? Check out our Call of Duty: Heroes review to find out! Just downloaded Call of Duty: Heroes and need some handy tips and tricks on how to get ahead of the rest? As we often do,... | Read more »
Call of Duty: Heroes Review
Call of Duty: Heroes Review By Jennifer Allen on November 25th, 2014 Our Rating: :: CLASH OF FRANCHISESUniversal App - Designed for iPhone and iPad Mix Clash of Clans with Call of Duty, and this is what you get.   | Read more »
Slider Review
Slider Review By Jordan Minor on November 25th, 2014 Our Rating: :: SLIDE TO PLAYUniversal App - Designed for iPhone and iPad Slider has all the excitement of unlocking your phone screen.   | Read more »
oh my giraffe (Games)
oh my giraffe 1.0.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0.0 (iTunes) Description: Eat fruits while being chased by lions. Cut the vines to send fruit plummeting onto the lions. Don't worry, your flexible... | Read more »
One of 2000’s Most Loves Adventure Games...
One of 2000’s Most Loves Adventure Games, The Longest Journey, has Come to iOS Posted by Jessica Fisher on November 25th, 2014 [ permalink ] | Read more »

Price Scanner via MacPrices.net

Early Black Friday MacBook Pro sale: 15-inch...
 Best Buy has posted early Black Friday prices on 15″ Retina MacBook Pros, with models on sale for $300 off MSRP on their online store for a limited time. Choose free local store pickup (if available... Read more
A9 Chips Already?
It’s barely more than a couple of months since Apple got the first A8 systems-on-chip into consumer hands, but rumor and news focus is already turning to the next-generation A9 SoC. Apple Daily... Read more
NewerTech Announces NuGuard KXs Impact X-Orbi...
NewerTech has announced updates to its family of Impact X-Orbing Screen Armor bringing military grade, triple layer protection to Apple’s new iPhone 6 and 6 Plus. Like all models in the NuGuard KXs... Read more
13-inch 1.4GHz MacBook Air on sale for $889,...
 B&H Photo has the 13″ 1.4GHz/128GB MacBook Air on sale for $889 including free shipping plus NY tax only. Their price is $110 off MSRP. B&H will also include free copies of Parallels Desktop... Read more
Save up to $300 on Macs and iPads with your A...
Purchase a new Mac or iPad at The Apple Store for Education and take up to $300 off MSRP. All teachers, students, and staff of any educational institution qualify for the discount. Shipping is free,... Read more
Apple refurbished Mac Pros available for up t...
The Apple Store is offering Apple Certified Refurbished Mac Pros for up to $600 off the cost of new models. An Apple one-year warranty is included with each Mac Pro, and shipping is free. The... Read more
Jumptuit Launches One-Tap Windows 8.1 iTunes...
Jumptuit has launched Windows 8.1 support for One-Tap iTunes Sync. with which Windows 8.1 users can now easily sync their iTunes libraries with Microsoft OneDrive. Jumptuit provides easy access from... Read more
Apple restocks refurbished 13-inch 2014 Retin...
The Apple Store has restocked Apple Certified Refurbished 2014 13″ 2.6GHz Retina MacBook Pros for up to $230 off the cost of new models. An Apple one-year warranty is included with each model, and... Read more
CEA Study Finds More People Recycling Electro...
A new study by the Consumer Electronics Association (CEA) finds that electronics recycling receives the continued and growing support of consumers. According to the CEA,s Recycling and Reuse Study,... Read more
15″ 2.2GHz Retina MacBook Pro on sale for $17...
 B&H Photo has the 2014 15″ 2.2GHz Retina MacBook Pro on sale today for $1749. Shipping is free, and B&H charges NY sales tax only. B&H will also include free copies of Parallels Desktop... Read more

Jobs Board

*Apple* Retail - Multiple Positions (US) - A...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
*Apple* Solutions Consultant (ASC) - Apple (...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
*Apple* Solutions Consultant (ASC) - Apple (...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
*Apple* Solutions Consultant (ASC)- Retail S...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
Project Manager, *Apple* Financial Services...
**Job Summary** Apple Financial Services (AFS) offers consumers, businesses and educational institutions ways to finance Apple purchases. We work with national and Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.