TweetFollow Us on Twitter

High Level Events
Volume Number:7
Issue Number:11
Column Tag:Jörg's Folder

Related Info: Event Manager Apple Event Mgr Edition Manager

High Level Events

By Jörg Langowski, MacTutor Editorial Board

“High Level Events”

You’ve seen System 7 for quite a while now. Over a year if you’ve had access to ‘official’ developer information, and over half a year if you’ve had to wait for the official release. You’ve had time to familiarize yourself with the most prominent features of the new system: an improved user interface, aliases, file sharing, virtual memory, and some applications that won’t work anymore

To me, the most important new addition in the System 7 release is the possibility of inter-program communication through ‘AppleEvents’, or high-level events. This feature is not as directly visible as the others, and only few programs so far make use of it, none of them to anything near its full capacity (not that I know of). But it may well be that AppleEvents are to the Macintosh in 1991 what the Macintosh was to computing in 1984.

To explain this enthusiastic remark, let’s compare the old (up to System 6) and new (System 7 and later) programming paradigms on the Macintosh.

Event Loops - System 6 and 7

The classical System 6 event loop waits for an event like mouse down, key down, etc., and calls a handler routine corresponding to that event. This works well as long as the user interacts directly with one program on the Macintosh at a time. You can, however, easily think of situations that this type of event loop cannot easily handle. One very simple example is the Shutdown command in the Finder’s Special menu. This command, issued under Sys6/Multifinder, somehow had to tell all the open applications to quit - and in doing so, clean up their act, saving files etc. - before shutting down the machine.

As users of foreign system versions with US programs may very well remember, in the early times of Multifinder the shutdown command would often not work: E.g., in France the application didn’t have a ‘’File’, but a ‘Fichier’ menu, in which there was no such item as ‘Quit’, but ‘Quitter’. Now, since the Finder was looking for the item and menu number of ‘Quit’ in the ‘File’ menu to fake a menu selection in order to force the application to quit, that mechanism wouldn’t work if the Quit item and/or File menu couldn’t be found. There was a work around then, by adding a resource that could contain strings for the ‘File’ menu and item such as ‘Open’, ‘Print’, ‘Quit’ in all sorts of possible languages; but this solution was awkward since that resource would have to be changed every time you hit upon a program localized for a different language.

A much more elegant solution is to define a new type of event to which the application has to respond, no matter what the localization, thereby isolating the program’s action (quitting, opening a document) from the particular implementation of the user interface (language in which the menu is written). The Finder would send a ‘quit’ event to an application, and the application would understand it and quit. Opening documents would work pretty much the same way: if a user opens a document in the Finder, and the application is already open, an ‘open document’ event would be sent to it and the program would open the new document (if it understands the event).

Since the Finder is just a program as well, one might as well generalize this event-sending protocol and allow any program to send a message to any other program. For instance, imagine a word processor document in which a table is pasted that was part of a spreadsheet. When the user changes some data in the table, the word processor program could send messages to the spreadsheet program to recalculate the table. The two programs might be running on the same Macintosh, or even on two different Macs connected through a network. Thus, one Macintosh can request ‘services’ on another one without having all the programs reside on its own hard disk, and without loading the program into its own memory first. Even more interesting, a program can send events to itself! This way, you can imagine a complete disconnection between user-produced events (menu selections, key downs etc.) and their handlers. When, for instance, the user selects ‘Quit’ from the file menu, the event loop does not directly call a routine that terminates the program, but sends a high-level ‘quit’ event to itself. That event will be received on one of the next WaitNextEvent calls, and the action (in this case, exit the program) is taken by the high-level event handler.

This is the principal difference between the pre-System 7 and the new programming paradigm: it is now possible to write an event loop that does not take any action directly, but in response to user actions posts high-level events to itself, to which the handlers will respond. You see immediately the possibilities that this mechanism gives: not only can programs communicate with each other, but you might go as far as controlling a program on one computer through the network from a user interface residing on another machine.

The Structure of a High-level Event

Inside Macintosh Vol. VI (which by the way is thicker than the first three volumes of Inside Mac taken together) devotes almost four hundred of its one thousand-odd pages to things connected with high-level event handling and program-to-program communication. That’s one indication how seriously Apple takes this business. The Apple Event Manager chapter explains how a high-level event looks like, and I’ll give a quick overview.

A high-level event has an event class and an event ID. Both are 32 bit integers, or rather, four-character constants just like the creator and type signatures of a Macintosh file. Typical event classes are

/* 1 */

kCoreEventClass = ‘aevt’;
kAEFinderEvents = ‘FNDR’;
kSectionEventMsgClass = ‘sect’;

(The constant names are the ones defined in the MPW Pascal and C interfaces). The core event class, ‘aevt’, contains events that correspond to very basic actions that most programs should understand. In fact, a System 7-aware application has to support the four events whose IDs are given by the following constants:

/* 2 */

kAEOpenApplication = ‘oapp’;
kAEOpenDocuments = ‘odoc’;
kAEPrintDocuments = ‘pdoc’;
kAEQuitApplication = ‘quit’;

The ‘FNDR’ event class corresponds to events that the finder understands; so for instance you may send a ‘shut’ event to the Finder, and it will faithfully shut down your machine. ‘sect’ events are used by the Edition manager, another part of program-to-program communication which supports different applications working on the same document. We’ll come to that later.

Data Descriptors

An Apple event has an extremely interesting and versatile structure. The fundamental data structure from which the Apple event and all data contained in it are built up is the descriptor record:

{3}

TYPE AEDesc =
 RECORD
 descriptorType: DescType;
 dataHandle:Handle
 END;

The descriptor type is a 4 byte character constant describing the data type; for instance, ‘long’ designates a 32-bit integer. ‘aevt’ means that the data referenced by the handle is an Apple event record; the record itself is a list of descriptor records. Each descriptor record is preceded by a keyword that identifies what the data is good for (it took me a while to understand this - the descriptor type specifies the format of the data, and the keyword its purpose). Thus, a ‘quit’ event record might contain the following data:

‘evcl’  ‘type’   <handle to event class> -> ‘aevt’
‘evid’  ‘type’ <handle to event ID> -> ‘quit’
‘addr’  ‘sign’ <handle to application sig> -> ‘JLMT’

‘evcl’ means that the event class descriptor record follows; ‘evid’ signifies the event ID, and ‘addr’ the address of the target application receiving the event. You immediately understand why such a rather complicated data structure was chosen for Apple events when you look at the third item in the list. ‘addr’ can be followed by a descriptor identifying the signature of another application residing on the same Macintosh, in which case the descriptor type is ‘sign’ and the handle points to the four-byte application signature; but you could also have the ‘psn ‘ descriptor and the handle giving the process serial number of the target program (which is a number assigned by System 7 to each program that is launched on the Mac), or the ‘targ’ descriptor and a handle referencing a target ID record for accessing an application that runs on another computer on the network.

To the user, program-program communication looks completely transparent, and it makes almost no difference whether the Apple event is sent to the same program, another program on the same computer, or across the network; but the data structures describing the event can be very different in content and size. The ‘qualified descriptor’ type data structure that Apple chose for the Apple events can accommodate all necessary changes.

Apple events can be much more complicated, containing not only simple messages sent from one program to another (or to itself), but important amounts of data as well; for instance, clipboard contents when an application would install a dynamic cut/paste link with another one. You can define your own Apple events and send whatever data you like.

If you feel a little overwhelmed, remember that you don’t have to keep all these complicated data structures in you head; they are internal to the Apple event manager, and accessible through a large set of Apple event manager routines. You should not even access the data structures directly (I think that’s asking for trouble when Apple decides to change the internal format). We’ll see how to create and post Apple events in a later column. This month I’ll only give a simple example how to make a program understand the four required Apple events, ‘oapp’, ‘odoc’, ‘pdoc’, and ‘quit’.

The Example

To illustrate in a simple way how to implement ‘high-level event awareness’ into an existing application, I’ve taken our old C++ sample application (MacTutor V5#12 and V6#1) and added some code to it. Only the files MacTutorApp.cp and MacTutorApp.h are concerned, the rest stays unchanged. We have to make some changes to the main application class, essentially changing the main event loop, the program setup (i.e. the constructor of the application class), and add the high-level event handling routines.

For every different high-level event that you wish to handle, you must install a high-level event handler. The handler is a routine that takes no parameters, and a pointer to it is passed to the install procedure:

/* 4 */

err = AEInstallEventHandler (kCoreEventClass, 
 kAEOpenApplication, 
 (EventHandlerProcPtr) &AEDoOpen, 
 0L, false);

for instance, installs the ‘Open Application’ handler AEDoOpen(). The procedure itself is a global routine which calls the DoOpen() method of the application object gApplication. The same procedure is followed for installing the three other handlers (see listing). All installations are done in the constructor method of the application object.

The beauty of C++ is that we can override the main event loop of the TApplication class. For installing high-level event awareness in the application, we simply write a new event loop procedure in our class, which was derived from TApplication. The event loop still calls WaitNextEvent() to get a new event on every pass, and we only add one new selector in the case statement: when the event type is a high-level event (fEvent.what = 23), we call our high level event handler.

That handler is a very simple procedure (one more new method in our application class):

{5}

void TMacTutorApp::DoHighLevelEvent(void)
 { AEProcessAppleEvent(&fTheEvent);}

AEProcessAppleEvent is the Apple Event Manager routine that does all the necessary actions to process the high level event: determine the type of event, see whether a handler has been installed, and call it if it exists.

Of course there is the possibility of errors, such as an Apple Event not having the correct format, too much or too little data, etc. ; we don’t handle that here, but you may look forward to an example in one of the next columns.

When you run the example application, you’ll notice nothing very special, except that it beeps when the initial window is opened (under System 7!). This tells you that the ‘oapp’ event has arrived and the handler was called (notice that I built a call to SysBeep() in for that reason). If you have a utility that sends Apple Events (there are several on the System 7 CD-ROM), you can also try and send ‘oapp’, ‘odoc’, ‘pdoc’, or ‘quit’ to the program from that other utility. It’s interesting to see how you can open new windows remotely, or make the program shut down. I’m preparing a Forth example for Apple Event handling C++ people will also get their share.

Listing 1:

// Constants, resource definitions, etc.

#define kErrStrings 129

#define eNoMemory1
#define eNoWindow2

#define kMinSize 48 // min heap needed in K

#define rMenuBar 128 /* app’s menu bar */
#define rAboutAlert128  /* about alert */
#define rDocWindow 128  /* app’s window */

#define mApple   128 /* Apple menu */
#define iAbout   1

#define mFile    129 /* File menu */
#define iNew1
#define iClose   4
#define iQuit    12

#define mEdit    130 /* Edit menu */
#define iUndo    1
#define iCut3
#define iCopy    4
#define iPaste   5
#define iClear   6

#define myMenu   131 /* Sample menu */
#define item1    1
#define item2    2
#define item3    3
#define item5    5

class TMacTutorApp : public TApplication {
public:
 TMacTutorApp(void); // Our constructor
 void EventLoop(void);  
 // overridden for high level event support

 // handle the four required apple events
 void DoOpen(void);
 void DoNew(void);
 void DoPrint(void);
 void Terminate(void);
 void DoHighLevelEvent(void);
private:
 // TApplication routines we are overriding
 long HeapNeeded(void);
 unsigned long SleepVal(void);
 void AdjustMenus(void);
 void DoMenuCommand
 (short menuID, short menuItem); 
};
const short kMaxOpenDocuments = 4;


/*------------------------------------------
#MacTutorApp
#
#A rudimentary application skeleton
#J. Langowski / MacTutor 1989
#JL 9/91- Added high-level event support
#----------------------------------------*/
#include <Types.h>
#include <QuickDraw.h>
#include <Fonts.h>
#include <Events.h>
#include <OSEvents.h>
#include <Controls.h>
#include <Windows.h>
#include <Menus.h>
#include <TextEdit.h>
#include <Dialogs.h>
#include <Desk.h>
#include <Scrap.h>
#include <ToolUtils.h>
#include <Memory.h>
#include <SegLoad.h>
#include <Files.h>
#include <OSUtils.h>
#include <Traps.h>
#include <StdLib.h>

#include <AppleEvents.h> 
#include <GestaltEqu.h> 

#include “TDocument.h”
#include “TApplication.h”
#include “MacTutor7App.h”
#include “MacTutorDoc.h”
#include “MacTutorGrow.h”

const short kOSEvent = app4Evt;

// Our application object, initialized in main(). 
// We make it global so our functions which don’t 
// belong to any class can find the active 
// document.
TMacTutorApp *gTheApplication;

/* Handlers for the requires AppleEvent suite */

// Create a new document and window. 
void TMacTutorApp::DoNew(void)
{
 TMacTutorGrow* tMacTutorDoc;
 
 tMacTutorDoc = new TMacTutorGrow
 (rDocWindow,”\pNothing selected yet.”);
 // if no allocation error, add to list
 if (tMacTutorDoc != nil)
   fDocList->AddDoc(tMacTutorDoc);
}

// handle ‘oapp’ high level event
void TMacTutorApp::DoOpen(void) 
 { SysBeep(5); DoNew(); }

// We don’t print any documents
void TMacTutorApp::DoPrint(void) { SysBeep(5); }

void TMacTutorApp::Terminate(void) 
 { ExitLoop(); }

void TMacTutorApp::DoHighLevelEvent(void)
{
 AEProcessAppleEvent(&fTheEvent);
}

void AEDoOpen(void)
  { gTheApplication->DoOpen(); }
void AEDoNew(void) 
 { gTheApplication->DoNew(); }
void AEDoPrint(void) 
 { gTheApplication->DoPrint(); }
void AETerminate(void) 
 { gTheApplication->Terminate(); }

// initialize the application
TMacTutorApp::TMacTutorApp(void)
{
 Handle menuBar;

 // initialize Apple Event handlers
 OSErr  err;
 long result;
 Boolean gHasAppleEvents;
 
 gHasAppleEvents = (Gestalt
 (gestaltAppleEventsAttr, &result) 
 ? false : result != 0);
 if (gHasAppleEvents) {
 err = AEInstallEventHandler (kCoreEventClass, 
 kAEOpenApplication, 
 (EventHandlerProcPtr) &AEDoOpen, 
 0L, false);
 err = AEInstallEventHandler(kCoreEventClass,
 kAEOpenDocuments, 
 (EventHandlerProcPtr) &AEDoNew, 
 0L, false);
 err = AEInstallEventHandler(kCoreEventClass,
 kAEPrintDocuments, 
 (EventHandlerProcPtr) &AEDoPrint, 
 0L, false);
 err = AEInstallEventHandler(kCoreEventClass,
 kAEQuitApplication,
 (EventHandlerProcPtr) &AETerminate, 
 0L, false);
 }
 
 // read menus into menu bar
 menuBar = GetNewMBar(rMenuBar);
 // install menus
 SetMenuBar(menuBar);
 DisposHandle(menuBar);
 // add DA names to Apple menu
 AddResMenu(GetMHandle(mApple), ‘DRVR’);
 DrawMenuBar();

 // create empty mouse region
 fMouseRgn = NewRgn();
}

// Tell TApplication class how much heap we need
long TMacTutorApp::HeapNeeded(void)
 { return (kMinSize * 1024);}

// Calculate a sleep value for WaitNextEvent. 

unsigned long TMacTutorApp::SleepVal(void)
{
 unsigned long sleep;
 const long kSleepTime = 0x7fffffff; 
 // a very large positive number

 sleep = kSleepTime;  // default value for sleep
 if ((!fInBackground))
 { sleep = GetCaretTime();}
 return sleep;
}

void TMacTutorApp::AdjustMenus(void)
{
 WindowPtrfrontmost;
 MenuHandle menu;
 Boolean undo,cutCopyClear,paste;

 TMacTutorDocument* fMacTutorCurDoc = 
 (TMacTutorDocument*) fCurDoc;

 frontmost = FrontWindow();

 menu = GetMHandle(mFile);
 if(fDocList->NumDocs() < kMaxOpenDocuments)
 EnableItem(menu, iNew);  
 else   DisableItem(menu, iNew);
 if ( frontmost != (WindowPtr) nil ) 
 EnableItem(menu, iClose);
 else   DisableItem(menu, iClose);

 undo = false; cutCopyClear = false;
 paste = false;
 
 if ( fMacTutorCurDoc == nil )
   {  undo = true; cutCopyClear = true;
 paste = true; }
   
 menu = GetMHandle(mEdit);
 if ( undo )
 EnableItem(menu, iUndo);
 else
 DisableItem(menu, iUndo);
 
 if ( cutCopyClear )
   {
 EnableItem(menu, iCut);
 EnableItem(menu, iCopy);
 EnableItem(menu, iClear);
   } 
 else
   {
 DisableItem(menu, iCut);
 DisableItem(menu, iCopy);
 DisableItem(menu, iClear);
   }
   
 if ( paste )
 EnableItem(menu, iPaste);
 else
 DisableItem(menu, iPaste);
 
 menu = GetMHandle(myMenu);
 EnableItem(menu, item1);
 EnableItem(menu, item2);
 EnableItem(menu, item3);
 EnableItem(menu, item5);

 CheckItem(menu, item1, false);
 CheckItem(menu, item2, false);
 CheckItem(menu, item3, false);
 CheckItem(menu, item5, false);
 CheckItem(menu, 
 fMacTutorCurDoc->GetItemSelected(),
 true);
} // AdjustMenus

void TMacTutorApp::DoMenuCommand
 (short menuID, short menuItem)
{
 short  itemHit;
 Str255 daName;
 short  daRefNum;
 WindowPtrwindow;
 TMacTutorDocument* fMacTutorCurDoc = 
 (TMacTutorDocument*) fCurDoc;

 window = FrontWindow();
 switch ( menuID )
   {
 case mApple:
 switch ( menuItem )
   {
 case iAbout:    // About box
 itemHit = Alert(rAboutAlert, nil);
 break;
 default: // DAs etc.
 GetItem(GetMHandle(mApple),
 menuItem, daName);
 daRefNum =
 OpenDeskAcc(daName);
 break;
   }
 break;
 case mFile:
 switch ( menuItem )
   {
 case iNew:
 DoNew(); break;
 case iClose:
 if (fMacTutorCurDoc != nil)
   {
 fDocList->RemoveDoc
 (fMacTutorCurDoc);
 delete fMacTutorCurDoc;
   }
 else CloseDeskAcc(
((WindowPeek) fWhichWindow)->windowKind);
 break;
 case iQuit:
 Terminate(); break;
   }
 break;
 case mEdit: 
 if ( !SystemEdit(menuItem-1) )
   {
 switch ( menuItem )
   {
 case iCut: break;
 case iCopy:break;
 case iPaste:  break;
 case iClear:  break;
    }
   }
 break;
 case myMenu:
 if (fMacTutorCurDoc != nil) 
 {
 switch ( menuItem )
   {
 case item1:
 fMacTutorCurDoc->
 SetDisplayString(“\pC++”);
 break;
 case item2:
 fMacTutorCurDoc->
 SetDisplayString(“\pSample”);
 break;
 case item3:
 fMacTutorCurDoc->
 SetDisplayString(“\pApplication”);
 break;
 case item5:
 fMacTutorCurDoc->
 SetDisplayString(“\pHave Fun”);
 break;
    }
 fMacTutorCurDoc->
 SetItemSelected(menuItem);
 InvalRect(&(window->portRect));
 fMacTutorCurDoc->DoUpdate();
 }
 break;
   }
 HiliteMenu(0);
} // DoMenuCommand


void TMacTutorApp::EventLoop(void)
 // Apple’s C++ mini-application example
 // defines the TApplication class from which
 // we derived TMacTutorApp. Here we 
 // override the event loop to accommodate
 // high level events. TApplication’s source 
 // code doesn’t interest us at all.
{
 int gotEvent;
 EventRecord tEvt;

 SetUp(); // call setup routine
 DoIdle();// do idle once

 while (fDone == false)
   {
 fWhichWindow = FrontWindow();
 fCurDoc = fDocList->
 FindDoc(fWhichWindow);
 SetPort(fWhichWindow);

 DoIdle();// call idle time handler
 
 if (fHaveWaitNextEvent)
   {
 gotEvent = WaitNextEvent(everyEvent,
 &tEvt, SleepVal(), fMouseRgn);
   }
 else
   {
 SystemTask();
 gotEvent = GetNextEvent
 (everyEvent, &tEvt);
   }
 fTheEvent = tEvt;

 if ( gotEvent )
   {
 AdjustCursor();
 switch (fTheEvent.what)
   {
 case mouseDown :
 DoMouseDown();  break;
 case mouseUp :
 DoMouseUp();    break;
 case keyDown :
 case autoKey :
 DoKeyDown();    break;
 case updateEvt :
 DoUpdateEvt();  break;
 case diskEvt :
 DoDiskEvt();    break;
 case activateEvt :
 DoActivateEvt();break;
 case kHighLevelEvent : // JL 9/91
 DoHighLevelEvent(); // added
 break; // code
 case kOSEvent :
 DoOSEvent();    break;
 default :break;
   } // end switch (fTheEvent.what)
   }
 AdjustCursor();
   }
 // call cleanup handler
 CleanUp();
}


// main is the entrypoint to the program
int main(void)
{
 gTheApplication = new TMacTutorApp;
 if (gTheApplication == nil)
   return 0;// go back to Finder
 gTheApplication->EventLoop();
 return 0;
}

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

Bartender 3.0.32 - Organize your menu-ba...
Bartender lets you organize your menu-bar apps by hiding them, rearranging them, or moving them to Bartender's Bar. You can display the full menu bar, set options to have menu-bar items show in the... Read more
Adobe Animate CC 2018 18.0.1.115 - Anima...
Animate CC 2018 is available as part of Adobe Creative Cloud for as little as $19.99/month (or $9.99/month if you're a previous Flash Professional customer). Animate CC 2018 (was Flash CC) lets you... Read more
Adobe Lightroom Classic CC 7.1 - Import,...
Adobe Lightroom is available as part of Adobe Creative Cloud for as little as $9.99/month bundled with Photoshop CC as part of the photography package. Lightroom 6 is also available for purchase as a... Read more
ExpanDrive 6.1.8 - Access cloud storage...
ExpanDrive builds cloud storage in every application, acts just like a USB drive plugged into your Mac. With ExpanDrive, you can securely access any remote file server directly from the Finder or... Read more
ExpanDrive 6.1.8 - Access cloud storage...
ExpanDrive builds cloud storage in every application, acts just like a USB drive plugged into your Mac. With ExpanDrive, you can securely access any remote file server directly from the Finder or... Read more
DiskCatalogMaker 7.2.7 - Catalog your di...
DiskCatalogMaker is a simple disk management tool which catalogs disks. Simple, light-weight, and fast Finder-like intuitive look and feel Super-fast search algorithm Can compress catalog data for... Read more
DiskCatalogMaker 7.2.7 - Catalog your di...
DiskCatalogMaker is a simple disk management tool which catalogs disks. Simple, light-weight, and fast Finder-like intuitive look and feel Super-fast search algorithm Can compress catalog data for... Read more
Iridient Developer 3.2.1 - Powerful imag...
Iridient Developer (was RAW Developer) is a powerful image-conversion application designed specifically for OS X. Iridient Developer gives advanced photographers total control over every aspect of... Read more
BusyContacts 1.2.7 - Fast, efficient con...
BusyContacts is a contact manager for OS X that makes creating, finding, and managing contacts faster and more efficient. It brings to contact management the same power, flexibility, and sharing... Read more
MegaSeg 6.0.5 - Professional DJ and radi...
MegaSeg is a complete solution for pro audio/video DJ mixing, radio automation, and music scheduling with rock-solid performance and an easy-to-use design. Mix with visual waveforms and Magic... Read more

Latest Forum Discussions

See All

The best deals on the App Store this wee...
A new week means new discounts on the App Store. This week's deals run the gamut of action-adventure titles, puzzle games, and one of the best narrative adventure series out there. If you're looking to fill out your mobile gaming library on a... | Read more »
What you need to know about Animal Cross...
We hope you've been hard at work on collecting all of those holiday items in Animal Crossing: Pocket Camp, because you're about to get a whole new list of fun things to do as the game receives its first big update sometime soon. There are a lot of... | Read more »
Reigns: Her Majesty guide - how to use e...
Ruling a kingdom isn't easy--doubly so for a queen whose every decision is questioned by the other factions seeking a slice of power. Reigns: Her Majesty builds on the original game's swipey tactics, adding items that you can use to move the story... | Read more »
The best new games we played this week -...
Friday has crept up on us once again, so it's time to honor the best new games we've played over the past few days. This past week was a pretty exciting one, with the debut of lots of beautiful new indies and some familiar faces returning to the... | Read more »
Portal Knights guide- beginner tips and...
Portal Knights is finally making the jump to iOS and Android, and it's already climbing the ranks to become the next big MMO experience on mobile. This sprawling sandbox game will let you pursue any adventure you wish, whether you want to sling... | Read more »
Reigns: Her Majesty guide - how to swipe...
Reigns: Her Majesty is storming the App Store this week, bringing more tinder-esque kingdom building to eager players everywhere. If you've played the original Reigns, you'll know that leading a kingdom is never easy. It's a careful balancing act... | Read more »
Getting Over It (Games)
Getting Over It 1.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0 (iTunes) Description: A game I madeFor a certain kind of person To hurt them. • Climb up an enormous mountain with nothing but a hammer and a pot.•... | Read more »
Reigns: Her Majesty (Games)
Reigns: Her Majesty 1.0 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0 (iTunes) Description: | Read more »
Pocket Legends Adventures guide - how to...
Pocket Legends Adventures is a fun action adventure RPG that takes control when you want it to, but also opens itself for player input, too, if you're looking to tkae a more active role in combat. Regardless of play style, the game can be quite... | Read more »
Portal Knights (Games)
Portal Knights 1.2.4 Device: iOS Universal Category: Games Price: $4.99, Version: 1.2.4 (iTunes) Description: Craft your adventure. Forge your hero. Become the ultimate Portal Knight! | Read more »

Price Scanner via MacPrices.net

Green Monday deal: 15″ 2.8GHz MacBook Pro on...
B&H Photo has the 15″ 2.8GHz Space Gray MacBook Pro on sale for $250 off MSRP for today only as part of their Green Monday/Holiday sale. Shipping is free, and B&H charges sales tax for NY... Read more
Green Monday sale: B&H offers 12″ Apple i...
B&H Photo has 12″ iPad Pros on sale for up to $150 off MSRP as part of their Green Monday/Holiday sale. Shipping is free, and B&H charges sales tax in NY & NJ only: – 12″ 64GB WiFi iPad... Read more
Holiday deal: 21″ and 27″ Apple iMacs on sale...
MacMall has 2017 21″ and 27″ Apple iMacs on sale for up to $200 off MSRP. Shipping is free: – 21″ 2.3GHz iMac: $999 $100 off MSRP – 21″ 3.0GHz iMac: $1199 $100 off MSRP – 21″ 3.4GHz iMac: $1379 $120... Read more
Holiday deal: Apple Mac minis for up to $150...
MacMall has Mac minis on sale for up to $100 off MSRP, each including free shipping: – 1.4GHz Mac mini: $399 $100 off MSRP – 2.6GHz Mac mini: $599 $100 off MSRP – 2.8GHz Mac mini: $949 $50 off MSRP... Read more
Beats by Dr. Dre – BeatsX Earphones on sale f...
Best Buy has BeatsX Earphones on sale for $109, $40 off, on their online store. Sale price for online orders only. Choose free store pickup, if available, or choose free shipping. Read more
10″ 64GB WiFi Apple iPad Pros on sale for $59...
MacMall has 10.5″ 64GB Apple iPad Pros on sale for $599 including free shipping. That’s $50 off MSRP and among the lowest prices available for these iPads from any Apple reseller. Read more
15″ 2.2GHz MacBook Pros on sale for $200-$300...
B&H Photo has the 15″ 2.2GHz MacBook Pro available for $200 off MSRP including free shipping plus NY & NJ sales tax only: – 15″ 2.2GHz MacBook Pro (MJLQ2LL/A): $1799 $200 off MSRP Apple has... Read more
Holiday sale: 15″ MacBook Pros for $200-$420...
MacMall has 15″ MacBook Pros on sale for $220-$300 off MSRP, each including free shipping: – 15″ 2.8GHz MacBook Pro Space Gray (MPTR2LL/A): $2179, $220 off MSRP – 15″ 2.8GHz MacBook Pro Silver (... Read more
Holiday sale: 13″ MacBook Airs for up to $150...
B&H Photo has 13″ MacBook Airs on sale for $100 off MSRP as part of their Holiday sale. Shipping is free, and B&H charges sales tax for NY & NJ residents only: – 13″ 1.8GHz/128GB MacBook... Read more
The best Holiday sale prices on 13″ MacBook P...
B&H Photo has 13″ MacBook Pros on sale this weekend, with models available for $100-$150 off MSRP. Shipping is free, and B&H charges sales tax for NY & NJ residents only: – 13-inch 2.3GHz... Read more

Jobs Board

*Apple* Retail - Multiple Positions - Apple,...
Job Description:SalesSpecialist - Retail Customer Service and SalesTransform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
*Apple* Retail - Multiple Positions - Apple,...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
*Apple* Retail - Multiple Positions - Apple,...
Job Description:SalesSpecialist - Retail Customer Service and SalesTransform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
*Apple* Information Security - Security Data...
# Apple Information Security - Security Data Analyst Job Number: 113119545 Austin, Texas, United States Posted: 10-Nov-2017 Weekly Hours: 40.00 **Job Summary** This Read more
*Apple* Retail - Multiple Positions - Apple,...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.