TweetFollow Us on Twitter

Required Events
Volume Number:10
Issue Number:12
Column Tag:Getting Started

Related Info: Apple Event Mgr

The Required Apple Events

Supporting them is easy

By Dave Mark, MacTech Magazine Regular Contributing Author

Note: Source code files accompanying article are located on MacTech CD-ROM or source code disks.

In last month’s column, I told you about a new class library we’ll be using as the basis for much of the software featured in this column. Ihope to bring you some Sprocket material starting next month. In the meantime, we’ve gotten a lot of requests for some code that handles the four required Apple events. That’s what this month’s column is all about.

The Required Apple Events

In the old days (before System 7), when a user double-clicked on a document, the Finder first looked up the document’s creator and type in its desktop database to figure out which application to launch. It then packaged information about the document (or set of documents if the user double-clicked on more than one) in a data structure, launched the appropriate application and passed the data structure to the application. To access this data structure, the application called the routine CountAppFiles() (to find out how many documents it needs to open or print) then, for each one, it called GetAppFiles() (to get the information necessary to open the file) and either opened or printed the file.

That model is no longer supported in the Power Mac interface files. It’s also way outdated. While existing applications which use the AppFiles method are supported as a compatibility feature of the system, any new code written these days should support the current Apple event scheme. When you mark your application as a modern, with-it application supporting high-level events, launching an application follows a different path. When a user opens a document, the Finder still uses the file’s creator and type to locate the right application to launch, but that’s where the similarity ends. Once the application is launched, the Finder sends it a series of Apple events.

• If the application was launched by itself, with no documents, the Finder sends it an Open Application Apple event. This tells the application to do its standard initialization and assume that no documents were opened. In response to an Open Application Apple event, the application will usually create a new, untitled document.

• If a document or set of documents were used to launch the application, the Finder packages descriptions of the documents in a data structure know as a descriptor, adds the descriptor to an Open Document Apple event, then sends the event to the application. When the application gets an Open Document event, it pulls the list of documents from the event and opens each document.

• If the user asked the Finder to print, rather than open a document or set of documents, the Finder follows the exact same procedure, but sends a Print Document Apple event instead of an Open Document event. In response to a Print Document Apple event, the application prints the document rather than opening it.

• Finally, if the Finder wants an application to quit (perhaps the user selected Shutdown from the Special menu) it sends the application a Quit Application Apple event. When the application gets a quit application event, it does whatever housekeeping it needs to do in preparation for quitting, then sets the global flag that allows it to drop out of the main event loop and exit.

These events are the four required Apple events. As the name implies, your application must handle these events. There are a couple of other situations where your application might receive one of these events.

For starters, any application can package and send an Apple event. If you own a recent copy of QuicKeys, you’ve got everything you need to build and send Apple events. If you install AppleScript, you can use the Script Editor to write scripts that get translated into Apple events. If you make your application recordable (so that the user can record your application’s actions using the Script Editor, or any other Apple event recording application) you’ll wrap all of your program’s actions in individual Apple events. This means that when the user selects Open from the File menu, you’ll send yourself an Open Document Apple event. If the user quits, you’ll send yourself a Quit Application event.

In addition to the events described above, there are other situations in which the Finder will send you one of the four required Apple events. If the user double-clicks on (or otherwise opens) one of your application’s documents, the Finder will package the document in an Open Document Apple event and send the event to your application. The same is true for the Print Document Apple event.

The user can also drag a document onto your application’s icon. If your application is set up to handle that type of document, your application’s icon will invert and, when the user let’s go of the mouse, the Finder will embed the document in an Open Document Apple event and send the event to your application. Note that this technique can be used to launch your application or to request that your application open a document once it is already running.

Apple Event Handlers

Apple events are placed in an event queue, much like the events you already know, love, and process, such as mouseDown, activateEvt, and updateEvt. So far, the events you’ve been handling have all been low-level events, the direct result of a user’s actions. The user uncovers a portion of a window, an updateEvt is generated. The user clicks the mouse button, a mouseDown is generated.

Apple events, on the other hand, are known as high-level events, the result of interprocess communication instead of user-process communication. As you process events retrieved by WaitNextEvent(), you’ll take action based on the value in the event’s what field. If the what field contains the constant updateEvt, you’ll call your update handling routine, etc. If the what field contains the constant kHighLevelEvent, you’ll pass the event to the routine AEProcessAppleEvent():


/* 1 */
switch ( eventPtr->what )
{
 case mouseDown: 
 HandleMouseDown( eventPtr );
 break;
 case keyDown:
 case autoKey:
 theChar = eventPtr->message & charCodeMask;
 if ( (eventPtr->modifiers & cmdKey) != 0 ) 
 HandleMenuChoice( MenuKey( theChar ) );
 break;
 case updateEvt:
 DoUpdate( eventPtr );
 break;
 case kHighLevelEvent:
 AEProcessAppleEvent( eventPtr );
 break;
}

AEProcessAppleEvent() passes the event to the Apple event handler you’ve written specifically for that event. To handle the four required events, you’ll write four Apple event handlers. You’ll install the handlers at initialization time by passing the address of each handler (in the form of a universal-procedure-pointer) to AEInstallEventHandler(). AEProcessAppleEvent() calls your handler for you automatically. Once your handler is installed your work is done.

This Month’s Program: AEHandler

This month’s program, AEHandler, provides a skeleton you can use to add the required Apple events to your own programs. We’ll start off by creating the AEHandler resources. Create a folder called AEHandler in your development folder. Launch ResEdit and create a new file called AEHandler.Π.rsrc in the AEHandler folder.

1) Create an MBAR resource with an ID of 128 containing the MENU IDs 128, 129, and 130.

2) Use the specs in Figure 1 to create three MENU resources with IDs of 128, 129, and 130.

Figure 1. The three MENUs used by AEHandler.

3) Create a WIND resource with an ID of 128, having a top of 41, a left of 3, a bottom of 91, and a right of 303. Use the standard document proc (left-most in a ResEdit editing pane).

4) Copy the standard error alert from one of our previous programs. If you don’t have one, create an ALRT with an ID of 128, a top of 40, left of 40, bottom of 156, and right of 332. Next, create a DITL with an ID of 128 and two items. Item 1 is an OK button with a top of 86, a left of 219, a bottom of 106, and a right of 279. Item 2 is a static text item just like the one shown in Figure 2.

Figure 2. The static text item for the error alert.

That covers the standard resources. Next come the resources that link specific document types to our application and that tie a set of small and large icons to our application. The Finder uses these resources to display an icon that represents our application in different situations (a large icon when the app is on the desktop, a small icon to display in the right-most corner of the menu bar when our app is front-most). The Finder uses the non-icon resources to update its desktop database.

5) Create a new BNDL resource with a resource ID of 128. When the BNDL editing window appears in ResEdit, select Extended View from the BNDL menu. This gives you access to some additional fields.

6) Put your application’s four-byte signature in the Signature: field. Every time you create a new application, you’ll have to come up with a unique four-byte string unique to your application. To verify that the signature is unique, you’ll need to send it to the AppleLink address DEVSUPPORT. If you don’t have a signature handy, feel free to use mine (DM=a). I’ve registered it for one of my applications but since it’s not an application I distribute, you won’t run into any conflicts.

To register your creator/file types with Apple, you’ll need to fill out a special request form and send it in to the AppleLink address DEVSUPPORT. Here’s where you can find the form:

• AppleLink™ network (Developer Support:Developer Services:Developer Technical Support:Often used DTS Forms:Creator/File Type Form)

• Your monthly Developer CD (Apple Information Resources:Developer Info Assistant:Developer forms:Creator/File Type form)

• Internet: ftp.apple.com (IP address 130.43.2.3) using the path /ftp/dts/mac/registration/.

7) Put 0 in the BNDL’s ID field.

8) Put a copyright string in the © String field. This string will appear in the Finder’s get info window for your application.

9) Select New File Type from the Resource menu. Use the specifications in Figure 3 to fill out the information for the APPL file type. This ties the first row of icons to the application itself. To edit the icons, double-click on the icon area and ResEdit will open an icon family editing window.

Figure 3. The AEHandler BNDL resource.

10) Back in the BNDL editing window, select New File Type again to add a second row of file types to the BNDL window. This time use the specs in Figure 3 to fill out the info for files of type TEXT. By doing this, we’ve told the finder that files with the signature ‘DM=a’ and of type ‘TEXT’ belong to the application AEHandler. Once again, double-click on the icon family to edit the individual icons.

If your application will support file types belonging to other applications, create file type entries in the BNDL resource for them as well, but don’t edit the icons - leave them blank.

In addition, be aware that the Finder uses the file type entries to determine what files can drop launch your application. Right now, the Finder will only let you drop launch files with the signature ‘DM=a’ and of type ‘TEXT’ on AEHandler. To make AEHandler respond to all file types, create a new file type entry with the file type ‘****’. Don’t edit the icons - leave them blank.

11) Save your changes and close the resource file.

12) In ResEdit, create a new resource file called test.text.

13) Select Get Info for test.text from the File menu.

14) When the info window appears, set the file’s type to TEXT and its creator to whatever signature you used (if you used mine, it’s DM=a).

That’s it. Save your changes, quit ResEdit, and let’s create the project.

Creating the AEHandler Project

Pick your favorite development environment and create a new project called AEHandler.Π, saving it in the AEHandler folder. Immediately edit your project type info (In THINK C, select Set Project Type... from the Project menu. In Code Warrior, pick the Project icon in the Preferences dialog). Set the project’s creator to the creator you used (mine was ‘DM=a’). Next, be sure to set the High-Level Event Aware flag in the SIZE resource flags. If you don’t do this, the Apple Event Manager won’t call your handlers!

Next, add either MacTraps or MacOS.lib to your project. Then, create a new source code file, save it as AEHandler.c and add it to your project. Here’s the source code:


/* 2 */
#include <GestaltEqu.h>
#include <AppleEvents.h>

#define kBaseResID 128
#define kErrorALRTid 128
#define kWINDResID 128

#define kVisible true
#define kMoveToFront (WindowPtr)-1L
#define kSleep   60L
#define kNilFilterProc    0L
#define kGestaltMask 1L
#define kKeepInSamePlane  false

#define kWindowStartX20
#define kWindowStartY50

#define mApple   kBaseResID
#define iAbout   1

#define mFile    kBaseResID+1
#define iClose   1
#define iQuit    3


Globals

Boolean gDone;
short   gNewWindowX = kWindowStartX,
 gNewWindowY = kWindowStartY;

Functions

void    ToolboxInit( void );
void    MenuBarInit( void );
void    AEInit( void );
void    AEInstallHandlers( void );
pascal OSErr DoOpenApp(   AppleEvent *event, 
 AppleEvent *reply, long refcon );
pascal OSErr DoOpenDoc(   AppleEvent *event, 
 AppleEvent *reply, long refcon );
OSErr CheckForRequiredParams( AppleEvent *event );
pascal OSErr DoPrintDoc(  AppleEvent *event, 
 AppleEvent *reply, long refcon );
pascal OSErr DoQuitApp(   AppleEvent *event, 
 AppleEvent *reply, long refcon );
void    OpenDocument( FSSpec *fileSpecPtr );
WindowPtr CreateWindow( Str255 name );
void    DoCloseWindow( WindowPtr window );
void    EventLoop( void );
void    DoEvent( EventRecord *eventPtr );
void    HandleMouseDown( EventRecord *eventPtr );
void    HandleMenuChoice( long menuChoice );
void    HandleAppleChoice( short item );
void    HandleFileChoice( short item );
void    DoUpdate( EventRecord *eventPtr );
void    DoError( Str255 errorString );


main
void  main( void )
{
 ToolboxInit();
 MenuBarInit();
 AEInit();
 
 EventLoop();
}


ToolboxInit

void  ToolboxInit( void )
{
 InitGraf( &qd.thePort );
 InitFonts();
 InitWindows();
 InitMenus();
 TEInit();
 InitDialogs( 0L );
 InitCursor();
}


MenuBarInit
void  MenuBarInit( void )
{
 Handle menuBar;
 MenuHandle menu;
 
 menuBar = GetNewMBar( kBaseResID );
 
 if ( menuBar == NULL )
 DoError( "\pCouldn't load the MBAR resource..." );
 
 SetMenuBar( menuBar );

 menu = GetMHandle( mApple );

 AddResMenu( menu, 'DRVR' );
 
 DrawMenuBar();
}


AEInit
void  AEInit( void )
{
 OSErr  err;
 long feature;
 
 err = Gestalt( gestaltAppleEventsAttr, &feature );
 
 if ( err != noErr )
 DoError( "\pError returned by Gestalt!" );
 
 if (   !( feature 
 & ( kGestaltMask << gestaltAppleEventsPresent ) ) )
 DoError("\pThis configuration does not support Apple events...");
 
 AEInstallHandlers();
}


AEInstallHandlers
void  AEInstallHandlers( void )
{
 OSErr  err;
 
 err = AEInstallEventHandler( kCoreEventClass, 
 kAEOpenApplication,
 NewAEEventHandlerProc( DoOpenApp ), 0L, false );
 
 if ( err != noErr )
 DoError( "\pError installing 'oapp' handler..." );
 
 err = AEInstallEventHandler( kCoreEventClass, 
 kAEOpenDocuments,
 NewAEEventHandlerProc( DoOpenDoc ), 0L, false );
 
 if ( err != noErr )
 DoError( "\pError installing 'odoc' handler..." );
 
 err = AEInstallEventHandler( kCoreEventClass, 
 kAEPrintDocuments,
 NewAEEventHandlerProc( DoPrintDoc ), 0L, false );
 
 if ( err != noErr )
 DoError( "\pError installing 'pdoc' handler..." );
 
 err = AEInstallEventHandler( kCoreEventClass, 
 kAEQuitApplication,
 NewAEEventHandlerProc( DoQuitApp ), 0L, false );
 
 if ( err != noErr )
 DoError( "\pError installing 'quit' handler..." );
}


DoOpenApp

pascal OSErrDoOpenApp( AppleEvent *event, 
 AppleEvent *reply, long refcon )
{
 OpenDocument( nil );
 
 return noErr;
}


DoOpenDoc

pascal OSErrDoOpenDoc( AppleEvent *event, 
 AppleEvent *reply, long refcon )
{
 OSErr  err;
 FSSpec fileSpec;
 long   i, numDocs;
 DescType returnedType;
 AEKeywordkeywd;
 Size   actualSize;
 AEDescList docList = { typeNull, nil };

 // get the direct parameter--a descriptor list--and put
 // it into docList
 err = AEGetParamDesc( event, keyDirectObject,
 typeAEList, &docList);

 // check for missing required parameters
 err = CheckForRequiredParams( event );
 if ( err )
 {
 // an error occurred:  do the necessary error handling
 err = AEDisposeDesc( &docList );
 return err;
 }

 // count the number of descriptor records in the list
 // should be at least 1 since we got called and no error
 err = AECountItems( &docList, &numDocs );
 
 if ( err )
 {
 // an error occurred:  do the necessary error handling
 err = AEDisposeDesc( &docList );
 return err;
 }

 // now get each descriptor record from the list, coerce
 // the returned data to an FSSpec record, and open the
 // associated file
 for ( i=1; i<=numDocs; i++ )
 {
 err = AEGetNthPtr( &docList, i, typeFSS, &keywd,
 &returnedType, (Ptr)&fileSpec,
 sizeof( fileSpec ), &actualSize );

 OpenDocument( &fileSpec );
 }

 err = AEDisposeDesc( &docList );

 return err;
}


CheckForRequiredParams

OSErr CheckForRequiredParams( AppleEvent *event )
{
 DescType returnedType;
 Size   actualSize;
 OSErr  err;

 err = AEGetAttributePtr( event, keyMissedKeywordAttr,
 typeWildCard, &returnedType,
 nil, 0, &actualSize);

 if ( err == errAEDescNotFound ) // you got all the required
 //parameters
 return noErr;
 else
 if ( err == noErr )      // you missed a required parameter
 return errAEParamMissed;
 else   // the call to AEGetAttributePtr failed
 return err;
}


DoPrintDoc

pascal OSErrDoPrintDoc(   AppleEvent *event, 
 AppleEvent *reply, long refcon )
{
 return noErr;
}

DoQuitApp
pascal OSErrDoQuitApp(  AppleEvent *event, 
 AppleEvent *reply, long refcon )
{
 SysBeep( 20 );
 gDone = true;
 
 return noErr;
}

OpenDocument

void  OpenDocument( FSSpec *fileSpecPtr )
{
 WindowPtrwindow;
 
 if ( fileSpecPtr == nil )
 window = CreateWindow( "\p<Untitled>" );
 else
 window = CreateWindow( fileSpecPtr->name );
}


CreateWindow

WindowPtr CreateWindow( Str255 name )
{
 WindowPtrwindow;
 short  windowWidth, windowHeight;
 
 window = GetNewWindow( kWINDResID, nil, kMoveToFront );
 
 SetWTitle( window, name );
 
 MoveWindow( window, gNewWindowX, gNewWindowY, 
  kKeepInSamePlane );
 
 gNewWindowX += 20;
 windowWidth = window->portRect.right 
 - window->portRect.left;
 
 if ( gNewWindowX + windowWidth > qd.screenBits.bounds.right )
 {
 gNewWindowX = kWindowStartX;
 gNewWindowY = kWindowStartY;
 }
 
 gNewWindowY += 20;
 windowHeight = window->portRect.bottom 
 - window->portRect.top;
 
 if ( gNewWindowY + windowHeight > 
 qd.screenBits.bounds.bottom )
 {
 gNewWindowX = kWindowStartX;
 gNewWindowY = kWindowStartY;
 }
 
 ShowWindow( window );
 SetPort( window );
 
 return window;
}


DoCloseWindow

void  DoCloseWindow( WindowPtr window )
{
 if ( window != nil )
 DisposeWindow( window );
}


EventLoop

void  EventLoop( void )
{
 EventRecordevent;
 
 gDone = false;
 while ( gDone == false )
 {
 if ( WaitNextEvent( everyEvent, &event, kSleep, nil ) )
 DoEvent( &event );
 }
}



DoEvent

void  DoEvent( EventRecord *eventPtr )
{
 char   theChar;
 
 switch ( eventPtr->what )
 {
 case mouseDown: 
 HandleMouseDown( eventPtr );
 break;
 case keyDown:
 case autoKey:
 theChar = eventPtr->message & charCodeMask;
 if ( (eventPtr->modifiers & cmdKey) != 0 ) 
 HandleMenuChoice( MenuKey( theChar ) );
 break;
 case updateEvt:
 DoUpdate( eventPtr );
 break;
 case kHighLevelEvent:
 AEProcessAppleEvent( eventPtr );
 break;
 }
}


HandleMouseDown

void  HandleMouseDown( EventRecord *eventPtr )
{
 WindowPtrwindow;
 short  thePart;
 long   menuChoice;
 
 thePart = FindWindow( eventPtr->where, &window );
 
 switch ( thePart )
 {
 case inMenuBar:
 menuChoice = MenuSelect( eventPtr->where );
 HandleMenuChoice( menuChoice );
 break;
 case inSysWindow : 
 SystemClick( eventPtr, window );
 break;
 case inGoAway:
 if ( TrackGoAway( window, eventPtr->where ) )
 DoCloseWindow( window );
 break;
 case inContent:
 SelectWindow( window );
 break;
 case inDrag : 
 DragWindow( window, eventPtr->where, &qd.screenBits.bounds );
 break;
 }
}


HandleMenuChoice

void  HandleMenuChoice( long menuChoice )
{
 short  menu;
 short  item;
 
 if ( menuChoice != 0 )
 {
 menu = HiWord( menuChoice );
 item = LoWord( menuChoice );
 
 switch ( menu )
 {
 case mApple:
 HandleAppleChoice( item );
 break;
 case mFile:
 HandleFileChoice( item );
 break;
 }
 HiliteMenu( 0 );
 }
}


HandleAppleChoice

void  HandleAppleChoice( short item )
{
 MenuHandle appleMenu;
 Str255 accName;
 short  accNumber;
 
 switch ( item )
 {
 case iAbout:
 SysBeep( 20 );
 break;
 default:
 appleMenu = GetMHandle( mApple );
 GetItem( appleMenu, item, accName );
 accNumber = OpenDeskAcc( accName );
 break;
 }
}

HandleFileChoice

void  HandleFileChoice( short item )
{
 switch ( item )
 {
 case iClose:
 DoCloseWindow( FrontWindow() );
 break;
 case iQuit:
 gDone = true;
 break;
 }
}


DoUpdate

void  DoUpdate( EventRecord *eventPtr )
{
 WindowPtrwindow;
 
 window = (WindowPtr)eventPtr->message;
 
 BeginUpdate(window);
 EndUpdate(window);
}


DoError

void  DoError( Str255 errorString )
{
 ParamText( errorString, "\p", "\p", "\p" );
 
 StopAlert( kErrorALRTid, kNilFilterProc );
 
 ExitToShell();
}

Running AEHandler

Save your code, then build AEHandler as an application (In MetroWerks, just run the application) and then run it. An untitled window should appear. If it didn’t, go back and check your SIZE resource to make sure the High-Level-Event Aware flag is set.

As you look through the code, you’ll see that the untitled window is created by the Open Application handler. Now double click on the file test.text. A window titled test.text should appear. This window was created by the Open Documents handler.

With AEHandler still running, go into the Finder and select Shutdown from the Special menu. The Finder should bring AEHandler to the front and send it a Quit Application Apple event. Our Quit Application handler beeps once then sets gDone to true. When you quit normally, you won’t hear this beep.

Till Next Month

Hopefully, next month will bring the first Sprocket column. Till then, read up on the Apple Event Manager. Play around with the AEHandler code. Add some code to the Open Document handler to open the specified file and display info about the file in its window (maybe the file’s size). If you are interested in learning more about Apple events, check out the first few chapters of Ultimate Mac Programming, due out in January from IDG Books. See you next month

 
AAPL
$112.94
Apple Inc.
+1.16
MSFT
$47.98
Microsoft Corpora
+0.32
GOOG
$524.87
Google Inc.
+8.52

MacTech Search:
Community Search:

Software Updates via MacUpdate

NeoOffice 2014.6 - Mac-tailored, OpenOff...
NeoOffice is a complete office suite for OS X. With NeoOffice, users can view, edit, and save OpenOffice documents, PDF files, and most Microsoft Word, Excel, and PowerPoint documents. NeoOffice 3.x... Read more
LibreOffice 4.3.5.2 - Free Open Source o...
LibreOffice is an office suite (word processor, spreadsheet, presentations, drawing tool) compatible with other major office suites. The Document Foundation is coordinating development and... Read more
CleanApp 5.0.0 Beta 5 - Application dein...
CleanApp is an application deinstaller and archiver.... Your hard drive gets fuller day by day, but do you know why? CleanApp 5 provides you with insights how to reclaim disk space. There are... Read more
Monolingual 1.6.2 - Remove unwanted OS X...
Monolingual is a program for removing unnecesary language resources from OS X, in order to reclaim several hundred megabytes of disk space. It requires a 64-bit capable Intel-based Mac and at least... Read more
NetShade 6.1 - Browse privately using an...
NetShade is an Internet security tool that conceals your IP address on the web. NetShade routes your Web connection through either a public anonymous proxy server, or one of NetShade's own dedicated... Read more
calibre 2.13 - Complete e-library manage...
Calibre is a complete e-book library manager. Organize your collection, convert your books to multiple formats, and sync with all of your devices. Let Calibre be your multi-tasking digital librarian... Read more
Mellel 3.3.7 - Powerful word processor w...
Mellel is the leading word processor for OS X and has been widely considered the industry standard since its inception. Mellel focuses on writers and scholars for technical writing and multilingual... Read more
ScreenFlow 5.0.1 - Create screen recordi...
Save 10% with the exclusive MacUpdate coupon code: AFMacUpdate10 Buy now! ScreenFlow is powerful, easy-to-use screencasting software for the Mac. With ScreenFlow you can record the contents of your... Read more
Simon 4.0 - Monitor changes and crashes...
Simon monitors websites and alerts you of crashes and changes. Select pages to monitor, choose your alert options, and customize your settings. Simon does the rest. Keep a watchful eye on your... Read more
BBEdit 11.0.2 - Powerful text and HTML e...
BBEdit is the leading professional HTML and text editor for the Mac. Specifically crafted in response to the needs of Web authors and software developers, this award-winning product provides a... Read more

Latest Forum Discussions

See All

This Week at 148Apps: December 15-19, 20...
Happy Holidays from 148Apps!   How do you know what apps are worth your time and money? Just look to the review team at 148Apps. We sort through the chaos and find the apps you’re looking for. The ones we love become Editor’s Choice, standing out... | Read more »
New Version of Tempo Smart Calendar Help...
New Version of Tempo Smart Calendar Helps You Plan Your Day Without Opening the App Posted by Jessica Fisher on December 22nd, 2014 [ permalink ] | Read more »
Sparkle - Advanced Cross-Synthesis (Mus...
Sparkle - Advanced Cross-Synthesis 1.0 Device: iOS Universal Category: Music Price: $6.99, Version: 1.0 (iTunes) Description: Sparkle is a tool for advanced spectral hybridizations made of several algorithms that operate on frequency... | Read more »
DICETINY is coming to iOS in 2015
DICETINY is coming to iOS in 2015 Posted by Jessica Fisher on December 22nd, 2014 [ permalink ] Fakedice has announced that they’re bringing their digital board game DICETINY to iOS. | Read more »
It Came From Canada: The Witcher Battle...
The Witcher 3: Wild Hunt may still be a few months away, but very soon players will be able to get a new taste of the acclaimed Polish RPG on their mobile devices with The Witcher Battle Arena. While it trades open-world exploration for compact... | Read more »
The Babies Get Lost Again in the New Azt...
The Babies Get Lost Again in the New Aztec Ruins Update for Light in the Dark Posted by Jessica Fisher on December 22nd, 2014 [ permalink ] | Read more »
Living Room 3D for IKEA Makes All In-App...
Living Room 3D for IKEA Makes All In-App Purchases Free Until 2015 Posted by Jessica Fisher on December 22nd, 2014 [ permalink ] | Read more »
Crossbow Warrior – The Legend of William...
Crossbow Warrior – The Legend of William Tell Review By Lee Hamlet on December 22nd, 2014 Our Rating: :: MISSES THE MARKUniversal App - Designed for iPhone and iPad Crossbow Warrior details the entertaining adventures of legendary... | Read more »
A New Update Races onto Asphalt 8: Airbo...
A New Update Races onto Asphalt 8: Airborne Posted by Jessica Fisher on December 22nd, 2014 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
Workflow: Powerful Automation Made Simpl...
Workflow: Powerful Automation Made Simple Review By Campbell Bird on December 22nd, 2014 Our Rating: :: GO WITH THE FLOWUniversal App - Designed for iPhone and iPad This powerful app lets users accomplish multiple tasks at touch of... | Read more »

Price Scanner via MacPrices.net

13-inch 2.4GHz Retina MacBook Pro (Apple refu...
The Apple Store has previous-generation Apple Certified Refurbished 13″ 2.4GHz/128GB Retina MacBook Pros available for $999. Apple’s one-year warranty is standard, and shipping is free: - 13″ 2.4GHz/... Read more
Apple resellers offer free overnight shipping
The Apple Store is now offering free next-day shipping on all in stock items if ordered before 12/23/14 at 10:00am PT. Local store pickup is also available within an hour of ordering for any in stock... Read more
Holiday sales continue: MacBook Airs for up t...
 B&H Photo has 2014 MacBook Airs on sale for up to $120 off MSRP, for a limited time, for the Thanksgiving/Christmas Holiday shopping season. Shipping is free, and B&H charges NY sales tax... Read more
Holiday sale continues: 13-inch Retina MacBoo...
 B&H Photo has new 13″ MacBook Pros on sale for up to $150 off MSRP as part of their Holiday pricing. Shipping is free, and B&H charges NY sales tax only: - 13″ 2.5GHz MacBook Pro: $979 save... Read more
Holiday sale continues: 15-inch Retina MacBoo...
 B&H Photo has the new 2014 15″ Retina MacBook Pros on sale for up to $300 off MSRP for a limited time. Shipping is free, and B&H charges NY sales tax only: - 15″ 2.2GHz Retina MacBook Pro: $... Read more
Holiday sale: 13-inch 128GB MacBook Air for $...
 Best Buy has the 2014 13-inch 1.4GHz 128GB MacBook Air on sale for $849.99, or $150 off MSRP, on their online store. Choose free home shipping or free local store pickup (if available). Price valid... Read more
13-inch 2.6GHz Retina MacBook Pro on sale for...
Best Buy has lowered their price on the 2014 13″ 2.6GHz/128GB Retina MacBook Pro to $1149.99 on their online store for a limited time. That’s $150 off MSRP and the lowest price available for this... Read more
Kodak Returns to CES With New Consumer Produ...
Former photography colossus Kodak is returning to CES for the first time in three years where the Kodak booth (#21818 South Hall 1) will showcase a wide range of innovative, imaging-related products... Read more
Invaluable Launches New Eponymously -Named A...
Invaluable, the world’s largest online live auction marketplace, hhas announced the official launch of the Invaluable app for iPad, now available for download in the iTunes App Store. Invaluable... Read more
IDC Reveals Worldwide Mobile Enterprise Appli...
International Data Corporation (IDC) last week hosted the IDC FutureScape: Worldwide Mobile Enterprise Applications and Solutions 2015 Predictions Web conference. The session provided organizations... Read more

Jobs Board

*Apple* Store Leader Program (US) - Apple, I...
…Summary Learn and grow as you explore the art of leadership at the Apple Store. You'll master our retail business inside and out through training, hands-on experience, Read more
Project Manager, *Apple* Financial Services...
**Job Summary** Apple Financial Services (AFS) offers consumers, businesses and educational institutions ways to finance Apple purchases. We work with national and Read more
*Apple* Retail - Multiple Positions (US) - A...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
*Apple* Retail - Multiple Positions (US) - A...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
*Apple* Retail - Multiple Positions (US) - A...
Job Description: Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.