MacTech Network:   MacForge.net  |  Computer Memory  |  Register Domains  |  Printer Supplies  |  Cables  |  iPod Deals  |  Mac Deals  |  Mac Book Shelf


  MacTech Magazine

The journal of Macintosh technology

 
 
Shared Storage Easier

Magazine In Print
  About MacTech  
  Home Page  
  Subscribe  
  Archives DVD  
  Submit News  
  Submit a Tip!  
  Get a copy of MacTech RISK FREE  
Google
Entire Web
mactech.com
Mac Community
More...
MacTech Central
  by Category  
  by Company  
  by Product  
MacTech News
  MacTech News  
  Previous News  
  MacTech RSS  
Article Archives
  Show Indices  
  by Volume  
  by Author  
  Source Code FTP  
Inside MacTech
  Writer's Kit  
  Editorial Staff  
  Editorial Calendar  
  Back Issues  
  Advertising  
Contact Us
  Customer Service  
  MacTech Store  
  Legal/Disclaimers  
  Webmaster Feedback  

Demonstration Program

Go to Contents
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
// Windows2.c
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××
// 
// This program demonstrates Mac OS 8.5 Window Manager features and functions relating
// to:
//
// ¥  Creating floating windows and document windows using CreateNewWindow.  (Note that
//    floating windows will not be created unless the program is run under Mac OS 8.6 or
//    later.)
//
// ¥  Saving document windows and their associated data to a 'wind' resource.
//
// ¥  Creating document windows from 'wind' resources using CreateWindowFromResource.
//
// ¥  Managing windows in a floating windows environment.
//
// ¥  Setting and getting a window's property.
//
// ¥  Re-sizing a window using ResizeWindow and zooming a window using ZoomWindowIdeal.
//
// ¥  Showing and hiding windows using TransitionWindow.
//
// ¥  Displaying window proxy icons.
//
// Those aspects of the Mac OS 8.5 Window Manager not demonstrated in this program
// (full implementation of window proxy icons and window path pop-up menus) are
// demonstrated at the demonstration program associated with Chapter 16B (Files2).
//
// The program utilises the following resources:
//
// ¥  An 'MBAR' resource, and 'MENU' resources for Apple, File, Edit, Document Windows
//    and Floating Windows menus (preload, non-purgeable).
//
// ¥  'TEXT' resources for the document windows (non-purgeable).  
//
// ¥  'PICT' resources for the floating windows (non-purgeable).
//
// ¥  An 'ALRT' resource (purgeable), plus associated 'DITL', 'alrx', and 'dftb' 
//    resources (all purgeable), for a modal alert box invoked when the user chooses the
//    About Windows2... item from the  Apple menu.
//
// ¥  A 'SIZE' resource with the acceptSuspendResumeEvents, doesActivateOnFGSwitch,
//    and is32BitCompatible flags set.
//
// In addition, the program itself creates a 'wind' resource, and saves it to the
// resource fork of the application file, when the user chooses CreateNewWindow from the
// Document Windows menu.
//
// Note that floating windows will not be created unless the program is run under Mac OS
// 8.6 or later.  
//
// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××

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

#include <Appearance.h>
#include <Devices.h>
#include <Folders.h>
#include <Gestalt.h>
#include <Resources.h>
#include <Sound.h>
#include <ToolUtils.h>

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

define mApple                128
define  iAbout               1
define mFile                 129
define mEdit                 130
define  iQuit                11
define mDocumentWindows      131
define  iCreateWindow        1
define  iCreateFromResource  2
define mFloatingWindows      132
define  iColours             1
define  iTools               2
define rMenubar              128
define rAboutAlert           128
define rText                 128
define rColoursPicture       128
define rToolsPicture         129
define rWind                 128
define MIN(a,b)              ((a) < (b) ? (a) : (b))

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

typedef struct
{
  TEHandle  editStrucHdl;
} docStructure, **docStructureHandle;

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

Boolean   gMacOS86Present  = false;
SInt16    gAppResFileRefNum;
WindowPtr gColoursFloatingWindowPtr;
WindowPtr gToolsFloatingWindowPtr;
Boolean   gDone;
Boolean   gInBackground;

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

void  main                        (void);
void  doInitManagers              (void);
void  doEvents                    (EventRecord *);
void  doMouseDown                 (EventRecord *);
void  doUpdate                    (EventRecord *);
void  doUpdateDocumentWindow      (WindowPtr);
void  doActivate                  (EventRecord *);
void  doActivateDocumentWindow    (WindowPtr,Boolean);
void  doOSEvent                   (EventRecord *);
void  doAdjustMenus               (void);
void  doMenuChoice                (SInt32);
void  doDocumentWindowsMenu       (SInt16);
void  doFloatingWindowsMenu       (SInt16);
OSErr doCreateNewWindow           (void);
OSErr doSaveWindow                (WindowPtr);
OSErr doCreateWindowFromResource  (void);
OSErr doCreateFloatingWindows     (void);
void  doCloseWindow               (WindowPtr);
void  doErrorAlert                (SInt16);
void  doConcatPStrings            (Str255,Str255);

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× main

void  main(void)
{
  OSErr               osError;
  SInt32              response;
  Handle              menubarHdl;
  MenuHandle          menuHdl;
  EventRecord         eventStructure;
  SInt32              sleepTime;
  WindowPtr           windowPtr;
  docStructureHandle  docStrucHdl;
  UInt32              actualSize;

  // .............................. check whether Mac OS 8.5 and 8.6 or later are present

  osError = Gestalt(gestaltSystemVersion,&response);

  if(osError == noErr && response < 0x00000850)
    ExitToShell();
  if(osError == noErr && response >= 0x00000860)
    gMacOS86Present = true;

  // ................................................................ initialise managers

  doInitManagers();

  // .......................................................... set up menu bar and menus
  
  menubarHdl = GetNewMBar(rMenubar);
  if(menubarHdl == NULL)
    ExitToShell();
  SetMenuBar(menubarHdl);
  DrawMenuBar();

  menuHdl = GetMenuHandle(mApple);
  if(menuHdl == NULL)
    ExitToShell();
  else
    AppendResMenu(menuHdl,'DRVR');

  // ............................. set current resource file to application resource fork
  
  gAppResFileRefNum = CurResFile();
  
  // ............................................................ create floating windows

  if(gMacOS86Present)
  {
    if(osError = doCreateFloatingWindows())
      doErrorAlert(osError);
  }
  else
  {
    menuHdl = GetMenuHandle(mFloatingWindows);
    DisableItem(menuHdl,0);
    menuHdl = GetMenuHandle(mApple);
    DisableItem(menuHdl,iAbout);
    DrawMenuBar();
  }  

  // .................................................................... enter eventLoop

  gDone = false;
  sleepTime = LMGetCaretTime();
    
  while(!gDone)
  {
    if(WaitNextEvent(everyEvent,&eventStructure,sleepTime,NULL))
      doEvents(&eventStructure);
    else
    {
      if(windowPtr = FrontNonFloatingWindow())
      {
         if(!(GetWindowProperty(windowPtr,0,'docs',sizeof(docStrucHdl),&actualSize,
                                &docStrucHdl)))
          TEIdle((*docStrucHdl)->editStrucHdl);
      }
    }
  }
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doInitManagers

void  doInitManagers(void)
{
  MaxApplZone();
  MoreMasters();
  MoreMasters();

  InitGraf(&qd.thePort);
  InitFonts();
  if(gMacOS86Present)
    InitFloatingWindows();
  else
    InitWindows();
  InitMenus();
  TEInit();
  InitDialogs(NULL);

  InitCursor();  
  FlushEvents(everyEvent,0);

  RegisterAppearanceClient();
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doEvents

void  doEvents(EventRecord *eventStrucPtr)
{
  SInt8  charCode;

  switch(eventStrucPtr->what)
  {
    case mouseDown:
      doMouseDown(eventStrucPtr);
      break;

    case keyDown:
    case autoKey:
      charCode = eventStrucPtr->message & charCodeMask;
      if((eventStrucPtr->modifiers & cmdKey) != 0)
      {
        doAdjustMenus();
        doMenuChoice(MenuEvent(eventStrucPtr));
      }
      break;

    case updateEvt:
      doUpdate(eventStrucPtr);
      break;

    case activateEvt:
      doActivate(eventStrucPtr);
      break;

    case osEvt:
      doOSEvent(eventStrucPtr);
      HiliteMenu(0);
      break;
  }
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doMouseDown

void  doMouseDown(EventRecord *eventStrucPtr)
{
  WindowPtr   windowPtr;
  SInt16      partCode, zoomPart;
  WindowClass windowClass;
  Rect        growRect, newContentRect;
  SInt32      newSize;
  Point       idealSize;

  partCode = FindWindow(eventStrucPtr->where,&windowPtr);
  
  switch(partCode)
  {
    case inMenuBar:
      doAdjustMenus();
      doMenuChoice(MenuSelect(eventStrucPtr->where));
      break;

    case inContent:
      GetWindowClass(windowPtr,&windowClass);
      if(windowClass == kFloatingWindowClass)
      {
        if(windowPtr != FrontWindow())
          SelectWindow(windowPtr);
        else
        {
          if(windowPtr == gColoursFloatingWindowPtr)
            ; // Appropriate action for Colours floating window here. 
          else if(windowPtr == gToolsFloatingWindowPtr)
            ; // Appropriate action for Tools floating window here.
        }
      }
      else
      {  
        if(windowPtr != FrontNonFloatingWindow())
          SelectWindow(windowPtr);
        else
          ; // Appropriate action for active document window here.
      }
      break;

    case inDrag:
      DragWindow(windowPtr,eventStrucPtr->where,&qd.screenBits.bounds);
      break;

    case inGoAway:
      GetWindowClass(windowPtr,&windowClass);
      if(windowClass == kFloatingWindowClass)
      {
        if(TrackGoAway(windowPtr,eventStrucPtr->where) == true)
          TransitionWindow(windowPtr,kWindowZoomTransitionEffect,
                           kWindowHideTransitionAction,NULL);
      }
      else
        if(TrackGoAway(windowPtr,eventStrucPtr->where) == true)
          doCloseWindow(windowPtr);
      break;

    case inGrow:
      growRect = qd.screenBits.bounds;
      growRect.top   = 80; 
      growRect.left = 160;

      if(gMacOS86Present)
      {
        ResizeWindow(windowPtr,eventStrucPtr->where,&growRect,&newContentRect);
        InvalWindowRect(windowPtr,&windowPtr->portRect);
      }
      else
      {
        newSize = GrowWindow(windowPtr,eventStrucPtr->where,&growRect);
        if(newSize != 0)
        {
          SizeWindow(windowPtr,LoWord(newSize),HiWord(newSize),true);
          InvalWindowRect(windowPtr,&windowPtr->portRect);
        }
      }
      break;

    case inZoomIn:
    case inZoomOut:
      idealSize.v = qd.screenBits.bounds.bottom - 100;
      idealSize.h = qd.screenBits.bounds.right - 200;

      if(IsWindowInStandardState(windowPtr,&idealSize,NULL))
        zoomPart = inZoomIn;
      else
        zoomPart = inZoomOut;

      if(TrackBox(windowPtr,eventStrucPtr->where,partCode))
        ZoomWindowIdeal(windowPtr,zoomPart,&idealSize);
      break;
  }
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doUpdate

void  doUpdate(EventRecord *eventStrucPtr)
{
  GrafPtr    oldPort;
  WindowPtr  windowPtr;

  GetPort(&oldPort);
  windowPtr = (WindowPtr) eventStrucPtr->message;

  BeginUpdate(windowPtr);

  SetPort(windowPtr);
  doUpdateDocumentWindow(windowPtr);

  EndUpdate(windowPtr);

  SetPort(oldPort);
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doUpdateDocumentWindow

void  doUpdateDocumentWindow(WindowPtr windowPtr)
{
  Rect                contentRect;
  OSStatus            osError;
  UInt32              actualSize;
  docStructureHandle  docStrucHdl;
  TEHandle            editStrucHdl;

  EraseRgn(windowPtr->visRgn);
  DrawGrowIcon(windowPtr);

  if(!(osError = GetWindowProperty(windowPtr,0,'docs',sizeof(docStrucHdl),&actualSize,
                                   &docStrucHdl)))
  {
    contentRect = windowPtr->portRect;
    contentRect.right -= 15;
    contentRect.bottom -= 15;
    editStrucHdl = (*docStrucHdl)->editStrucHdl;
    (*editStrucHdl)->destRect = (*editStrucHdl)->viewRect = contentRect;
    TECalText(editStrucHdl);
    TEUpdate(&contentRect,(*docStrucHdl)->editStrucHdl);
  }
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doActivate

void  doActivate(EventRecord *eventStrucPtr)
{
  WindowPtr  windowPtr;
  Boolean    becomingActive;

  windowPtr = (WindowPtr) eventStrucPtr->message;
  becomingActive = ((eventStrucPtr->modifiers & activeFlag) == activeFlag);

  doActivateDocumentWindow(windowPtr,becomingActive);
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doActivateDocumentWindow

void  doActivateDocumentWindow(WindowPtr windowPtr,Boolean becomingActive)
{
  docStructureHandle  docStrucHdl;
  UInt32              actualSize;
  OSStatus            osError;

  if(!(osError = GetWindowProperty(windowPtr,0,'docs',sizeof(docStrucHdl),&actualSize,
                                   &docStrucHdl)))
  {
    if(becomingActive)
      TEActivate((*docStrucHdl)->editStrucHdl);
    else
      TEDeactivate((*docStrucHdl)->editStrucHdl);
  }
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doOSEvent

void  doOSEvent(EventRecord *eventStrucPtr)
{
  WindowPtr windowPtr;

  switch((eventStrucPtr->message >> 24) & 0x000000FF)
  {
    case suspendResumeMessage:
      gInBackground = (eventStrucPtr->message & resumeFlag) == 0;

      windowPtr = FrontNonFloatingWindow();
      if(windowPtr != NULL)
        doActivateDocumentWindow(windowPtr,!gInBackground);

      if(gInBackground)
        HideFloatingWindows();
      else
        ShowFloatingWindows();

      break;
  }
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doAdjustMenus

void  doAdjustMenus(void)
{
  MenuHandle  floatMenuHdl;
  Boolean     isVisible;

  floatMenuHdl = GetMenuHandle(mFloatingWindows);

  isVisible = ((WindowPeek) gColoursFloatingWindowPtr)->visible;
  CheckItem(floatMenuHdl,iColours,isVisible);

  isVisible = ((WindowPeek) gToolsFloatingWindowPtr)->visible;
  CheckItem(floatMenuHdl,iTools,isVisible);

  DrawMenuBar();
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doMenuChoice

void  doMenuChoice(SInt32 menuChoice)
{
  SInt16  menuID, menuItem;
  Str255  itemName;
  SInt16  daDriverRefNum;

  menuID = HiWord(menuChoice);
  menuItem = LoWord(menuChoice);

  if(menuID == 0)
    return;

  switch(menuID)
  {
    case mApple:
      if(menuItem == iAbout)
      {
        Alert(rAboutAlert,NULL);
        HiliteWindow(gColoursFloatingWindowPtr,true);
        HiliteWindow(gToolsFloatingWindowPtr,true);
      }
      else
      {
        GetMenuItemText(GetMenuHandle(mApple),menuItem,itemName);
        daDriverRefNum = OpenDeskAcc(itemName);
      }
      break;

    case mFile:
      if(menuItem == iQuit)
        gDone = true;
      break;

    case mDocumentWindows:
      doDocumentWindowsMenu(menuItem);
      break;
  
    case mFloatingWindows:
      doFloatingWindowsMenu(menuItem);
      break;
  }

  HiliteMenu(0);
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doDocumentWindowsMenu

void  doDocumentWindowsMenu(SInt16 menuItem)
{
  OSErr  osError;
  
  switch(menuItem)
  {
    case iCreateWindow:
      if(osError = doCreateNewWindow())
        doErrorAlert(osError);
      break;

    case iCreateFromResource:
      if(osError = doCreateWindowFromResource())
        doErrorAlert(osError);
      break;
  }
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doFloatingWindowsMenu

void  doFloatingWindowsMenu(SInt16 menuItem)
{
  Boolean  isVisible;

  if(menuItem == iColours)
  {
    isVisible = ((WindowPeek) gColoursFloatingWindowPtr)->visible;
    if(isVisible)
      TransitionWindow(gColoursFloatingWindowPtr,kWindowZoomTransitionEffect,
                       kWindowHideTransitionAction,NULL);
    else
      TransitionWindow(gColoursFloatingWindowPtr,kWindowZoomTransitionEffect,
                       kWindowShowTransitionAction,NULL);
  }  
  else if(menuItem == iTools)
  {
    isVisible = ((WindowPeek) gToolsFloatingWindowPtr)->visible;
    if(isVisible)
      TransitionWindow(gToolsFloatingWindowPtr,kWindowZoomTransitionEffect,
                       kWindowHideTransitionAction,NULL);
    else
      TransitionWindow(gToolsFloatingWindowPtr,kWindowZoomTransitionEffect,
                       kWindowShowTransitionAction,NULL);
  }  
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doCreateFloatingWindows

OSErr  doCreateFloatingWindows(void)
{
  Rect      contentRect;
  OSStatus  osError;
  PicHandle pictureHdl;

  SetRect(&contentRect,102,59,391,132);

  if(!(osError = CreateNewWindow(kFloatingWindowClass,
                                 kWindowStandardFloatingAttributes + 
                                 kWindowSideTitlebarAttribute,
                                 &contentRect,&gColoursFloatingWindowPtr)))
  {
    if(pictureHdl = GetPicture(rColoursPicture))
      SetWindowPic(gColoursFloatingWindowPtr,pictureHdl);

    osError = TransitionWindow(gColoursFloatingWindowPtr,kWindowZoomTransitionEffect,
                               kWindowShowTransitionAction,NULL);
  }

  if(osError != noErr)
    return osError;

  SetRect(&contentRect,149,88,213,280);
  
  if(!(osError = CreateNewWindow(kFloatingWindowClass,
                                 kWindowStandardFloatingAttributes,
                                 &contentRect,&gToolsFloatingWindowPtr)))
  {
    if(pictureHdl = GetPicture(rToolsPicture))
      SetWindowPic(gToolsFloatingWindowPtr,pictureHdl);

    osError = TransitionWindow(gToolsFloatingWindowPtr,kWindowZoomTransitionEffect,
                               kWindowShowTransitionAction,NULL);
  }

  return osError;        
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doCreateNewWindow

OSErr  doCreateNewWindow(void)
{
  Rect                contentRect;
  OSStatus            osError;
  WindowPtr           windowPtr;
  docStructureHandle  docStrucHdl;
  Handle              textHdl;

  SetRect(&contentRect,10,40,470,340);

  do
  {
    if(osError = CreateNewWindow(kDocumentWindowClass,kWindowStandardDocumentAttributes,
                                 &contentRect,&windowPtr))
      break;

    if(!(docStrucHdl = (docStructureHandle) NewHandle(sizeof(docStructure))))
    {
      osError = MemError();
      break;
    }

    if(osError = SetWindowProperty(windowPtr,0,'docs',sizeof(docStructure),
                                   &docStrucHdl))
      break;

    SetPort(windowPtr);
    TextSize(10);

    textHdl = GetResource('TEXT',rText);
    osError = ResError();
    if(osError != noErr)
      break;

    OffsetRect(&contentRect,-contentRect.left,-contentRect.top);
    contentRect.right -= 15;
    contentRect.bottom -= 15;

    (*docStrucHdl)->editStrucHdl = TENew(&contentRect,&contentRect);
    TEInsert(*textHdl,GetHandleSize(textHdl),(*docStrucHdl)->editStrucHdl);

    SetWTitle(windowPtr,"\pCreateNewWindow");
    
    if(osError = SetWindowProxyCreatorAndType(windowPtr,0,'TEXT',kOnSystemDisk))
      break;
    if(osError = SetWindowModified(windowPtr,false))
      break;
    if(osError = RepositionWindow(windowPtr,NULL,kWindowCascadeOnMainScreen))
      break;
    if(osError = TransitionWindow(windowPtr,kWindowZoomTransitionEffect,
                                  kWindowShowTransitionAction,NULL))
      break;

    if(osError = doSaveWindow(windowPtr))
      break;

  } while(false);

  if(osError)
  {
    if(windowPtr)
      DisposeWindow(windowPtr);
      
    if(docStrucHdl)
      DisposeHandle((Handle) docStrucHdl);
  }

  return osError;
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doSaveWindow

OSErr  doSaveWindow(WindowPtr windowPtr)
{
  Collection          collection = NULL;
  OSStatus            osError;
  docStructureHandle  docStrucHdl;
  UInt32              actualSize;
  Handle              flatCollectHdl, flatCollectResHdl, existingResHdl;

  do
  {
    if(!(collection = NewCollection()))
    {
      osError = MemError();
      break;
    }
    
    if(osError = StoreWindowIntoCollection(windowPtr,collection))
      break;
      
    if(osError = GetWindowProperty(windowPtr,0,'docs',sizeof(docStrucHdl),&actualSize,
                                   &docStrucHdl))
      break;
      
    if(osError = AddCollectionItemHdl(collection,'TEXT',1,
                                      (*(*docStrucHdl)->editStrucHdl)->hText))
      break;

    if(!(flatCollectHdl = NewHandle(0)))
    {
      osError = MemError();
      break;
    }

    if(osError = FlattenCollectionToHdl(collection,flatCollectHdl))
      break;

    existingResHdl = Get1Resource('wind',rWind);
    osError = ResError();
    if(osError != noErr && osError != resNotFound)
      break;

    if(existingResHdl != NULL)
      RemoveResource(existingResHdl);
    osError = ResError();
    if(osError != noErr)
      break;

    AddResource(flatCollectHdl,'wind',rWind,"\p");
    osError = ResError();
    if(osError != noErr)
      break;

    flatCollectResHdl = flatCollectHdl;
    flatCollectHdl = NULL;

    WriteResource(flatCollectResHdl);
    osError = ResError();
    if(osError != noErr)
      break;

    UpdateResFile(gAppResFileRefNum);
    osError = ResError();
    if(osError != noErr)
      break;
  } while(false);

  if(collection)
    DisposeCollection(collection);
  if(flatCollectHdl)
    DisposeHandle(flatCollectHdl);
  if(flatCollectResHdl)
    ReleaseResource(flatCollectResHdl);

  return osError;
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doCreateWindowFromResource

OSErr  doCreateWindowFromResource(void)
{
  OSStatus            osError;
  WindowPtr           windowPtr;
  Collection          unflattenedCollection = NULL;
  Handle              windResHdl;
  docStructureHandle  docStrucHdl;
  SInt32              dataSize = 0;
  Handle              textHdl;
  Rect                contentRect;

  do
  {
    if(osError = CreateWindowFromResource(rWind,&windowPtr))
      break;

    if(!(unflattenedCollection = NewCollection()))
    {
      osError = MemError();
      break;
    }

    windResHdl = GetResource('wind',rWind);
    osError = ResError();
    if(osError != noErr)
      break;

    if(osError = UnflattenCollectionFromHdl(unflattenedCollection,windResHdl))
      break;

    if(!(docStrucHdl = (docStructureHandle) NewHandle(sizeof(docStructure))))
    {
      osError = MemError();
      break;
    }

    if(osError = GetCollectionItem(unflattenedCollection,'TEXT',1,&dataSize,
                                   kCollectionDontWantData))
      break;

    if(!(textHdl = NewHandle(dataSize)))
    {
      osError = MemError();
      break;
    }

    if(osError =
GetCollectionItem(unflattenedCollection,'TEXT',1,kCollectionDontWantSize,
                                   *textHdl))
      break;

    contentRect = windowPtr->portRect;
    contentRect.right -= 15;
    contentRect.bottom -= 15;
    SetPort(windowPtr);
    TextSize(10);
    (*docStrucHdl)->editStrucHdl = TENew(&contentRect,&contentRect);
    TEInsert(*textHdl,dataSize,(*docStrucHdl)->editStrucHdl);

    if(osError = SetWindowProperty(windowPtr,0,'docs',sizeof(docStrucHdl),&docStrucHdl))
      break;

    SetWTitle(windowPtr,"\pCreateWindowFromResource");
              
    if(osError = SetWindowProxyCreatorAndType(windowPtr,0,'TEXT',kOnSystemDisk))
      break;
    if(osError = SetWindowModified(windowPtr,false))
      break;
    if(osError = RepositionWindow(windowPtr,NULL,kWindowCascadeOnMainScreen))
      break;
    if(osError = TransitionWindow(windowPtr,kWindowZoomTransitionEffect,
                                  kWindowShowTransitionAction,NULL))
      break;
  } while(false);

  if(unflattenedCollection)
    DisposeCollection(unflattenedCollection);
  if(windResHdl)
    ReleaseResource(windResHdl);

  return osError;
}

// ×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doCloseWindow

void  doCloseWindow(WindowPtr windowPtr)
{
  OSStatus            osError;
  docStructureHandle  docStrucHdl;
  UInt32              actualSize;

  do
  {
    if(osError = TransitionWindow(windowPtr,kWindowZoomTransitionEffect,
                                  kWindowHideTransitionAction,NULL))
    break;

    if(osError = GetWindowProperty(windowPtr,0,'docs',sizeof(docStrucHdl),&actualSize,
                                   &docStrucHdl))
    break;
  } while(false);

  if(osError)
    doErrorAlert(osError);

  if((*docStrucHdl)->editStrucHdl)
    TEDispose((*docStrucHdl)->editStrucHdl);

  if(docStrucHdl)
    DisposeHandle((Handle) docStrucHdl);

  DisposeWindow(windowPtr);
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doErrorAlert

void  doErrorAlert(SInt16 errorCode)
{
  AlertStdAlertParamRec paramRec;
  Str255                errorCodeString;
  Str255                theString = "\pAn error occurred.  The error code is ";
  SInt16                itemHit;

  paramRec.movable        = false;
  paramRec.helpButton     = false;
  paramRec.filterProc     = NULL;
  paramRec.defaultText    = (StringPtr) kAlertDefaultOKText;
  paramRec.cancelText     = NULL;
  paramRec.otherText      = NULL;
  paramRec.defaultButton  = kAlertStdAlertOKButton;
  paramRec.cancelButton   = 0;
  paramRec.position       = kWindowAlertPositionMainScreen;

  NumToString((SInt32) errorCode,errorCodeString);
  doConcatPStrings(theString,errorCodeString);

  StandardAlert(kAlertStopAlert,theString,NULL,¶mRec,&itemHit);
  ExitToShell();
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××× doConcatPStrings

void  doConcatPStrings(Str255 targetString,Str255 appendString)
{
  SInt16  appendLength;

  appendLength = MIN(appendString[0],255 - targetString[0]);

  if(appendLength > 0)
  {
    BlockMoveData(appendString+1,targetString+targetString[0]+1,(SInt32) appendLength);
    targetString[0] += appendLength;
  }
}

// ××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××


Demonstration Program Comments

This program will run only under Mac OS 8.5 or later.  The program's floating windows
will be created only if the program is run under Mac OS 8.6 or later.

Two Mac OS 8.5 Window Manager features (full window proxy icon implementation and window
path pop-up menus) are not demonstrated in this program.  However, they are demonstrated
at the demonstration program associated with Chapter 16B (Files2).

When the program is run, the user should:

¥  Choose CreateNewWindow from the Document Windows menu, noting that, when the new 
   window is displayed, the floating windows and the new (document) window are all 
   active.

   (Note:  As well as creating the window, the program loads and displays a 'TEXT'
   resource (simulating a document associated with the window) and then saves the 
   window and the text to a 'wind' resource.)

¥  Choose CreateWindowFromResource from the Document Windows menu, noting that the
   window is created from the 'wind' resource saved when CreateNewWindow was chosen.

¥  Choose About Windows2... from the Apple menu, noting that the floating windows 
   appear in the deactivated state when the alert box opens.

¥  Hide the floating windows by clicking their close boxes, and toggle the floating
   windows between hidden and showing by choosing their items in the Floating Windows
   menu, noting the transitional animations and sounds.

¥  Click in the Finder to send the application to the background, noting that the
   floating windows are hidden by this action.  Then click in one of the application's
   windows, noting that the floating windows re-appear.

¥  Drag a document window to various locations on the screen, zoom the window in and 
   out at those locations, and note that the zoom out to the standard state conforms 
   with human interface guidelines.

¥  Resize the document windows.

¥  Note the transitional animations and sounds when the document windows are opened and 
   closed.

×define

The first twelve ×defines establish constants representing menu IDs and resources,
menu item numbers, and the menu bar resource ID.  The next five represent the resource
IDs for an 'ALRT' resource (and associated 'DITL', 'alrx', and 'dfnt' resources), a
'TEXT' resource, two 'PICT' resources, and the 'wind' resource created by the program. 
The (fairly common) macro which follows is required by the application-defined string
concatenation doConcatPStrings.

×typedef

A document structure of type docStructure will be "attached" to each document
window. The single field in the document structure (editStrucHdl) will be assigned a
handle to a TextEdit edit structure, which will contain the text displayed in the
window.

Global Variables

gMacOS86Present will be assigned true if Mac OS 8.6 or later is present. 
gAppResFileRefNum will be assigned the file reference number for the application file's
resource fork. gColoursFloatingWindowPtr and gToolsFloatingWindowPtr will be assigned
pointers to the colour graphics port structures for the floating windows.  gDone, when
set to true, will cause the main event loop to exit and the program to terminate. 
gInBackground relates to foreground/background switching.

main

Gestalt is called to determine which version of the Mac OS is present.  If Mac OS
8.5 or later is not present, the program terminates.  If Mac OS 8.6 or later is present,
the global variable gMacOS86Present is set to true.

The next block sets up the menus.  Note that error handling in this block is very
rudimentary: the program simply terminates.

At the next block CurResFile is called to set the application's resource fork as the
current resource file.  This is necessary because the program will be saving a 'wind'
resource to the application file's resource fork.

If Mac OS 8.6 is present, an application-defined function is called to create and show
the floating windows, otherwise the Floating Windows menu and the About Windows2... item
in the Apple menu are disabled.

In the next block (the main event loop), WaitNextEvent's sleep parameter is assigned the
value returned by LMGetCaretTime. (LMGetCaretTime returns the value stored in the low
memory global CaretTime, which determines the blinking rate for the insertion point caret
as set by the user using the General Controls Control Panel.)  This ensures that TEIdle,
which causes the caret to blink, will be called at the correct interval.

When WaitNextEvent returns a NULL event, the Mac OS 8.5 function FrontNonFloatingWindow
is called to obtain a pointer to the front document window.  If such a window exists, the
Mac OS 8.5 function GetWindowProperty is called to retrieve a handle to the window's
document structure.  The handle to the TextEdit edit structure, which is stored in the
window's document structure, is then passed in the call to TEIdle, which causes the caret
to blink.

doInitManagers

Note that, if Mac OS 8.6 is present, the Mac OS 8.5 function InitFloatingWindows is
called, otherwise InitWindows is called.

doMouseDown

doMouseDown continues the processing of mouse-down events, switching according to
the part code.

The inContent case is handled differently depending on whether the event is in a floating
window or a document window.  The Mac OS 8.5 function GetWindowClass returns the window's
class.  If the window is a floating window, and if that window is not the front floating
window, SelectWindow is called to bring that floating window to the front.  If the window
is the front floating window, the identity of the window is determined and the
appropriate further action is taken.  (In this demonstration, no further action is
taken.)

If the window is not a floating window, and if the window is not the front non-floating
window, SelectWindow is called to:

¥  Unhighlight the currently active non-floating window, bring the specified window to
   the front of the non-floating windows, and highlight it.

¥  Generate activate events for the two windows.

¥  Move the previously active non-floating window to a position immediately behind the
   specified window.

If the window is the front non-floating window, the appropriate further action is taken. 
(In this demonstration, no further action is taken.)

The inGoAway case is also handled differently depending on whether the event is in a
floating window or a document window.  TrackGoAway is called in both cases to track user
action while the mouse-button remains down.  If the pointer is still within the go away
box when the mouse-button is released, and if the window is a floating window, the Mac OS
8.5 function TransitionWindow is called to hide the window.  If the window is a
non-floating window, the application-defined function doCloseWindow is called to close
the window.

The inGrow case first sets up the Rect passed in the third parameter of the ResizeWindow
and GrowWindow calls which, in turn, will limit the minimum and maximum sizes to which
the window can be resized.  The top, left, bottom and right fields must contain,
respectively, the minimum vertical, the minimum horizontal, the maximum vertical, and the
maximum horizontal measurements.  At the first line, this Rect is set to the boundaries
of the screen, which is a reasonable way to get reasonable values into the bottom and
right fields.  The top and left fields, however, need to be manually set to some
reasonable values (the two next lines).

If Mac OS 8.6 or later is present, the Mac OS 8.6 function ResizeWindow is called to
retain control while the mouse-button remains down, and to draw the window frame in its
new size when the mouse button is released.  (When ResizeWindow returns, its
newContentRect parameter contains the new dimension of the window's content region in
global coordinates, although this information is not used in this demonstration.)  The
call to the Mac OS 8.5 function InvalWindowRect will cause the entire content region to
be erased and redrawn (see doUpdateDocumentWindow).

If Mac OS 8.5 or earlier is present, GrowWindow is called and retains control until the
user releases the mouse button, at which time the Rect variable newSize will contain the
new window size coordinates.  (Note that GrowWindow does not redraw the window in this
size.)  The SizeWindow call then redraws the window frame.  The call to the Mac OS 8.5
function InvalWindowRect will cause the entire content region to be erased and redrawn
(see doUpdateDocumentWindow).

At the inZoomIn and InZoomOut cases, the first two lines set the fields of a Point
variable to equal the height and width of the main screen less 100 and 200 pixels
respectively.  This represents what this application considers to be the ideal size for
the window.  The call to the Mac OS 8.5 function IsWindowInStandardState compares the
window's current size with this ideal size and, if they are equal, inZoomIn is assigned
to the local variable zoomPart, meaning that the window is to be zoomed in to the user
state.  If they are not equal, inZoomOut is assigned to zoomPart, meaning that the window
is to be zoomed out to the standard state.  TrackBox retains control until the user
releases the mouse button.  If the pointer is still within the zoom box when the mouse
button is released, the Mac OS 8.5 function ZoomWindowIdeal is called to zoom the window
in accordance with human interface guidelines, and in the direction specified by
zoomPart.

doUpdate

doUpdate further processes update events.  When an update event is received,
doUpdate calls doUpdateDocumentWindow.  (As will be seen, in this particular
demonstration, the Window Manager will not generate updates for the floating
windows.)

doUpdateDocumentWindow

doUpdateDocumentWindow is concerned with the redrawing of the content region of the
non-floating windows.

Firstly, the window's visible region, which at this point equates to the update region,
is erased and DrawGrowIcon is called to draw the scroll bar delimiting lines.  (This
latter call is for cosmetic purposes only and would not be made if the window contained
scroll bars.)  

The Mac OS 8.5 function GetWindowProperty is then called to retrieve the handle to the
window's document structure, which, as previously stated, contains a handle to a TextEdit
edit text structure containing the text displayed in the window.  If the call is
successful, measures are taken to redraw the text in the window, taking account of the
current height and width of the content region less the area that would ordinarily be
occupied by scroll bars.  (The TextEdit is calls in this section are incidental to the
demonstration.  TextEdit is addressed at Chapter 19 Ñ Text and TextEdit.)

doActivate

doActivate attends to those aspects of window activation not handled by the Window
Manager.  The modifiers field of the event structure is tested to determine whether the
window in question is being activated or deactivated.  The result of this test is passed
as a parameter in a call to the application-defined function for activating non-floating
windows.

doActivateDocumentWindow

doActivateDocumentWindow performs, for the non-floating windows, those window
activation actions for which the application is responsible.  In this demonstration, that
action is limited to calling TEActivate or TEDeactivate to show or remove the insertion
point caret.

The Mac OS 8.5 function GetWindowProperty is called to retrieve the handle to the
window's document structure, which contains a handle to the TextEdit edit text structure
containing the text displayed in the window.  If this call is successful, and if the
window is being activated, TEActivate is called to display the insertion point caret.  If
the window is being deactivated, TEDeactivate is called to remove the insertion point
caret.

doOSEvent

doOSEvent handles operating system events.  In this demonstration, action is taken
only in the case of suspend and resume messages.

If the event is a suspend event, the global variable gInBackground is assigned true,
otherwise it is assigned false.  The call to the Mac OS 8.5 function
FrontNonFloatingWindow and the following line determines whether there are any
non-floating windows present.  If so, a pointer to the front non-floating window is
passed in the call to the application-defined function for activating and deactivating
no-floating windows.  In the next block, if the event was a suspend event, the Mac OS 8.5
function HideFloatingWindows is called to hide the floating windows, otherwise the Mac OS
8.5 function ShowFloatingWindows is called to show the floating windows.

doAdjustMenus

doAdjustMenus is called in the event of a mouse-down event in the menu bar when a
key is pressed together with the Command key.  The function checks or unchecks the items
in the Floating Windows menu depending on whether the associated floating window is
currently showing or hidden.

doMenuChoice

doMenuChoice switches according to the menu choices of the user.

If the user chooses the About Windows2... item from the Apple menu, Alert is called to
display the About Windows2... alert box.

The calls to HiliteWindow explicitly activate the two floating windows when the alert box
is dismissed.  This is a workaround to compensate for what appears to be a Window Manager
window activation anomaly.  This anomaly is evidenced as follows:

¥  When the application is launched and a document window is opened before the alert box
   is invoked, the floating windows appear in the deactivated state while the alert box
   is present and in the activated state when the alert box is dismissed.  This is the
   expected correct behaviour.

¥  However, if a document window is not opened before the alert box is invoked, the
   floating windows remain in the deactivated state when the alert box is dismissed. 

The calls to HiliteWindow have been included to cater for the second of the above
situations. 

If the user chooses the Quit item in the File menu, the global variable gDone is set to
true, causing the program to terminate.

doDocumentWindowsMenu

doDocumentWindowsMenu further processes choices from the Document Windows menu.  If
the user chose the first item, the application-defined function doCreateNewWindow is
called.  If the user chose the second item, the application-defined function
doCreateWindowFromResource is called.  If either of these functions return an error, an
application-defined error-handling function is called.

doFloatingWindowsMenu

doFloatingWindowsMenu further processes choices from the Floating Windows menu.

When an item is chosen, the visible field of the window's colour window structure is
examined to determine whether the window is currently showing or hidden.  The Mac OS 8.5
function TransitionWindow is then called, with the appropriate constant passed in the
action parameter, to hide or show the window, depending on the previously determined
current visibility state.

doCreateFloatingWindows

doCreateFloatingWindows is called from main to create the floating windows.

The Colours floating window is created first. SetRect is called to define a rectangle
which will be used to establish the size of the window and its opening location in global
coordinates.  The Mac OS 8.5 function CreateNewWindow is then called to create a floating
window (first parameter) with a close box, a collapse box, and a side title bar (second
parameter), and with the previously defined content region size and location (third
parameter).

If this call is successful,  GetPicture is called to load the specified 'PICT' resource. 
If the resource is loaded successfully, SetWindowPic is called to store the handle to the
picture structure in the windowPic field of the window's colour window structure.  This
latter means that the Window Manager will draw the picture in the window instead of
generating update events for it.  Finally, the Mac OS 8.5 function TransitionWindow is
called to make the window visible (with animation and sound).

The same general procedure is then followed to create the Tools floating window.

doCreateNewWindow

doCreateNewWindow is called when the user chooses Create New Window from the
Document Windows menu.  In addition to creating a window, and for the purposes of this
demonstration, doCreateNewWindow also saves the window and its associated data (text) in
a 'wind' resource.

Firstly, SetRect is called to define a rectangle that will be used to establish the size
of the window and its opening location in global coordinates.  The call to the Mac OS 8.5
function CreateNewWindow creates a document window (first parameter) with a close box, a
full zoom box, a collapse box, and a size box (second parameter), and with the previously
defined content region size and location (third parameter).

NewHandle is then called to create a relocatable block for the document structure to be
associated with the window.  The Mac OS 8.5 function SetWindowProperty associates the
document structure with the window.  0 is passed in the propertyCreator parameter because
this demonstration has no application signature.  The value passed in the propertyTag
parameter ('docs') is just a convenient value with which to identify the data.

The call to SetPort sets the window's colour graphics port as the current port and the
call to TextSize ensures that the size of the text to be drawn in the window will be 10
points.

The next three blocks load a 'TEXT' resource, insert the text into a TextEdit edit text
structure, and assign a handle to that structure to the editStrucHdl field of the
window's document structure.  This is all for the purpose of simulating some text that
the user has typed into the window.

SetWTitle sets the window's title.

The window lacks an associated file, so the Mac OS 8.5 function
SetWindowProxyCreatorAndType is called to cause a proxy icon to be displayed in the
window's drag bar.  0 passed in the fileCreator parameter and 'TEXT' passed in the
fileType parameter cause the system's default icon for a document file to be displayed. 
The Mac OS 8.5 function SetWindowModified is then called with false passed in the
modified parameter to cause the proxy icon to appear in the enabled state (indicating no
unsaved changes).

The call to the Mac OS 8.5 function RepositionWindow positions the window relative to
other windows according to the constant passed in the method parameter.

As the final step in creating the window, the Mac OS 8.5 function TransitionWindow is
called to make the window visible (with animation and sound).

To facilitate the demonstration of creating a window from a 'wind' resource (see the
function doCreateWindowFromResource), an application-defined function is called to save
the window and its data (the text) to a 'wind' resource in the application's resource
fork.

If an error occurred within the do/while loop, if a window was created, it is disposed
of.  Also, if a nonrelocatable block for the document structure was created, it is
disposed of.

doSaveWindow

doSaveWindow is called by doCreateNewWindow to save the window and its data (the
text) to a 'wind' resource.

The call to the Collection Manager function NewCollection allocates memory for as new
collection object and initializes it.  The call to the Mac OS 8.5 function
StoreWindowIntoCollection stores data describing the window into the collection.

The Mac OS 8.5 function GetWindowProperty retrieves the handle to the window's document
structure.

The handle to the window's text is is stored in the hText field of the TextEdit edit text
structure.  The handle to the edit text structure is, in turn, stored in the window's
document structure.  The Collection Manager function AddCollectionItemHdl adds a new item
to the collection, specifically, a copy of the text.

The call to NewHandle allocates a zero-length handle which will be used to hold a
flattened collection.  The Collection Manager function FlattenCollectionToHdl flattens
the collection into a Memory Manager handle.

The next six blocks use Resource Manager functions to save the flattened collection as a
'wind' resource in the resource fork of the application file.

Get1Resource attempts to load a 'wind' resource with ID 128.  If ResError reports an
error, and if the error is not the "resource not found" error, the whole save process is
aborted.  (Accepting the "resource not found" error as an acceptable error caters for the
possibility that this may be the first time the window and its data have been saved.)

If Get1Resource successfully loaded a 'wind' resource with ID 128, RemoveResource is
called to remove that resource from the resource map, AddResource is called to make the
flattened collection in memory into a 'wind' resource, assigning a resource type, ID and
name to that resource, and inserting an entry in the resource map for the current
resource file.  WriteResource is called to write the resource to the application's
resource fork.  Since the resource map has been changed, UpdateResFile is called to
update the resource map on disk.

Below the do/while loop, the collection and the flattened collection block are disposed
of and the resource in memory is released.

doCreateWindowFromResource

doCreateWindowFromResource creates a window from the 'wind' resource created by
doSaveWindow.

The Mac OS 8.5 function CreateWindowFromResource creates a window, invisibly, from the
'wind' resource with ID 128.

The call to the Collection Manager function NewCollection creates a new collection. 
GetResource loads the 'wind' resource with ID 128.  The Collection Manager function
UnflattenCollectionFromHdl unflattens the 'wind' resource and stores the unflattened
collection in the collection object unflattenedCollection.

NewHandle allocates a relocatable block the size of a window document structure.

The Collection Manager function GetCollectionItem is called twice, the first time to get
the size of the text data, not the data itself.  (The item in the collection is specified
by the second and third parameters (tag and ID)).  This allows the call to NewHandle to
create a relocatable block of the same size.  GetCollection is then called again, this
time to obtain a copy of the text itself.

The next block creates a new TextEdit edit text structure (TENew), assigning its handle
to the editStrucHdl field of the document structure which will shortly be associated with
the window.  TEInsert inserts the copy of the text obtained by the second call to
GetCollectionItem into the edit text structure.

The call to the Mac OS 8.5 function SetWindowProperty associates the document structure
with the window, thus associating the edit text structure and its text with the window.

SetWTitle sets the window's title.

The window lacks an associated file, so the Mac OS 8.5 function
SetWindowProxyCreatorAndType is called to cause a proxy icon to be displayed in the
window's drag bar.  0 passed in the fileCreator parameter and 'TEXT' passed in the
fileType parameter cause the system's default icon for a document file to be displayed. 
The Mac OS 8.5 function SetWindowModified is then called with false passed in the
modified parameter to cause the proxy icon to appear in the enabled state (indicating no
unsaved changes).

The call to the Mac OS 8.5 function RepositionWindow positions the window relative to
other windows according to the constant passed in the method parameter.

As the final step in creating the window, the Mac OS 8.5 function TransitionWindow is
called to make the window visible (with animation and sound).

Below the do/while loop, the unflattened collection is disposed of and the 'wind'
resource is released.

doCloseWindow

doCloseWindow is called when the user clicks the close box of a document window.

TransitionWindow is called to hide the window (with animation and sound).  The Mac OS 8.5
function GetWindowProperty is then called to retrieve a handle to the window's document
structure, allowing the memory occupied by the edit text structure and document structure
associated with the window to be disposed of.  DisposeWindow is then called to remove the
window from the window list and discard all its data storage.

doErrorAlert and doConcatPStrings

doErrorAlert is called when errors are detected.  In this demonstration, the action
taken is somewhat rudimentary.  A stop alert box displaying the error number is invoked. 
When the user dismisses the alert box, the program terminates.

doConcatPStrings is called from doErrorAlert to concatenate two strings into the single
string displayed in the alert box. 


Click here to find out more about our best subscription bundle deal ever!
2 years of the magazine, and the all new MacTech DVD ... at 70% off!



Click on the cover to
see this month's issue!

TRIAL SUBSCRIPTION
Get a RISK-FREE subscription to the only technical Mac magazine!
 
 


MacTech Magazine. www.mactech.com
Toll Free 877-MACTECH, Outside US/Canada: 805-494-9797

Register Low Cost (ok dirt cheap!) Domain Names in the MacTech Domain Store. As low as $1.99!
Save on brand compatible and name brank ink jet and laser supplies.
Save on long distance * Upgrade your Computer
Movies with No Late Fees!

See local info about Westlake Village
SJ * BRJ * BJ * OJ * NITS
Staff Site Links



All contents are Copyright 1984-2008 by Xplain Corporation. All rights reserved.

MacTech is a registered trademark of Xplain Corporation. Xplain, Video Depot, Movie Depot, Palm OS Depot, Explain It, MacDev, MacDev-1, THINK Reference, NetProfessional, NetProLive, JavaTech, WebTech, BeTech, LinuxTech, Apple Expo, MacTech Central and the MacTutorMan are trademarks or service marks of Xplain Corporation. Sprocket is a registered trademark of eSprocket Corporation. Other trademarks and copyrights appearing in this printing or software remain the property of their respective holders.