TweetFollow Us on Twitter

MACINTOSH C CARBON

Demonstration Program DialogsAndAlerts

Goto Contents

// *******************************************************************************************
// DialogsAndAlerts.h                                                      CLASSIC EVENT MODEL
// *******************************************************************************************
// 
// This program initially opens a small modal dialog which is automatically closed after 10
// seconds, the timeout value having been set by a call to SetDialogTimeout.  The program
// then:
//
// o  Opens a window for the purposes of displaying  advisory text and proving correct window
//    updating and activation/deactivation in the  presence of alerts and dialogs.
//
// o  Allows the user to invoke, via the Demonstration menu, modal and movable modal alerts
//    and dialogs, a modeless dialog and, on Mac OS X, a window-modal alert and dialog
//    (i.e., sheets).  
//
// The modal alert box is created programmatically using the StandardAlert function.
//
// The movable modal alert is created programmatically using the StandardAlert function on Mac
// OS 9 and the CreateStandardAlert function on Mac OS X.
//
// The modal dialog contains three checkboxes in one group box, and two pop-up menu buttons in
// another group box.
//
// The movable modal dialog contains four radio buttons in one group box, and a clock control
// and edit text item in another group box.
//
// The modeless dialog contains, amongst other items, an edit text item.
//
// The modal and movable modal alerts and dialogs use an application-defined event filter
// (callback) function.
//
// The program utilises the following resources:
//
// o  A 'plst' resource.
//
// o  An 'MBAR' resource, and 'MENU' resources for Apple, File, and Demonstration pull-down
//    menus, and the pop-up menu buttons (preload, non-purgeable).
//
// o  A 'WIND' resource (purgeable) (initially visible).
//
// o  'DLOG' resources (purgeable) (initially not visible) and associated 'DITL' resources
//    (purgeable), 'dlgx' resources (purgeable), and 'dftb' resources (non-purgeable, but
//    'dftb' resources are automatically marked purgeable when read in).
//
// o  'CNTL' resources for primary group boxes, separator lines, pop-up menu buttons, a clock,
//    and an image well (all purgeable).
//
// o  'STR#' resources (purgeable) containing the message and informative text for the alerts.
//
// o  A 'cicn' resource (purgeable) for the modeless dialog box.
//
// o  A 'ppat' resource (purgeable), which is used to colour the content region of the
//    document window for update proving purposes.
//
// o  'hdlg' resources (purgeable) containing balloon help information for the modal and
//    movable modal dialog.
//
// o  An 'hrct' resource and associated 'hwin' resource (both purgeable) containing balloon
//    help information for the modeless dialog.
//
// o  A 'SIZE' resource with the acceptSuspendResumeEvents, canBackground, 
//    doesActivateOnFGSwitch, and isHighLevelEventAware flags set.
//
// *******************************************************************************************

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

#include <Carbon.h>

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

#define rMenubar                 128
#define mAppleApplication        128
#define  iAbout                  1
#define mFile                    129
#define  iClose                  4
#define  iQuit                   12
#define mEdit                    130
#define  iCut                    3
#define  iCopy                   4
#define  iPaste                  5
#define  iClear                  6
#define mDemonstration           131
#define  iModalAlert             1
#define  iMovableAlert           2
#define  iModalDialog            3
#define  iMovableModalDialog     4
#define  iModeless               5
#define  iWindowModalAlert       7
#define  iWindowModalDialog      8
#define mFont                    132
#define rWindow                  128
#define rSplash                  128
#define rModalDialog             129
#define  iGridSnap               4
#define  iShowGrid               5
#define  iShowRulers             6
#define  iFont                   11
#define  iSound                  12
#define rMovableModalDialog      130
#define  iCharcoal               7
#define  iOilPaint               8
#define  iPencil                 9
#define  iChalk                  10
#define  iClockOne               12
#define rModelessDialog          131
#define  iEditTextSearchModeless 2
#define rSheetDialog             132
#define  iEditTextSheetDialog    2
#define rAlertStrings            128
#define  sModalMessage           1
#define  sModalInformative       2
#define  sMovableMessage         3
#define  sMovableInformative     4
#define rSheetStrings            132
#define  sAlertSheetMessage      1
#define  sAlertSheetInformative  2
#define rPixelPattern            128
#define kSearchModeless          1
#define kSheetDialog             2

#define kReturn                  (SInt8) 0x0D
#define kEnter                   (SInt8) 0x03
#define kEscape                  (SInt8) 0x1B
#define kPeriod                  (SInt8) 0x2E

#define MAX_UINT32               0xFFFFFFFF

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

void    main                           (void);
void    doPreliminaries                (void);
OSErr   quitAppEventHandler            (AppleEvent *,AppleEvent *,SInt32);
void    eventLoop                      (void);
void    doIdle                         (void);
void    doEvents                       (EventRecord *);
void    doMouseDown                    (EventRecord *);
void    doKeyDown                      (EventRecord *);
void    doUpdate                       (EventRecord *);
void    doUpdateDocument               (WindowRef);
void    doActivate                     (EventRecord *);
void    doActivateDocument             (WindowRef,Boolean);
void    doActivateDialogs              (EventRecord *,Boolean);
void    doOSEvent                      (EventRecord *);
void    doAdjustMenus                  (void);
void    doMenuChoice                   (SInt32);
void    doEditMenu                     (MenuItemIndex);
void    doDemonstrationMenu            (MenuItemIndex);
void    doExplicitlyDeactivateDocument (void);
Boolean doModalAlerts                  (Boolean);
Boolean doMovableModalAlertOnX         (void);
Boolean doModalDialog                  (void);
Boolean doMovableModalDialog           (void);
Boolean doCreateOrShowModelessDialog   (void);
void    doInContent                    (EventRecord *);
void    doButtonHitInSearchModeless    (void);
void    doHideModelessDialog           (WindowRef);
Boolean eventFilter                    (DialogRef,EventRecord *,SInt16 *);
void    doPopupMenuChoice              (ControlRef,SInt16);
void    doDrawMessage                  (WindowRef,Boolean);
void    doCopyPString                  (Str255,Str255);

Boolean doSheetAlert                   (void);
Boolean doSheetDialog                  (void);
void    doButtonHitInSheetDialog       (void);

void    helpTagsModal                  (DialogRef);
void    helpTagsMovableModal           (DialogRef);
void    helpTagsModeless               (DialogRef);

// *******************************************************************************************
// DialogsAndAlerts.c
// *******************************************************************************************

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

#include "DialogsAndAlerts.h"

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

Boolean        gRunningOnX        = false;
ModalFilterUPP gEventFilterUPP;
Str255         gCurrentString;
WindowRef      gWindowRef;
SInt32         gSleepTime;
Boolean        gDone;
Boolean        gGridSnap          = kControlCheckBoxUncheckedValue;
Boolean        gShowGrid          = kControlCheckBoxUncheckedValue;
Boolean        gShowRule          = kControlCheckBoxUncheckedValue;  
SInt16         gBrushType         = iCharcoal;
DialogRef      gModelessDialogRef = NULL;

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

void  main(void)
{
  MenuBarHandle menubarHdl;
  SInt32        response;
  MenuRef       menuRef;
  DialogRef     dialogRef;
  SInt16        itemHit;

  // ........................................................................ do preliminaries
  
  doPreliminaries();

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

  menubarHdl = GetNewMBar(rMenubar);
  if(menubarHdl == NULL)
    ExitToShell();
  SetMenuBar(menubarHdl);
  DrawMenuBar();

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

  // ................... open small modal dialog and automatically dismiss it after 10 seconds

  dialogRef = GetNewDialog(rSplash,NULL,(WindowRef) -1);
  SetDialogTimeout(dialogRef,kStdOkItemIndex,10);

  do
  {
    ModalDialog(NULL,&itemHit);  
  } while(itemHit != kStdOkItemIndex);
  
  DisposeDialog(dialogRef);

  // ............................ create universal procedure pointer for event filter function

  gEventFilterUPP = NewModalFilterUPP((ModalFilterProcPtr) eventFilter);

  // ................................................. initial advisory text for window header

  doCopyPString("\pBalloon (OS 8/9) and Help tag (OS X) help is available",gCurrentString);

  // ............................................................ open a window, set font size

  if(!(gWindowRef = GetNewCWindow(rWindow,NULL,(WindowRef)-1)))
    ExitToShell();

  SetPortWindowPort(gWindowRef);
  if(!gRunningOnX)
    TextSize(10);

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

  eventLoop();
}

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

void  doPreliminaries(void)
{
  OSErr osError;
  
  MoreMasterPointers(192);
  InitCursor();
  FlushEvents(everyEvent,0);

  osError = AEInstallEventHandler(kCoreEventClass,kAEQuitApplication,
                            NewAEEventHandlerUPP((AEEventHandlerProcPtr) quitAppEventHandler),
                            0L,false);
  if(osError != noErr)
    ExitToShell();
}

// **************************************************************************** doQuitAppEvent

OSErr  quitAppEventHandler(AppleEvent *appEvent,AppleEvent *reply,SInt32 handlerRefcon)
{
  OSErr    osError;
  DescType returnedType;
  Size     actualSize;

  osError = AEGetAttributePtr(appEvent,keyMissedKeywordAttr,typeWildCard,&returnedType,NULL,0,
                              &actualSize);

  if(osError == errAEDescNotFound)
  {
    gDone = true;
    osError = noErr;
  } 
  else if(osError == noErr)
    osError = errAEParamMissed;

  return osError;
}

// ********************************************************************************* eventLoop

void  eventLoop(void)
{
  EventRecord eventStructure;
  Boolean     gotEvent;

  gSleepTime = MAX_UINT32;
  gDone = false;

  while(!gDone)
  {
    gotEvent = WaitNextEvent(everyEvent,&eventStructure,gSleepTime,NULL);
    if(gotEvent)
      doEvents(&eventStructure);
    else
    {
      if(eventStructure.what == nullEvent)
        if(!gRunningOnX)
          doIdle();
    }
  }
}

// ************************************************************************************ doIdle

void  doIdle(void)
{
  if(FrontWindow() == GetDialogWindow(gModelessDialogRef))
    IdleControls(GetDialogWindow(gModelessDialogRef));
}

// ********************************************************************************** doEvents

void  doEvents(EventRecord *eventStrucPtr)
{
  switch(eventStrucPtr->what)
  {
    case kHighLevelEvent:
      AEProcessAppleEvent(eventStrucPtr);
      break;
      
    case mouseDown:
      doMouseDown(eventStrucPtr);
      break;

    case keyDown:
      doKeyDown(eventStrucPtr);
      break;

    case autoKey:
      if((eventStrucPtr->modifiers & cmdKey) == 0)
        doKeyDown(eventStrucPtr);
      break;

    case updateEvt:
      doUpdate(eventStrucPtr);
      break;

    case activateEvt:
      doActivate(eventStrucPtr);
      break;

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

// ******************************************************************************* doMouseDown

void  doMouseDown(EventRecord *eventStrucPtr)
{
  WindowRef      windowRef;
  WindowPartCode partCode;

  partCode = FindWindow(eventStrucPtr->where,&windowRef);

  switch(partCode)
  {
    case inMenuBar:
      doAdjustMenus();
      doMenuChoice(MenuSelect(eventStrucPtr->where));
      break;

    case inContent:
      if(windowRef != FrontWindow())
        SelectWindow(windowRef);
      else
        doInContent(eventStrucPtr);
      break;

    case inDrag:
      DragWindow(windowRef,eventStrucPtr->where,NULL);
      break;

    case inGoAway:
      if(TrackGoAway(windowRef,eventStrucPtr->where))
      {
        if(GetWindowKind(windowRef) == kDialogWindowKind)
        {
          doHideModelessDialog(windowRef);
          doCopyPString("\pBalloon (OS 8/9) and Help tag (OS X) help is available",
                        gCurrentString);
        }
      }
      break;
  }
}

// ********************************************************************************* doKeyDown

void  doKeyDown(EventRecord *eventStrucPtr)
{
  WindowRef  windowRef;
  SInt8      charCode;
  SInt32     windowRefCon;
  SInt16     itemHit;
  ControlRef controlRef;
  UInt32     finalTicks;
  DialogRef  dialogRef;
  
  windowRef = FrontWindow();
  charCode = eventStrucPtr->message & charCodeMask;

  if(!(IsDialogEvent(eventStrucPtr)))
  {
    if((eventStrucPtr->modifiers & cmdKey) != 0)
    {
      doAdjustMenus();
      doMenuChoice(MenuEvent(eventStrucPtr));
    }
  }
  else
  {
    windowRefCon = GetWRefCon(windowRef);
    if(windowRefCon == kSearchModeless || windowRefCon == kSheetDialog)
    {
      if((charCode == kReturn) || (charCode == kEnter))
      {
        GetDialogItemAsControl(GetDialogFromWindow(windowRef),kStdOkItemIndex,&controlRef);
        HiliteControl(controlRef,kControlButtonPart);
        Delay(8,&finalTicks);
        HiliteControl(controlRef,kControlEntireControl);
        if(windowRefCon == kSearchModeless)
          doButtonHitInSearchModeless();
        else if(windowRefCon == kSheetDialog)
          doButtonHitInSheetDialog();
        return;
      }

      if((eventStrucPtr->modifiers & cmdKey) != 0)
      {
        if(charCode == 'X' || charCode == 'x' ||  charCode == 'C' || charCode == 'c' ||
            charCode == 'V' || charCode == 'v')
        {
          HiliteMenu(mEdit);
          DialogSelect(eventStrucPtr,&dialogRef,&itemHit);
          Delay(4,&finalTicks);
          HiliteMenu(0);
        }
        else
        {
          doAdjustMenus();
          doMenuChoice(MenuEvent(eventStrucPtr));
        }

        return;
      }

      DialogSelect(eventStrucPtr,&dialogRef,&itemHit);
    }
  }
}

// ********************************************************************************** doUpdate

void  doUpdate(EventRecord *eventStrucPtr)
{
  WindowRef windowRef;
  DialogRef dialogRef;
  SInt16    itemHit;

  if(!(IsDialogEvent(eventStrucPtr)))
  {
    windowRef = (WindowRef) eventStrucPtr->message;
    doUpdateDocument(windowRef);
  }
  else
    DialogSelect(eventStrucPtr,&dialogRef,&itemHit);
}

// ************************************************************************** doUpdateDocument

void  doUpdateDocument(WindowRef windowRef)
{
  GrafPtr      oldPort;
  PixPatHandle pixpatHdl;
  Rect         portRect;

  BeginUpdate(windowRef);

  GetPort(&oldPort);
  SetPortWindowPort(windowRef);

  pixpatHdl = GetPixPat(rPixelPattern);
  GetWindowPortBounds(windowRef,&portRect);
  FillCRect(&portRect,pixpatHdl);
  DisposePixPat(pixpatHdl);
  doDrawMessage(windowRef,windowRef == FrontWindow());

  SetPort(oldPort);

  EndUpdate(windowRef);
}

// ******************************************************************************** doActivate

void  doActivate(EventRecord *eventStrucPtr)
{
  Boolean   becomingActive;
  WindowRef windowRef;

  becomingActive = (eventStrucPtr->modifiers & activeFlag) == activeFlag;

  if(!(IsDialogEvent(eventStrucPtr)))
  {
    windowRef = (WindowRef) eventStrucPtr->message;
    doActivateDocument(windowRef,becomingActive);
  }
  else
    doActivateDialogs(eventStrucPtr,becomingActive);
}

// ************************************************************************ doActivateDocument

void  doActivateDocument(WindowRef windowRef,Boolean becomingActive)
{
  if(becomingActive)
    doAdjustMenus();

  doDrawMessage(windowRef,becomingActive);
}

// ****************************************************************** doActivateModelessDialog

void  doActivateDialogs(EventRecord *eventStrucPtr,Boolean becomingActive)
{
  DialogRef dialogRef;
  SInt16    windowRefCon;
  SInt16    itemHit;  

  DialogSelect(eventStrucPtr,&dialogRef,&itemHit);

  windowRefCon = GetWRefCon(GetDialogWindow(dialogRef));

  if(becomingActive)
  {
    doAdjustMenus();
    if(windowRefCon == kSearchModeless || windowRefCon == kSheetDialog)
      gSleepTime = GetCaretTime();
  }
  else
  {
    if(windowRefCon == kSearchModeless || windowRefCon == kSheetDialog)
      gSleepTime = MAX_UINT32;
  }
}

// ********************************************************************************* doOSEvent

void  doOSEvent(EventRecord *eventStrucPtr)
{
  switch((eventStrucPtr->message >> 24) & 0x000000FF)
  {
    case suspendResumeMessage:
      if((eventStrucPtr->message & resumeFlag) == 1)
        SetThemeCursor(kThemeArrowCursor);
      break;
  }
}

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

void  doAdjustMenus(void)
{
  WindowRef windowRef;
  MenuRef   menuRef;
  SInt32    windowRefCon;

  windowRef = FrontWindow();

  if(GetWindowKind(windowRef) == kApplicationWindowKind)
  {
    menuRef = GetMenuRef(mFile);
    DisableMenuItem(menuRef,iClose);
    menuRef = GetMenuRef(mEdit);
    DisableMenuItem(menuRef,0);
    menuRef = GetMenuRef(mDemonstration);
    EnableMenuItem(menuRef,iModeless);
    if(gRunningOnX)
    {
      if(IsWindowCollapsed(gWindowRef))
      {
        DisableMenuItem(menuRef,iWindowModalDialog);
        DisableMenuItem(menuRef,iWindowModalAlert);
      }
      else
      {
        EnableMenuItem(menuRef,iWindowModalDialog);
        EnableMenuItem(menuRef,iWindowModalAlert);
      }
    }
  }
  else if(GetWindowKind(windowRef) == kDialogWindowKind)
  {
    windowRefCon = GetWRefCon(windowRef);
    if(windowRefCon == kSearchModeless)
    {
      menuRef = GetMenuRef(mFile);
      EnableMenuItem(menuRef,iClose);
      menuRef = GetMenuRef(mEdit);
      EnableMenuItem(menuRef,0);    
      menuRef = GetMenuRef(mDemonstration);
      DisableMenuItem(menuRef,iModeless);
    }
    else if(windowRefCon == kSheetDialog)
    {
      menuRef = GetMenuRef(mFile);
      DisableMenuItem(menuRef,iClose);
      menuRef = GetMenuRef(mEdit);
      EnableMenuItem(menuRef,0);    
      menuRef = GetMenuRef(mDemonstration);
      EnableMenuItem(menuRef,iModeless);
      DisableMenuItem(menuRef,iWindowModalAlert);
    }
    else
    {
      menuRef = GetMenuRef(mFile);
      DisableMenuItem(menuRef,iClose);
      menuRef = GetMenuRef(mEdit);
      DisableMenuItem(menuRef,0);    
      menuRef = GetMenuRef(mDemonstration);
      EnableMenuItem(menuRef,iModeless);
    }
  }

  DrawMenuBar();
}

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

void  doMenuChoice(SInt32 menuChoice)
{
  MenuID        menuID;
  MenuItemIndex menuItem;
  SInt16        windowRefCon;

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

  if(menuID == 0)
    return;

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

    case mFile:
      if(menuItem == iQuit)
        gDone = true;
      else if(menuItem == iClose)
      {
        if(GetWindowKind(FrontWindow()) == kDialogWindowKind)
        {
          windowRefCon = GetWRefCon(FrontWindow());
          if(windowRefCon == kSearchModeless)
            doHideModelessDialog(GetDialogWindow(gModelessDialogRef));
        }
      }
      break;

    case mEdit:
      doEditMenu(menuItem);
      break;

    case mDemonstration:
      doDemonstrationMenu(menuItem);
      break;
  }

  HiliteMenu(0);
}

// ******************************************************************************** doEditMenu

void  doEditMenu(MenuItemIndex menuItem)
{
  WindowRef windowRef;
  SInt16    windowRefCon;
  DialogRef dialogRef;

  windowRef = FrontWindow();

  if(GetWindowKind(FrontWindow()) == kDialogWindowKind)
  {
    windowRefCon = GetWRefCon(windowRef);
    if(windowRefCon == kSearchModeless || windowRefCon == kSheetDialog)
    {
      dialogRef = GetDialogFromWindow(windowRef);

      switch(menuItem)
      {
        case iCut:
          DialogCut(dialogRef);
          break;

        case iCopy:
          DialogCopy(dialogRef);
          break;

        case iPaste:
          DialogPaste(dialogRef);
          break;

        case iClear:
          DialogDelete(dialogRef);
          break;
      }
    }
  }
}

// *********************************************************************** doDemonstrationMenu

void  doDemonstrationMenu(MenuItemIndex menuItem)
{
  switch(menuItem)
  {
    case iModalAlert:
      if(!doModalAlerts(false))
      {
        SysBeep(10);
        ExitToShell();
      }
      break;

    case iMovableAlert:
      if(gRunningOnX)
      {
        if(!doMovableModalAlertOnX())
        {
          SysBeep(10);
          ExitToShell();
        }
      }
      else if(!doModalAlerts(true))
      {
        SysBeep(10);
        ExitToShell();
      }
      break;

    case iModalDialog:
      if(!doModalDialog())
      {
        SysBeep(10);
        ExitToShell();
      }
      break;

    case iMovableModalDialog:
      if(!doMovableModalDialog())
      {
        SysBeep(10);
        ExitToShell();
      }
      break;

    case iModeless:
      if(!doCreateOrShowModelessDialog())
      {
        SysBeep(10);
        ExitToShell();
      }
      break;

    case iWindowModalAlert:
      if(!doSheetAlert())
      {
        SysBeep(10);
        ExitToShell();
      }
      break;

    case iWindowModalDialog:
      if(!doSheetDialog())
      {
        SysBeep(10);
        ExitToShell();
      }
      break;
  }
}

// ************************************************************ doExplicitlyDeactivateDocument

void  doExplicitlyDeactivateDocument(void)
{
  if(FrontWindow() && (GetWindowKind(FrontWindow()) != kDialogWindowKind))
    doActivateDocument(FrontWindow(),false);
}

// ***************************************************************************** doModalAlerts

Boolean  doModalAlerts(Boolean movable)
{
  AlertStdAlertParamRec paramRec;
  Str255                messageText, informativeText;
  Str255                otherText = "\pOther";
  OSErr                 osError;
  DialogItemIndex       itemHit;

  doExplicitlyDeactivateDocument();

  paramRec.movable       = movable;
  paramRec.helpButton    = true;
  paramRec.filterProc    = gEventFilterUPP;
  paramRec.defaultText   = (StringPtr) kAlertDefaultOKText;
  paramRec.cancelText    = (StringPtr) kAlertDefaultCancelText;
  paramRec.otherText     = (StringPtr) &otherText;
  paramRec.defaultButton = kAlertStdAlertOKButton;
  paramRec.cancelButton  = kAlertStdAlertCancelButton;
  paramRec.position      = kWindowDefaultPosition;

  if(!movable)
    GetIndString(messageText,rAlertStrings,sModalMessage);
  else
    GetIndString(messageText,rAlertStrings,sMovableMessage);
  GetIndString(informativeText,rAlertStrings,sModalInformative);

  osError = StandardAlert(kAlertStopAlert,messageText,informativeText,¶mRec,&itemHit);
  if(osError == noErr)
  {
    if(itemHit == kAlertStdAlertOKButton)
      doCopyPString("\pOK Button hit",gCurrentString);
    else if (itemHit == kAlertStdAlertCancelButton)
      doCopyPString("\pCancel Button hit",gCurrentString);
    else if (itemHit == kAlertStdAlertOtherButton)
      doCopyPString("\pOther Button hit",gCurrentString);
    else if (itemHit == kAlertStdAlertHelpButton)
      doCopyPString("\pHelp Button hit",gCurrentString);
  }

  return (osError == noErr);
}

// ******************************************************************** doMovableModalAlertOnX

Boolean  doMovableModalAlertOnX(void)
{
  AlertStdCFStringAlertParamRec paramRec;
  Str255                        messageText, informativeText;
  CFStringRef                   messageTextCF, informativeTextCF;
  OSErr                         osError;
  DialogRef                     dialogRef;
  DialogItemIndex               itemHit;

  doExplicitlyDeactivateDocument();

  GetStandardAlertDefaultParams(¶mRec,kStdCFStringAlertVersionOne);
  paramRec.movable      = true;
  paramRec.helpButton   = true;
  paramRec.cancelButton = kAlertStdAlertCancelButton;
  paramRec.cancelText   = CFSTR("Cancel");
  paramRec.otherText    = CFSTR("Other");

  GetIndString(messageText,rAlertStrings,sMovableMessage);
  GetIndString(informativeText,rAlertStrings,sMovableInformative);
  messageTextCF = CFStringCreateWithPascalString(NULL,messageText,
                                                 CFStringGetSystemEncoding());
  informativeTextCF = CFStringCreateWithPascalString(NULL,informativeText,
                                                     CFStringGetSystemEncoding());

  osError = CreateStandardAlert(kAlertCautionAlert,messageTextCF,informativeTextCF,¶mRec,
                                &dialogRef);
  if(osError == noErr)
  {
    osError = RunStandardAlert(dialogRef,NULL,&itemHit);
    if(osError == noErr)
    {
      if(itemHit == kAlertStdAlertOKButton)
        doCopyPString("\pOK Button hit",gCurrentString);
      else if (itemHit == kAlertStdAlertCancelButton)
        doCopyPString("\pCancel Button hit",gCurrentString);
      else if (itemHit == kAlertStdAlertOtherButton)
        doCopyPString("\pOther Button hit",gCurrentString);
      else if (itemHit == kAlertStdAlertHelpButton)
        doCopyPString("\pHelp Button hit",gCurrentString);
    }
  }

  if(messageTextCF != NULL)
    CFRelease(messageTextCF);
  if(informativeTextCF != NULL)
    CFRelease(informativeTextCF);

  return (osError == noErr);
}

// ***************************************************************************** doModalDialog

Boolean  doModalDialog(void)
{
  DialogRef  dialogRef;
  ControlRef controlRef;
  OSStatus   osError;
  MenuRef    menuRef;
  SInt16     numberOfItems, itemHit, controlValue;

  doExplicitlyDeactivateDocument();

  if(!(dialogRef = GetNewDialog(rModalDialog,NULL,(WindowRef) -1)))
    return false;
 
  SetDialogDefaultItem(dialogRef,kStdOkItemIndex);
  SetDialogCancelItem(dialogRef,kStdCancelItemIndex);

  GetDialogItemAsControl(dialogRef,iGridSnap,&controlRef);
  SetControlValue(controlRef,gGridSnap);
  GetDialogItemAsControl(dialogRef,iShowGrid,&controlRef);
  SetControlValue(controlRef,gShowGrid);
  GetDialogItemAsControl(dialogRef,iShowRulers,&controlRef);
  SetControlValue(controlRef,gShowRule);

  menuRef = NewMenu(mFont,NULL);

  if((osError = CreateStandardFontMenu(menuRef,0,0,0,NULL)) == noErr)
  {
    GetDialogItemAsControl(dialogRef,iFont,&controlRef);
    SetControlMinimum(controlRef,1);
    numberOfItems = CountMenuItems(menuRef);
    SetControlMaximum(controlRef,numberOfItems);
    SetControlData(controlRef,kControlEntireControl,kControlPopupButtonMenuRefTag,
                   sizeof(menuRef),&menuRef);
  }
  else
    return false;

  if(gRunningOnX)
    helpTagsModal(dialogRef);

  ShowWindow(GetDialogWindow(dialogRef));

  do
  {
    ModalDialog(gEventFilterUPP,&itemHit);
    
    if(itemHit == iGridSnap || itemHit == iShowGrid || itemHit == iShowRulers)
    {
      GetDialogItemAsControl(dialogRef,itemHit,&controlRef);
      SetControlValue(controlRef,!GetControlValue(controlRef));
    }
    else if(itemHit == iFont || itemHit == iSound)
    {
      GetDialogItemAsControl(dialogRef,itemHit,&controlRef);
      controlValue = GetControlValue(controlRef);
      doPopupMenuChoice(controlRef,controlValue);
    }
  } while((itemHit != kStdOkItemIndex) && (itemHit != kStdCancelItemIndex));

  if(itemHit == kStdOkItemIndex)
  {
    GetDialogItemAsControl(dialogRef,iGridSnap,&controlRef);
    gGridSnap = GetControlValue(controlRef);
    GetDialogItemAsControl(dialogRef,iShowGrid,&controlRef);
    gShowGrid = GetControlValue(controlRef);
    GetDialogItemAsControl(dialogRef,iShowRulers,&controlRef);
    gShowRule = GetControlValue(controlRef);        
  }

  DisposeDialog(dialogRef);

  doCopyPString("\pBalloon (OS 8/9) and Help tag (OS X) help is available",gCurrentString);

  return true;
}

// ********************************************************************** doMovableModalDialog

Boolean  doMovableModalDialog(void)
{
  DialogRef  dialogRef;
  ControlRef controlRef;
  SInt16     oldBrushType, itemHit, a;

  doExplicitlyDeactivateDocument();

  if(!(dialogRef = GetNewDialog(rMovableModalDialog,NULL,(WindowRef) -1)))
    return false;

  SetDialogDefaultItem(dialogRef,kStdOkItemIndex);
  SetDialogCancelItem(dialogRef,kStdCancelItemIndex);
  SetDialogTracksCursor(dialogRef,true);

  GetDialogItemAsControl(dialogRef,gBrushType,&controlRef);
  SetControlValue(controlRef,kControlRadioButtonCheckedValue);
  
  GetDialogItemAsControl(dialogRef,iClockOne,&controlRef);
  SetKeyboardFocus(GetDialogWindow(dialogRef),controlRef,kControlClockPart);

  oldBrushType = gBrushType;

  if(gRunningOnX)
    helpTagsMovableModal(dialogRef);

  ShowWindow(GetDialogWindow(dialogRef));

  do
  {
    ModalDialog(gEventFilterUPP,&itemHit);

    if(itemHit >= iCharcoal && itemHit <= iChalk)
    {
      for(a=iCharcoal;a<=iChalk;a++)
      {
        GetDialogItemAsControl(dialogRef,a,&controlRef);
        SetControlValue(controlRef,kControlRadioButtonUncheckedValue);
      }

      GetDialogItemAsControl(dialogRef,itemHit,&controlRef);
      SetControlValue(controlRef,kControlRadioButtonCheckedValue);
      gBrushType = itemHit;
    }
  } while((itemHit != kStdOkItemIndex) && (itemHit != kStdCancelItemIndex));

  if(itemHit == kStdCancelItemIndex)
    gBrushType = oldBrushType;

  DisposeDialog(dialogRef);

  return true;
}

// ************************************************************** doCreateOrShowModelessDialog

Boolean  doCreateOrShowModelessDialog(void)
{
  ControlRef controlRef;
  Str255     stringData = "\pwicked googly";
  MenuRef    menuRef;

  if(gModelessDialogRef == NULL)
  {
    if(!(gModelessDialogRef = GetNewDialog(rModelessDialog,NULL,(WindowRef) -1)))
      return false;

    SetWRefCon(GetDialogWindow(gModelessDialogRef),(SInt32) kSearchModeless);
    
    SetDialogDefaultItem(gModelessDialogRef,kStdOkItemIndex);

    GetDialogItemAsControl(gModelessDialogRef,iEditTextSearchModeless,&controlRef);
    SetDialogItemText((Handle) controlRef,stringData);
    SelectDialogItemText(gModelessDialogRef,iEditTextSearchModeless,0,32767);

    if(gRunningOnX)
      helpTagsModeless(gModelessDialogRef);

    ShowWindow(GetDialogWindow(gModelessDialogRef));
  }
  else
  {
    ShowWindow(GetDialogWindow(gModelessDialogRef));
    SelectWindow(GetDialogWindow(gModelessDialogRef));
  }

  if(gRunningOnX)
  {
    menuRef = GetMenuRef(mFile);
    EnableMenuItem(menuRef,0);
  }

  return true;
}

// ******************************************************************************* doInContent

void  doInContent(EventRecord *eventStrucPtr)
{
  WindowRef windowRef;
  SInt32    windowRefCon;
  DialogRef dialogRef;
  SInt16    itemHit;

  windowRef = FrontWindow();

  if(!(IsDialogEvent(eventStrucPtr)))
  {
    // Handle clicks in document window content region here.
  }
  else
  {
    windowRefCon = GetWRefCon(windowRef);
    if(windowRefCon == kSearchModeless)
    {
      if(DialogSelect(eventStrucPtr,&dialogRef,&itemHit))
        if(itemHit == kStdOkItemIndex)
          doButtonHitInSearchModeless();
    }
    else if(windowRefCon == kSheetDialog)
    {
      if(DialogSelect(eventStrucPtr,&dialogRef,&itemHit))
        if(itemHit == kStdOkItemIndex)
          doButtonHitInSheetDialog();
    }
  }
}

// *************************************************************** doButtonHitInSearchModeless

void  doButtonHitInSearchModeless(void)
{
  ControlRef controlRef;
  GrafPtr    oldPort;

  GetDialogItemAsControl(gModelessDialogRef,iEditTextSearchModeless,&controlRef);
  GetDialogItemText((Handle) controlRef,gCurrentString);

  GetPort(&oldPort);
  SetPortWindowPort(gWindowRef);
  doDrawMessage(gWindowRef,false);
  SetPort(oldPort);
}

// ********************************************************************** doHideModelessDialog

void  doHideModelessDialog(WindowRef windowRef)
{
  SInt16  windowRefCon;
  MenuRef menuRef;

  if(gRunningOnX)
    BringToFront(gWindowRef);

  HideWindow(windowRef);

  windowRefCon = GetWRefCon(windowRef);
  if(windowRefCon == kSearchModeless)
    gSleepTime = MAX_UINT32;

  if(gRunningOnX)
  {
    menuRef = GetMenuRef(mFile);
    DisableMenuItem(menuRef,0);
  }
}

// ******************************************************************************* eventFilter

Boolean  eventFilter(DialogRef dialogRef,EventRecord *eventStrucPtr,SInt16 *itemHit)
{
  Boolean handledEvent;
  GrafPtr oldPort;

  handledEvent = false;
  
  if((eventStrucPtr->what == updateEvt) && 
     ((WindowRef) eventStrucPtr->message != GetDialogWindow(dialogRef)))
  {
    if(!gRunningOnX)
      doUpdate(eventStrucPtr);
  }
  else if((eventStrucPtr->what == autoKey) && ((eventStrucPtr->modifiers & cmdKey) != 0))
  {
    handledEvent = true;
    return handledEvent;
  }
  else
  {
    GetPort(&oldPort);
    SetPortDialogPort(dialogRef);

    handledEvent = StdFilterProc(dialogRef,eventStrucPtr,itemHit);

    SetPort(oldPort);
  }

  return handledEvent;
}

// ************************************************************************* doPopupMenuChoice

void  doPopupMenuChoice(ControlRef controlRef,SInt16 controlValue)
{
  MenuRef menuRef;
  Size    actualSize;
  Str255  itemName;
  GrafPtr oldPort;

  GetControlData(controlRef,kControlEntireControl,kControlPopupButtonMenuHandleTag,
                 sizeof(menuRef),&menuRef,&actualSize);
  GetMenuItemText(menuRef,controlValue,itemName);    
  doCopyPString(itemName,gCurrentString);

  GetPort(&oldPort);
  SetPortWindowPort(gWindowRef);
  doDrawMessage(gWindowRef,false);
  SetPort(oldPort);
}

// ***************************************************************************** doDrawMessage

void  doDrawMessage(WindowRef windowRef,Boolean inState)
{
  Rect        portRect, headerRect;
  CFStringRef stringRef;
  Rect        textBoxRect;

  if(windowRef == gWindowRef)
  {
    SetPortWindowPort(windowRef);
    GetWindowPortBounds(windowRef,&portRect);
    SetRect(&headerRect,portRect.left - 1,portRect.bottom - 26,portRect.right + 1,
            portRect.bottom + 1);
    DrawThemePlacard(&headerRect,inState);

    if(inState == kThemeStateActive)
      TextMode(srcOr);
    else
      TextMode(grayishTextOr);

    stringRef = CFStringCreateWithPascalString(NULL,gCurrentString,
                                               CFStringGetSystemEncoding());
    SetRect(&textBoxRect,portRect.left,portRect.bottom - 19,portRect.right,
              portRect.bottom - 4);
    DrawThemeTextBox(stringRef,kThemeSmallSystemFont,0,true,&textBoxRect,teJustCenter,NULL);
    if(stringRef != NULL)    
      CFRelease(stringRef);

    TextMode(srcOr);
  }
}

// ***************************************************************************** doCopyPString

void  doCopyPString(Str255 sourceString,Str255 destinationString)
{
  SInt16 stringLength;

  stringLength = sourceString[0];
  BlockMove(sourceString + 1,destinationString + 1,stringLength);
  destinationString[0] = stringLength;
}

// *******************************************************************************************
// Sheets.c
// *******************************************************************************************

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

#include "DialogsAndAlerts.h"

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

WindowRef gSheetDialogWindowRef = NULL;

extern WindowRef gWindowRef;
extern Boolean   gRunningOnX;
extern Str255    gCurrentString;

// ****************************************************************************** doSheetAlert

Boolean  doSheetAlert(void)
{
  AlertStdCFStringAlertParamRec paramRec;
  Str255                        messageText, informativeText;
  CFStringRef                   messageTextCF, informativeTextCF;
  OSStatus                      osError;
  DialogRef                     dialogRef;
  MenuRef                       menuRef;

  GetStandardAlertDefaultParams(¶mRec,kStdCFStringAlertVersionOne);

  GetIndString(messageText,rSheetStrings,sAlertSheetMessage);
  GetIndString(informativeText,rSheetStrings,sAlertSheetInformative);
  messageTextCF = CFStringCreateWithPascalString(NULL,messageText,
                                                 CFStringGetSystemEncoding());
  informativeTextCF = CFStringCreateWithPascalString(NULL,informativeText,
                                                     CFStringGetSystemEncoding());

  osError = CreateStandardSheet(kAlertCautionAlert,messageTextCF,informativeTextCF,¶mRec,
                                GetWindowEventTarget(gWindowRef),&dialogRef);
  if(osError == noErr)
    osError = ShowSheetWindow(GetDialogWindow(dialogRef),gWindowRef);

  CFRelease(messageTextCF);
  CFRelease(informativeTextCF);

  menuRef = GetMenuRef(mDemonstration);
  if(menuRef != NULL)
  {
    DisableMenuItem(menuRef,iWindowModalDialog);
    DisableMenuItem(menuRef,iWindowModalAlert);
  }

  return (osError == noErr);
}

// ***************************************************************************** doSheetDialog

Boolean  doSheetDialog(void)
{
  DialogRef  dialogRef;
  ControlRef controlRef;
  Str255     stringData = "\pBradman";
  OSStatus   osError = noErr;
  MenuRef    menuRef;
 
  if(!(dialogRef = GetNewDialog(rSheetDialog,NULL,(WindowRef) -1)))
    return false;

  SetWRefCon(GetDialogWindow(dialogRef),(SInt32) kSheetDialog);
    
  SetDialogDefaultItem(dialogRef,kStdOkItemIndex);

  GetDialogItemAsControl(dialogRef,iEditTextSheetDialog,&controlRef);
  SetDialogItemText((Handle) controlRef,stringData);
  SelectDialogItemText(dialogRef,iEditTextSheetDialog,0,32767);

  gSheetDialogWindowRef = GetDialogWindow(dialogRef);
  osError = ShowSheetWindow(gSheetDialogWindowRef,gWindowRef);

  menuRef = GetMenuRef(mDemonstration);
  if(menuRef != NULL)
    DisableMenuItem(menuRef,iWindowModalDialog);

  return (osError == noErr);
}

// ****************************************************************** doButtonHitInSheetDialog

void  doButtonHitInSheetDialog(void)
{
  DialogRef  dialogRef;
  ControlRef controlRef;
  GrafPtr    oldPort;

  dialogRef = GetDialogFromWindow(gSheetDialogWindowRef);

  GetDialogItemAsControl(dialogRef,iEditTextSheetDialog,&controlRef);
  GetDialogItemText((Handle) controlRef,gCurrentString);

  HideSheetWindow(gSheetDialogWindowRef);
  DisposeDialog(dialogRef);
  gSheetDialogWindowRef = NULL;

  GetPort(&oldPort);
  SetPortWindowPort(gWindowRef);
  doDrawMessage(gWindowRef,true);
  SetPort(oldPort);
}

// *******************************************************************************************
// HelpTags.c
// *******************************************************************************************

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

#include "DialogsAndAlerts.h"
#include <string.h>

// ***************************************************************************** helpTagsModal

void  helpTagsModal(DialogRef dialogRef)
{
  HMHelpContentRec helpContent;
  SInt16           a;
  static SInt16    itemNumber[7] = { 1,2,3,7,8,10,11 };
  ControlRef       controlRef;

  memset(&helpContent,0,sizeof(helpContent));

  HMSetTagDelay(500);
  HMSetHelpTagsDisplayed(true);

  helpContent.version = kMacHelpVersion;
  helpContent.tagSide = kHMOutsideTopCenterAligned;
  helpContent.content[kHMMinimumContentIndex].contentType = kHMStringResContent;
  helpContent.content[kHMMinimumContentIndex].u.tagStringRes.hmmResID = 129;

  for(a = 1;a <= 7; a++)
  {
    helpContent.content[kHMMinimumContentIndex].u.tagStringRes.hmmIndex = a;
    GetDialogItemAsControl(dialogRef,itemNumber[a - 1],&controlRef);
    HMSetControlHelpContent(controlRef,&helpContent);
  }
}

// ********************************************************************** helpTagsMovableModal

void  helpTagsMovableModal(DialogRef dialogRef)
{
  HMHelpContentRec helpContent;
  SInt16           a;
  static SInt16    itemNumber[9] = { 1,2,3,4,6,11,12,13,14 };
  ControlRef       controlRef;

  memset(&helpContent,0,sizeof(helpContent));

  HMSetTagDelay(500);
  HMSetHelpTagsDisplayed(true);

  helpContent.version = kMacHelpVersion;
  helpContent.tagSide = kHMOutsideTopCenterAligned;
  helpContent.content[kHMMinimumContentIndex].contentType = kHMStringResContent;
  helpContent.content[kHMMinimumContentIndex].u.tagStringRes.hmmResID = 130;

  for(a = 1;a <= 9; a++)
  {
    helpContent.content[kHMMinimumContentIndex].u.tagStringRes.hmmIndex = a;
    GetDialogItemAsControl(dialogRef,itemNumber[a - 1],&controlRef);
    HMSetControlHelpContent(controlRef,&helpContent);
  }
}

// ************************************************************************** helpTagsModeless

void  helpTagsModeless(DialogRef dialogRef)
{
  HMHelpContentRec helpContent;
  SInt16           a;
  static SInt16    itemNumber[7] = { 1,2,3,4,5,6,7 };
  ControlRef       controlRef;

  memset(&helpContent,0,sizeof(helpContent));

  HMSetTagDelay(500);
  HMSetHelpTagsDisplayed(true);

  helpContent.version = kMacHelpVersion;
  helpContent.tagSide = kHMOutsideTopCenterAligned;
  helpContent.content[kHMMinimumContentIndex].contentType = kHMStringResContent;
  helpContent.content[kHMMinimumContentIndex].u.tagStringRes.hmmResID = 131;

  for(a = 1;a <= 7; a++)
  {
    helpContent.content[kHMMinimumContentIndex].u.tagStringRes.hmmIndex = a;
    GetDialogItemAsControl(dialogRef,itemNumber[a - 1],&controlRef);
    HMSetControlHelpContent(controlRef,&helpContent);
  }
}

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

Demonstration Program DialogsAndAlerts Comments

When this program is run, the user should:

o Invoke alerts and dialogs by choosing items in the Demonstration menu, noting window
  update/activation/deactivation and menu enabling/disabling effects.

o On Mac OS 8/9, choose Show Balloons from the Help menu and pass the cursor over the various
  items in the dialogs, noting the information in the help balloons.  Also note the updating of
  alerts and dialogs, and of the window, behind the help balloon when the balloon closes.

o On Mac OS X, pause the cursor over the various items in the dialogs, noting the information
  in the help tags.

o Note the effects on the menus when the various alerts and dialogs are the front window.

o Click anywhere outside the modal alert and modal dialog when they are the frontmost window,
  noting that the only response is the system alert sound.

o Note that, when the movable modal alert and movable modal dialog are displayed:

o The program can be sent to the background by clicking outside the alert or dialog and the
  document window, or by bringing another application to the foreground.

o The program can be brought to the foreground again by clicking inside the alert or dialog, or
  the document window.

o Note that, when the movable modal dialog and (on Mac OS X) the window-modal (sheet) dialog
  are displayed, the Edit menu and its Cut, Copy, and Paste items are enabled, given that the
  edit text items in these dialogs always have keyboard focus.

o Note that, when the modeless dialog is displayed:

  o It behaves like a normal document window when the user:

    o Clicks outside it when it is the frontmost window.

    o Clicks inside it when it is not the frontmost window.

  o It can be hidden by clicking in the close box/button or by selecting Close from the File
    menu.

  o A modal alert, movable modal alert, modal dialog or movable modal dialog can be invoked "on
    top of" the modeless dialog.

  o The Edit menu and its Cut, Copy, Paste, and Clear items are enabled so as to support text
    editing in the edit text item.

o Note that all alerts and dialogs respond correctly to Return and Enter key presses, and that
  the modal alert, modal dialog and movable modal dialog also respond correctly to escape key
  and Command-period presses.

o Note that, when an alert or dialog is the frontmost window, the window and content region are
  deactivated, the latter evidenced by dimming of the text in the document window's window
  header.

o In the modal dialog, click on the checkboxes to change their settings, noting that the new
  settings are remembered when the dialog is dismissed using the OK button, but not remembered
  when the dialog is dismissed using the Cancel button.  Also, choose items in the two pop-up
  menus, noting that the chosen item is displayed in the document window's window header.

o In the movable modal dialog, click on the radio buttons to change their settings, noting that
  the new setting is remembered when the dialog is dismissed using the OK button, but not
  remembered when the dialog is dismissed using the Cancel button.  In the case of the clock
  control and edit text item, change the item/part with keyboard focus using the Tab key or by
  clicking in that item/part.  In the case of the edit text item, enter text, and edit that 
  text using the Edit menu's Cut, Copy, Paste, and Clear items and their Command-key 
  equivalents.  Note that the cursor shape changes whenever the cursor is moved over the edit
  text item.

o In the modeless dialog and (on Mac OS X) the window-modal (sheet) dialog, enter text, and
  edit that text using the Edit menu's Cut, Copy, Paste, and Clear items and their Command-key
  equivalents.  Note that, because no cursor adjustment function is included in the program,
  the cursor shape does not change whenever the cursor is moved over the edit text item.  Also 
  note that, when the Search button is clicked (or the Return or Enter keys are pressed) the 
  text in the edit text item is displayed in the document window's window header.

o On Mac OS X, when a window-modal (sheet) alert or dialog is showing, minimise the window into
  the Dock and then expand the window from the dock. 

In the 'DITL' resources for the modal and movable modal dialogs, note that the item numbers of
the primary group box items are lower than the item numbers of the items visually contained by
those group box items.  This is to ensure that the group boxes do not draw over, and thus
erase, the image of these contained items.

In the 'dlgx' resources, note that all feature flags are set except for the
kDialogFlagsHandlesMovableModal flag in 'dlgx' resources for the modal dialog and modeless
dialog.  Thus dialogs have a root control and embedding hierarchy.

Although, for demonstration purposes, this program creates modal alerts and dialogs, it is
emphasised that Aqua Human Interface Guidelines require that, on Mac OS X, applications use
modal alerts and dialogs only in exceptional purposes.  On Mac OS X, the vast majority of
alerts and dialogs should be application-modal or window-modal.

On Mac OS X, explanatory Help tags are available for the modal, movable modal, and modeless
dialogs.  The associated source code (in the source code file HelpTags.c) is not explained in
these comments because the provision of Help tags is incidental to the demonstration.  For
information on creating help tags, see Chapter 25.  Note that it is also possible to display
help tags on Mac OS 8/9; however, it is considered by the author that their "look" is somewhat
at odds with the Platinum appearance, and that help balloons remain the most appropriate option
for Mac OS 8/9.

The CodeWarrior project for this program adds the CarbonFrameWorksLib stub library because
certain functions are used that are only available on Mac OS X.  (See "Carbon and Available
APIs" at Chapter 25.)  Those functions (CreateStandardAlert, RunStandardAlert,
GetStandardAlertDefaultParams, CreateStandardSheet, ShowSheetWindow, HideSheetWindow) are only
called when the program is run on Mac OS X.

DialogsAndAlerts.h

defines

Constants are established for dialog resource IDs and for the item numbers of certain items in
the item lists associated with the dialogs.  rAlertStrings and rSheetStrings represent the
resource IDs of 'STR#' resources holding strings for the message and informative text (label
and narrative text in Mac OS 8/9 parlance) for the modal alert, movable modal alert, and
window-modal (sheet) alert.

The values represented by kSearchModeless and kSheetDialog will be stored as the reference
constant in the window object in, respectively, the modeless dialog and window-modal (sheet)
dialog objects.  This enables the program to distinguish between these two dialogs.

The penultimate block establishes constants representing the character codes for the Return,
Enter, escape, and period keys.

Finally, MAX_UINT32 is defined as the maximum possible unsigned long value.  This value will be
assigned to WaitNextEvent's sleep parameter at program launch.

DialogsAndAlerts.c

Global Variables

gEventFilterUPP will be assigned a universal procedure pointer to an application-defined event
filter (callback) function.  gSleepTime will be assigned the value to be used as the sleep
parameter in the WaitNextEvent call.  (This value will be changed during program execution.)
 
The three variables after gDone will store the current control value of the checkboxes in the
modal dialog.  The next variable will store the item number of the currently selected radio
button in the movable modal dialog. 

Finally, the pointer to the dialog object for the modeless dialog is declared as a global
variable.

main

GetNewDialog is called to create a small modal dialog.  SetDialogTimeout is then called with 10
(seconds) passed in the inSecondsToWait parameter and 1 passed in the inButtonToPress
parameter.  (In the associated 'DITL' resource, Item 1 is the OK push button, which has been
hidden.)  The use of SetDialogTimeout requires that the application handle events for the
dialog through the ModalDialog function, hence the ModalDialog do-while loop.  This allows the
Dialog Manager to simulate an item selection.  After 10 seconds, the Dialog Manager simulates a
user click in the (invisible) OK button, causing the do-while loop to exit.  The dialog is then
disposed of.  (Note that pressing the Return key before the 10 seconds has elapsed will also
dispose of the dialog.)

The call to NewModalFilterUPP creates a universal procedure pointer for the event filter
(callback) function.

Note that error handling here and in other areas of this demonstration program is somewhat
rudimentary.  In the unlikely event that certain calls fail, ExitToShell is called to terminate
the program.

eventLoop

The variable that will be used as WaitNextEvent's sleep parameter (gSleepTime) is initially set
to the maximum unsigned long value.  Note that the value assigned to gSleepTime will be changed
at certain points in the program.

When a NULL event is returned by WaitNextEvent, if the program is running on Mac OS 8/9, doIdle
is called.

doIdle

doIdle is invoked, on Mac OS 8/9 only, whenever WaitNextEvent returns a null event.

If the front window is the modeless dialog, the function IdleControls is called.  IdleControls
calls the control definition function of those controls in the specified window which do
idle-time processing.  In this case, the control is an edit text control, and the call causes
the control definition function to call TextEdit to blink the insertion point caret.  (This
call is not necessary on Mac OS X because controls on Mac OS X have built-in timers.)

doEvents

doEvents switches according to the event type received.  (It is important to remember at this
point that events that occur when the modal dialog or movable modal dialog have been invoked
are not handled by the main event loop but by the ModalDialog function.)

Note that, at the autoKey case, the function doKeyDown is called only if the Command key is not
down.  This is to prevent the Command-key equivalents for cut, copy, and paste from repeating
when the user presses and holds down those Command-key equivalents while editing text in the
modeless dialog's edit text item.

In this program, autoKey events generated while the Command key is down are also discarded in
the event filter (callback) function eventFilter (see below).  This means that the behaviour of
the edit text item in the movable modal dialog will replicate that of the edit text item in the
modeless dialog.

(Many commercial and shareware programs (BBEdit excepted) do not discard autoKey events in
these circumstances.  The author considers that to be an oversight.)

doMouseDown

doMouseDown handles mouse-down events.  Mouse-downs in the content region and in the close
box/button are of significance to the demonstration.  If a mouse-down occurred in a close
box/button, if TrackGoAway returns true, and if the window is the modeless dialog,
doHideModelessDialog is called.  (In this demonstration, the modeless dialog, but not the
document window, has a close box/button.)

doKeyDown

doKeyDown handles all key-down and auto-key events.

First, the character code is extracted from the message field of the event structure.  Then
IsDialogEvent is called to determine whether the event occurred in the modeless dialog or
window-modal (sheet) dialog, or in the document window.

If the event occurred in a document window, and if the modifiers field of the event structure
indicates that the Command key was down, the function for adjusting the menus is called,
MenuEvent is called to return the long value containing the menu and menu item associated with
the Command-key equivalent, and the long value is passed to doMenuChoice for further handling.

If, however, the event occurred in the modeless dialog dialog or window-modal (sheet) dialog:

o If the key pressed was the Return or Enter key, GetDialogItemAsControl is called to get a
  reference to the single push button control in the modeless dialog (item 1 in the item 
  list). The push button is then highlighted for eight ticks (this has an effect on Mac OS 8/9
  only), and then unhighlighted before a function is called to extract the text from the edit
  text item and display it in the document window's window header.  doKeyDown then returns 
  because it is not intended that the edit text item receive Return and Enter key presses.

o If the Command key was down:

  o If either the X, C, or V key was pressed (that is, the user has pressed the Cut, Copy, or
    Paste Command-key equivalent), DialogSelect is called to further handle the event. 
    DialogSelect uses TextEdit to cut, copy, or paste the text in the edit text item.  (The
    calls to HiliteMenu briefly highlight the Edit menu to indicated to the user that an Edit 
    menu Command-key equivalent has just been used.  This replicates the highlighting that
    ModalDialog performs when Command-key presses occur in modal and movable modal dialogs with
    edit text items.)

  o If neither the X, C, nor V key was pressed, the function for adjusting the menus is called,
    MenuEvent is called to return the long value containing the menu and menu item associated 
    with the Command-key equivalent, and the long value is passed to doMenuChoice for further
    handling.

  o doKeyDown returns so as to bypass the second call to DialogSelect.

  Thus the Command-key equivalents other than those for Cut, Copy, and Paste remain available
  to the user via the main event loop, while the Command-key equivalents for Cut, Copy, and 
  Paste are trapped and passed to DialogSelect for handling.

o If the Return key and the Enter key were not pressed, and if the Command key was not down,
  DialogSelect is called to handle the keystroke in conjunction with TextEdit, the visual 
  result being that the character appears in the edit text item.

doUpdate

doUpdate performs the initial handling of update events.

If the call to IsDialogEvent reveals that the event is for a window of the document kind, a
function for updating the document window is called.

If the event is for the modeless dialog or window-modal (sheet) dialog, DialogSelect is called
to handle the event.  DialogSelect calls BeginUpdate, DrawDialog, and EndUpdate to redraw the
dialog's content area.  To restrict the redraw to the update region, an alternative is to call
BeginUpdate, UpdateDialog, and EndUpdate.  (Recall here that update regions BeginUpdate and
EndUpdate are irrelevant on Mac OS X.)

Note that, on Mac OS X, the call to DialogSelect is really only necessary in the case of the
window-modal (sheet) dialog.

doUpdateDocument

doUpdateDocument simply fills the content region of the document window with a colour, using a
pixel patter ('ppat') resource and a call to FillCRect for that purpose, and then calls a
function which draws a window header frame and the current contents of gCurrentString.

doActivate

doActivate performs initial handling of activate events.  If the call to IsDialogEvent reveals
that the event is for a window of the document kind, the function for activating/deactivating
the document window is called, otherwise the function for activating/deactivating the modeless
dialog is called.

doActivateDocument

doActivateDocument performs window activation/deactivation for the document window.  If the
window is becoming active, the menus are adjusted as appropriate for a document window.  The
call doDrawMessage draws a window header frame in the window, and the current contents of
gMessageString, in either the activated or deactivated mode.

doActivateDialogs

doActivateDialogs performs window activation and deactivation for the modeless dialog and
window-modal (sheet) dialog.

DialogSelect is called to handle the event.  If the modeless or window-modal (sheet) dialog is
becoming active, DialogSelect activates all controls and, on Mac OS 8/9, redraws the
one-pixel-wide modeless dialog frame in the active mode.  If the modeless dialog is going to
the back, DialogSelect deactivates all controls and, on Mac OS 8/9, redraws the one-pixel-wide
modeless dialog frame in the inactive mode.

In the remaining code, if either the modeless dialog or window-modal (sheet) dialog is becoming
active, the menus are adjusted and the global variable used in the sleep parameter of the
WaitNextEvent function is assigned the value returned by GetCaretTime (the cursor-blinking
interval set by the user in the General Controls control panel (Mac OS 8/9) and System
preferences (Mac OS X)).  This is necessary to ensure that null events will always be
generated, and thus doIdle and IdleControls will be called (necessary on Mac OS 8/9 only), at
an interval short enough to ensure insertion point caret blinking at the proper rate.

If if either the modeless dialog or window-modal (sheet) dialog is being deactivated, the sleep
parameter for the WaitNextEvent function is reset to the maximum unsigned long value.

(Recall that changing the value in gSleepTime is irrelevant on Mac OS X because the function
doIdle will not be called when the program is running on Mac OS X.)

doAdjustMenus

Note that, if the program is running on Mac OS X, and a call to IsWindowCollapsed reveals that
the document window has been minimised to the dock, the menu items which invoke the
window-modal (sheet) alert and (sheet) dialog are disabled.

doMenuChoice

doMenuChoice handles menu choices.  If the choice was the Close item in the File menu, and if
the front window is the modeless dialog, a function which hides that modeless dialog is called. 
(In this program, because the document window does not have a close box/button, the Close item
is only enabled when the modeless dialog is the front window.)

doEditMenu

doEditMenu first determines whether the front window is the modeless dialog or window-modal
(sheet) dialog (both of which have an edit text item).  If so, a reference to the dialog is
obtained, following which Dialog Manager functions are called to cut, copy, paste, or clear
text as appropriate.  The Dialog Manager, in conjunction with TextEdit, performs these
operations.

doDemonstrationMenu

doDemonstrationMenu handles choices from the Demonstration menu, switching according to the
menu item passed to it.  Error handling in this function is somewhat rudimentary in that the
program simply terminates.

Note that, when the Modal Alert item is chosen, doModalAlerts is called with false is passed in
the function's parameter.  Note also that, when the Movable Modal Alert item is chosen,
doMovableModalAlertonX is called if the program is running on Mac OS X, otherwise doModalAlerts
is called with true passed in the function's parameter.  This latter reflects the fact that, on
Mac OS X, the movable modal alert will be created by a function that is not available on Mac OS
8/9.

doExplicitlyDeactivateDocument

doExplicitlyDeactivateDocument is called at the beginning of those functions which create modal
and movable modal alerts and dialogs.

If there is at least one window of any type open, and if that front window is of the document
kind, the function for activating/deactivating document windows is called to deactivate the
window.

doModalAlerts

doModalAlerts creates, displays, manages, and disposes of the modal alert and, on Mac OS 8/9,
the movable modal alert.

The call to doExplicitlyDeactivateDocument deactivates the document window.

At the next nine lines, values are assigned to the fields of a standard alert parameter
structure.  In sequence: the alert is to be modal or movable modal depending on the value
received in the formal parameter movable; a help button is to be displayed; the event filter
(callback) function used is to be the application-defined event filter (callback) function
pointed to by the universal procedure pointer gEventFilterUPP; the default title for the OK
push button is to be used; a Cancel push button is required, and is to have the default title
for the Cancel button; an Other push button is required, and is to have the title "Other";  the
default push button is to be the first push button (which will thus have the default ring drawn
around it (Mac OS 8/9) or be pulsing blue (Mac OS X) and have the Return and Enter keys aliased
to it); the Cancel push button is to be the second push button (which will thus have escape and
Command-period key presses aliased to it); the alert is to be displayed in the alert position
on the parent window screen.  (With regard to the last field, the constant
kWindowDefaultPosition equates to kWindowAlertPositionParentWindowScreen.)

The calls to GetIndString retrieve the specified strings from the specified 'STR#' resource. 
These are passed in the inError and inExplanation parameters in the following call to
StandardAlert.

The call to StandardAlert creates and displays the alert (specifying a Stop alert in the first
parameter), and handles all user interaction (by internally calling ModalDialog), including
dismissing the alert when either the OK, Cancel, or Other button is hit.  The item hit is
returned in StandardAlert's outItemHit parameter.

In a real application, the appropriate action would be taken, based on which push button was
hit, following the call to StandardAlert; however, in this demonstration, the identity of the
push button is simply drawn in the document window.

doMovableModalAlertOnX

doMovableModalAlertOnX creates, displays, manages, and disposes of the movable modal alert when
the program is run on Mac OS X.  (The functions used in doMovableModalAlertOnX to create,
display, and manage the alert are not available on Mac OS 8/9.)

The call to doExplicitlyDeactivateDocument deactivates the document window.

The call to GetStandardAlertDefaultParams initialises a standard CFString alert parameter
structure with default values.  (The defaults are: not movable; no Help button; no Cancel
button; no Other button; alert position on parent window screen.)  The next four lines modify
the defaults by specifying that the alert is to be movable modal, and is to have a Help,
Cancel, and Other, push button.

The two calls to GetIndString retrieve the specified strings from the specified 'STR#'
resource, which are then converted to CFStrings before being passed in the error and
explanation fields in the following call to CreateStandardAlert.  CreateStandardAlert creates
the alert.

The call to RunStandardAlert displays the alert and runs the alert using a ModalDialog loop. 
When a push button is clicked, its item number is returned in the outItemHit parameter

In a real application, the appropriate action would be taken, based on which push button was
hit, following the call to RunStandardAlert; however, in this demonstration, the identity of
the push button is simply drawn in the document window.

doModalDialog

doModalDialog creates, displays, manages, and disposes of the modal dialog.

The call to doExplicitlyDeactivateDocument deactivates the document window.

The call to GetNewDialog creates the modal dialog from the specified resource as the frontmost
window.

The call to SetDialogDefaultItem tells the Dialog Manager which is the default push button item
and aliases the Return and Enter keys to that item.  The call to SetDialogCancelItem tells the
Dialog Manager which is the Cancel push button item, and aliases the escape key and
Command-period key presses to that item.

The next block gets handles to the three checkbox controls and sets the value of those controls
to the current values contained in the global variables relating to each control.

The call to NewMenu creates a new empty menu for a font menu.  A reference to this menu is
passed in the call to CreateStandardFontMenu, which creates a non-hierarchical font menu
containing the names of all resident fonts.  GetDialogItemAsControl gets a reference to the
Font pop-up menu button control, facilitating the calls to SetControlMinimum,
SetControlMaximum, and SetControlData.  The latter sets the menu to be used by the pop-up menu
button control.

With the modal dialog fully prepared, it is made visible by the call to ShowWindow.

The do/while loop continues to execute until ModalDialog reports that either the OK or Cancel
button has been "hit".  Within the loop, ModalDialog retains control until one of the enabled
items has been hit.

If a checkbox is hit, GetDialogItemAsControl is called to get a reference to the control and
SetControlValue is called to flip that control's control value.  (If it is 0, it is flipped to
1, and vice versa.)  If one of the pop-up menu buttons is hit, GetDialogItemAsControl is called
to get a reference to the control and GetControlValue is called to get the menu item number of
the menu item chosen, following which an function is called to extract the menu item text and
display it in the window header.

Note that the first parameter in the ModalDialog call is a universal procedure pointer to the
application-defined event filter (callback) function.

When the do/while loop exits, and if the user hit the OK button, handles to each of the three
checkboxes are retrieved for the purposes of retrieving the control's value and assigning it to
the relevant global variable.  (If the user hit the Cancel button, the global variables retain
the values they contained before the dialog was created and displayed.)

The dialog is then disposed of.

doMovableModalDialog

doMovableModalDialog creates, displays, manages, and disposes of the movable modal dialog.

The call to doExplicitlyDeactivateDocument deactivates the document window.

The call to GetNewDialog creates the movable modal dialog from the specified resource as the
frontmost window.

The call to SetDialogDefaultItem tells the Dialog Manager which is the default push button item
and aliases the Return and Enter keys to that item.  The call to SetDialogCancelItem tells the
Dialog Manager which is the Cancel push button item and aliases the escape key and
Command-period key presses to that item.  The call to SetDialogTracksCursor tells the Dialog
Manager to track the cursor and change it to the I-Beam cursor shape whenever it is over an
edit text item.

The first call to GetDialogItemAsControl gets a reference to the radio button control
represented by the current value in the global variable gBrushType.  The value of that control
is then set to 1.  The second call to GetDialogItemAsControl gets a reference to the clock
control.  The call to SetKeyboardFocus sets the keyboard focus to that item.

Before the session of user interaction begins, the current value in the global variable
gBrushType, which stores the item number of the currently selected radio button, is copied to
the local variable oldBrushTupe.  (This may be required later.)

With the movable modal dialog fully prepared, it is made visible by the call to ShowWindow.

The do/while loop continues to execute until ModalDialog reports that either the OK or Cancel
button has been hit.  Within the loop, ModalDialog retains control until one of the enabled
items is hit.

If a radio button is hit, a for loop sets the control value of all radio button controls to 0. 
A call to GetDialogItemAsControl then gets a reference to the radio button control that was
hit.  A call to SetControlValue then sets that control's value to 1, and the item number of
this radio button is assigned to the global variable gBrushType.

Note that the first parameter in the ModalDialog call is a universal procedure pointer to the
application-defined event filter (callback) function.  Note also that all user interaction
relating to the clock control and edit text item is handled automatically by ModalDialog,
including the movement of keyboard focus between the items.

When the do/while loop exits, and if the user hit the Cancel button, the value stored in the
local variable oldBrushType is assigned to gBrushType, ensuring that any change to the
currently selected radio button within the do/while loop is ignored.  (In a real application, a
long date/time value from the clock control, and the text from the edit text item would
possibly be retrieved at this point if the user hit the OK push button.)

doCreateOrShowModelessDialog

In this program, the modeless dialog is only created once, that is, when the user first chooses
Modeless Dialog from the Demonstration menu.  Clicks in its close box/button, or choosing Close
from the File menu while the modeless dialog is the frontmost window, will cause the dialog to
be hidden, not disposed of.

Accordingly, the first line determines whether the modeless dialog is already open.  If it is
not: the call to GetNewDialog creates the modeless dialog; the call to SetWRefCon assigns the
reference constant kSearchModeless to the dialog object's window object so as to differentiate
this dialog from the window-modal (sheet) dialog; a call to SetDialogDefaultItem causes the
push button to be drawn with the default ring (Mac OS 8/9) or in pulsing blue (Mac OS X); a
call to SetDialogItemText assigns some initial text to the edit text item; a call to
SelectDialogItemText selects the text in the edit text item.  (Note that, if the edit text item
did not contain text, this latter call would simply display the insertion point caret, which
would be made to blink by the call to IdleControls within the function doIdle (Mac OS 8/9).)

If, on the other hand, the modeless dialog has already been opened, the call to ShowWindow
displays the dialog and the call to SelectWindow generates the necessary activate events.

doInContent

doInContent continues the content region mouse-down handling initiated by doMouseDown. 
doInContent is called by doMouseDown only if the mouse-down occurred in the frontmost (active)
window.

If the event occurred in the document window, the mouse-down event would be handled in the if
section of the if/else block.  (No action is required in this demonstration.)

If the event occurred in the modeless dialog or the window-modal (sheet) dialog (both of which
contain an edit text item), DialogSelect is called to handle the event.  DialogSelect tracks
enabled controls (only the push button is enabled), returning true if the mouse button is
released while the cursor is still inside the control, and highlights any selection made in the
edit text item.  If DialogSelect returns true, and if the item hit was the OK push button, a
function is called to perform the actions required in the event of a hit on that button.

doButtonHitInSearchModeless

doButtonHitInSearchModeless further processes, to completion, a hit on the OK (Search) button
in the modeless dialog.  It simply demonstrates retrieval of the text in an edit text item in a
dialog.

The call to GetDialogItemAsControl gets a reference to the edit text control, and the call to
GetDialogItemText copies the text in the edit text control to the global variable
gCurrentString.  The following lines cause that text to be drawn in the window header in the
document window.

doHideModelessDialog

doHideModelessDialog hides a modeless dialog.  The call to HideWindow makes the dialog
invisible.  The sleep parameter for the WaitNextEvent function is reset to the maximum possible
long value (relevant only on Mac OS 8/9), because insertion point caret blinking is not
required while the Search dialog is hidden.

eventFilter

eventFilter is the application-defined event filter (callback) function which, in conjunction
with ModalDialog, handles events in the modal alerts, movable modal alert on OS 8/9, modal
dialog and movable modal dialog.

If the program is running on Mac OS 8/9, if the event is an update event, and if that event is
not for the dialog or alert in question, the application's document window updating function is
called and false is returned.  This response to an update event in the application's own
document windows also allows ModalDialog to perform a minor switch when necessary so that
background applications can update their windows as well.  The call to the window updating
function is not necessary on Mac OS X.

If the event is an autoKey event and the Command key is down, the event is, in effect,
discarded.  This means that, if the user is working within the edit text item in the movable
modal dialog and presses and holds the Command key equivalents for Cut, Copy or Paste,
repeating cut, copy and paste actions will be defeated.  That is, pressing and holding the
Command key equivalent will only result in a single cut, copy, or paste action.  (See also
doEvents, above.)

If the event is neither an update event nor an autoKey event with the Command key down, the
current graphics port is saved and then set to that of the alert or dialog.  The event is then
passed to the standard event filter (callback) function for handling.  If the standard event
filter (callback) function handles the event, it will return true and, in the itemHit
parameter, the number of the item that it handled.  ModalDialog will then return this item
number.  A call to SetPort then restores the previously save graphics port.

Note that the calls to GetPort and SetPort are actually redundant when this event filter
(callback) function is used by all but the movable modal dialog.  The calls are only necessary
when SetDialogTracksCursor has been called to cause the Dialog Manager to automatically track
the cursor, and the movable modal dialog is the only dialog which requires this tracking
(because it contains an edit text item.)

doPopupMenuChoice, doPlaySound, doDrawMessage, and doCopyPString

doPopupMenuChoice, doPlaySound, doDrawMessage, and doCopyPString are incidental to the
demonstration.  All perform the same duties as the similarly-named functions in the
demonstration program Controls1 (Chapter 7).  doDrawMessage is used in this program to prove
the explicit deactivation of the document window's content area when alerts and dialogs other
than the modeless dialog are invoked.

Sheets.c

Global Variables

gSheetDialogWindowRe will be assigned the window reference of the window-modal (sheet) dialog.

doSheetAlert

doSheetAlert creates, displays and handles a window-modal (sheet) alert.

The call to GetStandardAlertDefaultParams initialises a standard CFString alert parameter
structure with default values.

The two calls to GetIndString retrieve the specified strings from the specified 'STR#'
resource, which are then converted to CFStrings before being passed in the error and
explanation fields in the following call to CreateStandardSheet, which creates the alert.  The
call to ShowSheetWindow displays the sheet.  When the user clicks the OK button, the sheet is
dismissed.

doSheetDialog

doSheetAlert creates and displays a window-modal (sheet) dialog.

The call to GetNewDialog creates the dialog from the specified resource.  The call to
SetWRefCon assigns a value as the dialog window's reference constant.  This is used elsewhere
to differentiate the window-modal (sheet) dialog from the modeless dialog.

The call to SetDialogDefaultItem causes the push button to be drawn with the default ring (Mac
OS 8/9) or in pulsing blue (Mac OS X).  The call to SetDialogItemText assigns some initial text
to the edit text item and the call to SelectDialogItemText selects that text.

The next line assigns a reference to the dialog's window to the global variable
gSheetDialogWindowRef.  This is used in the function doButtonHitInSheetDialog.

The call to ShowSheetWindow displays the sheet.

doButtonHitInSheetDialog

doButtonHitInSearchModeless is called from doKeyDown and doInContent to further process, to
completion, a hit on the OK button in the window-modal (sheet) dialog.  In addition to
retrieving the text in an edit text item, it hides and disposes of the dialog.
 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Latest Forum Discussions

See All

Challenge those pesky wyverns to a dance...
After recently having you do battle against your foes by wildly flailing Hello Kitty and friends at them, GungHo Online has whipped out another surprising collaboration for Puzzle & Dragons. It is now time to beat your opponents by cha-cha... | Read more »
Pack a magnifying glass and practice you...
Somehow it has already been a year since Torchlight: Infinite launched, and XD Games is celebrating by blending in what sounds like a truly fantastic new update. Fans of Cthulhu rejoice, as Whispering Mist brings some horror elements, and tests... | Read more »
Summon your guild and prepare for war in...
Netmarble is making some pretty big moves with their latest update for Seven Knights Idle Adventure, with a bunch of interesting additions. Two new heroes enter the battle, there are events and bosses abound, and perhaps most interesting, a huge... | Read more »
Make the passage of time your plaything...
While some of us are still waiting for a chance to get our hands on Ash Prime - yes, don’t remind me I could currently buy him this month I’m barely hanging on - Digital Extremes has announced its next anticipated Prime Form for Warframe. Starting... | Read more »
If you can find it and fit through the d...
The holy trinity of amazing company names have come together, to release their equally amazing and adorable mobile game, Hamster Inn. Published by HyperBeard Games, and co-developed by Mum Not Proud and Little Sasquatch Studios, it's time to... | Read more »
Amikin Survival opens for pre-orders on...
Join me on the wonderful trip down the inspiration rabbit hole; much as Palworld seemingly “borrowed” many aspects from the hit Pokemon franchise, it is time for the heavily armed animal survival to also spawn some illegitimate children as Helio... | Read more »
PUBG Mobile teams up with global phenome...
Since launching in 2019, SpyxFamily has exploded to damn near catastrophic popularity, so it was only a matter of time before a mobile game snapped up a collaboration. Enter PUBG Mobile. Until May 12th, players will be able to collect a host of... | Read more »
Embark into the frozen tundra of certain...
Chucklefish, developers of hit action-adventure sandbox game Starbound and owner of one of the cutest logos in gaming, has released their roguelike deck-builder Wildfrost. Created alongside developers Gaziter and Deadpan Games, Wildfrost will... | Read more »
MoreFun Studios has announced Season 4,...
Tension has escalated in the ever-volatile world of Arena Breakout, as your old pal Randall Fisher and bosses Fred and Perrero continue to lob insults and explosives at each other, bringing us to a new phase of warfare. Season 4, Into The Fog of... | Read more »
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 below... | Read more »

Price Scanner via MacPrices.net

Free iPhone 15 plus Unlimited service for $60...
Boost Infinite, part of MVNO Boost Mobile using AT&T and T-Mobile’s networks, is offering a free 128GB iPhone 15 for $60 per month including their Unlimited service plan (30GB of premium data).... Read more
$300 off any new iPhone with service at Red P...
Red Pocket Mobile has new Apple iPhones on sale for $300 off MSRP when you switch and open up a new line of service. Red Pocket Mobile is a nationwide MVNO using all the major wireless carrier... Read more
Clearance 13-inch M1 MacBook Airs available a...
Apple has clearance 13″ M1 MacBook Airs, Certified Refurbished, available for $759 for 8-Core CPU/7-Core GPU/256GB models and $929 for 8-Core CPU/8-Core GPU/512GB models. Apple’s one-year warranty is... Read more
Updated Apple MacBook Price Trackers
Our Apple award-winning MacBook Price Trackers are continually updated with the latest information on prices, bundles, and availability for 16″ and 14″ MacBook Pros along with 13″ and 15″ MacBook... Read more
Every model of Apple’s 13-inch M3 MacBook Air...
Best Buy has Apple 13″ MacBook Airs with M3 CPUs in stock and on sale today for $100 off MSRP. Prices start at $999. Their prices are the lowest currently available for new 13″ M3 MacBook Airs among... Read more
Sunday Sale: Apple iPad Magic Keyboards for 1...
Walmart has Apple Magic Keyboards for 12.9″ iPad Pros, in Black, on sale for $150 off MSRP on their online store. Sale price for online orders only, in-store price may vary. Order online and choose... Read more
Apple Watch Ultra 2 now available at Apple fo...
Apple has, for the first time, begun offering Certified Refurbished Apple Watch Ultra 2 models in their online store for $679, or $120 off MSRP. Each Watch includes Apple’s standard one-year warranty... Read more
AT&T has the iPhone 14 on sale for only $...
AT&T has the 128GB Apple iPhone 14 available for only $5.99 per month for new and existing customers when you activate unlimited service and use AT&T’s 36 month installment plan. The fine... Read more
Amazon is offering a $100 discount on every M...
Amazon is offering a $100 instant discount on each configuration of Apple’s new 13″ M3 MacBook Air, in Midnight, this weekend. These are the lowest prices currently available for new 13″ M3 MacBook... Read more
You can save $300-$480 on a 14-inch M3 Pro/Ma...
Apple has 14″ M3 Pro and M3 Max MacBook Pros in stock today and available, Certified Refurbished, starting at $1699 and ranging up to $480 off MSRP. Each model features a new outer case, shipping is... Read more

Jobs Board

Omnichannel Associate - *Apple* Blossom Mal...
Omnichannel Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Read more
Operations Associate - *Apple* Blossom Mall...
Operations Associate - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Read more
Cashier - *Apple* Blossom Mall - JCPenney (...
Cashier - Apple Blossom Mall Location:Winchester, VA, United States (https://jobs.jcp.com/jobs/location/191170/winchester-va-united-states) - Apple Blossom Mall Read more
IT Systems Engineer ( *Apple* Platforms) - S...
IT Systems Engineer ( Apple Platforms) at SpaceX Hawthorne, CA SpaceX was founded under the belief that a future where humanity is out exploring the stars is Read more
*Apple* Systems Administrator - JAMF - Activ...
…**Public Trust/Other Required:** None **Job Family:** Systems Administration **Skills:** Apple Platforms,Computer Servers,Jamf Pro **Experience:** 3 + years of Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.