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]
 

Community Search:
MacTech Search:

Software Updates via MacUpdate

pwSafe 4.0.1 - Secure password managemen...
pwSafe provides simple and secure password management across devices and computers. pwSafe uses iCloud to keep your password databases backed-up and synced between Macs and iOS devices. It is... Read more
WALTR 1.5.4 - Drag-and-drop any media fi...
WALTR is designed to make it easy to upload and convert any music or video file to an iPad or iPhone format for native playback. It supports a huge variety of media file types, including MP3, MP4,... Read more
Audio Hijack 3.1 - Record and enhance au...
Audio Hijack (was Audio Hijack Pro) drastically changes the way you use audio on your computer, giving you the freedom to listen to audio when you want and how you want. Record and enhance any audio... Read more
PopChar 7.1 - Floating window shows avai...
We're also selling a 5-license family pack for only $25.99! PopChar helps you get the most out of your font collection. With its crystal-clear interface, PopChar X provides a frustration-free way to... Read more
BBEdit 11.1.1 - Powerful text and HTML e...
BBEdit is the leading professional HTML and text editor for the Mac. Specifically crafted in response to the needs of Web authors and software developers, this award-winning product provides a... Read more
Picasa 3.9.139 - Organize, edit, and sha...
Picasa and Picasa Web Albums allows you to organize, edit, and upload your photos to the Web from your computer in quick, simple steps. Arrange your photos into folders and albums and erase their... Read more
Mac DVDRipper Pro 5.0.5 - Copy, backup,...
Mac DVDRipper Pro is the DVD backup solution that lets you protect your DVDs from scratches, save your batteries by reading your movies from your hard disk, manage your collection with just a few... Read more
NetShade 6.2 - Browse privately using an...
This promotion is for NetShade and 1 year of Proxy and VPN services NetShade is an anonymous proxy and VPN app+service for Mac. Unblock your Internet through NetShade's high-speed proxy and VPN... Read more
CrossOver 14.1.3 - Run Windows apps on y...
CrossOver can get your Windows productivity applications and PC games up and running on your Mac quickly and easily. CrossOver runs the Windows software that you need on Mac at home, in the office,... Read more
Little Snitch 3.5.3 - Alerts you about o...
Little Snitch gives you control over your private outgoing data. Track background activity As soon as your computer connects to the Internet, applications often have permission to send any... Read more

Block Fortress has a Big New Update for...
Block Fortress is a survival-style game that's as fun as it is blocky. It's also just gotten a rather sizeable update that adds a lot more cool stuff. [Read more] | Read more »
Simple and Surreal Star Base Sim rymdkap...
I really like rymdkapsel. Not just because I'm a sucker for games that are cleverly simple or highly stylisitc, but because it's fun and challenging. Actually it's extremely challenging, which is why I was excited to learn that it's getting a couple... | Read more »
Check out the anticipated Angel Stone in...
Fincon has finally revealed Angel Stone in action in the first ever official gameplay trailer for the anticipated hack and slasher. Angel Stone is set in a post-apocalyptic world in which humanity is in danger of being wiped out by the demonic... | Read more »
Moleskine Timepage is an All-New Calenda...
Moleskine Timepage is a bit of a departure for the notebook manufacturer (since it has little to do with notebooks), but it certainly carries their simple and elegant style quite well. [Read more] | Read more »
Jog on Over and Check Out the New Runtas...
Runtastic has put out a fair number of apps to help you sleep, track excercise, and train various parts of your body. Now it's time for your legs to have their own time in the spotlight with Runtastic Leg Trainer. [Read more] | Read more »
It's Lights Out in the Upcoming Pla...
Ember’s Journey is a stark puzzle platformer with a twist: the entire game is played in darkness. The only light you can see by is the one emanating from your own character. [Read more] | Read more »
MooVee - Your Movies Guru (Entertainmen...
MooVee - Your Movies Guru 1.0 Device: iOS iPhone Category: Entertainment Price: $1.99, Version: 1.0 (iTunes) Description: MooVee helps you effortlessly manage your movies, on your iPhone. | Read more »
Geometry Wars 3: Dimensions (Games)
Geometry Wars 3: Dimensions 1.0.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0.0 (iTunes) Description: Enjoy the next chapter in the award-winning Geometry Wars franchise and enjoy stunning, console-quality... | Read more »
CHAOS RINGS â…¢ (Games)
CHAOS RINGS â…¢ 1.0.0 Device: iOS Universal Category: Games Price: $19.99, Version: 1.0.0 (iTunes) Description: The newest addition to the popular smartphone RPG series is finally here! ・CHAOS RINGS Overview | Read more »
The Popular Insight Series of Travel Gui...
Getting around in a country when you can't understand the primary language can be tough. Fortunately there are several options available to help wold travellers with the important stuff like giving directions to a cab driver or asking where the... | Read more »

Price Scanner via MacPrices.net

Top Markets Saturation To Slow Global Smartph...
According to a new mobile phone forecast from the International Data Corporation (IDC) Worldwide Quarterly Mobile Phone Tracker, smartphone shipments are expected to grow 11.3% in 2015 — down from 27... Read more
Apple refurbished 2014 13-inch Retina MacBook...
The Apple Store has Apple Certified Refurbished 2014 13″ Retina MacBook Pros available for up to $400 off original MSRP, starting at $979. An Apple one-year warranty is included with each model, and... Read more
What Would the ideal Apple Productivity Platf...
For the past four years I’ve kept a foot in both the Mac and iPad camps respectively. my daily computing hours divided about 50/50 between the two devices with remarkable consistency. However, there’... Read more
PageMeUp 1.2.1 Ten Dollar Page Layout Applica...
Paris, France-based Softobe, an OS X software development company, has announced that their PageMeUp v. 1.2.1, is available on the Mac App Store for $9.99. The license can be installed on up to 5... Read more
Eight New Products For USB Type-C Application...
Fresco Logic, specialists in advanced connectivity technologies and ICs, has introduced two new product families targeting the Type-C connector recently introduced across a number of consumer... Read more
Scripps National Spelling Bee Launches Buzzwo...
Scripps National Spelling Bee fans can monitor the action at the 2015 Spelling Bee with the new Buzzworthy app for iOS, Android and Windows mobile devices. The free Buzzworthy app provides friendly... Read more
13-inch 2.5GHz MacBook Pro on sale for $120 o...
B&H Photo has the 13″ 2.5GHz MacBook Pro on sale for $979 including free shipping plus NY sales tax only. Their price is $120 off MSRP, and it’s the lowest price for this model (except for Apple’... Read more
27-inch 3.3GHz 5K iMac on sale for $1899, $10...
B&H Photo has the new 27″ 3.3GHz 5K iMac on sale for $1899.99 including free shipping plus NY tax only. Their price is $100 off MSRP. Read more
Save up to $50 on iPad Air 2, NY tax only, fr...
B&H Photo has iPad Air 2s on sale for up to $50 off MSRP including free shipping plus NY sales tax only: - 16GB iPad Air 2 WiFi: $469 $30 off - 64GB iPad Air 2 WiFi: $549.99 $50 off - 128GB iPad... Read more
Updated Mac Price Trackers
We’ve updated our Mac Price Trackers with the latest information on prices, bundles, and availability on systems from Apple’s authorized internet/catalog resellers: - 15″ MacBook Pros - 13″ MacBook... Read more

Jobs Board

*Apple* Retail - Multiple Positions (US) - A...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
Program Manager, *Apple* Community Support...
**Job Summary** Apple Support Communities ( discussions. apple .com) helps customers get the most from their Apple products and services by providing access to Read more
Senior Data Scientist, *Apple* Retail - Onl...
**Job Summary** Apple Retail - Online sells Apple products to customers around the world. In addition to selling Apple products with unique services such as iPad Read more
*Apple* Solutions Consultant - Retail Sales...
**Job Summary** As an Apple Solutions Consultant (ASC) you are the link between our customers and our products. Your role is to drive the Apple business in a retail Read more
*Apple* Watch SW Application Project Manager...
**Job Summary** The Apple Watch software team is looking for an Application Engineering Project Manager to work on new projects for Apple . The successful candidate Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.