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

Latest Forum Discussions

See All

Top Mobile Game Discounts
Every day, we pick out a curated list of the best mobile discounts on the App Store and post them here. This list won't be comprehensive, but it every game on it is recommended. Feel free to check out the coverage we did on them in the links... | Read more »
Price of Glory unleashes its 1.4 Alpha u...
As much as we all probably dislike Maths as a subject, we do have to hand it to geometry for giving us the good old Hexgrid, home of some of the best strategy games. One such example, Price of Glory, has dropped its 1.4 Alpha update, stocked full... | Read more »
The SLC 2025 kicks off this month to cro...
Ever since the Solo Leveling: Arise Championship 2025 was announced, I have been looking forward to it. The promotional clip they released a month or two back showed crowds going absolutely nuts for the previous competitions, so imagine the... | Read more »
Dive into some early Magicpunk fun as Cr...
Excellent news for fans of steampunk and magic; the Precursor Test for Magicpunk MMORPG Crystal of Atlan opens today. This rather fancy way of saying beta test will remain open until March 5th and is available for PC - boo - and Android devices -... | Read more »
Prepare to get your mind melted as Evang...
If you are a fan of sci-fi shooters and incredibly weird, mind-bending anime series, then you are in for a treat, as Goddess of Victory: Nikke is gearing up for its second collaboration with Evangelion. We were also treated to an upcoming... | Read more »
Square Enix gives with one hand and slap...
We have something of a mixed bag coming over from Square Enix HQ today. Two of their mobile games are revelling in life with new events keeping them alive, whilst another has been thrown onto the ever-growing discard pile Square is building. I... | Read more »
Let the world burn as you have some fest...
It is time to leave the world burning once again as you take a much-needed break from that whole “hero” lark and enjoy some celebrations in Genshin Impact. Version 5.4, Moonlight Amidst Dreams, will see you in Inazuma to attend the Mikawa Flower... | Read more »
Full Moon Over the Abyssal Sea lands on...
Aether Gazer has announced its latest major update, and it is one of the loveliest event names I have ever heard. Full Moon Over the Abyssal Sea is an amazing name, and it comes loaded with two side stories, a new S-grade Modifier, and some fancy... | Read more »
Open your own eatery for all the forest...
Very important question; when you read the title Zoo Restaurant, do you also immediately think of running a restaurant in which you cook Zoo animals as the course? I will just assume yes. Anyway, come June 23rd we will all be able to start up our... | Read more »
Crystal of Atlan opens registration for...
Nuverse was prominently featured in the last month for all the wrong reasons with the USA TikTok debacle, but now it is putting all that behind it and preparing for the Crystal of Atlan beta test. Taking place between February 18th and March 5th,... | Read more »

Price Scanner via MacPrices.net

AT&T is offering a 65% discount on the ne...
AT&T is offering the new iPhone 16e for up to 65% off their monthly finance fee with 36-months of service. No trade-in is required. Discount is applied via monthly bill credits over the 36 month... Read more
Use this code to get a free iPhone 13 at Visi...
For a limited time, use code SWEETDEAL to get a free 128GB iPhone 13 Visible, Verizon’s low-cost wireless cell service, Visible. Deal is valid when you purchase the Visible+ annual plan. Free... Read more
M4 Mac minis on sale for $50-$80 off MSRP at...
B&H Photo has M4 Mac minis in stock and on sale right now for $50 to $80 off Apple’s MSRP, each including free 1-2 day shipping to most US addresses: – M4 Mac mini (16GB/256GB): $549, $50 off... Read more
Buy an iPhone 16 at Boost Mobile and get one...
Boost Mobile, an MVNO using AT&T and T-Mobile’s networks, is offering one year of free Unlimited service with the purchase of any iPhone 16. Purchase the iPhone at standard MSRP, and then choose... Read more
Get an iPhone 15 for only $299 at Boost Mobil...
Boost Mobile, an MVNO using AT&T and T-Mobile’s networks, is offering the 128GB iPhone 15 for $299.99 including service with their Unlimited Premium plan (50GB of premium data, $60/month), or $20... Read more
Unreal Mobile is offering $100 off any new iP...
Unreal Mobile, an MVNO using AT&T and T-Mobile’s networks, is offering a $100 discount on any new iPhone with service. This includes new iPhone 16 models as well as iPhone 15, 14, 13, and SE... Read more
Apple drops prices on clearance iPhone 14 mod...
With today’s introduction of the new iPhone 16e, Apple has discontinued the iPhone 14, 14 Pro, and SE. In response, Apple has dropped prices on unlocked, Certified Refurbished, iPhone 14 models to a... Read more
B&H has 16-inch M4 Max MacBook Pros on sa...
B&H Photo is offering a $360-$410 discount on new 16-inch MacBook Pros with M4 Max CPUs right now. B&H offers free 1-2 day shipping to most US addresses: – 16″ M4 Max MacBook Pro (36GB/1TB/... Read more
Amazon is offering a $100 discount on the M4...
Amazon has the M4 Pro Mac mini discounted $100 off MSRP right now. Shipping is free. Their price is the lowest currently available for this popular mini: – Mac mini M4 Pro (24GB/512GB): $1299, $100... Read more
B&H continues to offer $150-$220 discount...
B&H Photo has 14-inch M4 MacBook Pros on sale for $150-$220 off MSRP. B&H offers free 1-2 day shipping to most US addresses: – 14″ M4 MacBook Pro (16GB/512GB): $1449, $150 off MSRP – 14″ M4... Read more

Jobs Board

All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.